devflow-kit 2.5.0 → 3.0.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 (158) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +44 -19
  3. package/dist/agents/git.md +13 -15
  4. package/dist/cli/commands/ambient.js +160 -145
  5. package/dist/cli/commands/capture.js +29 -55
  6. package/dist/cli/commands/compliance.js +32 -61
  7. package/dist/cli/commands/context.js +17 -32
  8. package/dist/cli/commands/debug.js +65 -26
  9. package/dist/cli/commands/flags.js +3 -3
  10. package/dist/cli/commands/hud.js +34 -10
  11. package/dist/cli/commands/init-seed.js +40 -4
  12. package/dist/cli/commands/init.js +249 -271
  13. package/dist/cli/commands/install-report.js +10 -15
  14. package/dist/cli/commands/knowledge/index.js +1 -1
  15. package/dist/cli/commands/knowledge/toggle.js +11 -3
  16. package/dist/cli/commands/learning.js +52 -37
  17. package/dist/cli/commands/legacy-hooks.js +11 -14
  18. package/dist/cli/commands/memory.js +67 -78
  19. package/dist/cli/commands/proxy.js +23 -41
  20. package/dist/cli/commands/security.js +5 -13
  21. package/dist/cli/commands/skills.js +21 -3
  22. package/dist/cli/commands/tracker.js +100 -228
  23. package/dist/cli/commands/uninstall.js +343 -138
  24. package/dist/commands/bug-analysis.md +38 -12
  25. package/dist/commands/code-review.md +70 -21
  26. package/dist/commands/debug.md +37 -7
  27. package/dist/commands/dynamic-build.md +66 -17
  28. package/dist/commands/dynamic-plan.md +19 -8
  29. package/dist/commands/dynamic-profile.md +24 -10
  30. package/dist/commands/dynamic-tickets.md +22 -11
  31. package/dist/commands/explore.md +37 -7
  32. package/dist/commands/implement.md +96 -32
  33. package/dist/commands/plan.md +62 -19
  34. package/dist/commands/release.md +2 -2
  35. package/dist/commands/research.md +34 -8
  36. package/dist/commands/resolve.md +65 -17
  37. package/dist/commands/self-review.md +45 -9
  38. package/dist/core/compliance-compose.js +27 -27
  39. package/dist/core/evidence-policy.js +240 -24
  40. package/dist/core/feature-config.js +94 -25
  41. package/dist/core/feature-switch.js +1 -1
  42. package/dist/core/flags.js +30 -2
  43. package/dist/core/fs-atomic.js +27 -0
  44. package/dist/core/hook-log-dirs.js +104 -0
  45. package/dist/core/learning-tuning-config.js +5 -3
  46. package/dist/core/ledger-root.js +102 -0
  47. package/dist/core/manifest.js +6 -4
  48. package/dist/core/mds-variants.js +34 -97
  49. package/dist/core/migrations.js +49 -23
  50. package/dist/core/plugins.js +5 -4
  51. package/dist/core/project-paths.js +0 -17
  52. package/dist/core/same-location.js +25 -0
  53. package/dist/core/tracker.js +226 -139
  54. package/dist/hud/components/config-counts.js +15 -4
  55. package/dist/hud/components/learning-counts.js +14 -0
  56. package/dist/hud/config.js +2 -1
  57. package/dist/hud/cost-history.js +2 -4
  58. package/dist/hud/git.js +52 -7
  59. package/dist/hud/index.js +7 -9
  60. package/dist/skills/git/references/pr/check-merge-readiness.md +1 -1
  61. package/dist/skills/git/references/pr/ensure-pr-ready.md +1 -1
  62. package/dist/skills/git/references/pr/update-pr-evidence.md +1 -1
  63. package/dist/skills/git/references/tracker/_mcp.md +1 -1
  64. package/dist/skills/git/references/tracker/github/backlink-shipped-issues.md +1 -1
  65. package/dist/skills/git/references/tracker/github/ensure-traceable-issue.md +1 -1
  66. package/dist/skills/git/references/tracker/github/gather-release-evidence.md +2 -2
  67. package/dist/skills/git/references/tracker/github/manage-debt.md +3 -3
  68. package/dist/skills/git/references/tracker/jira/backlink-shipped-issues.md +1 -1
  69. package/dist/skills/git/references/tracker/jira/ensure-traceable-issue.md +1 -1
  70. package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +2 -2
  71. package/dist/skills/git/references/tracker/jira/manage-debt.md +1 -1
  72. package/dist/skills/git/references/tracker/jira/post-wave-report.md +1 -1
  73. package/dist/skills/git/references/tracker/jira/setup-task.md +1 -1
  74. package/dist/skills/git/references/tracker/linear/backlink-shipped-issues.md +1 -1
  75. package/dist/skills/git/references/tracker/linear/ensure-traceable-issue.md +1 -1
  76. package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +2 -2
  77. package/dist/skills/git/references/tracker/linear/manage-debt.md +1 -1
  78. package/dist/skills/git/references/tracker/linear/post-wave-report.md +1 -1
  79. package/dist/skills/git/references/tracker/linear/setup-task.md +1 -1
  80. package/dist/targets/claude-code/claude-paths.js +59 -57
  81. package/dist/targets/claude-code/compliance-install.js +49 -65
  82. package/dist/targets/claude-code/hooks.js +108 -3
  83. package/dist/targets/claude-code/installer.js +30 -57
  84. package/dist/targets/claude-code/post-install.js +232 -139
  85. package/dist/targets/claude-code/tracker-install.js +38 -65
  86. package/package.json +5 -4
  87. package/src/assets/agents/code.md +4 -3
  88. package/src/assets/agents/design.md +1 -0
  89. package/src/assets/agents/git.mds +55 -57
  90. package/src/assets/agents/knowledge.md +2 -2
  91. package/src/assets/agents/review.md +3 -1
  92. package/src/assets/agents/tracker.md +37 -30
  93. package/src/assets/commands/_partials/_compliance.mds +19 -1
  94. package/src/assets/commands/_partials/_decisions.mds +15 -3
  95. package/src/assets/commands/_partials/_docs_root.mds +35 -0
  96. package/src/assets/commands/_partials/_engine.mds +2 -2
  97. package/src/assets/commands/_partials/_evidence_policy.mds +3 -3
  98. package/src/assets/commands/_partials/_factory.mds +1 -1
  99. package/src/assets/commands/_partials/_knowledge.mds +27 -9
  100. package/src/assets/commands/_partials/_plan_contract.mds +2 -2
  101. package/src/assets/commands/_partials/_preamble.mds +1 -1
  102. package/src/assets/commands/_partials/_publication.mds +6 -2
  103. package/src/assets/commands/_partials/_settings.mds +28 -0
  104. package/src/assets/commands/_partials/_ticket_template.mds +3 -3
  105. package/src/assets/commands/_partials/_tracker.mds +4 -4
  106. package/src/assets/commands/_partials/_wave.mds +4 -4
  107. package/src/assets/commands/bug-analysis.mds +19 -17
  108. package/src/assets/commands/code-review.mds +39 -33
  109. package/src/assets/commands/debug.mds +4 -5
  110. package/src/assets/commands/dynamic-build.mds +75 -53
  111. package/src/assets/commands/dynamic-plan.mds +20 -15
  112. package/src/assets/commands/dynamic-profile.mds +24 -11
  113. package/src/assets/commands/dynamic-tickets.mds +25 -20
  114. package/src/assets/commands/explore.mds +4 -5
  115. package/src/assets/commands/implement.mds +58 -45
  116. package/src/assets/commands/plan.mds +34 -29
  117. package/src/assets/commands/release.md +2 -2
  118. package/src/assets/commands/research.mds +11 -9
  119. package/src/assets/commands/resolve.mds +41 -39
  120. package/src/assets/commands/self-review.mds +24 -25
  121. package/src/assets/mds/git/_pr.mds +61 -61
  122. package/src/assets/mds/git/_references.mds +19 -19
  123. package/src/assets/mds/tracker/_common.mds +8 -8
  124. package/src/assets/mds/tracker/_github.mds +71 -71
  125. package/src/assets/mds/tracker/_jira.mds +74 -74
  126. package/src/assets/mds/tracker/_linear.mds +75 -75
  127. package/src/assets/mds/tracker/_mcp.mds +23 -17
  128. package/src/assets/scripts/hooks/background-memory-update +35 -19
  129. package/src/assets/scripts/hooks/capture-prompt +18 -12
  130. package/src/assets/scripts/hooks/capture-question +18 -12
  131. package/src/assets/scripts/hooks/capture-turn +27 -17
  132. package/src/assets/scripts/hooks/debug-trace +11 -6
  133. package/src/assets/scripts/hooks/ensure-devflow-init +33 -6
  134. package/src/assets/scripts/hooks/ensure-proxy +9 -8
  135. package/src/assets/scripts/hooks/ensure-root-gitignore +111 -36
  136. package/src/assets/scripts/hooks/git-marker +48 -0
  137. package/src/assets/scripts/hooks/json-helper.cjs +6 -1
  138. package/src/assets/scripts/hooks/lib/project-paths.cjs +0 -19
  139. package/src/assets/scripts/hooks/log-paths +80 -0
  140. package/src/assets/scripts/hooks/memory-worker +17 -15
  141. package/src/assets/scripts/hooks/pre-compact-memory +41 -16
  142. package/src/assets/scripts/hooks/queue-append +104 -30
  143. package/src/assets/scripts/hooks/resolve-project-root +101 -7
  144. package/src/assets/scripts/hooks/session-start-context +289 -122
  145. package/src/assets/scripts/hooks/session-start-memory +35 -16
  146. package/src/assets/scripts/lib/project-config.cjs +633 -0
  147. package/src/assets/scripts/resolve-evidence-policy.cjs +300 -220
  148. package/src/assets/scripts/resolve-settings.cjs +1054 -0
  149. package/src/assets/scripts/verify-evidence.cjs +1 -1
  150. package/src/assets/skills/compliance/SKILL.md +2 -2
  151. package/src/assets/skills/docs-framework/SKILL.md +6 -7
  152. package/src/assets/skills/docs-framework/references/patterns.md +10 -17
  153. package/src/assets/skills/gap-analysis/SKILL.md +2 -2
  154. package/src/assets/skills/git/references/github-api.md +9 -9
  155. package/src/assets/skills/git/references/patterns.md +1 -1
  156. package/src/assets/skills/worktree-support/SKILL.md +1 -1
  157. package/src/assets/skills/worktree-support/references/roots.md +29 -0
  158. package/src/targets/claude-code/templates/managed-settings.json +25 -9
