@drafthq/draft 3.5.3 → 3.6.0

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.
Files changed (84) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.cursor-plugin/plugin.json +1 -1
  4. package/cli/src/hosts/cursor.js +3 -0
  5. package/cli/src/installer.js +7 -3
  6. package/cli/src/lib/fsx.js +3 -0
  7. package/cli/src/lib/marker.js +8 -3
  8. package/core/shared/condensation.md +1 -1
  9. package/core/shared/git-report-metadata.md +1 -1
  10. package/core/shared/graph-query.md +24 -24
  11. package/core/shared/tool-resolver.md +20 -15
  12. package/core/templates/plan.md +1 -1
  13. package/integrations/agents/AGENTS.md +122 -470
  14. package/integrations/copilot/.github/copilot-instructions.md +122 -470
  15. package/package.json +1 -1
  16. package/scripts/fetch-memory-engine.sh +1 -1
  17. package/scripts/lib.sh +79 -2
  18. package/scripts/tools/_graph_queries.sh +12 -5
  19. package/scripts/tools/_lib.sh +56 -8
  20. package/scripts/tools/adr-index.sh +1 -1
  21. package/scripts/tools/check-skill-line-caps.sh +2 -2
  22. package/scripts/tools/check-track-hygiene.sh +41 -21
  23. package/scripts/tools/classify-files.sh +1 -1
  24. package/scripts/tools/cycle-detect.sh +2 -9
  25. package/scripts/tools/detect-test-framework.sh +1 -1
  26. package/scripts/tools/emit-skill-metrics.sh +7 -2
  27. package/scripts/tools/freshness-check.sh +2 -2
  28. package/scripts/tools/git-metadata.sh +6 -6
  29. package/scripts/tools/graph-arch.sh +4 -10
  30. package/scripts/tools/graph-callers.sh +4 -12
  31. package/scripts/tools/graph-deps.sh +3 -10
  32. package/scripts/tools/graph-errors.sh +4 -11
  33. package/scripts/tools/graph-hierarchy.sh +4 -11
  34. package/scripts/tools/graph-impact.sh +17 -17
  35. package/scripts/tools/graph-init.sh +1 -1
  36. package/scripts/tools/graph-preflight.sh +1 -1
  37. package/scripts/tools/graph-query.sh +5 -12
  38. package/scripts/tools/graph-risk.sh +3 -10
  39. package/scripts/tools/graph-search.sh +4 -11
  40. package/scripts/tools/graph-snapshot.sh +9 -4
  41. package/scripts/tools/graph-snippet.sh +3 -10
  42. package/scripts/tools/graph-tests.sh +3 -10
  43. package/scripts/tools/graph-traces.sh +3 -10
  44. package/scripts/tools/hotspot-rank.sh +4 -11
  45. package/scripts/tools/mermaid-from-graph.sh +3 -10
  46. package/scripts/tools/migrate-track-frontmatter.sh +3 -1
  47. package/scripts/tools/okf-coverage-check.sh +4 -4
  48. package/scripts/tools/okf-emit-catalog.sh +256 -0
  49. package/scripts/tools/okf-fix-links.sh +326 -0
  50. package/scripts/tools/okf-plan-concepts.sh +245 -14
  51. package/scripts/tools/okf-render-views.sh +46 -9
  52. package/scripts/tools/okf-validate-all.sh +20 -9
  53. package/scripts/tools/okf-validate-quality.sh +2 -8
  54. package/scripts/tools/okf-validate.sh +7 -4
  55. package/scripts/tools/parse-git-log.sh +4 -4
  56. package/scripts/tools/parse-reports.sh +1 -1
  57. package/scripts/tools/render-track.sh +1 -1
  58. package/scripts/tools/run-coverage.sh +1 -1
  59. package/scripts/tools/scan-markers.sh +4 -4
  60. package/scripts/tools/validate-frontmatter.sh +2 -2
  61. package/scripts/tools/verify-citations.sh +2 -2
  62. package/scripts/tools/verify-doc-anchors.sh +1 -1
  63. package/scripts/tools/verify-graph-binary.sh +2 -2
  64. package/skills/adr/SKILL.md +1 -1
  65. package/skills/bughunt/SKILL.md +1 -1
  66. package/skills/coverage/SKILL.md +2 -2
  67. package/skills/debug/SKILL.md +1 -1
  68. package/skills/decompose/SKILL.md +3 -3
  69. package/skills/deep-review/SKILL.md +2 -2
  70. package/skills/deploy-checklist/SKILL.md +1 -1
  71. package/skills/graph/SKILL.md +1 -1
  72. package/skills/impact/SKILL.md +1 -1
  73. package/skills/implement/SKILL.md +2 -2
  74. package/skills/init/SKILL.md +10 -7
  75. package/skills/init/references/architecture-spec.md +1 -1
  76. package/skills/init/references/okf-emitter.md +39 -75
  77. package/skills/learn/SKILL.md +1 -1
  78. package/skills/quick-review/SKILL.md +1 -1
  79. package/skills/review/SKILL.md +3 -3
  80. package/skills/standup/SKILL.md +1 -1
  81. package/skills/status/SKILL.md +1 -1
  82. package/skills/tech-debt/SKILL.md +2 -2
  83. package/skills/upload/SKILL.md +1 -1
  84. package/core/templates/track-architecture.md +0 -311
