@dx-do/cli 5.2.49 → 5.2.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -6
- package/dist-node/01-discover-vertices.tas-pwngv2fz.md +31 -0
- package/dist-node/01-discover-vertices.tas.data-store-svjfrm1f.json5 +29 -0
- package/dist-node/01-discover-vertices.tas.data-store-tmd-w650nfzt.json +4 -0
- package/dist-node/02-discover-services.tas-867m0m88.md +30 -0
- package/dist-node/02-discover-services.tas.data-store-jz0gx5vn.json5 +40 -0
- package/dist-node/02-discover-services.tas.data-store-tmd-eq264m6y.json +4 -0
- package/dist-node/03-discover-sources.nassql-4tgp9jvv.md +34 -0
- package/dist-node/03-discover-sources.nassql.data-store-by6sqk23.json5 +63 -0
- package/dist-node/03-discover-sources.nassql.data-store-tmd-n3gy57wm.json +4 -0
- package/dist-node/04-discover-metadata-columns.nassql-vhzb0mrq.md +26 -0
- package/dist-node/04-discover-metadata-columns.nassql.data-store-c9zr7p0q.json5 +35 -0
- package/dist-node/04-discover-metadata-columns.nassql.data-store-tmd-4ygrjvty.json +4 -0
- package/dist-node/10-filter-attribute-matches.tas-tafqmtw1.md +33 -0
- package/dist-node/10-filter-attribute-matches.tas.data-store-tmd-m2sendv0.json +4 -0
- package/dist-node/10-filter-attribute-matches.tas.data-store-whdc6vbc.json5 +35 -0
- package/dist-node/11-filter-and-compose.tas-m8856738.md +29 -0
- package/dist-node/11-filter-and-compose.tas.data-store-dh5meyk8.json5 +56 -0
- package/dist-node/11-filter-and-compose.tas.data-store-tmd-mfn8a16f.json +4 -0
- package/dist-node/12-filter-or-not.tas-21zab96s.md +35 -0
- package/dist-node/12-filter-or-not.tas.data-store-7vjr4fnd.json5 +83 -0
- package/dist-node/12-filter-or-not.tas.data-store-tmd-am9smwe5.json +4 -0
- package/dist-node/13-filter-layer.tas-r1ff5anv.md +29 -0
- package/dist-node/13-filter-layer.tas.data-store-5mneyz77.json5 +30 -0
- package/dist-node/13-filter-layer.tas.data-store-tmd-9qmhyfzr.json +4 -0
- package/dist-node/14-filter-traverse.tas-da9jene0.md +38 -0
- package/dist-node/14-filter-traverse.tas.data-store-p0vxtfvj.json5 +63 -0
- package/dist-node/14-filter-traverse.tas.data-store-tmd-5hepg5wf.json +4 -0
- package/dist-node/15-filter-take-vertices-edges.tas-m160qc7z.md +35 -0
- package/dist-node/15-filter-take-vertices-edges.tas.data-store-drmcme43.json5 +46 -0
- package/dist-node/15-filter-take-vertices-edges.tas.data-store-tmd-8fewsp5s.json +4 -0
- package/dist-node/16-filter-projection.tas-dh39mcx8.md +31 -0
- package/dist-node/16-filter-projection.tas.data-store-tmd-3r8anggx.json +4 -0
- package/dist-node/16-filter-projection.tas.data-store-xjbdry1x.json5 +36 -0
- package/dist-node/17-filter-lucene.tas-gyvtzwaa.md +29 -0
- package/dist-node/17-filter-lucene.tas.data-store-1knw6srt.json5 +39 -0
- package/dist-node/17-filter-lucene.tas.data-store-tmd-5cf3tygg.json +5 -0
- package/dist-node/18-filter-variable-reuse.tas-89fq0y6x.md +46 -0
- package/dist-node/18-filter-variable-reuse.tas.data-store-by35113t.json5 +55 -0
- package/dist-node/18-filter-variable-reuse.tas.data-store-tmd-ak7aprgk.json +4 -0
- package/dist-node/19-filter-order-statefilter.tas-hm3z71qj.md +36 -0
- package/dist-node/19-filter-order-statefilter.tas.data-store-ra9hj1rz.json5 +51 -0
- package/dist-node/19-filter-order-statefilter.tas.data-store-tmd-wqer9xy2.json +4 -0
- package/dist-node/20-nassql-from-metadata-basic.nassql-szr2xax1.md +28 -0
- package/dist-node/20-nassql-from-metadata-basic.nassql.data-store-tmd-c7drxs1m.json +4 -0
- package/dist-node/20-nassql-from-metadata-basic.nassql.data-store-zdf1gp1v.json5 +42 -0
- package/dist-node/21-nassql-from-metadata-regex.nassql-78jnsn3e.md +30 -0
- package/dist-node/21-nassql-from-metadata-regex.nassql.data-store-ckzsv7h1.json5 +53 -0
- package/dist-node/21-nassql-from-metadata-regex.nassql.data-store-tmd-zgr6r9my.json +4 -0
- package/dist-node/22-nassql-from-topology.nassql-a71qw9r0.md +42 -0
- package/dist-node/22-nassql-from-topology.nassql.data-store-81m23nge.json5 +58 -0
- package/dist-node/22-nassql-from-topology.nassql.data-store-tmd-vhpjy6c7.json +4 -0
- package/dist-node/23-nassql-join-topology-metadata.nassql-hywxhcg2.md +35 -0
- package/dist-node/23-nassql-join-topology-metadata.nassql.data-store-da7q90n2.json5 +76 -0
- package/dist-node/23-nassql-join-topology-metadata.nassql.data-store-tmd-rr8wt9qa.json +4 -0
- package/dist-node/24-nassql-from-data-window-mean.nassql-q6qsgdxw.md +33 -0
- package/dist-node/24-nassql-from-data-window-mean.nassql.data-store-j7xmg7fc.json5 +81 -0
- package/dist-node/24-nassql-from-data-window-mean.nassql.data-store-tmd-qgzz2f7v.json +4 -0
- package/dist-node/25-nassql-group-order-top.nassql-awgnwn3r.md +30 -0
- package/dist-node/25-nassql-group-order-top.nassql.data-store-cmrn300b.json5 +48 -0
- package/dist-node/25-nassql-group-order-top.nassql.data-store-tmd-7xpqeh7c.json +4 -0
- package/dist-node/26-nassql-filter-predicate.nassql-2t27h5ev.md +41 -0
- package/dist-node/26-nassql-filter-predicate.nassql.data-store-k2rgp609.json5 +59 -0
- package/dist-node/26-nassql-filter-predicate.nassql.data-store-tmd-m4dddgwm.json +4 -0
- package/dist-node/27-nassql-distinct-keep.nassql-6z55dvk3.md +24 -0
- package/dist-node/27-nassql-distinct-keep.nassql.data-store-mrx00ys5.json5 +52 -0
- package/dist-node/27-nassql-distinct-keep.nassql.data-store-tmd-0p9hy42g.json +4 -0
- package/dist-node/28-nassql-format-time.nassql-6wraqgdk.md +30 -0
- package/dist-node/28-nassql-format-time.nassql.data-store-tmd-bbbqhz1x.json +4 -0
- package/dist-node/28-nassql-format-time.nassql.data-store-tvy8y2cs.json5 +59 -0
- package/dist-node/29-nassql-describe-log.nassql-t9vnxeb0.md +31 -0
- package/dist-node/29-nassql-describe-log.nassql.data-store-tmd-q4mtczy8.json +4 -0
- package/dist-node/29-nassql-describe-log.nassql.data-store-x16y4crx.json5 +51 -0
- package/dist-node/30-nassql-map-string.nassql-f2tdknzs.md +30 -0
- package/dist-node/30-nassql-map-string.nassql.data-store-t8ahcabn.json5 +53 -0
- package/dist-node/30-nassql-map-string.nassql.data-store-tmd-a6xq0bdx.json +4 -0
- package/dist-node/31-nassql-join-data-sum.nassql-p16y3xk6.md +26 -0
- package/dist-node/31-nassql-join-data-sum.nassql.data-store-dje7wm6v.json5 +64 -0
- package/dist-node/31-nassql-join-data-sum.nassql.data-store-tmd-c1pyx1qw.json +4 -0
- package/dist-node/32-nassql-bottom-aggregation.nassql-hpgfn77p.md +26 -0
- package/dist-node/32-nassql-bottom-aggregation.nassql.data-store-tmd-p0ssj1vc.json +4 -0
- package/dist-node/32-nassql-bottom-aggregation.nassql.data-store-v9580caa.json5 +43 -0
- package/dist-node/33-nassql-cross-domain-pipeline.nassql-fm0ynphf.md +45 -0
- package/dist-node/33-nassql-cross-domain-pipeline.nassql.data-store-tmd-18881drs.json +4 -0
- package/dist-node/33-nassql-cross-domain-pipeline.nassql.data-store-vqs9hkx4.json5 +79 -0
- package/dist-node/3rdpartylicenses-hx59bakt.txt +885 -0
- package/dist-node/50-discover-custom-layers.tas-2hvvpkzw.md +66 -0
- package/dist-node/50-discover-custom-layers.tas.data-store-h85zgna9.json5 +36 -0
- package/dist-node/50-discover-custom-layers.tas.data-store-tmd-hagn9eak.json +4 -0
- package/dist-node/51-collect-counts-everything.tas-nz0ksgdc.md +46 -0
- package/dist-node/51-collect-counts-everything.tas.data-store-eypcjah8.json5 +48 -0
- package/dist-node/51-collect-counts-everything.tas.data-store-tmd-4pcj94s9.json +4 -0
- package/dist-node/52-collect-counts-bulk.tas-eerw4z8s.md +54 -0
- package/dist-node/52-collect-counts-bulk.tas.data-store-scedtw1m.json5 +65 -0
- package/dist-node/52-collect-counts-bulk.tas.data-store-tmd-csyzj189.json +4 -0
- package/dist-node/53-collect-attributes-by-type.tas-cw0285hx.md +71 -0
- package/dist-node/53-collect-attributes-by-type.tas.data-store-fvjge4yr.json5 +65 -0
- package/dist-node/53-collect-attributes-by-type.tas.data-store-tmd-274qrd8f.json +4 -0
- package/dist-node/README-ghxecaz0.md +84 -0
- package/dist-node/SKILL-1xn7r9nt.md +104 -0
- package/dist-node/agent-25q752kd.md +55 -0
- package/dist-node/agent_connection_and_status-0dq7zkpc.md +62 -0
- package/dist-node/agent_source_collector-6s06n3rs.md +40 -0
- package/dist-node/agentic-mcp-rycd2gh8.md +140 -0
- package/dist-node/application-dfva8tz0.md +48 -0
- package/dist-node/application-m0q2vaxj.md +74 -0
- package/dist-node/attribute_resource_metric_name-pxrceab5.md +56 -0
- package/dist-node/browseragent-snippet.template-9megjp8a.html +12 -0
- package/dist-node/bulkvertexpatch-1a4qy5vb.md +78 -0
- package/dist-node/bundle.pbd-38r15kyd.template +13 -0
- package/dist-node/bundle.profile-1wpzpt3d.template +2 -0
- package/dist-node/business_transaction-mbqz5ex9.md +61 -0
- package/dist-node/chunk-4I3HBO6U-2ebgf7kh.js +127 -0
- package/dist-node/chunk-4PMCLJMS-0mqvr4m4.js +1 -0
- package/dist-node/chunk-5VSFINOX-ewzpx7wh.js +5 -0
- package/dist-node/chunk-72HYG3XZ-kf7hy4vs.js +3625 -0
- package/dist-node/chunk-JRM4BLOM-rg32z8w4.js +1 -0
- package/dist-node/chunk-Q2JA73UH-akkb8bh3.js +14 -0
- package/dist-node/chunk-RNMHSXZF-pdwasrg7.js +1358 -0
- package/dist-node/chunk-VV2FJEMA-3rvtkmga.js +321 -0
- package/dist-node/chunk-YVD3UK5I-9pxr1jka.js +695 -0
- package/dist-node/configuration-1vczsdex.md +104 -0
- package/dist-node/dashboards-x0xddksy.md +17 -0
- package/dist-node/database_or_inferred-8vqf5gyr.md +75 -0
- package/dist-node/default-licensing-config-0p879qpb.template +122 -0
- package/dist-node/dependency-3b0neg5x.md +40 -0
- package/dist-node/description.md-qwc2bj9r.template +30 -0
- package/dist-node/discovery-flow-fw79kbx4.md +116 -0
- package/dist-node/dxi_service-13prnpd5.md +59 -0
- package/dist-node/entity-relationships-cevz61kj.md +142 -0
- package/dist-node/gotchas-8ab64kcd.md +389 -0
- package/dist-node/host-es6fxtgx.md +46 -0
- package/dist-node/host-j3qqrm5f.md +55 -0
- package/dist-node/index-104hyb1m.html +13 -0
- package/dist-node/index-7fp2dfas.json +178 -0
- package/dist-node/index-g3hh5wez.json +403 -0
- package/dist-node/index-mbzg9rhc.json +270 -0
- package/dist-node/index-qffdhwgm.json +2479 -0
- package/dist-node/inferred-w998vfq1.md +41 -0
- package/dist-node/installInstructions.md-k9ghf3dr.template +21 -0
- package/dist-node/inventorize-xc9h9bjr.md +34 -0
- package/dist-node/investigation-planning-6kcm01h9.md +149 -0
- package/dist-node/investigator-flow-jc2s0n46.md +186 -0
- package/dist-node/k8s_deployment_and_namespace-69c29152.md +88 -0
- package/dist-node/k8s_pod_and_container-9h4v6cmj.md +64 -0
- package/dist-node/main-SGLYO5YX-ht69eb0y.js +13 -0
- package/dist-node/main.js +397415 -0
- package/dist-node/marketplace-srdmzxkj.json +15 -0
- package/dist-node/metric-source-names-6cbczyks.md +75 -0
- package/dist-node/metrics-grounding-2h4kkbe3.md +130 -0
- package/dist-node/mm-cookbook-23jpw721.md +231 -0
- package/dist-node/mm-quickstart-x2adfc16.md +106 -0
- package/dist-node/nassql-cookbook-n8kc0mff.md +812 -0
- package/dist-node/nassql-quickstart-090e0yex.md +149 -0
- package/dist-node/plugin-c3bavxvf.json +18 -0
- package/dist-node/polyfills-A7ZF72EO-mp884a0b.js +2 -0
- package/dist-node/prerendered-routes-523d8gat.json +3 -0
- package/dist-node/primeicons-4GST5W3O-jac3wxrf.woff2 +0 -0
- package/dist-node/primeicons-DHQU4SEP-760n99pp.svg +345 -0
- package/dist-node/primeicons-GEFHGEHP-rc4kaa3b.ttf +0 -0
- package/dist-node/primeicons-P53SE5CV-4saz3d5j.woff +0 -0
- package/dist-node/primeicons-RSSEDYLY-4d4vbd67.eot +0 -0
- package/dist-node/query-vs-analysis-separation-sag1ezcq.md +97 -0
- package/dist-node/run-query-vs-run-partial-6138pc94.md +80 -0
- package/dist-node/service-5pz5nhzf.md +133 -0
- package/dist-node/service-hierarchies-87a4ynpj.md +178 -0
- package/dist-node/service-k4f5mkbq.md +51 -0
- package/dist-node/servlet_or_frontend-1kjcb7ar.md +76 -0
- package/dist-node/src-apm-mfnsq6vw.svg +4 -0
- package/dist-node/src-axa-nn28yqmj.svg +4 -0
- package/dist-node/src-dxim-fv7ne4qa.svg +4 -0
- package/dist-node/styles-23VUPSCU-9ehggc1f.css +1 -0
- package/dist-node/tas-cookbook-0y4826rp.md +693 -0
- package/dist-node/tas-quickstart-wgcvwffc.md +138 -0
- package/dist-node/time-format-0595g01j.md +41 -0
- package/dist-node/toggles.pbd-9wscbmng.template +2 -0
- package/dist-node/type-host-agbhmn6v.svg +6 -0
- package/dist-node/type-metric-p9b90bpx.svg +4 -0
- package/dist-node/type-service-k7f1x71k.svg +4 -0
- package/dist-node/ui-0b5grqrg.md +113 -0
- package/dist-node/universe-b9nhf325.md +47 -0
- package/dist-node/universe-fzpwzvxr.md +91 -0
- package/dist-node/universes-and-scopes-1cb9pfk7.md +105 -0
- package/dist-node/vertex_entity_node-mm3yp9d0.md +31 -0
- package/package.json +1 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# 50-discover-custom-layers (TAS)
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Find all vertices whose layer is **not** one of the built-in DataStore layers. This surfaces custom integration layers that third-party or internal connectors may use when writing their entities to the topology graph.
|
|
6
|
+
|
|
7
|
+
## Query Construction
|
|
8
|
+
|
|
9
|
+
Wraps a `LAYER` filter (using the multi-value `values` array) in a `NOT` filter:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
NOT(
|
|
13
|
+
LAYER(values: ["ATC", "UIM", "APM_INFRASTRUCTURE", "INFRASTRUCTURE",
|
|
14
|
+
"SA", "ACN", "CONNECTOR_METADATA", "ACN_CONFIGURATION"])
|
|
15
|
+
)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The `LAYER` filter with `values` performs an OR match across all listed layer names. `NOT` inverts this, selecting every vertex whose layer is absent from the list. The result set therefore contains only vertices on unknown/custom layers.
|
|
19
|
+
|
|
20
|
+
The exclusion list is the union of:
|
|
21
|
+
- **Java API constants** (`TasConstants`): `ATC`, `APM_INFRASTRUCTURE`, `SA`, `ACN`
|
|
22
|
+
- **`Layer` class static instances**: `ATC`, `UIM`, `APM_INFRASTRUCTURE`, `INFRASTRUCTURE`
|
|
23
|
+
- **Conditional but server-recognized** (appear when the tenant uses connectors that publish to them): `CONNECTOR_METADATA`, `ACN_CONFIGURATION`
|
|
24
|
+
|
|
25
|
+
## API Surface Exercised
|
|
26
|
+
|
|
27
|
+
- **Filter**: `NOT` — inverts any inner filter result
|
|
28
|
+
- **Filter**: `LAYER` with `values` (array) — multi-layer OR match
|
|
29
|
+
- Together these form the idiomatic "exclude known layers" pattern; there is no native `NOT_LAYER` op
|
|
30
|
+
|
|
31
|
+
## Expected Output
|
|
32
|
+
|
|
33
|
+
Up to 200 vertices with `DETAILED` projection. For each vertex inspect:
|
|
34
|
+
- `externalId` — the first colon-delimited segment is the custom layer name
|
|
35
|
+
- `attributes.type` — the vertex type registered by the integration
|
|
36
|
+
|
|
37
|
+
If the tenant has no custom integrations, the result will be empty (0 vertices).
|
|
38
|
+
|
|
39
|
+
A typical result on a tenant with one or two integrations might look like:
|
|
40
|
+
|
|
41
|
+
| Layer | Vertex count | Sample externalId prefix |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `CUSTOM` | tens | `CUSTOM:LOGANALYTICS\|…` |
|
|
44
|
+
| `INFRASTRUCTURE_UIM` | tens | `INFRASTRUCTURE_UIM:OpenAccess_…` |
|
|
45
|
+
| `NETWORK_SPECTRUM` | tens | `NETWORK_SPECTRUM:<entity-id>` |
|
|
46
|
+
|
|
47
|
+
To enumerate distinct custom layer names from any result file:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
python3 -c "
|
|
51
|
+
import json
|
|
52
|
+
with open('packages/.tmp/output/datastore-driver/<dir>/<TENANT>_50-discover-custom-layers.tas.data-store.result.json') as f:
|
|
53
|
+
data = json.load(f)
|
|
54
|
+
layers = sorted({v.get('externalId','').split(':')[0] for v in data['vertices']})
|
|
55
|
+
print('Custom layers found:', layers)
|
|
56
|
+
"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## What the Results Tell You
|
|
60
|
+
|
|
61
|
+
Any layer name that appears here was written by an integration that is not part of the core DataStore product. Common examples include:
|
|
62
|
+
- Cloud-provider collectors (e.g., `AWS`, `AZURE`, `GCP` specific namespaces)
|
|
63
|
+
- Custom on-premise connectors
|
|
64
|
+
- Partner integrations that declare their own namespace
|
|
65
|
+
|
|
66
|
+
Once you know the custom layer names, you can query them directly with a targeted `LAYER` filter (see query 13 for the pattern).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Find vertices in CUSTOM (non-standard) topology layers — i.e.
|
|
3
|
+
* anything written by integrations that aren't part of the core
|
|
4
|
+
* DataStore product. Pattern: NOT(LAYER(values: <known layers>))
|
|
5
|
+
* — invert the filter against the known-standard set.
|
|
6
|
+
*
|
|
7
|
+
* The exclusion list combines:
|
|
8
|
+
* - Java API constants (TasConstants): ATC, APM_INFRASTRUCTURE,
|
|
9
|
+
* SA, ACN
|
|
10
|
+
* - `Layer` class static instances: ATC, UIM, APM_INFRASTRUCTURE,
|
|
11
|
+
* INFRASTRUCTURE
|
|
12
|
+
* - Conditional but server-recognized (appear when the tenant
|
|
13
|
+
* uses connectors that publish to them): CONNECTOR_METADATA,
|
|
14
|
+
* ACN_CONFIGURATION
|
|
15
|
+
*
|
|
16
|
+
* Result-set on a tenant with integrations: typically tens of
|
|
17
|
+
* vertices across a handful of partner-defined layers
|
|
18
|
+
* (NETWORK_SPECTRUM, INFRASTRUCTURE_UIM, CUSTOM, etc.). Empty on
|
|
19
|
+
* tenants without integrations.
|
|
20
|
+
*/
|
|
21
|
+
{
|
|
22
|
+
/*
|
|
23
|
+
* NOT-wrapping a LAYER-with-values is the idiomatic "anything
|
|
24
|
+
* NOT in this layer set" pattern. There is no native `NOT_LAYER`
|
|
25
|
+
* op; this is the canonical replacement.
|
|
26
|
+
*/
|
|
27
|
+
"filter": {
|
|
28
|
+
"op": "NOT",
|
|
29
|
+
"input": {
|
|
30
|
+
"op": "LAYER",
|
|
31
|
+
"values": ["ATC", "UIM", "APM_INFRASTRUCTURE", "INFRASTRUCTURE", "SA", "ACN", "CONNECTOR_METADATA", "ACN_CONFIGURATION"]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"limit": 200,
|
|
35
|
+
"projection": "DETAILED"
|
|
36
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# 51-collect-counts-everything (TAS)
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Answer "how many vertices does this tenant have?" in a single round trip without paying the wire cost of the actual vertex set. The right thing to run before deciding whether to dump a tenant's full topology to a UI / agent / file — small tenants might be 1k vertices, big ones can hit 500k.
|
|
6
|
+
|
|
7
|
+
> **MCP shortcut:** the same answer is one call away via `discovery_entity_count`. Use the shortcut when you just need the number; come back here when you want to see the underlying TAS pattern (so you can adapt it — same shape with `ALL` swapped for any vertex-shaped filter gives a count for that subset).
|
|
8
|
+
|
|
9
|
+
## Query Construction
|
|
10
|
+
|
|
11
|
+
The query composes three ops, outside-in:
|
|
12
|
+
|
|
13
|
+
1. `EMPTY` — pass-through wrapper that forces the final result vertex set to be empty.
|
|
14
|
+
2. `COLLECT_COUNTS` — analytic op that records its input's vertex count under a named `id` and emits it on `result.analytics[]`. Otherwise pass-through.
|
|
15
|
+
3. `ALL` — every vertex in the tenant.
|
|
16
|
+
|
|
17
|
+
The inner pipeline counts everything; the outer `EMPTY` drops the vertex set so only the analytic crosses the wire. Response is under 200 bytes regardless of tenant size.
|
|
18
|
+
|
|
19
|
+
## API Surface Exercised
|
|
20
|
+
|
|
21
|
+
- **EMPTY**: drop the final vertex set; keep analytics. Useful any time you only want aggregate metadata, not the vertices themselves.
|
|
22
|
+
- **COLLECT_COUNTS**: cheap pass-through analytic. Records `{ id, vertexCount }` on `result.analytics[]`. The `id` is your read-key — use a stable string you can match against when multiple analytics are emitted.
|
|
23
|
+
- **ALL**: matches every vertex in the tenant.
|
|
24
|
+
|
|
25
|
+
## Expected Output
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"vertices": [],
|
|
30
|
+
"edges": [],
|
|
31
|
+
"analytics": [
|
|
32
|
+
{ "t": "COLLECT_COUNTS", "id": "EVERYTHING", "vertexCount": 1718 }
|
|
33
|
+
],
|
|
34
|
+
"totalVertices": 0,
|
|
35
|
+
"totalEdges": 0,
|
|
36
|
+
"nextOffset": -1
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`vertices` and `edges` are empty by design (the EMPTY wrapper). The analytic carries the count.
|
|
41
|
+
|
|
42
|
+
## What the Results Tell You
|
|
43
|
+
|
|
44
|
+
`vertexCount` is the total live vertex count in the tenant at query time. Tenants under ~5k vertices can usually be loaded whole into a graph visualizer; bigger tenants need scoping (by service, by type, by neighborhood traversal) before a full-topology load is worth attempting.
|
|
45
|
+
|
|
46
|
+
This pattern generalizes — replace `ALL` with any vertex-shaped filter and you get a count for that subset. See `52-collect-counts-bulk` for the bulk-fan-in extension that gets multiple counts in a single query.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Pre-flight tenant-size probe — answer "how many vertices does
|
|
3
|
+
* this tenant have?" in one cheap analytic-only round trip. No
|
|
4
|
+
* vertices on the wire, just a single number.
|
|
5
|
+
*
|
|
6
|
+
* Pattern: EMPTY > COLLECT_COUNTS > ALL.
|
|
7
|
+
* - ALL produces every vertex.
|
|
8
|
+
* - COLLECT_COUNTS records the count as an analytic (it's a
|
|
9
|
+
* pass-through op, so vertices flow through unchanged).
|
|
10
|
+
* - EMPTY drops the vertex set on the way out so the response
|
|
11
|
+
* is just `{ analytics: [{ t: "COLLECT_COUNTS", id, vertexCount }] }`.
|
|
12
|
+
*
|
|
13
|
+
* Response is < 200 bytes regardless of tenant size — 100 vertices
|
|
14
|
+
* or 500,000. Use this BEFORE deciding whether to dump the whole
|
|
15
|
+
* topology to a UI / agent / file.
|
|
16
|
+
*/
|
|
17
|
+
{
|
|
18
|
+
"filter": {
|
|
19
|
+
/*
|
|
20
|
+
* EMPTY — pass-through "force-empty-output" wrapper. The inner
|
|
21
|
+
* filter still runs (and any analytics inside still emit), but
|
|
22
|
+
* the final vertex set returned to the client is empty.
|
|
23
|
+
*/
|
|
24
|
+
"op": "EMPTY",
|
|
25
|
+
"input": {
|
|
26
|
+
/*
|
|
27
|
+
* COLLECT_COUNTS — analytic pass-through. Records
|
|
28
|
+
* `vertexCount` for whatever its `input` produces, keyed by
|
|
29
|
+
* the unique `id`. Read it back from `result.analytics[]`.
|
|
30
|
+
*/
|
|
31
|
+
"op": "COLLECT_COUNTS",
|
|
32
|
+
"id": "EVERYTHING",
|
|
33
|
+
"input": {
|
|
34
|
+
/*
|
|
35
|
+
* ALL — every vertex in the tenant. Pair with
|
|
36
|
+
* COLLECT_COUNTS to get the total tenant size.
|
|
37
|
+
*/
|
|
38
|
+
"op": "ALL"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
/*
|
|
43
|
+
* `limit: 1` is symbolic here — EMPTY drops the vertex set
|
|
44
|
+
* regardless. Some servers reject `limit: 0`, so 1 is the
|
|
45
|
+
* conventional placeholder for "I don't want any vertices".
|
|
46
|
+
*/
|
|
47
|
+
"limit": 1
|
|
48
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# 52-collect-counts-bulk (TAS)
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Get N vertex counts (per type, per service, per layer — whatever the axis) in a single round trip instead of N parallel queries. The pattern that makes "count per service" UIs feasible on tenants with hundreds of services without a request storm.
|
|
6
|
+
|
|
7
|
+
> **MCP shortcut for the per-service case:** `discovery_service_counts` returns `{services: [{id, name, count, childServiceNames}]}` in one call — it composes this exact `OR(COLLECT_COUNTS(SERVICE([name])))` query over the OI service catalog (and batches by 200 names so it scales past the multi-thousand-service tenants). Reach for the shortcut for the per-service axis; reach for the underlying pattern (this query) when you want counts on a different axis (per-type, per-layer, per-traversal-result, …).
|
|
8
|
+
|
|
9
|
+
## Query Construction
|
|
10
|
+
|
|
11
|
+
Three ops, nested:
|
|
12
|
+
|
|
13
|
+
1. `EMPTY` — drop the final vertex set; keep the analytics.
|
|
14
|
+
2. `OR` — compose multiple branches under one filter tree. Each branch produces a vertex set; OR returns their union. (The union is discarded by EMPTY — we don't actually want it.)
|
|
15
|
+
3. Each branch is a `COLLECT_COUNTS` analytic with a unique `id`, wrapping whatever vertex-shaped filter defines its slice.
|
|
16
|
+
|
|
17
|
+
The example uses three branches:
|
|
18
|
+
- `count:host` — vertices with `type = HOST`
|
|
19
|
+
- `count:agent` — vertices with `type = AGENT`
|
|
20
|
+
- `count:all` — every vertex (`ALL`)
|
|
21
|
+
|
|
22
|
+
The inner filter for each branch can be anything — `SERVICE`, `LAYER`, `LUCENE`, `ATTRIBUTE`, `TRAVERSE`, even another nested composition. Each branch's analytic is independent.
|
|
23
|
+
|
|
24
|
+
## API Surface Exercised
|
|
25
|
+
|
|
26
|
+
- **EMPTY**: as in `51-collect-counts-everything` — discard the vertex set, keep analytics.
|
|
27
|
+
- **OR**: composes multiple sub-filters under one tree. Each branch runs in parallel inside the server, sharing the same query-plan context.
|
|
28
|
+
- **COLLECT_COUNTS** with unique `id` per branch: each one emits an independent analytic entry.
|
|
29
|
+
|
|
30
|
+
## Expected Output
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"vertices": [],
|
|
35
|
+
"edges": [],
|
|
36
|
+
"analytics": [
|
|
37
|
+
{ "t": "COLLECT_COUNTS", "id": "count:host", "vertexCount": 32 },
|
|
38
|
+
{ "t": "COLLECT_COUNTS", "id": "count:agent", "vertexCount": 96 },
|
|
39
|
+
{ "t": "COLLECT_COUNTS", "id": "count:all", "vertexCount": 1718 }
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Read the per-branch counts back by matching on `id`. Order isn't guaranteed — always look up by id, don't rely on positional indexing.
|
|
45
|
+
|
|
46
|
+
## What the Results Tell You
|
|
47
|
+
|
|
48
|
+
How big each slice is, before you commit to fetching its vertices. Concretely:
|
|
49
|
+
|
|
50
|
+
- A "service picker" UI can render `Service Foo · 175 entities` rows for hundreds of services on the strength of one query — no need to issue one query per service.
|
|
51
|
+
- A "topology summary" tool can answer "how is this tenant composed?" with one query: count by type, count by layer, count by source-product.
|
|
52
|
+
- A scoping decision (e.g. "should I load this neighborhood or just sample it?") can call this once with the proposed filter to know the size before committing.
|
|
53
|
+
|
|
54
|
+
The fan-in trick is the load-bearing pattern — without it, count-per-X UIs default to N parallel queries, which scales poorly with N. The unique-id-per-branch contract is non-negotiable; reusing an id silently collapses the analytics.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Bulk count probe — multiple `COLLECT_COUNTS` analytics in a
|
|
3
|
+
* SINGLE round trip via `OR` composition. Each branch contributes
|
|
4
|
+
* its own analytic to `result.analytics[]`, keyed by a unique `id`.
|
|
5
|
+
*
|
|
6
|
+
* Use this any time you'd otherwise loop over N filters running
|
|
7
|
+
* one COLLECT_COUNTS each. Counts per type, per layer, per service,
|
|
8
|
+
* per attribute value — all collapse into one query. The inner
|
|
9
|
+
* `OR` produces a UNION of vertex sets but the outer `EMPTY`
|
|
10
|
+
* discards that — only the analytics matter.
|
|
11
|
+
*
|
|
12
|
+
* The example below counts HOSTs, AGENTs, and the total tenant
|
|
13
|
+
* vertices in one query. Swap the inner ATTRIBUTE filters for
|
|
14
|
+
* SERVICE / LAYER / LUCENE / TRAVERSE / etc. to count along any
|
|
15
|
+
* axis you care about.
|
|
16
|
+
*/
|
|
17
|
+
{
|
|
18
|
+
"filter": {
|
|
19
|
+
/*
|
|
20
|
+
* EMPTY drops the unioned vertex set. The analytics survive.
|
|
21
|
+
*/
|
|
22
|
+
"op": "EMPTY",
|
|
23
|
+
"input": {
|
|
24
|
+
/*
|
|
25
|
+
* OR composes multiple branches — each branch runs its own
|
|
26
|
+
* COLLECT_COUNTS over a distinct vertex slice and emits its
|
|
27
|
+
* own analytic. The OR's vertex output is the union of
|
|
28
|
+
* branch outputs, but EMPTY makes that irrelevant.
|
|
29
|
+
*
|
|
30
|
+
* Important: each COLLECT_COUNTS needs a UNIQUE `id`. Use
|
|
31
|
+
* something stable you can match against when reading the
|
|
32
|
+
* analytics back (e.g. `count:host`, `svc:42`, `layer:apm`).
|
|
33
|
+
*/
|
|
34
|
+
"op": "OR",
|
|
35
|
+
"input": [
|
|
36
|
+
{
|
|
37
|
+
"op": "COLLECT_COUNTS",
|
|
38
|
+
"id": "count:host",
|
|
39
|
+
"input": {
|
|
40
|
+
"op": "ATTRIBUTE",
|
|
41
|
+
"expressions": [
|
|
42
|
+
{ "name": "type", "operator": "IN", "values": ["HOST"] }
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"op": "COLLECT_COUNTS",
|
|
48
|
+
"id": "count:agent",
|
|
49
|
+
"input": {
|
|
50
|
+
"op": "ATTRIBUTE",
|
|
51
|
+
"expressions": [
|
|
52
|
+
{ "name": "type", "operator": "IN", "values": ["AGENT"] }
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"op": "COLLECT_COUNTS",
|
|
58
|
+
"id": "count:all",
|
|
59
|
+
"input": { "op": "ALL" }
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"limit": 1
|
|
65
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# 53-collect-attributes-by-type (TAS)
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Bucket every vertex in the tenant by its `type` attribute and get the per-value count in one query — a complete "what kinds of entities are here, and how many of each?" histogram. Companion to `COLLECT_COUNTS`:
|
|
6
|
+
|
|
7
|
+
- `COLLECT_COUNTS` — "how many?"
|
|
8
|
+
- `COLLECT_ATTRIBUTES` — "how many of each value?"
|
|
9
|
+
|
|
10
|
+
Run this on a new tenant to get the type breakdown without iterating per-type queries.
|
|
11
|
+
|
|
12
|
+
## Query Construction
|
|
13
|
+
|
|
14
|
+
Two ops:
|
|
15
|
+
|
|
16
|
+
1. `EMPTY` — drop the actual vertex set; keep the analytic.
|
|
17
|
+
2. `COLLECT_ATTRIBUTES` — for each vertex in `input`, record its value of `attributeName` and tally how many vertices share each distinct value.
|
|
18
|
+
|
|
19
|
+
`attributeName: "type"` makes this a type histogram. Swap for any attribute key — `"agent"` for an agent-name histogram, `"layer"` for a layer histogram, `"hostname"` for a hostname histogram, etc.
|
|
20
|
+
|
|
21
|
+
`input: { op: "ALL" }` runs the histogram over every vertex. Replace with a more specific filter (`SERVICE`, `LAYER`, `ATTRIBUTE`, `TRAVERSE`) to scope the histogram to a population.
|
|
22
|
+
|
|
23
|
+
## API Surface Exercised
|
|
24
|
+
|
|
25
|
+
- **EMPTY**: drop the vertex set; keep analytics. As in `51` and `52`.
|
|
26
|
+
- **COLLECT_ATTRIBUTES**: analytic op. Required: `id`, `attributeName`. Optional knobs:
|
|
27
|
+
- `layer` — restrict collection to one layer
|
|
28
|
+
- `includeIds: true` — also return `vertexIds[]` per bucket (handy when you want to drill into one without re-querying)
|
|
29
|
+
- `caseInsensitive: true` — dedupe value strings case-insensitively
|
|
30
|
+
- `skipBackends: true` — exclude backend-type vertices
|
|
31
|
+
|
|
32
|
+
## Expected Output
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"vertices": [],
|
|
37
|
+
"edges": [],
|
|
38
|
+
"analytics": [
|
|
39
|
+
{
|
|
40
|
+
"t": "COLLECT_ATTRIBUTES",
|
|
41
|
+
"id": "type-histogram",
|
|
42
|
+
"values": [
|
|
43
|
+
{
|
|
44
|
+
"attribValue": "k8s_CONTAINER",
|
|
45
|
+
"occurances": 257,
|
|
46
|
+
"alerts": 0,
|
|
47
|
+
"cautionAlerts": 0,
|
|
48
|
+
"dangerAlerts": 0,
|
|
49
|
+
"vertexIds": null
|
|
50
|
+
},
|
|
51
|
+
{ "attribValue": "k8s_POD", "occurances": 192, "alerts": 0, "cautionAlerts": 0, "dangerAlerts": 0, "vertexIds": null },
|
|
52
|
+
{ "attribValue": "GENERICFRONTEND","occurances": 144, "alerts": 0, "cautionAlerts": 0, "dangerAlerts": 0, "vertexIds": null }
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Note the canonical wire fields are `attribValue` (not `attributeValue`) and `occurances` (not `occurrences`) — both typos are baked into the Java model. Match the wire form exactly.
|
|
60
|
+
|
|
61
|
+
Each value entry also carries `alerts` / `cautionAlerts` / `dangerAlerts` (per-bucket alert counts inherited from `TasGroupingAlertStatistics`) and a `vertexIds` field that's `null` unless `includeIds: true` is set on the COLLECT_ATTRIBUTES op. The alert counts are usually `0` on tenants without a configured alarm pipeline.
|
|
62
|
+
|
|
63
|
+
## What the Results Tell You
|
|
64
|
+
|
|
65
|
+
A complete profile of what's in the tenant, by entity kind. Concretely:
|
|
66
|
+
|
|
67
|
+
- A "what's deployed?" inspection picks out the dominant types (k8s heavy? agent heavy? business-transaction heavy?) without needing to know the type vocabulary up front.
|
|
68
|
+
- An adapter that styles a graph by type can pre-allocate per-type style rules from this histogram, sized to actual cardinality.
|
|
69
|
+
- Anomaly detection: comparing the histogram across time reveals onboarded / offboarded entity classes — a tenant that grew a `MYSQL_DB` bucket overnight just connected a database collector.
|
|
70
|
+
|
|
71
|
+
The pattern generalizes. Same shape with `attributeName: "agent"` gives you a load distribution across agents. With `attributeName: "SourceProduct"` (and a population that has it), you get a per-product entity census.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Histogram-by-attribute — `COLLECT_ATTRIBUTES` over a population
|
|
3
|
+
* groups vertices by a chosen attribute and returns the per-value
|
|
4
|
+
* occurrence count. Companion to COLLECT_COUNTS:
|
|
5
|
+
*
|
|
6
|
+
* COLLECT_COUNTS — "how many?"
|
|
7
|
+
* COLLECT_ATTRIBUTES — "how many of each value?"
|
|
8
|
+
*
|
|
9
|
+
* Output entry shape (under `result.analytics[]`):
|
|
10
|
+
*
|
|
11
|
+
* {
|
|
12
|
+
* t: "COLLECT_ATTRIBUTES",
|
|
13
|
+
* id, layer?,
|
|
14
|
+
* values: [
|
|
15
|
+
* { attribValue, occurances, vertexIds? },
|
|
16
|
+
* ...
|
|
17
|
+
* ]
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* Note the canonical wire field is `attribValue` (not
|
|
21
|
+
* `attributeValue`) and `occurances` (not `occurrences`) — both
|
|
22
|
+
* are typos baked into the Java model. Match exactly.
|
|
23
|
+
*
|
|
24
|
+
* The example below buckets every vertex in the tenant by its
|
|
25
|
+
* `type` attribute, returning a complete type histogram in a
|
|
26
|
+
* single query — useful as a "what's in this tenant?" probe.
|
|
27
|
+
*/
|
|
28
|
+
{
|
|
29
|
+
"filter": {
|
|
30
|
+
/*
|
|
31
|
+
* EMPTY drops the actual vertex set so the response is just
|
|
32
|
+
* the histogram. Drop EMPTY if you want both the vertices
|
|
33
|
+
* AND the histogram in one shot — analytics flow through
|
|
34
|
+
* regardless of whether vertices reach the client.
|
|
35
|
+
*/
|
|
36
|
+
"op": "EMPTY",
|
|
37
|
+
"input": {
|
|
38
|
+
/*
|
|
39
|
+
* COLLECT_ATTRIBUTES — analytic pass-through. For each
|
|
40
|
+
* vertex in `input`, record its value of `attributeName`
|
|
41
|
+
* and tally how many vertices share it.
|
|
42
|
+
*/
|
|
43
|
+
"op": "COLLECT_ATTRIBUTES",
|
|
44
|
+
"id": "type-histogram",
|
|
45
|
+
/*
|
|
46
|
+
* `attributeName` selects which attribute's values to
|
|
47
|
+
* collect. "type" gives a type histogram; "agent" gives an
|
|
48
|
+
* agent-name histogram; any attribute key works.
|
|
49
|
+
*/
|
|
50
|
+
"attributeName": "type",
|
|
51
|
+
/*
|
|
52
|
+
* Optional knobs (omitted here):
|
|
53
|
+
* - `layer`: restrict collection to one layer
|
|
54
|
+
* - `includeIds: true`: also return `vertexIds[]` per value
|
|
55
|
+
* (use when you want to drill into a specific bucket
|
|
56
|
+
* without re-querying)
|
|
57
|
+
* - `caseInsensitive: true`: dedupe values case-insensitively
|
|
58
|
+
*/
|
|
59
|
+
"input": {
|
|
60
|
+
"op": "ALL"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"limit": 1
|
|
65
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# investigate (Claude Code plugin)
|
|
2
|
+
|
|
3
|
+
The `investigate@dx-do` plugin — for asking a DXO2 tenant investigative questions in natural language ("are there any hosts with high CPU right now?", "which services depend on host X?", "where's the noise coming from?") and having Claude carry the conversation through scope-clarification → discovery → query authoring → UI / analyzer handoff.
|
|
4
|
+
|
|
5
|
+
Lives under [`@dx-do/claude`](../README.md) — the umbrella package that hosts all dx-do Claude Code plugins.
|
|
6
|
+
|
|
7
|
+
## What you get
|
|
8
|
+
|
|
9
|
+
- **`dx-do-query` MCP server** — auto-wired at plugin enable time. 21 tools across 4 modules (discovery, corpus, datastore, ui — see `dx-do help agentic-mcp`). Corpus tools surface 5 entities, 14 cookbooks, and 29 worked-example queries shipped via `@dx-do/corpus`.
|
|
10
|
+
- **`investigator` skill** — auto-loaded summary that reaches into the corpus for the right cookbook / entity / example before authoring a query. Teaches the decision tree, schema landmines, handoff phrasing.
|
|
11
|
+
|
|
12
|
+
(Sibling skills planned in this same plugin: `analyzer` for thresholding/anomaly work on a saved query's data, `organizer` for curating the user's saved-query catalog.)
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
1. **A `dx-do` binary the plugin can find.** The plugin's MCP server entry resolves `${DXDO_BIN:-dx-do}` — so either:
|
|
17
|
+
- Set `DXDO_BIN=/path/to/your/dx-do` in your shell environment (point it at `packages/cli/dist-bun/dx-do` from a source checkout if you don't want a global install), OR
|
|
18
|
+
- Put `dx-do` on `$PATH` the conventional way: `sudo cp packages/cli/dist-bun/dx-do /usr/local/bin/dx-do && sudo chown $USER /usr/local/bin/dx-do` (the chown is required on macOS Sequoia or AMFI SIGKILLs the binary), OR
|
|
19
|
+
- npm-installed: `npx @dx-do/cli` works once `@dx-do/cli` is published.
|
|
20
|
+
|
|
21
|
+
`DXDO_BIN` is the lowest-friction option for source-checkout devs — no `sudo`, no `/usr/local/bin/` mutation, and the binary always points at whatever you most recently rebuilt under `packages/cli/dist-bun/`.
|
|
22
|
+
2. **A tenant config** at `~/.dxdo/<alias>.dxo2.config.json`. Default plugin invocation uses `default`; override with `DXDO_CONFIG_ALIAS=<your-alias>` in your shell environment before launching Claude Code.
|
|
23
|
+
|
|
24
|
+
> **About the experimental gate.** `dx-do agentic mcp` (and `dx-do ui start`) are currently marked experimental. The plugin's `plugin.json` already sets `DXDO_ENABLE_EXPERIMENTAL_COMMANDS=true` in the MCP-server spawn env, so users do **not** need to do anything special — Claude Code spawns the subprocess with the gate open. The same env var is needed if you ever invoke `dx-do agentic extract-claude-marketplace` from the shell yourself; see the install section below.
|
|
25
|
+
|
|
26
|
+
## Install — for users with the `dx-do` binary
|
|
27
|
+
|
|
28
|
+
The marketplace + this plugin are embedded in every `dx-do` binary. Extract once (the env var opens the experimental gate so the command runs):
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
DXDO_ENABLE_EXPERIMENTAL_COMMANDS=true \
|
|
32
|
+
dx-do agentic extract-claude-marketplace base-directory=~/
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Then in a Claude Code session:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
/plugin marketplace add ~/dx-do-claude-marketplace
|
|
39
|
+
/plugin install investigate@dx-do
|
|
40
|
+
/reload-plugins
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The extract command prints the exact slash-command sequence so you can copy-paste it into Claude Code. Plugin management is interactive-only — there is no shell `claude plugin install`.
|
|
44
|
+
|
|
45
|
+
## Install — source-checkout dev
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
/plugin marketplace add /Users/$USER/github/dx-do-mono/packages/claude
|
|
49
|
+
/plugin install investigate@dx-do
|
|
50
|
+
/reload-plugins
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
(`packages/claude/` already has `.claude-plugin/marketplace.json` + per-plugin subdirs — same layout extract produces.)
|
|
54
|
+
|
|
55
|
+
## Verify
|
|
56
|
+
|
|
57
|
+
After install, in a fresh Claude Code session:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
"What entities can you ground me in for the bound tenant?"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Expected: Claude invokes the `investigator` skill (visible in the skill list), calls `corpus_sections` + `corpus_list('entities')`, and surfaces the universe / service / dxi_service / host / agent entries.
|
|
64
|
+
|
|
65
|
+
If Claude doesn't reach for the skill automatically, the description trigger isn't strong enough — file a follow-up.
|
|
66
|
+
|
|
67
|
+
## What's in here
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
.claude-plugin/
|
|
71
|
+
plugin.json ← plugin manifest (mcpServers + metadata)
|
|
72
|
+
skills/
|
|
73
|
+
investigator/
|
|
74
|
+
SKILL.md ← the auto-loaded investigator skill
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The skill points at content in `@dx-do/corpus` for the rich grounding (cookbooks, entities, queries). The MCP server `dx-do-query` (from `@dx-do/ui`) is the agent's tool surface.
|
|
78
|
+
|
|
79
|
+
## Related
|
|
80
|
+
|
|
81
|
+
- [`@dx-do/claude` README](../README.md) — why one package, many plugins.
|
|
82
|
+
- `dx-do help agentic-mcp` — full tool surface + module flags.
|
|
83
|
+
- `@dx-do/corpus` — `cookbooks/`, `entities/`, `queries/` content the skill references.
|
|
84
|
+
- `~/.claude/plans/` (this Mac) — milestone plan.
|