@@ -5,14 +5,15 @@ output-dir: dist/commands
5
5
  ---
6
6
  @import { authoring_preamble } from "./_partials/_preamble.mds"
7
7
  @import { evidence_policy } from "./_partials/_evidence_policy.mds"
8
+ @import { docs_root } from "./_partials/_docs_root.mds"
8
9
  @import { agent_roster, agent_caveats } from "./_partials/_roster.mds"
9
10
  @import { gate1_postcode, gate2_acceptance, evaluator_panel, implement_bundle, review_pass, concurrency_doctrine, build_execution_doctrine, engine_output_schema, engine_invariants } from "./_partials/_engine.mds"
10
11
  @import { wave_loop, branch_merge_model, merge_doctrine, escalation_model } from "./_partials/_wave.mds"
11
12
  @import { acceptance_criteria_contract } from "./_partials/_plan_contract.mds"
12
13
  @import { issue_ref_grammar, issue_capture_contract } from "./_partials/_tracker.mds"
13
14
  @import "./_partials/_publication.mds" as pub
14
-
15
- {authoring_preamble()}
15
+ @import "./_partials/_compliance.mds" as compliance
16
+ {{authoring_preamble()}}
16
17
 
17
18
  ---
18
19
 
@@ -20,14 +21,14 @@ output-dir: dist/commands
20
21
 
21
22
  This command instructs you to construct and run a Claude Code dynamic Workflow that implements, reviews, and verifies one ticket or a full wave of tickets, reusing devflow's existing agents via `agentType`.
22
23
 
23
- {agent_roster()}
24
+ {{agent_roster()}}
24
25
 
25
- {agent_caveats()}
26
+ {{agent_caveats()}}
26
27
 
27
28
  ---
28
29
 
29
30
  **Requires:** ticket or task description; optional plan document and acceptance criteria from `/devflow:dynamic-plan`
30
- **Produces:** implemented and reviewed branch per ticket; wave run report at `.devflow/docs/waves/\{slug\}/\{ts\}/wave-report.md`
31
+ **Produces:** implemented and reviewed branch per ticket; wave run report at `{integration worktree root}/.devflow/docs/waves/{slug}/{ts}/wave-report.md`
31
32
 
32
33
  ---
33
34
 
@@ -37,7 +38,7 @@ Before authoring, verify:
37
38
 
38
39
  1. **Workflow tool available:** if the `Workflow` tool is not in your available tools, STOP and tell the user: "The Workflow tool is not available in this session. dynamic-build requires Claude Code's dynamic workflow runtime."
39
40
  2. **`agentType` support:** confirmed available (spike F5, 2026-06-11). If spawned agents return no results, check that devflow is installed (`devflow init` has been run).
40
- 3. **Tracker paths:** an issue reference or URL in the input is read through the Git agent, which resolves the configured tracker and its access itself and reports `TRACEABILITY: DEGRADED (\{reason\})` when it cannot read one — then note it and fall back to the issue text the user provided. No tracker CLI is checked here.
41
+ 3. **Tracker paths:** an issue reference or URL in the input is read through the Git agent, which resolves the configured tracker and its access itself and reports `TRACEABILITY: DEGRADED ({reason})` when it cannot read one — then note it and fall back to the issue text the user provided. No tracker CLI is checked here.
41
42
  4. **No-remote path:** if the repo has no remote, skip the remote-dependent steps (the wave PR and its evidence) and proceed with local branch operations only; the Git agent reports DEGRADED for any tracker step it cannot reach.
42
43
 
43
44
  ---
@@ -50,10 +51,24 @@ Before you write the workflow script:
50
51
 
51
52
  **Produces:** EVIDENCE_POLICY, ISSUE_REQUIRED, APPLY_CONVENTIONS, REQUIRE_NON_AUTHOR_APPROVAL
52
53
 
53
- {evidence_policy()}
54
+ {{evidence_policy()}}
54
55
 
55
56
  Author the resolved `ISSUE_REQUIRED` and `APPLY_CONVENTIONS` into the workflow script as constants — pass them as `issueRequired` and `applyConventions` when invoking the workflow — and pass both to the Git `setup-task` spawn.
56
57
 
58
+ **0b. Resolve the compliance lens**
59
+
60
+ **Produces:** COMPLIANCE_FRAMEWORKS
61
+
62
+ {{compliance.compliance_lens()}}
63
+
64
+ Pass it as `complianceFrameworks` when invoking the workflow; the engine hands it to every Code agent.
65
+
66
+ **0c. Resolve the docs root**
67
+
68
+ {{docs_root()}}
69
+
70
+ `{integration worktree root}` is the toplevel of the checkout the integration branch is checked out in: `{worktree}` unless the wave runs in a linked worktree.
71
+
57
72
  **1. Apply decisions context**