@@ -338,13 +338,16 @@ The tier-gated default rests on **maintainability/readability** (one navigable c
338
338
 
339
339
  **OKF Completeness Verification (blocking — tier 3+ `okf` mode).** Completeness is enforced by tooling, not honor system, so the wiki is generated completely for every module/sub-module/component on every run. Before promoting `draft.tmp/` → `draft/`, ALL must hold (see `references/okf-emitter.md` for the pipeline):
340
340
 
341
- 1. `okf-plan-concepts.sh` ran and the expected/required/deferred counts were logged **before** any page was written (the concept boundary is a tool output, not an in-context guess).
342
- 2. Every `required` entry in `concept-plan.json` has a non-stub page.
343
- 3. `okf-validate-all.sh --plan … --strict` exits 0 (structure + per-type quality + coverage all pass).
344
- 4. `systems/coverage.md` was generated by tooling (verify the `<!-- okf:coverage-generated -->` marker) — **every** package/module the graph found is required by default (the fan-in floor only types Subsystem-vs-Module, it does not exempt), so none may be **MISSING**. Section `index.md` tables are regenerated by `okf-render-views.sh --section-indexes`, never hand-authored, so their links cannot dangle.
345
- 5. On any failure: **do not** atomic-rename; surface `.state/validation-report.json`.
341
+ 1. `okf-plan-concepts.sh` ran and counts were logged **before** any page was written. Plan discovery is language-aware: **Cargo workspace members / npm workspaces / Go modules first**, then graph packages (noise-filtered), then heuristic dirs. Log `discovery[]` (e.g. `cargo+graph`).
342
+ 2. `okf-emit-catalog.sh` ran so every REQUIRED plan entry has at least a minimum non-stub catalog page (LLM deep-dives may enrich top hotspots afterward).
343
+ 3. Every `required` entry in `concept-plan.json` has a non-stub page.
344
+ 4. `okf-render-views.sh` + `okf-fix-links.sh --fix` produced `architecture.md` with resolving `wiki/…` links and GFM TOC anchors.
345
+ 5. `okf-validate-all.sh --plan --strict` exits 0 (**quality coverage → structure**; structure runs last so coverage.md rewrites are checked).
346
+ 6. `okf-fix-links.sh --draft draft.tmp --check` exits 0 (zero dead links in architecture / wiki views).
347
+ 7. `systems/coverage.md` has the `<!-- okf:coverage-generated -->` marker; section indexes were regenerated by `okf-render-views.sh --section-indexes`.
348
+ 8. On any failure: **do not** atomic-rename; surface `.state/validation-report.json`.
346
349
 
347
- > **Red flag:** writing concept pages without first running `okf-plan-concepts.sh`, or finishing generation while any `required` plan entry is unwritten, is a **completeness failure** — not a stylistic one.
350
+ > **Red flag:** writing concept pages without first running `okf-plan-concepts.sh` + `okf-emit-catalog.sh`, or finishing while any `required` plan entry is unwritten, is a **completeness failure** — not a stylistic one.
348
351
 
349
352
  ### Route Explicit Modes Before Initialization
350
353
 
@@ -644,7 +647,7 @@ One command resolves ROOT, ensures the engine, builds the whole-repo spine, and
644
647
  ```bash
645
648
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
646
649
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
647
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
650
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
648
651
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
649
652
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
650
653
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -2284,7 +2287,7 @@ First resolve the bundled helpers:
2284
2287
  ```bash
2285
2288
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
2286
2289
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
2287
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
2290
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
2288
2291
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
2289
2292
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
2290
2293
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -3409,75 +3412,40 @@ Derive concepts from the graph, not by hand:
3409
3412
  ```
3410
3413
  1. Survey → existing draft init 5-phase + graph snapshot (graph-snapshot.sh)
3411
3414
  2. Plan → DETERMINISTIC. okf-plan-concepts.sh derives the expected-concept
3412
- set from the graph. EVERY package the graph knows about is
3413
- required (fan_in floor Subsystem; below floor Module — the
3414
- floor only types/orders, it never exempts); entrypoints required;
3415
- only --allow-defer matches are deferred (with a reason). Writes
3416
- draft.tmp/.state/concept-plan.json.
3415
+ set. Discovery order (exclusive of --manifest):
3416
+ a) Cargo workspace members / npm workspaces / Go modules
3417
+ b) graph packages (noise-filtered when a language inventory exists)
3418
+ c) heuristic top-level source dirs
3419
+ Coarse graph parents (e.g. crates/codegen) become Subsystems;
3420
+ crate/package names become Modules. Tokenizer noise (str, int, …)
3421
+ is dropped when unmapped. Writes draft.tmp/.state/concept-plan.json.
3417
3422
  okf-plan-concepts.sh --repo . [--scope PATH] \
3418
3423
  [--manifest FILE] [--min-fan-in 2] [--allow-defer GLOB]... \
3419
3424
  --out draft.tmp/.state/concept-plan.json
3420
- This replaces the old in-context concept enumeration — the boundary
3421
- of the work is now a tool output, not an LLM judgment, so modules
3422
- and sub-modules cannot be silently dropped. (Legacy fan-in
3423
- exemption is opt-in via --defer-below-floor.) LOG the counts
3424
- (expected/required/deferred) BEFORE writing any page.
3425
- `generated_order` is topo-ish (required + high-fan-in first) so
3426
- forward cross-links resolve.
3427
- 3. Generate → iterate concept-plan.generated_order; write ONE page per REQUIRED
3428
- entry, grounding each from the graph:
3429
- x-callers ← graph-callers.sh --symbol <c>
3430
- x-grounded-paths ← graph-impact.sh --symbol <c> (blast radius)
3431
- x-hotspot-score ← hotspot-rank.sh
3432
- overview diagrams mermaid-from-graph.sh
3433
- Record each source path → page in .state/path-to-concept.json.
3434
- Loop post-condition: every required concept_id has an output file.
3435
- Writing pages via shell heredoc without reading x-grounded-paths
3436
- sources, or finishing while any required entry is unwritten, is a
3437
- completeness failure not a stylistic one.
3438
- 4. Render views → ai-context.md (synopsis + Concept Map), architecture.md
3439
- (concatenated view + coverage banner), wiki/log.md (see M4).
3440
- 5. Validate → the promotion gate. Run all layers via the orchestrator:
3441
- 5a. okf-validate-all.sh draft.tmp/wiki \
3442
- --repo . \
3443
- --plan draft.tmp/.state/concept-plan.json \
3444
- --path-index draft.tmp/.state/path-to-concept.json \
3445
- --strict --report draft.tmp/.state/validation-report.json
3446
- It runs, in order: okf-validate.sh (structure + reverse index +
3447
- empty/untyped-page + leftover-template-token + dangling-link checks),
3448
- okf-validate-quality.sh (per-type anti-stub / depth / per-section
3449
- content / mermaid lint), okf-coverage-check.sh (every required plan
3450
- entry → real page).
3451
- ANY layer failing ⇒ exit non-zero ⇒ DO NOT atomic-rename.
3452
- coverage.md (systems/coverage.md) is regenerated by the coverage
3453
- layer; it is tool-owned (marker <!-- okf:coverage-generated -->) —
3454
- never hand-author it except deferral reasons in the manifest.
3455
- 6. Emit → mv draft.tmp/ draft/ ONLY IF step 5 exit 0 ; update .state/.
3456
- On failure keep draft.tmp/ and surface validation-report.json.
3457
- ```
3458
-
3459
- ### Validation report schema (`.state/validation-report.json`)
3460
-
3461
- ```json
3462
- { "valid": false, "bundle": "draft.tmp/wiki",
3463
- "layers": { "structure": "pass", "quality": "pass", "coverage": "fail" } }
3425
+ LOG counts (expected/required/deferred + discovery[]) BEFORE pages.
3426
+ 3. Catalog floor okf-emit-catalog.sh writes a quality-passing MINIMUM page for
3427
+ every REQUIRED plan entry that is still missing (so XL monorepos
3428
+ do not depend on the LLM for completeness):
3429
+ okf-emit-catalog.sh --plan draft.tmp/.state/concept-plan.json \
3430
+ --bundle draft.tmp/wiki --repo .
3431
+ 4. Generate/enrich → iterate concept-plan.generated_order; enrich top hotspots
3432
+ (LLM) beyond the catalog floor. Record path-to-concept.json.
3433
+ Post-condition: every required concept_id has a non-stub page.
3434
+ 5. Render views → okf-render-views.sh (architecture.md + Concept Map + section
3435
+ indexes). Uses GFM slugs for TOC; rewrites sibling links to
3436
+ wiki/<section>/…. Then okf-fix-links.sh --draft draft.tmp --fix.
3437
+ 6. Validate → promotion gate (order is intentional):
3438
+ okf-validate-all.sh draft.tmp/wiki \
3439
+ --plan draft.tmp/.state/concept-plan.json \
3440
+ --path-index draft.tmp/.state/path-to-concept.json \
3441
+ --strict --report draft.tmp/.state/validation-report.json
3442
+ Runs: quality coverage (rewrites coverage.md) → structure LAST
3443
+ so coverage relative links are checked. Also run:
3444
+ okf-fix-links.sh --draft draft.tmp --check
3445
+ ANY failure DO NOT atomic-rename.
3446
+ 7. Emit → mv draft.tmp/ draft/ ONLY IF step 6 exit 0 ; update .state/.
3464
3447
  ```
3465
3448
 
3466
- ### Component manifest (optional — `--manifest FILE`)
3467
-
3468
- When the graph engine is unavailable (or a repo wants an authoritative list), pass
3469
- a plain-text manifest: one component name per line, `#` comments and blanks ignored.
3470
- Every listed component becomes a REQUIRED concept; `--allow-defer GLOB` still moves
3471
- matches to deferred. Without a manifest the plan comes from the graph, and only if
3472
- both are unavailable does it fall back to a heuristic top-level-dir scan (which it
3473
- marks `degraded: true`).
3474
-
3475
- Page bodies are LLM-narrated for readability **but** the graph-derived
3476
- frontmatter and the `Blast radius`/`Used by` sections are deterministic. To keep
3477
- incremental carry-forward byte-identical (open decision 2), cache the narrated
3478
- prose keyed by the source hash of `x-grounded-paths` — unchanged sources reuse
3479
- the cached narration verbatim.
3480
-
3481
3449
  ## Render views (M4)
3482
3450
 
3483
3451
  Both are produced by the deterministic helper `okf-render-views.sh` (no LLM) —
@@ -3531,17 +3499,16 @@ section `index.md` tables are the injection slots for the routing tables.
3531
3499
  `draft init refresh` under `okf` mode:
3532
3500
 
3533
3501
  ```
3534
- 1. Re-derive the plan: okf-plan-concepts.sh (modules added since last run become
3535
- REQUIRED — a new package can't slip through a refresh either)
3536
- 2. Diff hashes.json vs working tree changed source paths
3537
- 3. path-to-concept.json affected concept pages
3538
- 4. Regenerate ONLY affected concepts; carry the rest verbatim (cached narration)
3539
- 5. Re-render ai-context.md / architecture.md / log.md (cheap; always regenerated)
3540
- 6. Re-validate (full gate): okf-validate-all.sh on the bundle with --plan and
3541
- --path-index. Refresh re-runs structure + quality + coverage — a changed
3542
- concept must still clear the quality bar, and a newly-required module must
3543
- still be present.
3544
- 7. Append log.md; update hashes.json + path-to-concept.json
3502
+ 1. Re-derive the plan: okf-plan-concepts.sh (cargo/npm/go + graph). Modules added
3503
+ since last run become REQUIRED — a new crate cannot slip through a refresh.
3504
+ 2. Diff plan vs previous concept-plan.json NEW required concept_ids
3505
+ 3. Diff hashes.json vs working tree changed source paths
3506
+ 4. path-to-concept.json → affected concept pages
3507
+ 5. okf-emit-catalog.sh for any NEW missing required pages (completeness floor)
3508
+ 6. Regenerate/enrich changed + new concepts; carry the rest verbatim
3509
+ 7. Re-render ai-context.md / architecture.md / log.md + okf-fix-links --fix
3510
+ 8. Re-validate: okf-validate-all + okf-fix-links --check
3511
+ 9. Append log.md; update hashes.json + path-to-concept.json + concept-plan.json
3545
3512
  ```
3546
3513
 
3547
3514
  A 1-file change regenerates only the concept(s) that file grounds. Unchanged
@@ -3606,7 +3573,7 @@ echo "Target repo: $REPO_ABS"
3606
3573
  # Locate Draft's bundled helpers. Skills run with cwd = the user's project and
3607
3574
  # ${CLAUDE_PLUGIN_ROOT} is not exported into skill Bash, so resolve DRAFT_TOOLS here
3608
3575
  # and call helpers as "$DRAFT_TOOLS/<tool>.sh". See core/shared/tool-resolver.md.
3609
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
3576
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
3610
3577
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
3611
3578
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
3612
3579
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -4540,7 +4507,7 @@ First resolve the bundled helpers:
4540
4507
  ```bash
4541
4508
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
4542
4509
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
4543
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
4510
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
4544
4511
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
4545
4512
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
4546
4513
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -4943,7 +4910,7 @@ Resolve the script via the canonical tool resolver (see [core/shared/tool-resolv
4943
4910
  ```bash
4944
4911
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
4945
4912
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
4946
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
4913
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
4947
4914
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
4948
4915
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
4949
4916
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -5190,7 +5157,7 @@ As the last step after the completion announcement, emit a metrics record. Best-
5190
5157
  ```bash
5191
5158
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
5192
5159
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
5193
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
5160
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
5194
5161
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
5195
5162
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
5196
5163
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -5338,7 +5305,7 @@ If one of these applies, route directly to the specialist workflow and stop this
5338
5305
  ```bash
5339
5306
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
5340
5307
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
5341
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
5308
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
5342
5309
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
5343
5310
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
5344
5311
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -5838,7 +5805,7 @@ After a phase passes review, refresh `metadata.json.impact` so future tracks can
5838
5805
 
5839
5806
  2. **Compute downstream blast radius (graph-aware, optional):** If `draft/graph/schema.yaml` exists, for each file in `files_touched` query (this runs in its own Bash session — re-resolve the helpers):
5840
5807
  ```bash
5841
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
5808
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
5842
5809
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
5843
5810
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
5844
5811
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -6042,7 +6009,7 @@ If no active track and no argument provided:
6042
6009
  **Preferred:** use the deterministic `detect-test-framework.sh` wrapper — it emits JSON `{languages:[{language,framework,runner_command,test_globs,config_file}]}`. Resolve via the canonical tool resolver (see [core/shared/tool-resolver.md](../../core/shared/tool-resolver.md)):
6043
6010
 
6044
6011
  ```bash
6045
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
6012
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
6046
6013
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
6047
6014
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
6048
6015
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -6084,7 +6051,7 @@ Build the coverage command with the appropriate scope/filter flags.
6084
6051
 
6085
6052
  ```bash
6086
6053
  # Re-resolve helpers (this is a separate Bash session from Step 2).
6087
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
6054
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
6088
6055
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
6089
6056
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
6090
6057
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -6417,7 +6384,7 @@ by validator.
6417
6384
  ```bash
6418
6385
  TRACK_DIR="$1" # absolute path to track-under-deploy, or .
6419
6386
 
6420
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
6387
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
6421
6388
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
6422
6389
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
6423
6390
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -6677,7 +6644,7 @@ Read and follow the base procedure in `core/shared/draft-context-loading.md`.
6677
6644
  ```bash
6678
6645
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
6679
6646
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
6680
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
6647
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
6681
6648
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
6682
6649
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
6683
6650
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -7710,7 +7677,7 @@ First resolve the bundled helpers:
7710
7677
  ```bash
7711
7678
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
7712
7679
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
7713
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
7680
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
7714
7681
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
7715
7682
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
7716
7683
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -8079,7 +8046,7 @@ For the files changed in the diff, perform static checks using `grep` or similar
8079
8046
  ```bash
8080
8047
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
8081
8048
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
8082
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
8049
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
8083
8050
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
8084
8051
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
8085
8052
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -8824,7 +8791,7 @@ As the last step after saving the review report, emit a metrics record. Best-eff
8824
8791
  ```bash
8825
8792
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
8826
8793
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
8827
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
8794
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
8828
8795
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
8829
8796
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
8830
8797
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -8885,7 +8852,7 @@ Run the WS-9 chain from [verification-gates.md](../../core/shared/verification-g
8885
8852
 
8886
8853
  ```bash
8887
8854
  TRACK_DIR="draft/tracks/<id>"
8888
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
8855
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
8889
8856
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
8890
8857
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
8891
8858
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -11142,7 +11109,7 @@ First resolve the bundled helpers:
11142
11109
  ```bash
11143
11110
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
11144
11111
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
11145
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
11112
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
11146
11113
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
11147
11114
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
11148
11115
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -11368,7 +11335,7 @@ First resolve the bundled helpers:
11368
11335
  ```bash
11369
11336
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
11370
11337
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
11371
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
11338
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
11372
11339
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
11373
11340
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
11374
11341
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -11683,7 +11650,7 @@ As the last step after saving the deep-review report, emit a metrics record. Bes
11683
11650
  ```bash
11684
11651
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
11685
11652
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
11686
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
11653
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
11687
11654
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
11688
11655
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
11689
11656
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -11901,7 +11868,7 @@ First resolve the bundled helpers:
11901
11868
  ```bash
11902
11869
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
11903
11870
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
11904
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
11871
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
11905
11872
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
11906
11873
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
11907
11874
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -12430,7 +12397,7 @@ Check for arguments:
12430
12397
  If argument is `list`:
12431
12398
  1. Prefer the deterministic `adr-index.sh` wrapper for the listing — it returns a structured JSON `{adrs:[{id,title,date,status,path,related_tracks}]}` derived from each ADR's frontmatter. Resolve via the canonical tool resolver (see [core/shared/tool-resolver.md](../../core/shared/tool-resolver.md)):
12432
12399
  ```bash
12433
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
12400
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
12434
12401
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
12435
12402
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
12436
12403
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -12765,7 +12732,7 @@ First resolve the bundled helpers:
12765
12732
  ```bash
12766
12733
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
12767
12734
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
12768
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
12735
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
12769
12736
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
12770
12737
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
12771
12738
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -13017,7 +12984,7 @@ Check for arguments:
13017
12984
  **Preferred:** invoke `parse-git-log.sh` — it parses conventional commits into structured JSONL `{sha,type,scope,track_id,subject,author,timestamp,files_changed}`, eliminating ambiguity in `type(track-id): subject` parsing. Resolve via the canonical tool resolver (see [core/shared/tool-resolver.md](../../core/shared/tool-resolver.md)):
13018
12985
 
13019
12986
  ```bash
13020
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
12987
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
13021
12988
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
13022
12989
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
13023
12990
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -13161,7 +13128,7 @@ First resolve the bundled helpers:
13161
13128
  ```bash
13162
13129
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
13163
13130
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
13164
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
13131
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
13165
13132
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
13166
13133
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
13167
13134
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -13242,7 +13209,7 @@ For TODO/FIXME/HACK/XXX/DEPRECATED markers, prefer the deterministic `scan-marke
13242
13209
  ```bash
13243
13210
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
13244
13211
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
13245
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
13212
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
13246
13213
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
13247
13214
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
13248
13215
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -13965,7 +13932,7 @@ Display a comprehensive overview of project progress.
13965
13932
  If `parse-reports.sh` and `freshness-check.sh` are available, gather structured signals to enrich the status output (severity counts per track, stale `draft/` docs). Resolve via the canonical tool resolver (see [core/shared/tool-resolver.md](../../core/shared/tool-resolver.md)):
13966
13933
 
13967
13934
  ```bash
13968
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
13935
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
13969
13936
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
13970
13937
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
13971
13938
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -14609,7 +14576,7 @@ First resolve the bundled helpers:
14609
14576
  ```bash
14610
14577
  # Locate Draft's bundled helpers (cwd is the user's project; ${CLAUDE_PLUGIN_ROOT}
14611
14578
  # is not exported into skill Bash). See core/shared/tool-resolver.md.
14612
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
14579
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
14613
14580
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
14614
14581
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
14615
14582
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -16551,7 +16518,7 @@ Referenced by: All skills that generate Draft reports — including `draft bughu
16551
16518
  Use `git-metadata.sh` from the plugin install, resolved via the canonical tool resolver (see [tool-resolver.md](tool-resolver.md)):
16552
16519
 
16553
16520
  ```bash
16554
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
16521
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
16555
16522
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
16556
16523
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
16557
16524
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -16986,7 +16953,7 @@ Write the completed content to `draft/.ai-context.md`.
16986
16953
  After writing both output files, strip trailing whitespace and blank lines at EOF to prevent GitHub upload failures. Resolve the script via the canonical tool resolver (see [tool-resolver.md](tool-resolver.md)):
16987
16954
 
16988
16955
  ```bash
16989
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
16956
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
16990
16957
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
16991
16958
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
16992
16959
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -17447,10 +17414,10 @@ These fields are appended to `~/.draft/metrics.jsonl` along with the existing sk
17447
17414
 
17448
17415
  ## Tooling Wrappers
17449
17416
 
17450
- For common query modes, prefer the deterministic wrappers that ship with the plugin. Resolve their location via the canonical tool resolver (see [tool-resolver.md](tool-resolver.md)) before invoking. Skills run with cwd = the user's project and `${CLAUDE_PLUGIN_ROOT}` is **not** exported into skill Bash, so a bare `scripts/tools/foo.sh` fails — establish `DRAFT_TOOLS` once before the first helper call, in the same Bash session as your tool calls (re-establish it if you split helper calls into a separate, later Bash block):
17417
+ For common query modes, prefer the deterministic wrappers that ship with the plugin. Resolve their location via the canonical tool resolver (see [tool-resolver.md](tool-resolver.md)) before invoking. Skills run with cwd = the user's project and `${CLAUDE_PLUGIN_ROOT}` is **not** exported into skill Bash, so a bare `scripts/tools/git-metadata.sh` fails — establish `DRAFT_TOOLS` once before the first helper call, in the same Bash session as your tool calls (re-establish it if you split helper calls into a separate, later Bash block):
17451
17418
 
17452
17419
  ```bash
17453
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
17420
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
17454
17421
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
17455
17422
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
17456
17423
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -17566,7 +17533,7 @@ Live queries go through the shell tools under `scripts/tools/`, which drive the
17566
17533
  ### Callers — who calls this function?
17567
17534
 
17568
17535
  ```bash
17569
- scripts/tools/graph-callers.sh --repo . --symbol <name>
17536
+ "$DRAFT_TOOLS/graph-callers.sh" --repo . --symbol <name>
17570
17537
  ```
17571
17538
 
17572
17539
  Output: `{symbol, callers[{name, file}], source}`. Use when enumerating call sites before claiming "no other usages" or judging breaking-change severity.
@@ -17574,8 +17541,8 @@ Output: `{symbol, callers[{name, file}], source}`. Use when enumerating call sit
17574
17541
  ### Impact — blast radius of a file or symbol
17575
17542
 
17576
17543
  ```bash
17577
- scripts/tools/graph-impact.sh --repo . --file <path> # changed-file impact (working-tree diff)
17578
- scripts/tools/graph-impact.sh --repo . --symbol <name> # transitive callers of a function
17544
+ "$DRAFT_TOOLS/graph-impact.sh" --repo . --file <path> # changed-file impact (working-tree diff)
17545
+ "$DRAFT_TOOLS/graph-impact.sh" --repo . --symbol <name> # transitive callers of a function
17579
17546
  ```
17580
17547
 
17581
17548
  Output: `{target, kind, impacted[{name, file, hop}], source}`. Use when sizing risk before modifying a file or symbol, especially high-fan-in hotspots.
@@ -17583,7 +17550,7 @@ Output: `{target, kind, impacted[{name, file, hop}], source}`. Use when sizing r
17583
17550
  ### Hotspots — fan-in ranking
17584
17551
 
17585
17552
  ```bash
17586
- scripts/tools/hotspot-rank.sh --repo . [--top N]
17553
+ "$DRAFT_TOOLS/hotspot-rank.sh" --repo . [--top N]
17587
17554
  ```
17588
17555
 
17589
17556
  Output: `{hotspots[{id, name, fanIn}], source}` (server-computed by the engine).
@@ -17591,7 +17558,7 @@ Output: `{hotspots[{id, name, fanIn}], source}` (server-computed by the engine).
17591
17558
  ### Cycles — call-cycle detection
17592
17559
 
17593
17560
  ```bash
17594
- scripts/tools/cycle-detect.sh --repo .
17561
+ "$DRAFT_TOOLS/cycle-detect.sh" --repo .
17595
17562
  ```
17596
17563
 
17597
17564
  Output: `{cycles[[a,b],[a,b,c]], source}` — fixed-length 2- and 3-node `CALLS` cycles (mutual recursion / tight coupling).
@@ -17601,7 +17568,7 @@ Output: `{cycles[[a,b],[a,b,c]], source}` — fixed-length 2- and 3-node `CALLS`
17601
17568
  Query the engine's architecture view live with the `graph-arch.sh` wrapper (it resolves the engine, indexes on demand, and auto-resolves the project):
17602
17569
 
17603
17570
  ```bash
17604
- scripts/tools/graph-arch.sh --repo . \
17571
+ "$DRAFT_TOOLS/graph-arch.sh" --repo . \
17605
17572
  | jq '{packages, node_labels, edge_types, routes, layers, boundaries}'
17606
17573
  ```
17607
17574
 
@@ -17610,8 +17577,8 @@ scripts/tools/graph-arch.sh --repo . \
17610
17577
  ### Mermaid — diagram text
17611
17578
 
17612
17579
  ```bash
17613
- scripts/tools/mermaid-from-graph.sh --repo . --diagram module-deps # co-change coupling
17614
- scripts/tools/mermaid-from-graph.sh --repo . --diagram proto-map # detected routes
17580
+ "$DRAFT_TOOLS/mermaid-from-graph.sh" --repo . --diagram module-deps # co-change coupling
17581
+ "$DRAFT_TOOLS/mermaid-from-graph.sh" --repo . --diagram proto-map # detected routes
17615
17582
  ```
17616
17583
 
17617
17584
  Emits a ready-to-inject ` ```mermaid ``` ` block on the fly (computed live by the engine), or an empty stub (exit 2) when the engine is unavailable. Diagrams are generated at the moment of use — they are never committed.
@@ -17619,7 +17586,7 @@ Emits a ready-to-inject ` ```mermaid ``` ` block on the fly (computed live by th
17619
17586
  ### Snippet — verified source + caller/callee counts
17620
17587
 
17621
17588
  ```bash
17622
- scripts/tools/graph-snippet.sh --repo . --qualified <pkg.Mod.Class.method>
17589
+ "$DRAFT_TOOLS/graph-snippet.sh" --repo . --qualified <pkg.Mod.Class.method>
17623
17590
  ```
17624
17591
 
17625
17592
  Output: `{qualified_name, file, start_line, end_line, callers, callees, transitive_loop_depth, complexity, code, status, source}`. Prefer this over grep+Read when you have a qualified name — it returns the engine's attributed source plus pre-computed counts.
@@ -17627,7 +17594,7 @@ Output: `{qualified_name, file, start_line, end_line, callers, callees, transiti
17627
17594
  ### Search — semantic / ranked symbol lookup
17628
17595
 
17629
17596
  ```bash
17630
- scripts/tools/graph-search.sh --repo . --query "auth token refresh" [--limit N]
17597
+ "$DRAFT_TOOLS/graph-search.sh" --repo . --query "auth token refresh" [--limit N]
17631
17598
  ```
17632
17599
 
17633
17600
  Output: `{query, results[{name, qualified_name, label, file, rank}], total, source}`. Use when the user names an **intent/concept** rather than an exact symbol — this is the first move in the Concept-to-Files recipe.
@@ -17635,8 +17602,8 @@ Output: `{query, results[{name, qualified_name, label, file, rank}], total, sour
17635
17602
  ### Tests — coverage edges and untested surface
17636
17603
 
17637
17604
  ```bash
17638
- scripts/tools/graph-tests.sh --repo . --symbol <name> # tests covering a symbol
17639
- scripts/tools/graph-tests.sh --repo . --untested # exported symbols with no TESTS edge
17605
+ "$DRAFT_TOOLS/graph-tests.sh" --repo . --symbol <name> # tests covering a symbol
17606
+ "$DRAFT_TOOLS/graph-tests.sh" --repo . --untested # exported symbols with no TESTS edge
17640
17607
  ```
17641
17608
 
17642
17609
  Output: `{symbol, tests[{test,file}], status, source}` or `{untested[{symbol,file}], total, truncated, source}`. Feeds coverage gaps for `init`/`testing-strategy`/`coverage`.
@@ -17644,7 +17611,7 @@ Output: `{symbol, tests[{test,file}], status, source}` or `{untested[{symbol,fil
17644
17611
  ### Deps — real module/file import graph
17645
17612
 
17646
17613
  ```bash
17647
- scripts/tools/graph-deps.sh --repo . [--file PATH]
17614
+ "$DRAFT_TOOLS/graph-deps.sh" --repo . [--file PATH]
17648
17615
  ```
17649
17616
 
17650
17617
  Output: `{imports[{src,dst}], total, truncated, source}` from actual `IMPORTS` edges (self-imports filtered). This is the auto-derived dependency graph behind `mermaid-from-graph.sh --diagram module-deps` and `architecture.md §9`.
@@ -17652,7 +17619,7 @@ Output: `{imports[{src,dst}], total, truncated, source}` from actual `IMPORTS` e
17652
17619
  ### Hierarchy — class inheritance
17653
17620
 
17654
17621
  ```bash
17655
- scripts/tools/graph-hierarchy.sh --repo . [--symbol <Class> | --derived <Base>]
17622
+ "$DRAFT_TOOLS/graph-hierarchy.sh" --repo . [--symbol <Class> | --derived <Base>]
17656
17623
  ```
17657
17624
 
17658
17625
  Output: `{edges[{child,parent}], status, source}`. `--derived` gives the blast radius of changing a base class.
@@ -17660,8 +17627,8 @@ Output: `{edges[{child,parent}], status, source}`. `--derived` gives the blast r
17660
17627
  ### Errors — error-propagation paths
17661
17628
 
17662
17629
  ```bash
17663
- scripts/tools/graph-errors.sh --repo . --symbol <name> # what it raises/throws
17664
- scripts/tools/graph-errors.sh --repo . --type <ErrType> # who raises/throws that type
17630
+ "$DRAFT_TOOLS/graph-errors.sh" --repo . --symbol <name> # what it raises/throws
17631
+ "$DRAFT_TOOLS/graph-errors.sh" --repo . --type <ErrType> # who raises/throws that type
17665
17632
  ```
17666
17633
 
17667
17634
  Output: `{symbol, raises[...], status, source}` or `{type, raisers[...], status, source}`. `--type` drives fail-closed audits.
@@ -17669,7 +17636,7 @@ Output: `{symbol, raises[...], status, source}` or `{type, raisers[...], status,
17669
17636
  ### Risk — pre-computed risk hotspots
17670
17637
 
17671
17638
  ```bash
17672
- scripts/tools/graph-risk.sh --repo . [--min-complexity N]
17639
+ "$DRAFT_TOOLS/graph-risk.sh" --repo . [--min-complexity N]
17673
17640
  ```
17674
17641
 
17675
17642
  Output: `{risky[{symbol, file, complexity, flags}], total, truncated, source}` from the engine's pre-computed flags (`unguarded_recursion`, `recursion_in_loop`, `alloc_in_loop`, `linear_scan_in_loop`). High-signal input for `bughunt`/`deep-review` — the engine already found these.
@@ -17677,8 +17644,8 @@ Output: `{risky[{symbol, file, complexity, flags}], total, truncated, source}` f
17677
17644
  ### Generic — read-only escape hatch (all 20 edges / ~30 properties)
17678
17645
 
17679
17646
  ```bash
17680
- scripts/tools/graph-query.sh --repo . --cypher 'MATCH (f)-[:WRITES]->(v) RETURN f.name, v.name LIMIT 50'
17681
- scripts/tools/graph-query.sh --repo . --tool get_graph_schema --json '{}'
17647
+ "$DRAFT_TOOLS/graph-query.sh" --repo . --cypher 'MATCH (f)-[:WRITES]->(v) RETURN f.name, v.name LIMIT 50'
17648
+ "$DRAFT_TOOLS/graph-query.sh" --repo . --tool get_graph_schema --json '{}'
17682
17649
  ```
17683
17650
 
17684
17651
  Unlocks any edge type or node property without a purpose-built wrapper. Write verbs are rejected; stay inside the SAFE dialect set (above). Emits raw engine JSON.
@@ -17686,7 +17653,7 @@ Unlocks any edge type or node property without a purpose-built wrapper. Write ve
17686
17653
  ### Indexing / refreshing the gate marker
17687
17654
 
17688
17655
  ```bash
17689
- scripts/tools/graph-snapshot.sh --repo .
17656
+ "$DRAFT_TOOLS/graph-snapshot.sh" --repo .
17690
17657
  ```
17691
17658
 
17692
17659
  Indexes the repo into the engine and writes the `draft/graph/schema.yaml` gate marker (now including the `detect_changes` delta: `changed_files`/`impacted_symbols`). It writes **no** graph data. Run during `draft init` and `draft graph`, or whenever the index should be refreshed.
@@ -17705,7 +17672,7 @@ The engine is the `codebase-memory-mcp` binary. Resolution order (implemented by
17705
17672
  The canonical verifier is `scripts/tools/verify-graph-binary.sh` (`--json --verbose --strict`). It resolves and liveness-checks the engine and, in a `draft/` context, writes the usage-report side-effect:
17706
17673
 
17707
17674
  ```bash
17708
- ENGINE_INFO="$(scripts/tools/verify-graph-binary.sh --repo . --json 2>/dev/null || true)"
17675
+ ENGINE_INFO="$("$DRAFT_TOOLS/verify-graph-binary.sh" --repo . --json 2>/dev/null || true)"
17709
17676
  # {"status":"ok","engine_bin":"...","source":"managed|path|bundled:<arch>|override","arch":"..."}
17710
17677
  ```
17711
17678
 
@@ -17718,7 +17685,7 @@ After successful detection, `draft/.graph-binary-report.json` contains: `detecte
17718
17685
  Run during `draft:init` / `draft:graph`, or manually:
17719
17686
 
17720
17687
  ```bash
17721
- scripts/tools/graph-snapshot.sh --repo .
17688
+ "$DRAFT_TOOLS/graph-snapshot.sh" --repo .
17722
17689
  ```
17723
17690
 
17724
17691
  The engine indexes C/C++, Go, Python, TypeScript/JS, and more (tree-sitter, 159 languages) plus LSP-assisted resolution for the major ones, and detects HTTP/gRPC/GraphQL routes. Indexing is incremental in the engine (content-based, git-aware). This refreshes the engine index and rewrites the `schema.yaml` gate marker; it produces no committed graph data.
@@ -18557,7 +18524,7 @@ project**, not the plugin. The helpers live inside the plugin install directory,
18557
18524
  which on a marketplace/npm install is `~/.claude/plugins/cache/<marketplace>/draft/<version>/`
18558
18525
  — never the cwd. `${CLAUDE_PLUGIN_ROOT}` is **not** exported into skill-driven Bash
18559
18526
  (it is only set for hooks, MCP/LSP servers, and monitor commands), so a bare
18560
- `scripts/tools/foo.sh` or `${CLAUDE_PLUGIN_ROOT}/...` invocation silently fails.
18527
+ `scripts/tools/git-metadata.sh` or `${CLAUDE_PLUGIN_ROOT}/...` invocation silently fails.
18561
18528
 
18562
18529
  Every skill MUST resolve `DRAFT_TOOLS` and invoke helpers as `"$DRAFT_TOOLS/<tool>.sh"`.
18563
18530
 
@@ -18566,16 +18533,20 @@ Every skill MUST resolve `DRAFT_TOOLS` and invoke helpers as `"$DRAFT_TOOLS/<too
18566
18533
  `DRAFT_TOOLS` resolves to the first directory that exists, in this order:
18567
18534
 
18568
18535
  1. `${DRAFT_PLUGIN_ROOT}/scripts/tools` — explicit override (testing / pinned installs)
18569
- 2. `$(cat ~/.cache/draft/plugin-root)/scripts/tools` — install marker written by `draft install` (authoritative)
18570
- 3. `${CLAUDE_PLUGIN_ROOT}/scripts/tools` set in hook/MCP contexts; harmless to probe
18571
- 4. `installed_plugins.json installPath` for `draft@*` Claude Code's own registry (needs `jq`)
18572
- 5. `~/.claude/plugins/cache/*/draft/*/scripts/tools` — newest cache install (glob, `sort -V`)
18573
- 6. `~/.claude/plugins/marketplaces/*draft*/scripts/tools` — marketplace clone
18574
- 7. `~/.cursor/plugins/local/draft/scripts/tools` — Cursor local install
18575
- 8. `$PWD/scripts/tools` — dev / dogfooding (running inside the draft repo itself)
18576
-
18577
- The marker (step 2) is the fast, authoritative path; steps 5–6 are the glob fallback
18578
- that keeps resolution working on installs predating the marker (no reinstall required).
18536
+ 2. `$PWD/scripts/tools` — dev / dogfooding when cwd IS the draft repo (guarded by
18537
+ `resolve-tools.sh`'s own presence, so it can never misfire in a user project;
18538
+ deliberately beats the install marker so a repo checkout always wins)
18539
+ 3. `$(cat ~/.cache/draft/plugin-root)/scripts/tools` — install marker written by `draft install` (authoritative for installs)
18540
+ 4. `${CLAUDE_PLUGIN_ROOT}/scripts/tools` — set in hook/MCP contexts; harmless to probe
18541
+ 5. `installed_plugins.json → installPath` for `draft@*` Claude Code's own registry (needs `jq`)
18542
+ 6. `~/.claude/plugins/cache/*/draft/*/scripts/tools` — newest cache install (glob, `sort -V`)
18543
+ 7. `~/.claude/plugins/marketplaces/*draft*/scripts/tools` — marketplace clone
18544
+ 8. `~/.cursor/plugins/local/draft/scripts/tools` Cursor local install
18545
+ 9. `$PWD/scripts/tools` last-resort cwd fallback (unguarded)
18546
+
18547
+ The marker (step 3) is the fast, authoritative path for installs; steps 6–7 are the
18548
+ glob fallback that keeps resolution working on installs predating the marker (no
18549
+ reinstall required).
18579
18550
 
18580
18551
  ## Skill preamble (copy verbatim)
18581
18552
 
@@ -18586,7 +18557,7 @@ invocations (only the cwd does), so if you split helper calls into a later, sepa
18586
18557
  Bash block, re-establish `DRAFT_TOOLS` there too:
18587
18558
 
18588
18559
  ```bash
18589
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
18560
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
18590
18561
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
18591
18562
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
18592
18563
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"
@@ -18600,9 +18571,10 @@ Then invoke helpers through the variable:
18600
18571
  ```
18601
18572
 
18602
18573
  The four-line inline preamble is self-contained and is the recommended form for
18603
- skills — it needs no marker file and no prior `source`. The full 8-step resolver
18604
- (adding the `${DRAFT_PLUGIN_ROOT}` override, `${CLAUDE_PLUGIN_ROOT}`, the jq-registry
18605
- lookup, and the Cursor path) is shipped as `scripts/tools/resolve-tools.sh` for tests
18574
+ skills — it needs no marker file and no prior `source`. The full resolver
18575
+ (adding the `${DRAFT_PLUGIN_ROOT}` override, the guarded dogfood short-circuit,
18576
+ `${CLAUDE_PLUGIN_ROOT}`, the jq-registry lookup, and the Cursor path) is shipped
18577
+ as `scripts/tools/resolve-tools.sh` for tests
18606
18578
  and for callers that prefer a single source of truth:
18607
18579
 
18608
18580
  ```bash
@@ -19786,326 +19758,6 @@ This is the single forward-looking source of truth. Legacy 28-section volume-ori
19786
19758
 
19787
19759
  ---
19788
19760
 
19789
- ## core/templates/track-architecture.md
19790
-
19791
- <core-file path="core/templates/track-architecture.md">
19792
-
19793
- ---
19794
- project: "{PROJECT_NAME}"
19795
- module: "root"
19796
- track_id: "{TRACK_ID}"
19797
- generated_by: "draft:decompose"
19798
- generated_at: "{ISO_TIMESTAMP}"
19799
- git:
19800
- branch: "{LOCAL_BRANCH}"
19801
- remote: "{REMOTE/BRANCH}"
19802
- commit: "{FULL_SHA}"
19803
- commit_short: "{SHORT_SHA}"
19804
- commit_date: "{COMMIT_DATE}"
19805
- commit_message: "{COMMIT_MESSAGE}"
19806
- dirty: false
19807
- synced_to_commit: "{FULL_SHA}"
19808
- ---
19809
-
19810
- # Track Architecture: {TRACK_TITLE}
19811
-
19812
- > Track-scoped HLD/LLD for a single feature, bug fix, or refactor.
19813
- > Source of truth for implementation — `draft implement` consumes this to guide build order, contracts, and story generation.
19814
- > For project-wide architecture, see `draft/architecture.md`.
19815
-
19816
- | Field | Value |
19817
- |-------|-------|
19818
- | **Track ID** | `{TRACK_ID}` |
19819
- | **Spec** | `./spec.md` |
19820
- | **Plan** | `./plan.md` |
19821
- | **Branch** | `{LOCAL_BRANCH}` → `{REMOTE/BRANCH}` |
19822
- | **Commit** | `{SHORT_SHA}` — {COMMIT_MESSAGE} |
19823
- | **Generated** | {ISO_TIMESTAMP} |
19824
- | **LLD Included** | {true | false} |
19825
-
19826
- ---
19827
-
19828
- ## Table of Contents
19829
-
19830
- 1. [Overview](#1-overview)
19831
- 2. [Module Breakdown](#2-module-breakdown)
19832
- 3. [High-Level Design (HLD)](#3-high-level-design-hld)
19833
- - 3.1 Component Diagram
19834
- - 3.2 Data Flow
19835
- - 3.3 Sequence Diagrams (Critical Flows)
19836
- - 3.4 State Machine(s)
19837
- 4. [Dependency Analysis](#4-dependency-analysis)
19838
- 5. [Implementation Order](#5-implementation-order)
19839
- 6. [Low-Level Design (LLD)](#6-low-level-design-lld)
19840
- - 6.1 Per-Module API Contracts
19841
- - 6.2 Data Models & Schemas
19842
- - 6.3 Error Handling & Retry Semantics
19843
- - 6.4 Algorithm Pseudocode (where non-trivial)
19844
- 7. [Notes & Decisions](#7-notes--decisions)
19845
-
19846
- ---
19847
-
19848
- ## 1. Overview
19849
-
19850
- **What this track delivers:** {one paragraph from spec.md — the feature, bug fix, or refactor being scoped}
19851
-
19852
- **Inputs:** {what triggers or feeds into this feature}
19853
- **Outputs:** {what this feature produces — data, side effects, API responses}
19854
- **Constraints:** {latency, throughput, compatibility, security — anything from spec.md Non-Functional Requirements}
19855
-
19856
- **Integration points:** {which existing modules from `draft/.ai-context.md` this track touches}
19857
-
19858
- ---
19859
-
19860
- ## 2. Module Breakdown
19861
-
19862
- ### Modules Introduced or Modified
19863
-
19864
- For each module in scope, fill out one block:
19865
-
19866
- #### Module: `{module-name}`
19867
-
19868
- - **Status:** `[ ] New` | `[ ] Modified` | `[x] Existing (unchanged)`
19869
- - **Responsibility:** {one sentence — what this module owns}
19870
- - **Files:** `{path/to/file1}`, `{path/to/file2}`
19871
- - **API Surface:** {public functions, classes, or interfaces — names only, contracts in §6.1}
19872
- - **Dependencies:** {other modules this imports from}
19873
- - **Complexity:** `Low` | `Medium` | `High`
19874
- - **Story placeholder:** _populated by `draft implement`_
19875
-
19876
- {Repeat for each module.}
19877
-
19878
- ---
19879
-
19880
- ## 3. High-Level Design (HLD)
19881
-
19882
- ### 3.1 Component Diagram
19883
-
19884
- Shows modules in scope + the external collaborators they talk to.
19885
-
19886
- ```mermaid
19887
- flowchart TD
19888
- subgraph Track["Track: {TRACK_ID}"]
19889
- M1["{module-1}"]
19890
- M2["{module-2}"]
19891
- M3["{module-3}"]
19892
- end
19893
- subgraph Existing["Existing System"]
19894
- E1["{existing-module-A}"]
19895
- E2["{existing-module-B}"]
19896
- end
19897
- subgraph External["External"]
19898
- X1["{DB / queue / API}"]
19899
- end
19900
-
19901
- M1 --> M2
19902
- M2 --> M3
19903
- M1 --> E1
19904
- M3 --> X1
19905
- ```
19906
-
19907
- > Draw one node per module in scope. Include existing modules only when this track calls into them. Label edges with the transport (HTTP, RPC, queue, direct call) when non-obvious.
19908
-
19909
- ### 3.2 Data Flow
19910
-
19911
- End-to-end flow of data through the track's modules.
19912
-
19913
- ```mermaid
19914
- flowchart LR
19915
- In["{input — request / event}"] --> V["{validation}"]
19916
- V --> L["{business logic}"]
19917
- L --> P["{persistence}"]
19918
- P --> Out["{output — response / emitted event}"]
19919
- ```
19920
-
19921
- > Replace with the actual transforms. If the track has distinct read and write paths, draw them separately.
19922
-
19923
- ### 3.3 Sequence Diagrams — Critical Flows
19924
-
19925
- One sequence per acceptance criterion that involves more than a single module call. Skip for trivial single-module tracks.
19926
-
19927
- #### Flow: {name — e.g., "Happy path: user submits X"}
19928
-
19929
- ```mermaid
19930
- sequenceDiagram
19931
- participant U as {Caller}
19932
- participant A as {module-1}
19933
- participant B as {module-2}
19934
- participant D as {DB / external}
19935
-
19936
- U->>A: {request payload}
19937
- A->>B: {internal call}
19938
- B->>D: {query / write}
19939
- D-->>B: {result}
19940
- B-->>A: {response}
19941
- A-->>U: {final response}
19942
-
19943
- Note over A,B: {invariant / gate — e.g., "tx must be open here"}
19944
- ```
19945
-
19946
- #### Flow: {error path — e.g., "Dependency timeout"}
19947
-
19948
- ```mermaid
19949
- sequenceDiagram
19950
- participant U as {Caller}
19951
- participant A as {module-1}
19952
- participant D as {External}
19953
-
19954
- U->>A: {request}
19955
- A->>D: {call with timeout={N}ms}
19956
- D--xA: {timeout}
19957
- A->>A: {fallback / circuit breaker}
19958
- A-->>U: {degraded response or error}
19959
- ```
19960
-
19961
- ### 3.4 State Machine(s)
19962
-
19963
- Include only if the track introduces or modifies stateful entities. Omit otherwise.
19964
-
19965
- ```mermaid
19966
- stateDiagram-v2
19967
- [*] --> Pending
19968
- Pending --> Processing: start
19969
- Processing --> Complete: success
19970
- Processing --> Failed: error
19971
- Failed --> Pending: retry (max {N})
19972
- Failed --> DeadLetter: retries exhausted
19973
- Complete --> [*]
19974
- ```
19975
-
19976
- ---
19977
-
19978
- ## 4. Dependency Analysis
19979
-
19980
- ### ASCII Dependency Graph
19981
-
19982
- ```
19983
- [module-1] ──> [module-2]
19984
- │ │
19985
- └──> [module-3] <──┘
19986
- ```
19987
-
19988
- ### Dependency Table
19989
-
19990
- | Module | Depends On | Depended By | Cycle? |
19991
- |--------|------------|-------------|--------|
19992
- | `{mod}` | `{list}` | `{list}` | no |
19993
-
19994
- ### Cycle Mitigation
19995
-
19996
- _If any cycles detected, describe how they are broken (shared interface extraction, dependency inversion, etc.). Otherwise: "No cycles detected."_
19997
-
19998
- ---
19999
-
20000
- ## 5. Implementation Order
20001
-
20002
- Topological sort — leaves first.
20003
-
20004
- 1. `{module-A}` (no internal deps) — foundational
20005
- 2. `{module-B}` (depends on: A)
20006
- 3. `{module-C}` (depends on: A, B)
20007
-
20008
- **Parallel opportunities:** {which modules can be built concurrently}
20009
-
20010
- ---
20011
-
20012
- ## 6. Low-Level Design (LLD)
20013
-
20014
- > Present when `--lld` flag was passed to `draft decompose` OR any module in §2 has `Complexity: High`. Otherwise this section reads: _"LLD not generated. Run `draft decompose --lld` to expand."_
20015
-
20016
- ### 6.1 Per-Module API Contracts
20017
-
20018
- For each module in §2 marked `New` or `Modified`:
20019
-
20020
- #### `{module-name}` — Public API
20021
-
20022
- | Function / Method | Signature | Params | Returns | Errors / Exceptions |
20023
- |-------------------|-----------|--------|---------|---------------------|
20024
- | `{name}` | `{lang-appropriate signature}` | `{param: type — constraint}` | `{type — shape}` | `{error types / codes}` |
20025
-
20026
- **Preconditions:** {what must be true before call — caller responsibilities}
20027
- **Postconditions:** {what is guaranteed after successful call}
20028
- **Invariants:** {properties preserved across calls — thread safety, idempotency, ordering}
20029
-
20030
- {Repeat per module.}
20031
-
20032
- ### 6.2 Data Models & Schemas
20033
-
20034
- Concrete shapes for every new or modified entity this track introduces.
20035
-
20036
- #### `{ModelName}`
20037
-
20038
- ```{language}
20039
- {actual type definition — struct, class, interface, proto message, TypedDict, etc.}
20040
- ```
20041
-
20042
- | Field | Type | Nullable | Default | Validation / Constraint |
20043
- |-------|------|----------|---------|-------------------------|
20044
- | `{field}` | `{type}` | yes/no | `{default or —}` | `{rule}` |
20045
-
20046
- **Storage:** {where persisted — table, collection, key prefix}
20047
- **Indexes / Keys:** {primary key, unique constraints, indexed fields}
20048
- **Migration:** {if this is a schema change — migration path and rollback}
20049
-
20050
- {Repeat per model.}
20051
-
20052
- ### 6.3 Error Handling & Retry Semantics
20053
-
20054
- Per-operation policy. One row per operation that has non-trivial error handling.
20055
-
20056
- | Operation | Error Class | Classification | Retry? | Backoff | Max Attempts | Fallback |
20057
- |-----------|-------------|----------------|--------|---------|--------------|----------|
20058
- | `{op}` | `{ErrorType}` | transient / permanent / timeout | yes/no | `{policy}` | `{N}` | `{behavior}` |
20059
-
20060
- **Propagation model:** {how errors surface — Result type, exceptions, error codes}
20061
- **Circuit breaker:** {thresholds, half-open policy, reset} — omit if N/A
20062
- **Idempotency:** {which operations are idempotent and how — dedup key, tx id}
20063
-
20064
- ### 6.4 Algorithm Pseudocode
20065
-
20066
- Include only for non-trivial logic. Skip for straightforward CRUD.
20067
-
20068
- #### {Algorithm name}
20069
-
20070
- **Inputs:** `{...}`
20071
- **Outputs:** `{...}`
20072
- **Complexity:** `O({...})` time, `O({...})` space
20073
-
20074
- ```
20075
- {numbered or indented pseudocode — language-agnostic}
20076
- 1. validate inputs
20077
- 2. ...
20078
- 3. return result
20079
- ```
20080
-
20081
- **Edge cases handled:**
20082
- - {case 1 — what happens}
20083
- - {case 2 — what happens}
20084
-
20085
- ---
20086
-
20087
- ## 7. Notes & Decisions
20088
-
20089
- ### Architecture Decisions
20090
-
20091
- - {decision 1 — rationale, alternatives considered}
20092
- - {decision 2 — rationale, alternatives considered}
20093
-
20094
- ### Open Questions
20095
-
20096
- - {question tracked during decomposition — to resolve before or during implementation}
20097
-
20098
- ### Links
20099
-
20100
- - Spec: `./spec.md`
20101
- - Plan: `./plan.md`
20102
- - Related ADRs: `{paths if any, created via draft adr}`
20103
- - Project architecture: `draft/.ai-context.md` → `draft/architecture.md`
20104
-
20105
- </core-file>
20106
-
20107
- ---
20108
-
20109
19761
  ## core/templates/jira.md
20110
19762
 
20111
19763
  <core-file path="core/templates/jira.md">
@@ -21022,7 +20674,7 @@ validator chain via the canonical resolver pattern (see
21022
20674
  [core/shared/verification-gates.md](../../core/shared/verification-gates.md)):
21023
20675
 
21024
20676
  ```bash
21025
- DRAFT_TOOLS="$(cat ~/.cache/draft/plugin-root 2>/dev/null)/scripts/tools"
20677
+ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}/scripts/tools"
21026
20678
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/cache/*/draft/*/scripts/tools 2>/dev/null | sort -V | tail -1)"
21027
20679
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$(ls -d ~/.claude/plugins/marketplaces/*draft*/scripts/tools 2>/dev/null | tail -1)"
21028
20680
  [ -d "$DRAFT_TOOLS" ] || DRAFT_TOOLS="$PWD/scripts/tools"