@drafthq/draft 4.0.0 → 5.0.1
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/bin/README.md +14 -13
- package/core/shared/condensation.md +8 -7
- package/core/shared/draft-context-loading.md +1 -1
- package/core/shared/graph-query.md +25 -19
- package/core/templates/architecture.md +1 -1
- package/integrations/agents/AGENTS.md +36 -29
- package/integrations/copilot/.github/copilot-instructions.md +36 -29
- package/package.json +2 -2
- package/scripts/fetch-memory-engine.sh +43 -10
- package/scripts/tools/_graph_queries.sh +25 -11
- package/scripts/tools/_lib.sh +38 -29
- package/scripts/tools/cycle-detect.sh +9 -5
- package/scripts/tools/graph-impact.sh +63 -37
- package/scripts/tools/graph-init.sh +5 -10
- package/scripts/tools/graph-preflight.sh +6 -3
- package/scripts/tools/graph-query.sh +8 -7
- package/scripts/tools/graph-snapshot.sh +13 -28
- package/scripts/tools/graph-traces.sh +2 -2
- package/scripts/tools/hotspot-rank.sh +10 -1
- package/scripts/tools/verify-graph-binary.sh +14 -2
- package/skills/implement/SKILL.md +1 -1
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"name": "draft",
|
|
14
14
|
"source": "./",
|
|
15
15
|
"description": "Context-Driven Development: draft specs and plans before implementation. Structured workflows for features and fixes.",
|
|
16
|
-
"version": "
|
|
16
|
+
"version": "5.0.1",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "Mayur Pise",
|
|
19
19
|
"email": "mayur@getdraft.dev",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "draft",
|
|
3
3
|
"description": "Context-Driven Development: draft specs and plans before implementation. Structured workflows for features and fixes.",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "5.0.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mayur Pise",
|
|
7
7
|
"email": "mayur@getdraft.dev",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "draft",
|
|
3
3
|
"displayName": "Draft",
|
|
4
4
|
"description": "Context-Driven Development: draft specs and plans before implementation. Structured workflows for features and fixes.",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "5.0.1",
|
|
6
6
|
"skills": "./skills/",
|
|
7
7
|
"agents": "./core/agents/",
|
|
8
8
|
"author": {
|
package/bin/README.md
CHANGED
|
@@ -17,7 +17,7 @@ This installs the binary to the **Draft-managed location**:
|
|
|
17
17
|
~/.cache/draft/bin/codebase-memory-mcp
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
The fetch script picks the right release archive for the host OS/arch, verifies its SHA-256 against the
|
|
20
|
+
The fetch script picks the right release archive for the host OS/arch, verifies its SHA-256 (against hashes pinned in the script for the default version, else against the release's `checksums.txt`), extracts it, and installs it there. An existing install is kept only when its version matches the requested one, so a pin bump upgrades it. Downloads pin `curl --proto '=https' --proto-redir '=https'` so a compromised redirect cannot downgrade to HTTP. `draft install claude-code` / `draft install cursor` run this automatically (best-effort, network-gated); skip it with `--no-graph`.
|
|
21
21
|
|
|
22
22
|
## Resolution order
|
|
23
23
|
|
|
@@ -39,10 +39,10 @@ Set `DRAFT_MEMORY_DISABLE=1` to force the engine off. All graph-backed skills an
|
|
|
39
39
|
## How tools use it
|
|
40
40
|
|
|
41
41
|
Shell helpers under `scripts/tools/` drive the engine via its CLI
|
|
42
|
-
(`codebase-memory-mcp cli <tool
|
|
42
|
+
(`codebase-memory-mcp cli <tool>`, JSON args on stdin) and shape results into Draft's
|
|
43
43
|
contracts — see `hotspot-rank.sh`, `cycle-detect.sh`, `mermaid-from-graph.sh`,
|
|
44
44
|
and `verify-graph-binary.sh`. The shared wrappers (`memory_cli`,
|
|
45
|
-
`memory_ensure_index`, `
|
|
45
|
+
`memory_ensure_index`, `memory_index_bounded`) live in `_lib.sh`.
|
|
46
46
|
|
|
47
47
|
## Snapshot artifacts
|
|
48
48
|
|
|
@@ -50,9 +50,9 @@ and `verify-graph-binary.sh`. The shared wrappers (`memory_cli`,
|
|
|
50
50
|
|
|
51
51
|
| Artifact | Content |
|
|
52
52
|
|----------|---------|
|
|
53
|
-
| `schema.yaml` | Engine
|
|
53
|
+
| `schema.yaml` | Engine metadata and point-of-index node/edge counts (gates graph use). No machine- or run-specific fields, so it only changes when the engine or the codebase does. |
|
|
54
54
|
|
|
55
|
-
Structural graph data (architecture, hotspots, module deps, service routes) is queried **live** from the `codebase-memory-mcp` engine — either via the wrapper scripts under `scripts/tools/` (`graph-callers.sh`, `graph-impact.sh`, `hotspot-rank.sh`, `cycle-detect.sh`, `mermaid-from-graph.sh`) or
|
|
55
|
+
Structural graph data (architecture, hotspots, module deps, service routes) is queried **live** from the `codebase-memory-mcp` engine — either via the wrapper scripts under `scripts/tools/` (`graph-callers.sh`, `graph-impact.sh`, `hotspot-rank.sh`, `cycle-detect.sh`, `mermaid-from-graph.sh`), or, for any other read-only engine tool, `graph-query.sh --tool <name> --json '{...}'`.
|
|
56
56
|
|
|
57
57
|
## Offline / air-gapped distributions
|
|
58
58
|
|
|
@@ -68,22 +68,23 @@ Draft's differentiator depends on a binary published by a third party ([DeusData
|
|
|
68
68
|
|
|
69
69
|
| Property | Status |
|
|
70
70
|
|---|---|
|
|
71
|
-
| Version pinned | Yes — `DEFAULT_VERSION` in `scripts/fetch-memory-engine.sh`. Bumps are deliberate commits, never floating. `CMM_VERSION` overrides per-install. |
|
|
72
|
-
| SHA-256 verified | Yes
|
|
73
|
-
| Missing checksum | **
|
|
71
|
+
| Version pinned | Yes — `DEFAULT_VERSION` in `scripts/fetch-memory-engine.sh`. Bumps are deliberate commits, never floating. `CMM_VERSION` overrides per-install. An install at another version is replaced on the next fetch, and `verify-graph-binary.sh` / `graph-preflight.sh` warn when the resolved engine (e.g. one on `$PATH`) is off-pin. |
|
|
72
|
+
| SHA-256 verified | Yes. The default version's four platform archives are checked against hashes **pinned in the script** (a replaced release asset fails even if the release's own `checksums.txt` agrees). Other versions are checked against the release's `checksums.txt` when it lists the archive. A **mismatch is always fatal.** |
|
|
73
|
+
| Missing checksum | Applies only to non-default versions: **warns and installs by default.** Set `DRAFT_STRICT_VERIFY=1` to make an unverifiable download fatal instead. |
|
|
74
74
|
| Signature / attestation | **No.** There is no code signing or SLSA provenance today. Verification is checksum-only. |
|
|
75
75
|
| Source available | Yes — the engine is open source at [DeusData/codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp). |
|
|
76
76
|
| Reproducible build | Not verified by Draft. We check the archive matches the publisher's checksum, not that the checksum matches the source. |
|
|
77
77
|
|
|
78
|
-
Be explicit about the residual risk: a checksum proves the download matches what the publisher released. It does not prove the publisher released what the source says.
|
|
78
|
+
Be explicit about the residual risk: a pinned checksum proves the download matches what the publisher released when Draft pinned it. It does not prove the publisher released what the source says.
|
|
79
79
|
|
|
80
80
|
### What the engine does at runtime
|
|
81
81
|
|
|
82
82
|
- Reads the repository you point it at and writes a SQLite graph under its own cache.
|
|
83
|
-
- Runs entirely locally. No API key, no telemetry endpoint, no outbound calls during indexing or querying.
|
|
84
|
-
-
|
|
83
|
+
- Runs entirely locally as Draft invokes it (`cli` mode). No API key, no telemetry endpoint, no outbound calls during indexing or querying — verified under `strace` for `index_repository` and queries on 0.9.0 (zero `connect()` calls, no spawned `curl`).
|
|
84
|
+
- The binary does embed an update checker (`api.github.com/.../releases/latest`) and `update` / `install` subcommands for its own MCP-server workflow. Draft never runs the server or those subcommands.
|
|
85
|
+
- Draft uses the network exactly once, in `fetch-memory-engine.sh`, to download the release archive.
|
|
85
86
|
|
|
86
|
-
Draft invokes it only through `codebase-memory-mcp cli <tool
|
|
87
|
+
Draft invokes it only through `codebase-memory-mcp cli <tool>` with JSON args on stdin (see `_lib.sh:memory_cli`). It is never given credentials and never writes into your source tree.
|
|
87
88
|
|
|
88
89
|
### If you cannot run an unvetted binary
|
|
89
90
|
|
|
@@ -97,7 +98,7 @@ Three supported postures, in increasing strictness:
|
|
|
97
98
|
|
|
98
99
|
The dependency is bounded by design, which is what makes this survivable:
|
|
99
100
|
|
|
100
|
-
- **The interface is small.** Draft consumes a documented CLI (`cli <tool
|
|
101
|
+
- **The interface is small.** Draft consumes a documented CLI (`cli <tool>`, JSON on stdin), not a library. The entire coupling lives in `scripts/tools/_lib.sh` (`memory_cli`, `memory_ensure_index`, `memory_index_bounded`) and `_graph_queries.sh`. Swapping engines means reimplementing those, not rewriting skills.
|
|
101
102
|
- **Skills never call the engine directly.** They call `graph-*.sh` wrappers, all of which already fail loud with `source: "unavailable"`. An engine that disappears degrades the product; it does not break it.
|
|
102
103
|
- **Pinning buys time.** A stalled upstream keeps working at the pinned version; only new language support would be lost.
|
|
103
104
|
- **The graph contract is replaceable.** The queries are ordinary Cypher-shaped structural lookups (callers, callees, fan-in, cycles, routes) over a tree-sitter/LSP index — reproducible on another indexer.
|
|
@@ -24,7 +24,7 @@ Any skill that mutates `architecture.md` should execute this subroutine afterwar
|
|
|
24
24
|
| Input | Path | Description |
|
|
25
25
|
|-------|------|-------------|
|
|
26
26
|
| architecture.md | `draft/architecture.md` | Comprehensive human-readable engineering reference (source of truth) |
|
|
27
|
-
|
|
|
27
|
+
| Architecture view | `scripts/tools/graph-arch.sh --repo .` | Live graph metrics for tier computation (optional — skip when `draft/graph/schema.yaml` is absent) |
|
|
28
28
|
|
|
29
29
|
## Outputs
|
|
30
30
|
|
|
@@ -37,11 +37,12 @@ Any skill that mutates `architecture.md` should execute this subroutine afterwar
|
|
|
37
37
|
|
|
38
38
|
## Target Size
|
|
39
39
|
|
|
40
|
-
Compute tier from `
|
|
40
|
+
Compute tier from the live architecture view (the same metrics as `/draft:init` Step 1.4.5 — `schema.yaml` carries only counts, not these):
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
ARCH=$("$DRAFT_TOOLS/graph-arch.sh" --repo .) (DRAFT_TOOLS: resolver below)
|
|
43
|
+
M = $ARCH | jq '.packages | length' (modules)
|
|
44
|
+
F = $ARCH | jq '[.node_labels[] | select(.label=="Function" or .label=="Method") | .count] | add // 0' (functions + methods)
|
|
45
|
+
P = $ARCH | jq '.routes | length' (routes / RPCs)
|
|
45
46
|
|
|
46
47
|
| Tier | Label | Condition | Budget |
|
|
47
48
|
|------|--------|----------------------------------------|---------------|
|
|
@@ -51,7 +52,7 @@ Compute tier from `draft/graph/schema.yaml` after graph build:
|
|
|
51
52
|
| 4 | large | M≤100 AND F≤5000 AND P≤500 | 400–600 lines |
|
|
52
53
|
| 5 | XL | M>100 OR F>5000 OR P>500 | 600–900 lines |
|
|
53
54
|
|
|
54
|
-
If `schema.yaml` does not exist: default to tier 2 (180–280 lines).
|
|
55
|
+
If `schema.yaml` does not exist (no graph) or `graph-arch.sh` reports `source: unavailable`: default to tier 2 (180–280 lines).
|
|
55
56
|
|
|
56
57
|
- Below tier minimum: incomplete condensation — ensure all sections are represented
|
|
57
58
|
- Above tier maximum: insufficient compression — apply prioritization rules below
|
|
@@ -171,7 +172,7 @@ Before writing `draft/.ai-context.md`, verify:
|
|
|
171
172
|
- [ ] No references to `architecture.md` (file must be self-contained)
|
|
172
173
|
- [ ] All invariants from architecture.md are preserved
|
|
173
174
|
- [ ] Extension cookbooks are complete (an agent can follow them without other files)
|
|
174
|
-
- [ ] Output is within tier budget bounds (compute from
|
|
175
|
+
- [ ] Output is within tier budget bounds (compute from `graph-arch.sh` or default tier 2)
|
|
175
176
|
- [ ] GRAPH:HOTSPOTS present (or note "No hotspot data available" if graph absent)
|
|
176
177
|
- [ ] GRAPH:CYCLES present ("None ✓" or cycle list; or note if graph absent)
|
|
177
178
|
- [ ] GRAPH:MODULE-HOTSPOTS present for tier ≥ 3 (or note if no hotspot data)
|
|
@@ -71,7 +71,7 @@ If `draft/graph/schema.yaml` exists, the project has automated graph analysis da
|
|
|
71
71
|
|
|
72
72
|
| File | Purpose | Content |
|
|
73
73
|
|------|---------|---------|
|
|
74
|
-
| `draft/graph/schema.yaml` | Gate marker (engine
|
|
74
|
+
| `draft/graph/schema.yaml` | Gate marker (engine metadata + point-of-index counts); presence gates graph use | YAML, ~10 lines |
|
|
75
75
|
|
|
76
76
|
Note: `.ai-context.md` embeds a condensed graph summary (`GRAPH:MODULES`, `GRAPH:HOTSPOTS`, `GRAPH:CYCLES`) for first-pass structural ground truth. Deep structural data is queried live from the engine (see Live structural queries below).
|
|
77
77
|
|
|
@@ -115,7 +115,7 @@ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}
|
|
|
115
115
|
| `bash "$DRAFT_TOOLS/graph-query.sh" (--cypher STR \| --tool NAME --json '{...}')` | generic read-only passthrough | `{source:"unavailable"}`, exit 2 |
|
|
116
116
|
| `bash "$DRAFT_TOOLS/graph-traces.sh" ingest --file F --experimental` | runtime traces (experimental write) | `{source:"unavailable"}`, exit 2 |
|
|
117
117
|
|
|
118
|
-
For
|
|
118
|
+
For an engine tool without a dedicated wrapper, use the read-only passthrough `graph-query.sh --repo . --tool <name> --json '{...}'` (project injected, write tools refused, `source:"unavailable"` on failure). Never call the engine binary directly — that skips engine resolution, the index refresh before each query, and the fail-loud contract.
|
|
119
119
|
|
|
120
120
|
### Capability wrappers & dialect limits (graph-tooling-v2)
|
|
121
121
|
|
|
@@ -123,8 +123,9 @@ All Cypher lives in `scripts/tools/_graph_queries.sh` (the single source of quer
|
|
|
123
123
|
truth). Wrappers are thin arg-parse → builder → fail-loud JSON. Three contracts
|
|
124
124
|
matter when consuming them:
|
|
125
125
|
|
|
126
|
-
**Fail-loud status.** Symbol-scoped wrappers (`graph-callers`, `graph-
|
|
127
|
-
`graph-tests --symbol`, `graph-hierarchy --symbol/--derived`,
|
|
126
|
+
**Fail-loud status.** Symbol-scoped wrappers (`graph-callers`, `graph-impact`,
|
|
127
|
+
`graph-snippet`, `graph-tests --symbol`, `graph-hierarchy --symbol/--derived`,
|
|
128
|
+
`graph-errors`)
|
|
128
129
|
emit a `status` field that distinguishes the three real outcomes — never read a
|
|
129
130
|
bare `[]` as a confirmed true negative:
|
|
130
131
|
|
|
@@ -137,7 +138,7 @@ bare `[]` as a confirmed true negative:
|
|
|
137
138
|
|
|
138
139
|
**Shapeless JSON is unavailable.** `gq_run` requires `has("rows") and (.rows|type=="array")`. A bare `{}` (or any object without a `.rows` array) is not a measured empty result — wrappers emit `source:"unavailable"` and a non-zero exit. Do not read `{}` as "no callers / no cycles / no edges". `graph-impact`, `graph-callers`, and `mermaid-from-graph` also require their tool-shaped object; a failed snapshot refresh does not rewrite `schema.yaml`.
|
|
139
140
|
|
|
140
|
-
**Verified engine param shapes** (engine v0.
|
|
141
|
+
**Verified engine param shapes** (engine v0.9.0 — the runtime source of truth is
|
|
141
142
|
`get_graph_schema`; do not hardcode a property set):
|
|
142
143
|
|
|
143
144
|
```bash
|
|
@@ -150,13 +151,18 @@ get_graph_schema '{"project":P}' # → {node_labels:[{label,count,properties}
|
|
|
150
151
|
|
|
151
152
|
**Cypher dialect — keep queries inside the SAFE set:**
|
|
152
153
|
|
|
153
|
-
- ✅ SAFE:
|
|
154
|
-
`
|
|
155
|
-
`[:
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
154
|
+
- ✅ SAFE: `=`, `<>`/`!=`, `<`, `>`, `<=`, `>=` against a literal; `STARTS WITH`,
|
|
155
|
+
`NOT x STARTS WITH`, `AND`, `OR`; explicit and variable-length patterns
|
|
156
|
+
(`[:R*1..3]`, fixed depth `[:R*2..2]`); relationship-type alternation `[:A|B]`;
|
|
157
|
+
`coalesce()`; `DISTINCT`; `count(x)`, `count(DISTINCT x)`; `WITH`-grouping
|
|
158
|
+
aggregation.
|
|
159
|
+
- ❌ UNSAFE: comparing one property against another (`a.x < b.x`), `NOT EXISTS(...)`,
|
|
160
|
+
`NOT (pattern)`, path variables (`p=(...)`, `length(p)`) — all rejected; and
|
|
161
|
+
multi-pattern joins (`MATCH (a)…, (b)…`), which parse but ignore `RETURN` and
|
|
162
|
+
`LIMIT`. `graph-query.sh --cypher` returns the engine's raw error, not a silent
|
|
159
163
|
empty — but the builders never emit these forms.
|
|
164
|
+
- ⚠️ `LIMIT` applies before `DISTINCT`: `RETURN DISTINCT … LIMIT n` can return
|
|
165
|
+
fewer than n rows while more exist. Judge truncation on raw rows.
|
|
160
166
|
|
|
161
167
|
**Caveats consumers must respect:**
|
|
162
168
|
|
|
@@ -191,15 +197,15 @@ The only committed file is the gate marker:
|
|
|
191
197
|
|
|
192
198
|
| File | Role |
|
|
193
199
|
|------|------|
|
|
194
|
-
| `draft/graph/schema.yaml` | Engine
|
|
200
|
+
| `draft/graph/schema.yaml` | Engine metadata and point-of-index counts (provenance, not authoritative). Carries **no graph data**. Its presence is the **gate** (see Pre-Check) — it signals the engine is wired for this repo. Written by `scripts/tools/graph-snapshot.sh`. |
|
|
195
201
|
|
|
196
|
-
All structural data is obtained live
|
|
202
|
+
All structural data is obtained live through the query-tool wrappers under `scripts/tools/`; `graph-query.sh --tool` covers every read-only engine tool that has no dedicated wrapper. The wrappers refresh the repo's index in the engine's own cache before each query, so no committed files are required.
|
|
197
203
|
|
|
198
204
|
### How skills query (engine is the interface; jq is optional)
|
|
199
205
|
|
|
200
|
-
- **The engine is the query
|
|
206
|
+
- **The engine is the query; the wrappers are the interface.** Every wrapper drives the engine's CLI and returns JSON. There is no other query surface.
|
|
201
207
|
- **Prefer the wrappers — they resolve the engine for you.** `graph-arch.sh` (architecture view: packages/routes/layers/hotspots), `graph-callers.sh`, `hotspot-rank.sh`, `graph-impact.sh`, `cycle-detect.sh`, `mermaid-from-graph.sh` return already-shaped JSON. The engine binary is usually **not on `$PATH`** (it lives under `~/.cache/draft/bin/`); the wrappers locate it via `_lib.sh:find_memory_bin`, so a skill using a wrapper needs no resolution step.
|
|
202
|
-
- **
|
|
208
|
+
- **Tools without a dedicated wrapper go through `graph-query.sh`:** `"$DRAFT_TOOLS/graph-query.sh" --repo . --tool search_code --json '{"pattern":"..."}'` (likewise `trace_path`, `get_graph_schema`, `index_status`). `search_graph` has its own wrapper, `graph-search.sh`.
|
|
203
209
|
- **`jq` is not a query tool — it only trims output.** Reach for it solely to slice a *large* response (chiefly the `get_architecture` blob) down to the field you need, for token economy. The agent can read raw JSON directly; jq is an optimization, not a requirement. Don't pipe wrapper output through jq unless you genuinely need a sub-field.
|
|
204
210
|
|
|
205
211
|
The engine uses a **unified, language-agnostic** node model — `Function`, `Method`, `Class`, `Module`, `File`, `Folder`, `Route`, `Section`, `Variable` (language is inferred from file extension) — and edges `CALLS`, `DEFINES`, `CONTAINS_FILE`, `IMPORTS`, `HTTP_CALLS`, `FILE_CHANGES_WITH`, `SEMANTICALLY_RELATED`, `SIMILAR_TO`. Each node carries `file_path` + `start_line`/`end_line` and rich `properties` (complexity, signature, parent_class), and the engine exposes full-text (`search_code`) and semantic search — none of which a committed snapshot reproduced.
|
|
@@ -219,11 +225,11 @@ Output: `{symbol, callers[{name, file}], source}`. Use when enumerating call sit
|
|
|
219
225
|
### Impact — blast radius of a file or symbol
|
|
220
226
|
|
|
221
227
|
```bash
|
|
222
|
-
"$DRAFT_TOOLS/graph-impact.sh" --repo . --file <path> #
|
|
223
|
-
"$DRAFT_TOOLS/graph-impact.sh" --repo . --symbol <name> # transitive callers of a function
|
|
228
|
+
"$DRAFT_TOOLS/graph-impact.sh" --repo . --file <path> # dependents of a file: its symbols' callers + its importers
|
|
229
|
+
"$DRAFT_TOOLS/graph-impact.sh" --repo . --symbol <name> # dependents (transitive callers) of a function
|
|
224
230
|
```
|
|
225
231
|
|
|
226
|
-
Output: `{target, kind, impacted[{name, file, hop}], source}`. Use when sizing risk before modifying a file or symbol, especially high-fan-in hotspots.
|
|
232
|
+
Output: `{target, kind, impacted[{name, file, qualified, hop}], downstream_files, affected_modules, max_depth, by_category{code,test}, status, truncated, source}`. `impacted` lists each dependent once at its nearest hop (default depth 3), capped at 200 with `truncated:true`; the aggregates always cover the full set. `status` is `ok`, `no-edges` (target known, nothing depends on it), or `no-match` (target unknown to the graph — check the path). Use when sizing risk before modifying a file or symbol, especially high-fan-in hotspots.
|
|
227
233
|
|
|
228
234
|
### Hotspots — fan-in ranking
|
|
229
235
|
|
|
@@ -334,7 +340,7 @@ Unlocks any edge type or node property without a purpose-built wrapper. Write ve
|
|
|
334
340
|
"$DRAFT_TOOLS/graph-snapshot.sh" --repo .
|
|
335
341
|
```
|
|
336
342
|
|
|
337
|
-
Indexes the repo into the engine and writes the `draft/graph/schema.yaml` gate marker
|
|
343
|
+
Indexes the repo into the engine and writes the `draft/graph/schema.yaml` gate marker, and prints the `detect_changes` delta (`changed_files`/`impacted_symbols`) without committing it. It writes **no** graph data. Run during `/draft:init` and `/draft:graph`, or whenever the index should be refreshed.
|
|
338
344
|
|
|
339
345
|
## Finding the Engine (Resolution + Usage Report)
|
|
340
346
|
|
|
@@ -375,4 +381,4 @@ The engine indexes C/C++, Go, Python, TypeScript/JS, and more (tree-sitter, 159
|
|
|
375
381
|
| No engine resolvable (or `DRAFT_MEMORY_DISABLE=1`) | Skip graph indexing in init; all skills proceed without graph data; tools emit `source: unavailable` |
|
|
376
382
|
| Engine present but a query fails, or returns shapeless `{}` | Treat as unavailable — never as a true-negative empty result; skills proceed without graph data |
|
|
377
383
|
| `draft/graph/schema.yaml` exists | Engine is wired — use live query tools as needed during the run |
|
|
378
|
-
| Engine index out of date |
|
|
384
|
+
| Engine index out of date | Every wrapper re-indexes incrementally (content-based, git-aware) before it queries — ~0.1 s on an unchanged repo — so live answers track the working tree, including the run's own edits. `graph-snapshot.sh` (or init) also refreshes the `schema.yaml` marker. |
|
|
@@ -29,7 +29,7 @@ graph:
|
|
|
29
29
|
cpp: "{high}"
|
|
30
30
|
go: "{approximate | high}"
|
|
31
31
|
stats:
|
|
32
|
-
modules: "{N from
|
|
32
|
+
modules: "{N from engine: get_architecture .packages}"
|
|
33
33
|
edges: "{total_edges from engine: get_architecture .edges}"
|
|
34
34
|
hotspots: "{N}"
|
|
35
35
|
notes: "{explicit fidelity summary from engine: get_architecture .languages/.packages}"
|
|
@@ -6025,7 +6025,7 @@ After a phase passes review, refresh `metadata.json.impact` so future tracks can
|
|
|
6025
6025
|
"$DRAFT_TOOLS/graph-impact.sh" --repo . --file <path>
|
|
6026
6026
|
```
|
|
6027
6027
|
|
|
6028
|
-
Aggregate across all files: `downstream_files` =
|
|
6028
|
+
Aggregate across all files: `downstream_files` = count of the union of each query's `downstream_files` array, `downstream_modules` = union of `affected_modules`, `max_depth` = max across queries, `by_category` = sum of each query's `by_category`. If the graph is absent, leave these fields as zeros / empty arrays — the snapshot still records the directly-touched files.
|
|
6029
6029
|
|
|
6030
6030
|
3. **Write metadata.json** with the populated `impact` block and `computed_at` set to the current timestamp.
|
|
6031
6031
|
|
|
@@ -17030,7 +17030,7 @@ If `draft/graph/schema.yaml` exists, the project has automated graph analysis da
|
|
|
17030
17030
|
|
|
17031
17031
|
| File | Purpose | Content |
|
|
17032
17032
|
|------|---------|---------|
|
|
17033
|
-
| `draft/graph/schema.yaml` | Gate marker (engine
|
|
17033
|
+
| `draft/graph/schema.yaml` | Gate marker (engine metadata + point-of-index counts); presence gates graph use | YAML, ~10 lines |
|
|
17034
17034
|
|
|
17035
17035
|
Note: `.ai-context.md` embeds a condensed graph summary (`GRAPH:MODULES`, `GRAPH:HOTSPOTS`, `GRAPH:CYCLES`) for first-pass structural ground truth. Deep structural data is queried live from the engine (see Live structural queries below).
|
|
17036
17036
|
|
|
@@ -17558,7 +17558,7 @@ Any skill that mutates `architecture.md` should execute this subroutine afterwar
|
|
|
17558
17558
|
| Input | Path | Description |
|
|
17559
17559
|
|-------|------|-------------|
|
|
17560
17560
|
| architecture.md | `draft/architecture.md` | Comprehensive human-readable engineering reference (source of truth) |
|
|
17561
|
-
|
|
|
17561
|
+
| Architecture view | `scripts/tools/graph-arch.sh --repo .` | Live graph metrics for tier computation (optional — skip when `draft/graph/schema.yaml` is absent) |
|
|
17562
17562
|
|
|
17563
17563
|
## Outputs
|
|
17564
17564
|
|
|
@@ -17571,11 +17571,12 @@ Any skill that mutates `architecture.md` should execute this subroutine afterwar
|
|
|
17571
17571
|
|
|
17572
17572
|
## Target Size
|
|
17573
17573
|
|
|
17574
|
-
Compute tier from `draft
|
|
17574
|
+
Compute tier from the live architecture view (the same metrics as `draft init` Step 1.4.5 — `schema.yaml` carries only counts, not these):
|
|
17575
17575
|
|
|
17576
|
-
|
|
17577
|
-
|
|
17578
|
-
|
|
17576
|
+
ARCH=$("$DRAFT_TOOLS/graph-arch.sh" --repo .) (DRAFT_TOOLS: resolver below)
|
|
17577
|
+
M = $ARCH | jq '.packages | length' (modules)
|
|
17578
|
+
F = $ARCH | jq '[.node_labels[] | select(.label=="Function" or .label=="Method") | .count] | add // 0' (functions + methods)
|
|
17579
|
+
P = $ARCH | jq '.routes | length' (routes / RPCs)
|
|
17579
17580
|
|
|
17580
17581
|
| Tier | Label | Condition | Budget |
|
|
17581
17582
|
|------|--------|----------------------------------------|---------------|
|
|
@@ -17585,7 +17586,7 @@ Compute tier from `draft/graph/schema.yaml` after graph build:
|
|
|
17585
17586
|
| 4 | large | M≤100 AND F≤5000 AND P≤500 | 400–600 lines |
|
|
17586
17587
|
| 5 | XL | M>100 OR F>5000 OR P>500 | 600–900 lines |
|
|
17587
17588
|
|
|
17588
|
-
If `schema.yaml` does not exist: default to tier 2 (180–280 lines).
|
|
17589
|
+
If `schema.yaml` does not exist (no graph) or `graph-arch.sh` reports `source: unavailable`: default to tier 2 (180–280 lines).
|
|
17589
17590
|
|
|
17590
17591
|
- Below tier minimum: incomplete condensation — ensure all sections are represented
|
|
17591
17592
|
- Above tier maximum: insufficient compression — apply prioritization rules below
|
|
@@ -17705,7 +17706,7 @@ Before writing `draft/.ai-context.md`, verify:
|
|
|
17705
17706
|
- [ ] No references to `architecture.md` (file must be self-contained)
|
|
17706
17707
|
- [ ] All invariants from architecture.md are preserved
|
|
17707
17708
|
- [ ] Extension cookbooks are complete (an agent can follow them without other files)
|
|
17708
|
-
- [ ] Output is within tier budget bounds (compute from
|
|
17709
|
+
- [ ] Output is within tier budget bounds (compute from `graph-arch.sh` or default tier 2)
|
|
17709
17710
|
- [ ] GRAPH:HOTSPOTS present (or note "No hotspot data available" if graph absent)
|
|
17710
17711
|
- [ ] GRAPH:CYCLES present ("None ✓" or cycle list; or note if graph absent)
|
|
17711
17712
|
- [ ] GRAPH:MODULE-HOTSPOTS present for tier ≥ 3 (or note if no hotspot data)
|
|
@@ -18216,7 +18217,7 @@ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}
|
|
|
18216
18217
|
| `bash "$DRAFT_TOOLS/graph-query.sh" (--cypher STR \| --tool NAME --json '{...}')` | generic read-only passthrough | `{source:"unavailable"}`, exit 2 |
|
|
18217
18218
|
| `bash "$DRAFT_TOOLS/graph-traces.sh" ingest --file F --experimental` | runtime traces (experimental write) | `{source:"unavailable"}`, exit 2 |
|
|
18218
18219
|
|
|
18219
|
-
For
|
|
18220
|
+
For an engine tool without a dedicated wrapper, use the read-only passthrough `graph-query.sh --repo . --tool <name> --json '{...}'` (project injected, write tools refused, `source:"unavailable"` on failure). Never call the engine binary directly — that skips engine resolution, the index refresh before each query, and the fail-loud contract.
|
|
18220
18221
|
|
|
18221
18222
|
### Capability wrappers & dialect limits (graph-tooling-v2)
|
|
18222
18223
|
|
|
@@ -18224,8 +18225,9 @@ All Cypher lives in `scripts/tools/_graph_queries.sh` (the single source of quer
|
|
|
18224
18225
|
truth). Wrappers are thin arg-parse → builder → fail-loud JSON. Three contracts
|
|
18225
18226
|
matter when consuming them:
|
|
18226
18227
|
|
|
18227
|
-
**Fail-loud status.** Symbol-scoped wrappers (`graph-callers`, `graph-
|
|
18228
|
-
`graph-tests --symbol`, `graph-hierarchy --symbol/--derived`,
|
|
18228
|
+
**Fail-loud status.** Symbol-scoped wrappers (`graph-callers`, `graph-impact`,
|
|
18229
|
+
`graph-snippet`, `graph-tests --symbol`, `graph-hierarchy --symbol/--derived`,
|
|
18230
|
+
`graph-errors`)
|
|
18229
18231
|
emit a `status` field that distinguishes the three real outcomes — never read a
|
|
18230
18232
|
bare `[]` as a confirmed true negative:
|
|
18231
18233
|
|
|
@@ -18238,7 +18240,7 @@ bare `[]` as a confirmed true negative:
|
|
|
18238
18240
|
|
|
18239
18241
|
**Shapeless JSON is unavailable.** `gq_run` requires `has("rows") and (.rows|type=="array")`. A bare `{}` (or any object without a `.rows` array) is not a measured empty result — wrappers emit `source:"unavailable"` and a non-zero exit. Do not read `{}` as "no callers / no cycles / no edges". `graph-impact`, `graph-callers`, and `mermaid-from-graph` also require their tool-shaped object; a failed snapshot refresh does not rewrite `schema.yaml`.
|
|
18240
18242
|
|
|
18241
|
-
**Verified engine param shapes** (engine v0.
|
|
18243
|
+
**Verified engine param shapes** (engine v0.9.0 — the runtime source of truth is
|
|
18242
18244
|
`get_graph_schema`; do not hardcode a property set):
|
|
18243
18245
|
|
|
18244
18246
|
```bash
|
|
@@ -18251,13 +18253,18 @@ get_graph_schema '{"project":P}' # → {node_labels:[{label,count,properties}
|
|
|
18251
18253
|
|
|
18252
18254
|
**Cypher dialect — keep queries inside the SAFE set:**
|
|
18253
18255
|
|
|
18254
|
-
- ✅ SAFE:
|
|
18255
|
-
`
|
|
18256
|
-
`[:
|
|
18257
|
-
|
|
18258
|
-
|
|
18259
|
-
|
|
18256
|
+
- ✅ SAFE: `=`, `<>`/`!=`, `<`, `>`, `<=`, `>=` against a literal; `STARTS WITH`,
|
|
18257
|
+
`NOT x STARTS WITH`, `AND`, `OR`; explicit and variable-length patterns
|
|
18258
|
+
(`[:R*1..3]`, fixed depth `[:R*2..2]`); relationship-type alternation `[:A|B]`;
|
|
18259
|
+
`coalesce()`; `DISTINCT`; `count(x)`, `count(DISTINCT x)`; `WITH`-grouping
|
|
18260
|
+
aggregation.
|
|
18261
|
+
- ❌ UNSAFE: comparing one property against another (`a.x < b.x`), `NOT EXISTS(...)`,
|
|
18262
|
+
`NOT (pattern)`, path variables (`p=(...)`, `length(p)`) — all rejected; and
|
|
18263
|
+
multi-pattern joins (`MATCH (a)…, (b)…`), which parse but ignore `RETURN` and
|
|
18264
|
+
`LIMIT`. `graph-query.sh --cypher` returns the engine's raw error, not a silent
|
|
18260
18265
|
empty — but the builders never emit these forms.
|
|
18266
|
+
- ⚠️ `LIMIT` applies before `DISTINCT`: `RETURN DISTINCT … LIMIT n` can return
|
|
18267
|
+
fewer than n rows while more exist. Judge truncation on raw rows.
|
|
18261
18268
|
|
|
18262
18269
|
**Caveats consumers must respect:**
|
|
18263
18270
|
|
|
@@ -18292,15 +18299,15 @@ The only committed file is the gate marker:
|
|
|
18292
18299
|
|
|
18293
18300
|
| File | Role |
|
|
18294
18301
|
|------|------|
|
|
18295
|
-
| `draft/graph/schema.yaml` | Engine
|
|
18302
|
+
| `draft/graph/schema.yaml` | Engine metadata and point-of-index counts (provenance, not authoritative). Carries **no graph data**. Its presence is the **gate** (see Pre-Check) — it signals the engine is wired for this repo. Written by `scripts/tools/graph-snapshot.sh`. |
|
|
18296
18303
|
|
|
18297
|
-
All structural data is obtained live
|
|
18304
|
+
All structural data is obtained live through the query-tool wrappers under `scripts/tools/`; `graph-query.sh --tool` covers every read-only engine tool that has no dedicated wrapper. The wrappers refresh the repo's index in the engine's own cache before each query, so no committed files are required.
|
|
18298
18305
|
|
|
18299
18306
|
### How skills query (engine is the interface; jq is optional)
|
|
18300
18307
|
|
|
18301
|
-
- **The engine is the query
|
|
18308
|
+
- **The engine is the query; the wrappers are the interface.** Every wrapper drives the engine's CLI and returns JSON. There is no other query surface.
|
|
18302
18309
|
- **Prefer the wrappers — they resolve the engine for you.** `graph-arch.sh` (architecture view: packages/routes/layers/hotspots), `graph-callers.sh`, `hotspot-rank.sh`, `graph-impact.sh`, `cycle-detect.sh`, `mermaid-from-graph.sh` return already-shaped JSON. The engine binary is usually **not on `$PATH`** (it lives under `~/.cache/draft/bin/`); the wrappers locate it via `_lib.sh:find_memory_bin`, so a skill using a wrapper needs no resolution step.
|
|
18303
|
-
- **
|
|
18310
|
+
- **Tools without a dedicated wrapper go through `graph-query.sh`:** `"$DRAFT_TOOLS/graph-query.sh" --repo . --tool search_code --json '{"pattern":"..."}'` (likewise `trace_path`, `get_graph_schema`, `index_status`). `search_graph` has its own wrapper, `graph-search.sh`.
|
|
18304
18311
|
- **`jq` is not a query tool — it only trims output.** Reach for it solely to slice a *large* response (chiefly the `get_architecture` blob) down to the field you need, for token economy. The agent can read raw JSON directly; jq is an optimization, not a requirement. Don't pipe wrapper output through jq unless you genuinely need a sub-field.
|
|
18305
18312
|
|
|
18306
18313
|
The engine uses a **unified, language-agnostic** node model — `Function`, `Method`, `Class`, `Module`, `File`, `Folder`, `Route`, `Section`, `Variable` (language is inferred from file extension) — and edges `CALLS`, `DEFINES`, `CONTAINS_FILE`, `IMPORTS`, `HTTP_CALLS`, `FILE_CHANGES_WITH`, `SEMANTICALLY_RELATED`, `SIMILAR_TO`. Each node carries `file_path` + `start_line`/`end_line` and rich `properties` (complexity, signature, parent_class), and the engine exposes full-text (`search_code`) and semantic search — none of which a committed snapshot reproduced.
|
|
@@ -18320,11 +18327,11 @@ Output: `{symbol, callers[{name, file}], source}`. Use when enumerating call sit
|
|
|
18320
18327
|
### Impact — blast radius of a file or symbol
|
|
18321
18328
|
|
|
18322
18329
|
```bash
|
|
18323
|
-
"$DRAFT_TOOLS/graph-impact.sh" --repo . --file <path> #
|
|
18324
|
-
"$DRAFT_TOOLS/graph-impact.sh" --repo . --symbol <name> # transitive callers of a function
|
|
18330
|
+
"$DRAFT_TOOLS/graph-impact.sh" --repo . --file <path> # dependents of a file: its symbols' callers + its importers
|
|
18331
|
+
"$DRAFT_TOOLS/graph-impact.sh" --repo . --symbol <name> # dependents (transitive callers) of a function
|
|
18325
18332
|
```
|
|
18326
18333
|
|
|
18327
|
-
Output: `{target, kind, impacted[{name, file, hop}], source}`. Use when sizing risk before modifying a file or symbol, especially high-fan-in hotspots.
|
|
18334
|
+
Output: `{target, kind, impacted[{name, file, qualified, hop}], downstream_files, affected_modules, max_depth, by_category{code,test}, status, truncated, source}`. `impacted` lists each dependent once at its nearest hop (default depth 3), capped at 200 with `truncated:true`; the aggregates always cover the full set. `status` is `ok`, `no-edges` (target known, nothing depends on it), or `no-match` (target unknown to the graph — check the path). Use when sizing risk before modifying a file or symbol, especially high-fan-in hotspots.
|
|
18328
18335
|
|
|
18329
18336
|
### Hotspots — fan-in ranking
|
|
18330
18337
|
|
|
@@ -18435,7 +18442,7 @@ Unlocks any edge type or node property without a purpose-built wrapper. Write ve
|
|
|
18435
18442
|
"$DRAFT_TOOLS/graph-snapshot.sh" --repo .
|
|
18436
18443
|
```
|
|
18437
18444
|
|
|
18438
|
-
Indexes the repo into the engine and writes the `draft/graph/schema.yaml` gate marker
|
|
18445
|
+
Indexes the repo into the engine and writes the `draft/graph/schema.yaml` gate marker, and prints the `detect_changes` delta (`changed_files`/`impacted_symbols`) without committing it. It writes **no** graph data. Run during `draft init` and `draft graph`, or whenever the index should be refreshed.
|
|
18439
18446
|
|
|
18440
18447
|
## Finding the Engine (Resolution + Usage Report)
|
|
18441
18448
|
|
|
@@ -18476,7 +18483,7 @@ The engine indexes C/C++, Go, Python, TypeScript/JS, and more (tree-sitter, 159
|
|
|
18476
18483
|
| No engine resolvable (or `DRAFT_MEMORY_DISABLE=1`) | Skip graph indexing in init; all skills proceed without graph data; tools emit `source: unavailable` |
|
|
18477
18484
|
| Engine present but a query fails, or returns shapeless `{}` | Treat as unavailable — never as a true-negative empty result; skills proceed without graph data |
|
|
18478
18485
|
| `draft/graph/schema.yaml` exists | Engine is wired — use live query tools as needed during the run |
|
|
18479
|
-
| Engine index out of date |
|
|
18486
|
+
| Engine index out of date | Every wrapper re-indexes incrementally (content-based, git-aware) before it queries — ~0.1 s on an unchanged repo — so live answers track the working tree, including the run's own edits. `graph-snapshot.sh` (or init) also refreshes the `schema.yaml` marker. |
|
|
18480
18487
|
|
|
18481
18488
|
</core-file>
|
|
18482
18489
|
|
|
@@ -20433,7 +20440,7 @@ graph:
|
|
|
20433
20440
|
cpp: "{high}"
|
|
20434
20441
|
go: "{approximate | high}"
|
|
20435
20442
|
stats:
|
|
20436
|
-
modules: "{N from
|
|
20443
|
+
modules: "{N from engine: get_architecture .packages}"
|
|
20437
20444
|
edges: "{total_edges from engine: get_architecture .edges}"
|
|
20438
20445
|
hotspots: "{N}"
|
|
20439
20446
|
notes: "{explicit fidelity summary from engine: get_architecture .languages/.packages}"
|