58
73
 
59
74
  Apply the `devflow:apply-decisions` algorithm to the DECISIONS_CONTEXT loaded per the preamble above: scan the index, Read relevant entries, note the verbatim ADR/PF IDs you will inject into Code agent and Evaluate agent prompts.
@@ -66,7 +81,7 @@ Note the `budget` value from the Workflow tool context (or default to "medium" i
66
81
 
67
82
  - **SINGLE mode:** input is one ticket, one issue, one task description, or one plan document
68
83
  - **WAVE mode:** input is a set of tracker issues (wave labels, milestone, issue list), or the user says "wave" / "all tickets in wave N"
69
- - **A `/devflow:dynamic-tickets` ticket directory** (`.devflow/docs/tickets/\{slug\}/\{ts\}/`) is WAVE input: in each ticket file (every `.md` there but `tracking-issue.md`), the `**Issue:**` line directly after `**Depends on:**` is one raw `ISSUE_REFS` token, forwarded to the wave's pre-fetch verbatim — never rendered, normalised or re-derived. A ticket file with no `**Issue:**` line, or more than one, contributes no token; name it in the run summary as `not filed`.
84
+ - **A `/devflow:dynamic-tickets` ticket directory** (`{worktree}/.devflow/docs/tickets/{slug}/{ts}/`) is WAVE input: in each ticket file (every `.md` there but `tracking-issue.md`), the `**Issue:**` line directly after `**Depends on:**` is one raw `ISSUE_REFS` token, forwarded to the wave's pre-fetch verbatim — never rendered, normalised or re-derived. A ticket file with no `**Issue:**` line, or more than one, contributes no token; name it in the run summary as `not filed`.
70
85
 
71
86
  When ambiguous, ask the user before authoring: "Is this a single ticket or a wave of tickets?"
72
87
 
@@ -78,7 +93,7 @@ Check for (in priority order):
78
93
  - The current working context (recent `/devflow:dynamic-plan` output)
79
94
  - An in-context task description
80
95
 
81
- {issue_capture_contract()}
96
+ {{issue_capture_contract()}}
82
97
 
83
98
  Extract or note:
84
99
  - Implementation plan (for Code agent prompt and Evaluate agent)
@@ -86,7 +101,7 @@ Extract or note:
86
101
  - The test plan (for Gate 2) — a plan's TP lines, passed only once they pass this check. Copy the plan's `## Test Plan` section byte for byte into a fresh `mktemp` file with the Write tool, never through an interpolated shell string, and run:
87
102
 
88
103
  ```bash
89
- node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/verify-evidence.cjs" check tp <that file>; echo "exit=$?"
104
+ node "$HOME/.devflow/scripts/verify-evidence.cjs" check tp <that file>; echo "exit=$?"
90
105
  ```
91
106
 
92
107
  Only `exit=0` passes it: pass the section's TP lines, as one string, as `testPlan` when invoking the workflow — a test plan alone still runs the Test agent. Any other result, or a plan with no `## Test Plan` section: omit `testPlan` and note `Test plan: missing or malformed` in the run summary. Nothing is repaired, and a test plan in any other shape — an older JSON one included — is never passed.
@@ -99,10 +114,10 @@ If none found: build proceeds Gate-1-only (Gate 2 skipped with a note). Never re
99
114
 
100
115
  Check, in priority order:
101
116
  - An explicit candidate issue reference or issue URL in the user's input (e.g. `#42`, `42`, or `https://github.com/…/issues/42`)
102
- - The `**Issue:**` line directly after the H1 of the ticket set's `tracking-issue.md` (written by `/devflow:dynamic-tickets`' filing step; the file is at `.devflow/docs/tickets/\{slug\}/\{ts\}/tracking-issue.md`), as a raw token — only when the file holds exactly one `**Issue:**` line
117
+ - The `**Issue:**` line directly after the H1 of the ticket set's `tracking-issue.md` (written by `/devflow:dynamic-tickets`' filing step; the file is at `{worktree}/.devflow/docs/tickets/{slug}/{ts}/tracking-issue.md`), as a raw token — only when the file holds exactly one `**Issue:**` line
103
118
  - Otherwise: none
104
119
 
105
- {issue_ref_grammar()}
120
+ {{issue_ref_grammar()}}
106
121
 
107
122
  If a number is found, record it as the command-level `ISSUE_NUMBER`:
108
123
  - **SINGLE mode:** it is the ticket's own reference. Pass it as `issueNumber: <number>` when invoking the workflow; the engine hands it to setup-task as `ISSUE_INPUT`. If none is found, pass nothing.
@@ -133,6 +148,7 @@ const DECISIONS_CONTEXT = args.decisionsContext || ""; // injected before autho
133
148
  const ISSUE_INPUT = args.issueInput || args.issueNumber || "(none)"; // this ticket's OWN raw reference (Pre-authoring step 5; a wave passes issueInput) — setup-task's input, never a Code agent's
134
149
  const ISSUE_REQUIRED = String(args.issueRequired) === "false" ? "false" : "true"; // Pre-authoring step 0; only an explicit false turns it off — absent or unrecognised fails closed, like the resolver
135
150
  const APPLY_CONVENTIONS = String(args.applyConventions) === "false" ? "false" : "true";
151
+ const COMPLIANCE_FRAMEWORKS = /^(?:off|none|[a-z][a-z0-9-]{0,15}(?:,[a-z][a-z0-9-]{0,15}){0,7})$/.test(String(args.complianceFrameworks)) ? String(args.complianceFrameworks) : "off"; // Pre-authoring step 0b; any other shape is no lens
136
152
 
137
153
  // Phase 1: Git setup — declare the operation; the agent owns the process, the branch name included
138
154
  const setup = await phase("setup", () =>
@@ -176,6 +192,7 @@ ${DECISIONS_CONTEXT}
176
192
 
177
193
  ISSUE_NUMBER: ${ISSUE_NUMBER}
178
194
  ISSUE_PR_LINK: ${ISSUE_PR_LINK}
195
+ COMPLIANCE_FRAMEWORKS: ${COMPLIANCE_FRAMEWORKS}
179
196
 
180
197
  When you build or run tests to verify your work, use your "Long-running commands" discipline (background-Bash + Monitor poll) for anything that may run silent >120s, and prefer package-scoped commands.
181
198
 
@@ -199,6 +216,7 @@ Report: PASS or FAIL with details.`, { agentType: "Validate" });
199
216
  ${validation.details}
200
217
  ISSUE_NUMBER: ${ISSUE_NUMBER}
201
218
  ISSUE_PR_LINK: ${ISSUE_PR_LINK}
219
+ COMPLIANCE_FRAMEWORKS: ${COMPLIANCE_FRAMEWORKS}
202
220
  Commit fixes with conventional-commit message.`, { agentType: "Code" });
203
221
  const recheck = await agent(`Re-run build, typecheck, lint, tests on branch ${BRANCH}. Report: PASS or FAIL.`, { agentType: "Validate" });
204
222
  if (recheck.verdict === "PASS") break;
@@ -242,6 +260,7 @@ Report: PASS or FAIL with rationale.`, { agentType: "Evaluate" }),
242
260
  ${panel.filter(p => p.verdict === "FAIL").map(p => p.rationale).join("\n")}
243
261
  ISSUE_NUMBER: ${ISSUE_NUMBER}
244
262
  ISSUE_PR_LINK: ${ISSUE_PR_LINK}
263
+ COMPLIANCE_FRAMEWORKS: ${COMPLIANCE_FRAMEWORKS}
245
264
  Self-verify your fix compiles (background-Bash + Monitor for any build >120s — see your "Long-running commands" discipline). Commit fixes.`, { agentType: "Code" });
246
265
  evalVerdict = "FAIL-FIXED"; // issues found, fixes applied, not re-evaluated by design
247
266
  }
@@ -261,6 +280,7 @@ Cover: functionality, API contracts, performance, and cover every TEST_PLAN scen
261
280
  ${testResult.failures}
262
281
  ISSUE_NUMBER: ${ISSUE_NUMBER}
263
282
  ISSUE_PR_LINK: ${ISSUE_PR_LINK}
283
+ COMPLIANCE_FRAMEWORKS: ${COMPLIANCE_FRAMEWORKS}
264
284
  Self-verify your fix compiles and the scenarios pass (background-Bash + Monitor for any build/test >120s). Commit fixes.`, { agentType: "Code" });
265
285
  testVerdict = "FAIL-FIXED"; // issues found, fixes applied, not re-evaluated by design
266
286
  }
@@ -374,6 +394,7 @@ ${chunk.map(f => `- ${f.description} (${f.severity})`).join("\n")}
374
394
 
375
395
  ISSUE_NUMBER: ${ISSUE_NUMBER}
376
396
  ISSUE_PR_LINK: ${ISSUE_PR_LINK}
397
+ COMPLIANCE_FRAMEWORKS: ${COMPLIANCE_FRAMEWORKS}
377
398
  Fix all findings in this batch. Self-verify your fix compiles (background-Bash + Monitor for any build >120s — see your "Long-running commands" discipline). Commit with conventional-commit message.
378
399
  Return: {"status": "fixed"|"blocked", "commitShas": ["<sha>"], "unresolved": ["<description of any finding that could not be fixed>"]}`, { agentType: "Code" });
379
400
  chunkResults.push({ chunk, result: r });
@@ -424,6 +445,7 @@ Report: PASS or FAIL with details.`, { agentType: "Validate" });
424
445
  ${failureDetails}
425
446
  ISSUE_NUMBER: ${ISSUE_NUMBER}
426
447
  ISSUE_PR_LINK: ${ISSUE_PR_LINK}
448
+ COMPLIANCE_FRAMEWORKS: ${COMPLIANCE_FRAMEWORKS}
427
449
  Self-verify your fix compiles. Commit fixes with conventional-commit message.`, { agentType: "Code" });
428
450
  const recheck = await agent(`Re-run build, typecheck, lint, tests on branch ${BRANCH} (background+Monitor for long commands). Report: PASS or FAIL.`, { agentType: "Validate" });
429
451
  if (recheck.verdict === "PASS") break;
@@ -476,25 +498,25 @@ Write a concise report. Present only surviving findings as outstanding — never
476
498
  });
477
499
  ```
478
500
 
479
- {concurrency_doctrine()}
501
+ {{concurrency_doctrine()}}
480
502
 
481
- {build_execution_doctrine()}
503
+ {{build_execution_doctrine()}}
482
504
 
483
- {implement_bundle()}
505
+ {{implement_bundle()}}
484
506
 
485
- {gate1_postcode()}
507
+ {{gate1_postcode()}}
486
508
 
487
- {gate2_acceptance()}
509
+ {{gate2_acceptance()}}
488
510
 
489
- {evaluator_panel()}
511
+ {{evaluator_panel()}}
490
512
 
491
- {acceptance_criteria_contract()}
513
+ {{acceptance_criteria_contract()}}
492
514
 
493
- {review_pass()}
515
+ {{review_pass()}}
494
516
 
495
- {engine_invariants()}
517
+ {{engine_invariants()}}
496
518
 
497
- {engine_output_schema()}
519
+ {{engine_output_schema()}}
498
520
 
499
521
  ---
500
522
 
@@ -502,17 +524,17 @@ Write a concise report. Present only surviving findings as outstanding — never
502
524
 
503
525
  When WAVE mode is detected, author a workflow that wraps the single-ticket engine with the wave loop:
504
526
 
505
- {wave_loop()}
527
+ {{wave_loop()}}
506
528
 
507
- {branch_merge_model()}
529
+ {{branch_merge_model()}}
508
530
 
509
- {merge_doctrine()}
531
+ {{merge_doctrine()}}
510
532
 
511
- {escalation_model()}
533
+ {{escalation_model()}}
512
534
 
513
535
  **Wave workflow structure (author after the SINGLE engine blocks above):**
514
536
 
515
- The wave workflow uses the same phases as SINGLE but wraps them in a wave loop. The integration branch is `wave/<initiative>` — the initiative slug, referenced below as `\{slug\}` — (or the user's current branch). Each ticket works on the branch setup-task created. The Git agent manages worktrees for parallel-eligible tickets. After every merge: Validate agent (build + test). Escalations accumulate in a list; the final report lists all of them.
537
+ The wave workflow uses the same phases as SINGLE but wraps them in a wave loop. The integration branch is `wave/<initiative>` — the initiative slug, referenced below as `{slug}` — (or the user's current branch). Each ticket works on the branch setup-task created. The Git agent manages worktrees for parallel-eligible tickets. After every merge: Validate agent (build + test). Escalations accumulate in a list; the final report lists all of them.
516
538
 
517
539
  Wave skeleton — compact reference (see `wave_loop()` doctrine for full semantics):
518
540
 
@@ -556,7 +578,7 @@ Return: {"ready": [...ticket-ids], "blocked": [{"ticket": "id", "namedBlocker":
556
578
  try {
557
579
  // ticketId is the ISSUE_REF the pre-fetch heading printed — this ticket's OWN reference: the engine's `ticket` (its TICKET)
558
580
  // and its setup-task ISSUE_INPUT; the engine returns the branch that setup-task created, merged below; plans[ticketId] is its own plan, criteria and checked testPlan (Pre-authoring step 4)
559
- const engineResult = await runSingleTicketEngine({ ticket: ticketId, baseBranch: INTEGRATION_BRANCH, ...(plans[ticketId] || {}), decisionsContext: DECISIONS_CONTEXT, issueRequired: ISSUE_REQUIRED, applyConventions: APPLY_CONVENTIONS, issueInput: ticketId });
581
+ const engineResult = await runSingleTicketEngine({ ticket: ticketId, baseBranch: INTEGRATION_BRANCH, ...(plans[ticketId] || {}), decisionsContext: DECISIONS_CONTEXT, issueRequired: ISSUE_REQUIRED, applyConventions: APPLY_CONVENTIONS, complianceFrameworks: COMPLIANCE_FRAMEWORKS, issueInput: ticketId });
560
582
  // Check both verdict (engine_output_schema) and overallVerdict (SINGLE skeleton alias).
561
583
  // PASS and UNVERIFIED merge; PARTIAL, FAIL, ESCALATED (the ticket-link and branch stops included) or no verdict quarantine.
562
584
  if (["PASS", "UNVERIFIED"].includes(engineResult.verdict || engineResult.overallVerdict)) {
@@ -587,21 +609,21 @@ return { tickets: WAVE_TICKETS.map(t => results[t] || { ticket: t, ran: false, v
587
609
 
588
610
  A workflow cannot pause mid-run. After the build/wave workflow returns, you (the main model) surface anything that needs a human decision — all at once:
589
611
 
590
- 1. Read the wave report (`.devflow/docs/waves/\{slug\}/\{ts\}/wave-report.md`) for its **escalations** (quarantined/blocked tickets and why), and read any `DECISIONS-NEEDED.md` left by a prior `/devflow:dynamic-plan` run for this initiative.
591
- 2. **Post wave-report as tracking-issue comment** (WAVE mode only — skip this step entirely in SINGLE mode; SINGLE runs produce no wave report): In WAVE mode, if a tracking-issue number was resolved in Pre-authoring step 5 (`ISSUE_NUMBER` is not `(none)`) AND `.devflow/docs/waves/\{slug\}/\{ts\}/wave-report.md` exists, define `WAVE_ID` as the timestamped wave directory slug (the `\{ts\}` component, e.g. `2026-08-20_1730`), then spawn:
612
+ 1. Read the wave report (`{integration worktree root}/.devflow/docs/waves/{slug}/{ts}/wave-report.md`) for its **escalations** (quarantined/blocked tickets and why), and read any `DECISIONS-NEEDED.md` left by a prior `/devflow:dynamic-plan` run for this initiative.
613
+ 2. **Post wave-report as tracking-issue comment** (WAVE mode only — skip this step entirely in SINGLE mode; SINGLE runs produce no wave report): In WAVE mode, if a tracking-issue number was resolved in Pre-authoring step 5 (`ISSUE_NUMBER` is not `(none)`) AND `{integration worktree root}/.devflow/docs/waves/{slug}/{ts}/wave-report.md` exists, define `WAVE_ID` as the timestamped wave directory slug (the `{ts}` component, e.g. `2026-08-20_1730`), then spawn:
592
614
  ```
593
615
  Agent(subagent_type="Git"):
594
616
  "OPERATION: post-wave-report
595
- TRACKING_ISSUE: \{ISSUE_NUMBER\}
596
- WAVE_REPORT_PATH: .devflow/docs/waves/\{slug\}/\{ts\}/wave-report.md
597
- WAVE_ID: \{WAVE_ID\}
598
- WORKTREE_PATH: \{integration worktree root, when the wave ran in a linked worktree; omit if cwd\}"
617
+ TRACKING_ISSUE: {ISSUE_NUMBER}
618
+ WAVE_REPORT_PATH: .devflow/docs/waves/{slug}/{ts}/wave-report.md
619
+ WAVE_ID: {WAVE_ID}
620
+ WORKTREE_PATH: {integration worktree root}"
599
621
  ```
600
- The Git agent deduplicates via its own marker — it skips if a report for this `WAVE_ID` is already posted. The marker's format belongs to the operation; this caller passes `WAVE_ID` and never restates the literal. On API failure it degrades gracefully (`TRACEABILITY: DEGRADED (\{reason\})`) and continues — never blocks the post-wave step. This comment is the evidence surface for the PR-less integration-branch path; no other PR machinery is invented.
622
+ The Git agent deduplicates via its own marker — it skips if a report for this `WAVE_ID` is already posted. The marker's format belongs to the operation; this caller passes `WAVE_ID` and never restates the literal. On API failure it degrades gracefully (`TRACEABILITY: DEGRADED ({reason})`) and continues — never blocks the post-wave step. This comment is the evidence surface for the PR-less integration-branch path; no other PR machinery is invented.
601
623
 
602
624
  In WAVE mode, if no tracking-issue number was resolved in Pre-authoring step 5: state `TRACEABILITY: DEGRADED (no tracking issue for this run)` in the run summary and skip — never skip silently.
603
- 3. **Compose the wave PR inputs** (WAVE mode only — skip this step entirely in SINGLE mode). The workflow returned `tickets`: one entry per wave ticket, in its input order, each `\{ticket, ran, verdict, merged, issuePrLink, evaluateVerdict, testVerdict, surviving, coverageComplete\}`. Every value in it is agent-reported and treated as untrusted: nothing below is repaired, and no reference is ever composed from a number.
604
- - **Branch check.** Run `git -C "\{integration worktree root\}" branch --show-current`. Only a name matching `^wave/[a-z0-9][a-z0-9-]\{0,59\}$` opens a wave PR, and its part after `wave/` is the `\{slug\}` below. Any other name: record `TRACEABILITY: DEGRADED (not a wave branch)` and go to step 4 with no wave PR.
625
+ 3. **Compose the wave PR inputs** (WAVE mode only — skip this step entirely in SINGLE mode). The workflow returned `tickets`: one entry per wave ticket, in its input order, each `{ticket, ran, verdict, merged, issuePrLink, evaluateVerdict, testVerdict, surviving, coverageComplete}`. Every value in it is agent-reported and treated as untrusted: nothing below is repaired, and no reference is ever composed from a number.
626
+ - **Branch check.** Run `git -C "{integration worktree root}" branch --show-current`. Only a name matching `^wave/[a-z0-9][a-z0-9-]{0,59}$` opens a wave PR, and its part after `wave/` is the `{slug}` below. Any other name: record `TRACEABILITY: DEGRADED (not a wave branch)` and go to step 4 with no wave PR.
605
627
  - **Nothing merged** (no entry has `merged: true`): record `Wave PR: skipped (nothing merged)` and go to step 4.
606
628
  - Otherwise compose (a) and then (b).
607
629
 
@@ -628,25 +650,25 @@ Refs {tracking ref}
628
650
  Then check it:
629
651
 
630
652
  ```bash
631
- node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/verify-evidence.cjs" check wave <that file>; echo "exit=$?"
653
+ node "$HOME/.devflow/scripts/verify-evidence.cjs" check wave <that file>; echo "exit=$?"
632
654
  ```
633
655
 
634
656
  Only `exit=0` admits the file's text, verbatim, as `PR_WAVE_BLOCK`. Any other result: no wave PR — record `Wave PR: not opened (wave block refused: <the code on stderr>)` and go to step 4.
635
657
 
636
658
  **Required link** — only when `EVIDENCE_POLICY` is `required`: a `PASS` or `UNVERIFIED` row whose Ticket is `(none)` — a merged ticket whose setup-task captured an Issue ID but no link line, so the wave PR would close nothing for it — ⇒ `Wave PR: BLOCKED (no ticket link for T<k>, …)`, with no wave PR question and the remedy "link or create those tickets' issues, then re-run"; there is no exception. Under `standard` such a row stays as the Ticket rule above renders it.
637
659
 
638
- **(b) The wave test plan.** Take the checked TP lines each merged row's ticket was given in Pre-authoring step 4, in row order; renumber them `TP-1`, `TP-2`, … and prefix each scenario with its row's `T<k>: `. A line is never shortened or reworded: one whose prefixed scenario would pass 200 characters leaves its ticket with no usable test plan. Write `## Test Plan` and those lines, and nothing else, to `"\{integration worktree root\}/.devflow/docs/evidence-wave-\{slug\}.md"` with the Write tool, then run (the path double-quoted; one rewrite from the same lines after a refusal, never a second):
660
+ **(b) The wave test plan.** Take the checked TP lines each merged row's ticket was given in Pre-authoring step 4, in row order; renumber them `TP-1`, `TP-2`, … and prefix each scenario with its row's `T<k>: `. A line is never shortened or reworded: one whose prefixed scenario would pass 200 characters leaves its ticket with no usable test plan. Write `## Test Plan` and those lines, and nothing else, to `"{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md"` with the Write tool, then run (the path double-quoted; one rewrite from the same lines after a refusal, never a second):
639
661
 
640
662
  ```bash
641
- node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/verify-evidence.cjs" check tp "{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md"; echo "exit=$?"
642
- node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/verify-evidence.cjs" render --plan "{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md"; echo "exit=$?"
663
+ node "$HOME/.devflow/scripts/verify-evidence.cjs" check tp "{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md"; echo "exit=$?"
664
+ node "$HOME/.devflow/scripts/verify-evidence.cjs" render --plan "{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md"; echo "exit=$?"
643
665
  ```
644
666
 
645
667
  Only when both exit 0 is `PR_TEST_PLAN_BLOCK` the render's stdout, byte for byte without its `exit=` line; in every other case it is `(none)`.
646
668
 
647
669
  **Required plan** — only when `EVIDENCE_POLICY` is `required`: a merged ticket with no usable test plan ⇒ `Wave PR: BLOCKED (no test plan for T<k>, …)`, more than 200 lines in all ⇒ `Wave PR: BLOCKED (test plan over 200 lines)`, and a plan that did not check and render ⇒ `Wave PR: BLOCKED (test plan malformed)` — each with no wave PR question and the remedy "run `/devflow:dynamic-plan` for those tickets and re-run, or ship them through `/implement`"; no exception is offered here. Otherwise the block is optional: a ticket with no usable test plan is left out of it and named in the summary, and `(none)` is passed when no line remains.
648
670
  4. Surface ALL of them — escalations AND open decisions — to the user in ONE batched `AskUserQuestion` (never one-at-a-time). `_wave.mds`'s escalation model already quarantines-and-continues; this batches the surfacing so the user answers everything in a single pass.
649
- - **The wave PR question.** Only when step 3 composed `PR_WAVE_BLOCK`, the batch gains exactly one question: "Open the wave PR from wave/\{slug\}? It links \{n\} merged tickets (\{u\} UNVERIFIED) and references \{q\} quarantined." It has exactly two options: open it, or don't. The counts come from the checked block's rows: `\{n\}` PASS and UNVERIFIED, `\{u\}` UNVERIFIED, `\{q\}` QUARANTINED.
671
+ - **The wave PR question.** Only when step 3 composed `PR_WAVE_BLOCK`, the batch gains exactly one question: "Open the wave PR from wave/{slug}? It links {n} merged tickets ({u} UNVERIFIED) and references {q} quarantined." It has exactly two options: open it, or don't. The counts come from the checked block's rows: `{n}` PASS and UNVERIFIED, `{u}` UNVERIFIED, `{q}` QUARANTINED.
650
672
  - A `ticket-link-missing` escalation carries its remedy: link or create that ticket's issue, then re-run. There is no per-ticket exception.
651
673
  - **Headless** — `AskUserQuestion` is unavailable, or no answer comes — is a decline: nothing is created and nothing is pushed.
652
674
  5. If `~/.devflow/preference-profile.md` was absent, note in your summary: "no preference profile found — N decisions surfaced that a profile might have auto-resolved; consider `/devflow:dynamic-profile`."
@@ -654,19 +676,19 @@ node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/verify-evidence.cjs" render --plan
654
676
  ```
655
677
  Agent(subagent_type="Git"):
656
678
  "OPERATION: ensure-pr-ready
657
- WORKTREE_PATH: \{integration worktree root\}
658
- PR_DESCRIPTION_GUIDANCE: \{counts only — the wave slug and the merged, quarantined and blocked counts; never an issue title or body\}
659
- APPLY_CONVENTIONS: \{APPLY_CONVENTIONS\}
660
- PR_WAVE_BLOCK: \{PR_WAVE_BLOCK verbatim\}
661
- PR_TEST_PLAN_BLOCK: \{PR_TEST_PLAN_BLOCK verbatim, or (none)\}"
679
+ WORKTREE_PATH: {integration worktree root}
680
+ PR_DESCRIPTION_GUIDANCE: {counts only — the wave slug and the merged, quarantined and blocked counts; never an issue title or body}
681
+ APPLY_CONVENTIONS: {APPLY_CONVENTIONS}
682
+ PR_WAVE_BLOCK: {PR_WAVE_BLOCK verbatim}
683
+ PR_TEST_PLAN_BLOCK: {PR_TEST_PLAN_BLOCK verbatim, or (none)}"
662
684
  ```
663
- The Git agent pastes each block only behind its own check. Report its `**PR**` line and any `TRACEABILITY: DEGRADED (\{reason\})` lines. The wave PR is opened here and nowhere else; it is never merged, and main is never touched — the user merges.
685
+ The Git agent pastes each block only behind its own check. Report its `**PR**` line and any `TRACEABILITY: DEGRADED ({reason})` lines. The wave PR is opened here and nowhere else; it is never merged, and main is never touched — the user merges.
664
686
 
665
687
  Do NOT ask questions mid-workflow — that is impossible (F4). The workflow only WRITES the report; you read it and ask.
666
688
 
667
- 7. **Wave PR evidence** — only when step 6 reported the wave PR, after it; it never blocks, and every outcome below goes into the run summary. Take `\{n\}` from step 6's `- **PR**: #\{n\}` line when `\{n\}` matches `^[1-9][0-9]\{0,9\}$` as a whole; no such line ⇒ record `TRACEABILITY: DEGRADED (wave PR number not captured)` and skip this step. `PR_TEST_PLAN_BLOCK` `(none)` ⇒ record `Wave evidence: skipped (no wave test plan)` and skip it.
689
+ 7. **Wave PR evidence** — only when step 6 reported the wave PR, after it; it never blocks, and every outcome below goes into the run summary. Take `{n}` from step 6's `- **PR**: #{n}` line when `{n}` matches `^[1-9][0-9]{0,9}$` as a whole; no such line ⇒ record `TRACEABILITY: DEGRADED (wave PR number not captured)` and skip this step. `PR_TEST_PLAN_BLOCK` `(none)` ⇒ record `Wave evidence: skipped (no wave test plan)` and skip it.
668
690
 
669
- **(a) Test the wave.** Spawn one Test agent on the integration worktree with the wave test plan — the TP lines of the `## Test Plan` section step 3(b) wrote to `.devflow/docs/evidence-wave-\{slug\}.md`:
691
+ **(a) Test the wave.** Spawn one Test agent on the integration worktree with the wave test plan — the TP lines of the `## Test Plan` section step 3(b) wrote to `{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md`:
670
692
 
671
693
  ```
672
694
  Agent(subagent_type="Test"):
@@ -679,7 +701,7 @@ Cover every TEST_PLAN line on the integration branch as it stands. Report PASS o
679
701
 
680
702
  Nothing is fixed here, PASS or FAIL: the wave is done and its PR is open. Report the Test agent's Status.
681
703
 
682
- **(b) Claims.** Append its TP claims, PASS or FAIL alike, to the `## Claims` section of `"\{integration worktree root\}/.devflow/docs/evidence-wave-\{slug\}.md"` — the file's last section, created when absent. Append only: never edit or remove a claim. Each line is `/implement`'s TP claim, keyed to the 40-hex `HEAD:` the Test agent's report shows:
704
+ **(b) Claims.** Append its TP claims, PASS or FAIL alike, to the `## Claims` section of `"{integration worktree root}/.devflow/docs/evidence-wave-{slug}.md"` — the file's last section, created when absent. Append only: never edit or remove a claim. Each line is `/implement`'s TP claim, keyed to the 40-hex `HEAD:` the Test agent's report shows:
683
705
 
684
706
  ```
685
707
  - TP-<n> <PASS|FAIL|SKIP> sha:<head> by:test exit:<0-255>
@@ -697,7 +719,7 @@ git -C "{integration worktree root}" push origin HEAD; echo "exit=$?"
697
719
 
698
720
  **(d) Refresh.** Resolve the publication value for the integration worktree:
699
721
 
700
- {pub.publication_gate()}
722
+ {{pub.publication_gate()}}
701
723
 
702
724
  Then spawn:
703
725
 
@@ -711,7 +733,7 @@ WORKTREE_PATH: {integration worktree root}
711
733
  Update the wave PR's test-plan block and post its evidence comment."
712
734
  ```
713
735
 
714
- `update-pr-evidence` decides what each publication value means for the evidence comment. Report its `## PR Evidence` block — its `EVIDENCE` line and its `**Body**:` / `**Comment**:` line — or its `TRACEABILITY: DEGRADED (\{reason\})` line; a spawn that returns neither ⇒ `TRACEABILITY: DEGRADED (evidence refresh failed)`. Whatever it returns, the run ends here.
736
+ `update-pr-evidence` decides what each publication value means for the evidence comment. Report its `## PR Evidence` block — its `EVIDENCE` line and its `**Body**:` / `**Comment**:` line — or its `TRACEABILITY: DEGRADED ({reason})` line; a spawn that returns neither ⇒ `TRACEABILITY: DEGRADED (evidence refresh failed)`. Whatever it returns, the run ends here.
715
737
 
716
738
  ---
717
739
 
@@ -4,11 +4,11 @@ argument-hint: "[tickets-dir | issue-list]"
4
4
  output-dir: dist/commands
5
5
  ---
6
6
  @import { authoring_preamble } from "./_partials/_preamble.mds"
7
+ @import { docs_root } from "./_partials/_docs_root.mds"
7
8
  @import { agent_roster, agent_caveats } from "./_partials/_roster.mds"
8
9
  @import { acceptance_criteria_contract } from "./_partials/_plan_contract.mds"
9
10
  @import { issue_ref_grammar, issue_capture_contract } from "./_partials/_tracker.mds"
10
-
11
- {authoring_preamble()}
11
+ {{authoring_preamble()}}
12
12
 
13
13
  ---
14
14
 
@@ -16,14 +16,14 @@ output-dir: dist/commands
16
16
 
17
17
  This command instructs you to construct and run a Claude Code dynamic Workflow that plans all tickets in parallel, challenges each plan (gaps, edge cases, side-effects), produces well-structured acceptance criteria and a test plan for each ticket (consumed by `/devflow:dynamic-build`'s Gate 2), runs a cross-plan conflict critic, auto-resolves decisions matching the user's preference profile, and writes per-ticket plan files + one `DECISIONS-NEEDED.md`.
18
18
 
19
- {agent_roster()}
19
+ {{agent_roster()}}
20
20
 
21
- {agent_caveats()}
21
+ {{agent_caveats()}}
22
22
 
23
23
  ---
24
24
 
25
25
  **Requires:** ticket files directory or tracker issue list; optional `~/.devflow/preference-profile.md`
26
- **Produces:** per-ticket plan files + `DECISIONS-NEEDED.md` at `.devflow/docs/design/\{slug\}/\{ts\}/`
26
+ **Produces:** per-ticket plan files + `DECISIONS-NEEDED.md` at `{worktree}/.devflow/docs/design/{slug}/{ts}/`
27
27
 
28
28
  ---
29
29
 
@@ -33,13 +33,17 @@ Before authoring, verify:
33
33
 
34
34
  1. **Workflow tool available:** if the `Workflow` tool is not in your available tools, STOP and tell the user: "The Workflow tool is not available in this session. dynamic-plan requires Claude Code's dynamic workflow runtime."
35
35
  2. **`agentType` support:** confirmed available (spike F5, 2026-06-11).
36
- 3. **Tracker paths:** a list of issue references or URLs is read through the Git agent, which resolves the configured tracker and its access itself and reports `TRACEABILITY: DEGRADED (\{reason\})` when it cannot read an issue — then fall back to reading ticket `.md` files from a local path. No tracker CLI is checked here.
36
+ 3. **Tracker paths:** a list of issue references or URLs is read through the Git agent, which resolves the configured tracker and its access itself and reports `TRACEABILITY: DEGRADED ({reason})` when it cannot read an issue — then fall back to reading ticket `.md` files from a local path. No tracker CLI is checked here.
37
37
  4. **No-remote path:** if the repo has no remote, read ticket files from the provided local path; the Git agent reports DEGRADED for any issue it cannot reach.
38
38
 
39
39
  ---
40
40
 
41
41
  ### Pre-authoring setup
42
42
 
43
+ {{docs_root()}}
44
+
45
+ Pass `{worktree}` to the workflow as its `root` argument.
46
+
43
47
  **1. Apply decisions context**
44
48
 
45
49
  Apply the `devflow:apply-decisions` algorithm to the DECISIONS_CONTEXT loaded per the preamble above: scan the index, Read relevant entries, note verbatim ADR/PF IDs to inject into Design agent and Evaluate agent prompts.
@@ -60,11 +64,11 @@ Determine the ticket source (in priority order):
60
64
  - A list of candidate issue references or issue URLs
61
65
  - Inline ticket descriptions passed as args
62
66
 
63
- {issue_ref_grammar()}
67
+ {{issue_ref_grammar()}}
64
68
 
65
69
  Read or note the tickets. The agents will read them in full; you need the list and any key constraints.
66
70
 
67
- {issue_capture_contract()}
71
+ {{issue_capture_contract()}}
68
72
 
69
73
  ---
70
74
 
@@ -76,11 +80,11 @@ After the workflow completes:
76
80
  1. **Check each plan's test plan.** For every path in `planPaths`, copy that plan's `## Test Plan` section — the heading and its TP lines, up to the next `## ` heading — byte for byte into a fresh `mktemp` file with the Write tool, never through an interpolated shell string, and run:
77
81
 
78
82
  ```bash
79
- node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/verify-evidence.cjs" check tp <that file>; echo "exit=$?"
83
+ node "$HOME/.devflow/scripts/verify-evidence.cjs" check tp <that file>; echo "exit=$?"
80
84
  ```
81
85
 
82
86
  Check the section, never the whole plan file: the plan's other `## ` headings are not evidence-file sections, so the script would parse the whole document as the plan. `exit=0` passes. Any other result names that plan `test plan malformed (<code>)` in your summary, `<code>` being the code the script printed on stderr; a plan with no `## Test Plan` section copies as an empty file, which the script refuses. Nothing is repaired: `/devflow:dynamic-build` passes no test plan from that plan.
83
- 2. Read the `decisionsNeededPath` returned by the workflow (e.g. `.devflow/docs/design/<slug>/<ts>/DECISIONS-NEEDED.md`). Always use the OUTDIR-scoped path the workflow wrote — never the flat `.devflow/docs/design/DECISIONS-NEEDED.md`.
87
+ 2. Read the `decisionsNeededPath` returned by the workflow (e.g. `{worktree}/.devflow/docs/design/<slug>/<ts>/DECISIONS-NEEDED.md`). Always use the OUTDIR-scoped path the workflow wrote — never the flat `{worktree}/.devflow/docs/design/DECISIONS-NEEDED.md`.
84
88
  3. First surface the **Auto-Resolved Decisions** section (decision → resolution → source) for audit, then surface ALL open **Decisions Needed** to the user in ONE batched `AskUserQuestion` (never one-at-a-time).
85
89
  4. The user's answers feed into their own plan edits or a follow-up `/devflow:dynamic-plan` run.
86
90
 
@@ -107,7 +111,8 @@ const PREFERENCE_PROFILE = args.preferenceProfile || ""; // injected before aut
107
111
  const TP_CONTRACT = args.tpContract || ""; // the "Test-plan line (TP)" contract below — its paragraph and four bullets — passed verbatim as tpContract when invoking the workflow, never pasted into this script (it holds backticks)
108
112
  const slug = args.slug || "wave";
109
113
  const ts = new Date().toISOString().slice(0,16).replace(/[-:T]/g, (c) => c === 'T' ? '_' : c === ':' ? '' : c);
110
- const OUTDIR = `.devflow/docs/design/${slug}/${ts}`;
114
+ const ROOT = args.root; // {worktree} from Pre-authoring setup: the checkout's toplevel, never cwd
115
+ const OUTDIR = `${ROOT}/.devflow/docs/design/${slug}/${ts}`;
111
116
 
112
117
  // Phase 1: Read all tickets
113
118
  const tickets = await phase("read-tickets", () =>
@@ -230,17 +235,17 @@ Return: { planPaths (array), decisionsNeededPath (string), decisionsNeededCount
230
235
 
231
236
  The plan-challenge step (Phase 3 above) MUST produce the acceptance criteria and test plan shape that `/devflow:dynamic-build`'s Gate 2 consumes:
232
237
 
233
- {acceptance_criteria_contract()}
238
+ {{acceptance_criteria_contract()}}
234
239
 
235
240
  ---
236
241
 
237
242
  ### Artifact paths
238
243
 
239
- Per-ticket plans → `.devflow/docs/design/\{slug\}/\{ts\}/\{ticket-slug\}-plan.md`
244
+ Per-ticket plans → `{worktree}/.devflow/docs/design/{slug}/{ts}/{ticket-slug}-plan.md`
240
245
 
241
- Decisions needed → `.devflow/docs/design/\{slug\}/\{ts\}/DECISIONS-NEEDED.md`
246
+ Decisions needed → `{worktree}/.devflow/docs/design/{slug}/{ts}/DECISIONS-NEEDED.md`
242
247
 
243
- Honor the `WORKTREE_PATH` prefix when provided.
248
+ `{worktree}` is the docs root resolved in Pre-authoring setup (it honours `WORKTREE_PATH` when provided).
244
249
 
245
250
  ---
246
251
 
@@ -4,8 +4,7 @@ argument-hint: "[--dry-run]"
4
4
  output-dir: dist/commands
5
5
  ---
6
6
  @import { authoring_preamble } from "./_partials/_preamble.mds"
7
-
8
- {authoring_preamble()}
7
+ {{authoring_preamble()}}
9
8
 
10
9
  ---
11
10
 
@@ -19,14 +18,26 @@ The profile is then consumed by `/devflow:dynamic-plan` to pre-resolve design de
19
18
 
20
19
  ---
21
20
 
22
- **Requires:** read access to `~/.claude/projects/*/` session transcripts and `~/.claude/rules/`
21
+ **Requires:** read access to `{claude_dir}/projects/*/` session transcripts and `{claude_dir}/rules/`
23
22
  **Produces:** `~/.devflow/preference-profile.md` — plain-prose decision-preference profile
24
23
 
25
24
  ---
26
25
 
26
+ ### Claude Code's directory
27
+
28
+ `{claude_dir}` is Claude Code's directory, resolved once, the way the installer resolves it (D-CLAUDE-DIR-PROMPTS): `CLAUDE_CONFIG_DIR` when that is set to an absolute path, else `$HOME/.claude`. Run
29
+
30
+ ```bash
31
+ d="${CLAUDE_CONFIG_DIR:-}"; case "$d" in /*) ;; *) d="$HOME/.claude" ;; esac; printf '%s\n' "$d"
32
+ ```
33
+
34
+ and use its one-line output. Pass it to the agent below as `CLAUDE_DIR`.
35
+
36
+ ---
37
+
27
38
  ### Privacy note
28
39
 
29
- This command mines session transcripts across **all projects** on this machine — `~/.claude/projects/*/*.jsonl`, `~/.claude/history.jsonl`, and feedback memories. The resulting profile is then injected into planning prompts as context. This is a cross-project surface: patterns from one project's decisions may influence planning in another.
40
+ This command mines session transcripts across **all projects** on this machine — `{claude_dir}/projects/*/*.jsonl`, `{claude_dir}/history.jsonl`, and feedback memories. The resulting profile is then injected into planning prompts as context. This is a cross-project surface: patterns from one project's decisions may influence planning in another.
30
41
 
31
42
  Mitigation: the profile is plain prose that you review and edit before use. You can trim, redact, or rewrite any section. The profile is at `~/.devflow/preference-profile.md` — open it, read it, adjust it. It is never committed to any repo.
32
43
 
@@ -38,8 +49,8 @@ Session transcripts on a typical machine are gigabytes. **The agent MUST NOT ful
38
49
 
39
50
  1. Use `rg` (ripgrep) or `grep` to search for `AskUserQuestion` occurrences across transcript files — extracting just the question text and the surrounding user response (a few lines each).
40
51
  2. Sample the results — take up to ~200 instances spread across projects and time; do not feed everything into context at once.
41
- 3. Read `~/.claude/rules/` files (these are small) to supplement with explicitly stated preferences.
42
- 4. Read existing feedback memory files (`~/.claude/projects/*/memory/*.md`) — these are small and already distilled.
52
+ 3. Read `{claude_dir}/rules/` files (these are small) to supplement with explicitly stated preferences.
53
+ 4. Read existing feedback memory files (`{claude_dir}/projects/*/memory/*.md`) — these are small and already distilled.
43
54
 
44
55
  This grep-and-sample approach is both efficient and Iron-Rule-safe: the agent uses `rg`/`grep` as tools — no extractor or clustering logic is authored.
45
56
 
@@ -47,7 +58,7 @@ This grep-and-sample approach is both efficient and Iron-Rule-safe: the agent us
47
58
 
48
59
  ### When --dry-run is passed
49
60
 
50
- Print what the agent would do (a summary of which paths it would search, what it would write) and STOP — do not spawn the agent.
61
+ Print what the agent would do (a summary of which paths under the resolved `{claude_dir}` it would search, what it would write) and STOP — do not spawn the agent.
51
62
 
52
63
  ---
53
64
 
@@ -58,15 +69,17 @@ Spawn a single Knowledge agent with this task:
58
69
  ```
59
70
  You are distilling a decision-preference profile from past session history.
60
71
 
72
+ CLAUDE_DIR: {claude_dir} — Claude Code's directory, already resolved; every path below is under it.
73
+
61
74
  BOUNDED READING — MANDATORY: transcripts are gigabytes; never full-read them.
62
- 1. Run: rg -l "AskUserQuestion" ~/.claude/projects/ 2>/dev/null | head -50
75
+ 1. Run: rg -l "AskUserQuestion" "{claude_dir}/projects/" 2>/dev/null | head -50
63
76
  to find transcript files that contain AskUserQuestion moments.
64
77
  2. For each found file, run: rg -A 5 "AskUserQuestion" <file> | head -200
65
78
  to extract the question + nearby user response context. Sample broadly —
66
79
  aim for ~150-200 instances spread across projects and time windows.
67
- 3. Read ~/.claude/history.jsonl if it exists (rg "AskUserQuestion" ... similarly).
68
- 4. Read all files in ~/.claude/rules/ (small — read fully).
69
- 5. Read all *.md files in ~/.claude/projects/*/memory/ (small — read fully).
80
+ 3. Read {claude_dir}/history.jsonl if it exists (rg "AskUserQuestion" ... similarly).
81
+ 4. Read all files in {claude_dir}/rules/ (small — read fully).
82
+ 5. Read all *.md files in {claude_dir}/projects/*/memory/ (small — read fully).
70
83
 
71
84
  From this evidence, identify the recurring patterns in how the user answers design
72
85
  questions. Look for preferences about: