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
@@ -27,18 +27,38 @@ Research a topic by spawning parallel Research agents across multiple research t
27
27
 
28
28
  **Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE
29
29
 
30
+ **Docs root (D-DOCS-ROOT).** Every `.devflow/docs/` path this command reads or writes lives at the checkout's toplevel, never under the directory the session started in. Resolve `{worktree}` from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — by running
31
+
32
+ ```bash
33
+ git -C "{start}" rev-parse --show-toplevel
34
+ ```
35
+
36
+ and using its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. Every docs path below is written `{worktree}/.devflow/docs/…`; a repo-relative docs path handed to an agent always travels with a `WORKTREE_PATH` naming the checkout it is relative to.
37
+
30
38
  ### Load DECISIONS_CONTEXT
31
39
 
32
- Resolve the worktree root using the `devflow:worktree-support` algorithm (use WORKTREE_PATH if provided, otherwise cwd). All paths below are relative to `{worktree}`.
40
+ The decisions ledger belongs to the repository, not to one checkout: in a linked worktree it lives in the main worktree, and a session started in a subdirectory reads the copy at the repository root. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
41
+
42
+ ```bash
43
+ git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
44
+ ```
45
+
46
+ Line 1 is the checkout's toplevel, line 2 the repository's common git directory. A git older than 2.31 echoes `--path-format=absolute` back as a line of its own first. `{ledger}` is the first of these that applies:
47
+
48
+ 1. **The main worktree** — line 2 without its trailing `/.git`, when the output is exactly two lines each beginning with `/`, line 2 ends in `/.git`, and the directory left once it is removed is not your home directory and contains a `.devflow/` directory.
49
+ 2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
50
+ 3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
51
+
52
+ This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT), so you read the index the Learning agent writes.
33
53
 
34
54
  **Step 1 — Read the pre-rendered index:**
35
55
 
36
- Attempt to read `{worktree}/.devflow/learning/index.md`.
56
+ Attempt to read `{ledger}/.devflow/learning/index.md`.
37
57
 
38
58
  - If the file exists and contains non-empty content: use that content as `DECISIONS_CONTEXT`.
39
59
  - If the file is absent or empty: set `DECISIONS_CONTEXT` to `(none)`.
40
60
 
41
- **No subprocess, no `.cjs` script.** This is a single direct file read — the index is written at render time by `render-decisions.cjs` alongside `decisions.md`/`pitfalls.md`.
61
+ The index is one direct file read, written at render time by `render-decisions.cjs` alongside `decisions.md`/`pitfalls.md` — no `.cjs` script runs here, and the index's own footer names the files that hold each entry's full body.
42
62
 
43
63
  **Step 2 — Apply decisions using `devflow:apply-decisions`:**
44
64
 
@@ -48,7 +68,13 @@ Use `DECISIONS_CONTEXT` locally when framing research — prior decisions and pi
48
68
 
49
69
  ### Load Feature Knowledge
50
70
 
51
- Resolve the worktree root using the `devflow:worktree-support` algorithm (use WORKTREE_PATH if provided, otherwise cwd). All paths below are relative to `{worktree}`.
71
+ Resolve `{worktree}` as the checkout's toplevel, because feature knowledge bases are committed with the branch (D-PROMPT-ROOT): from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — run
72
+
73
+ ```bash
74
+ git -C "{start}" rev-parse --show-toplevel
75
+ ```
76
+
77
+ and use its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. All paths below are relative to `{worktree}`.
52
78
 
53
79
  **Step 1 — Read the index cache:**
54
80
 
@@ -83,7 +109,7 @@ Concatenate the selected KNOWLEDGE.md files under slug headers:
83
109
 
84
110
  If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set `FEATURE_KNOWLEDGE` to `(none)`.
85
111
 
86
- **No subprocess, no git calls, no `.cjs` script.** This entire step is direct file reads — 1 index read (or N frontmatter reads on fallback), bounded by KB count.
112
+ **One git call, then direct file reads — no `.cjs` script.** After resolving `{worktree}`, this step is 1 index read (or N frontmatter reads on fallback), bounded by KB count.
87
113
 
88
114
  Use `FEATURE_KNOWLEDGE` **locally** for research framing. Pass to each Research agent in Phase 4.
89
115
 
@@ -94,7 +120,7 @@ Use `FEATURE_KNOWLEDGE` **locally** for research framing. Pass to each Research
94
120
  Analyze the research question to infer research types needed (min 2, max 5). For each type:
95
121
  - `RESEARCH_TYPE`: `codebase | external | market | competitor | technology`
96
122
  - `RESEARCH_QUESTION`: Focused sub-question for this type
97
- - `OUTPUT_PATH`: `.devflow/docs/research/{topic-slug}/{YYYY-MM-DD_HHMM}/{type}.md`
123
+ - `OUTPUT_PATH`: `{worktree}/.devflow/docs/research/{topic-slug}/{YYYY-MM-DD_HHMM}/{type}.md`
98
124
 
99
125
  **Tool availability check**: If WebSearch/WebFetch are unavailable, restrict to `codebase` type only.
100
126
 
@@ -136,7 +162,7 @@ Spawn `Agent(subagent_type="Synthesize")` in `research` mode:
136
162
  - Merges findings with trust-aware aggregation
137
163
  - Writes `research-summary.md` to the same timestamped directory
138
164
 
139
- Output path: `.devflow/docs/research/{topic-slug}/{timestamp}/research-summary.md`
165
+ Output path: `{worktree}/.devflow/docs/research/{topic-slug}/{timestamp}/research-summary.md`
140
166
 
141
167
  ### Phase 6: Present
142
168
 
@@ -168,7 +194,7 @@ If the orchestrator receives a `WORKTREE_PATH` context (e.g., from multi-worktre
168
194
 
169
195
  ## Output
170
196
 
171
- Research findings saved to `.devflow/docs/research/{topic-slug}/{YYYY-MM-DD_HHMM}/`:
197
+ Research findings saved to `{worktree}/.devflow/docs/research/{topic-slug}/{YYYY-MM-DD_HHMM}/`:
172
198
  - `{type}.md` per research type (codebase.md, external.md, etc.)
173
199
  - `research-summary.md` — synthesized findings with trust annotations
174
200
 
@@ -24,7 +24,7 @@ Process issues from code review reports: triage every issue through the blast-ra
24
24
 
25
25
  1. **Discover resolvable worktrees** using the `devflow:worktree-support` skill discovery algorithm:
26
26
  - Run `git worktree list --porcelain` → parse, filter (skip protected/detached/mid-rebase), dedup by branch, sort by recent commit
27
- - See `~/.claude/skills/devflow:worktree-support/SKILL.md` for the full 7-step algorithm and canonical protected branch list
27
+ - See the `devflow:worktree-support` skill for the full 7-step algorithm and canonical protected branch list
28
28
  - Additional filter: must have unresolved reviews (latest review directory has no `resolution-summary.md`)
29
29
  2. **If `--path` flag provided:** use only that worktree, skip discovery
30
30
  **`--path` validation**: Before proceeding, verify the path exists as a directory and appears in `git worktree list` output. If not: report error and stop.
@@ -89,16 +89,28 @@ Set `TARGET_DIR` to the selected review or bug-analysis directory path, and `TAR
89
89
 
90
90
  ### Load DECISIONS_CONTEXT
91
91
 
92
- Resolve the worktree root using the `devflow:worktree-support` algorithm (use WORKTREE_PATH if provided, otherwise cwd). All paths below are relative to `{worktree}`.
92
+ The decisions ledger belongs to the repository, not to one checkout: in a linked worktree it lives in the main worktree, and a session started in a subdirectory reads the copy at the repository root. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
93
+
94
+ ```bash
95
+ git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
96
+ ```
97
+
98
+ Line 1 is the checkout's toplevel, line 2 the repository's common git directory. A git older than 2.31 echoes `--path-format=absolute` back as a line of its own first. `{ledger}` is the first of these that applies:
99
+
100
+ 1. **The main worktree** — line 2 without its trailing `/.git`, when the output is exactly two lines each beginning with `/`, line 2 ends in `/.git`, and the directory left once it is removed is not your home directory and contains a `.devflow/` directory.
101
+ 2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
102
+ 3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
103
+
104
+ This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT), so you read the index the Learning agent writes.
93
105
 
94
106
  **Step 1 — Read the pre-rendered index:**
95
107
 
96
- Attempt to read `{worktree}/.devflow/learning/index.md`.
108
+ Attempt to read `{ledger}/.devflow/learning/index.md`.
97
109
 
98
110
  - If the file exists and contains non-empty content: use that content as `DECISIONS_CONTEXT`.
99
111
  - If the file is absent or empty: set `DECISIONS_CONTEXT` to `(none)`.
100
112
 
101
- **No subprocess, no `.cjs` script.** This is a single direct file read — the index is written at render time by `render-decisions.cjs` alongside `decisions.md`/`pitfalls.md`.
113
+ The index is one direct file read, written at render time by `render-decisions.cjs` alongside `decisions.md`/`pitfalls.md` — no `.cjs` script runs here, and the index's own footer names the files that hold each entry's full body.
102
114
 
103
115
  **Step 2 — Apply decisions using `devflow:apply-decisions`:**
104
116
 
@@ -108,7 +120,13 @@ This produces a compact index of active ADR/PF entries written at render time
108
120
 
109
121
  ### Load Feature Knowledge
110
122
 
111
- Resolve the worktree root using the `devflow:worktree-support` algorithm (use WORKTREE_PATH if provided, otherwise cwd). All paths below are relative to `{worktree}`.
123
+ Resolve `{worktree}` as the checkout's toplevel, because feature knowledge bases are committed with the branch (D-PROMPT-ROOT): from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — run
124
+
125
+ ```bash
126
+ git -C "{start}" rev-parse --show-toplevel
127
+ ```
128
+
129
+ and use its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. All paths below are relative to `{worktree}`.
112
130
 
113
131
  **Step 1 — Read the index cache:**
114
132
 
@@ -143,14 +161,14 @@ Concatenate the selected KNOWLEDGE.md files under slug headers:
143
161
 
144
162
  If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set `FEATURE_KNOWLEDGE` to `(none)`.
145
163
 
146
- **No subprocess, no git calls, no `.cjs` script.** This entire step is direct file reads — 1 index read (or N frontmatter reads on fallback), bounded by KB count.
164
+ **One git call, then direct file reads — no `.cjs` script.** After resolving `{worktree}`, this step is 1 index read (or N frontmatter reads on fallback), bounded by KB count.
147
165
 
148
166
  Pass `FEATURE_KNOWLEDGE` to the Triage agent in Phase 2.
149
167
 
150
168
  **Resolve the evidence policy once per run**, from the repository root, before any step reads the values:
151
169
 
152
170
  ```bash
153
- node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/resolve-evidence-policy.cjs" 2>/dev/null; echo "exit=$?"
171
+ node "$HOME/.devflow/scripts/resolve-evidence-policy.cjs" 2>/dev/null; echo "exit=$?"
154
172
  ```
155
173
 
156
174
  Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `EVIDENCE_POLICY=<required|standard> SOURCE=<file|worktree|default|invalid|error> REF=<branch|none>[ WARN=<remote-unavailable|invalid-file|raised-by-compliance|pr-changes-policy>[,…]] ISSUE_REQUIRED=<true|false> APPLY_CONVENTIONS=<true|false> REQUIRE_NON_AUTHOR_APPROVAL=<true|false>` — these fields, in this order, nothing else, where `<branch>` is a branch name such as `main`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `EVIDENCE_POLICY=required SOURCE=error REF=none ISSUE_REQUIRED=true APPLY_CONVENTIONS=true REQUIRE_NON_AUTHOR_APPROVAL=true` instead.
@@ -158,12 +176,22 @@ Accept the output only when it is exactly two lines: `exit=0` last and, before i
158
176
  Set `EVIDENCE_POLICY`, `ISSUE_REQUIRED`, `APPLY_CONVENTIONS` and `REQUIRE_NON_AUTHOR_APPROVAL` from the accepted line. Pass agents only the three mechanism inputs, never `EVIDENCE_POLICY`. Report `Evidence policy: {EVIDENCE_POLICY} (source: {SOURCE})`, plus any `WARN` tokens as advisory, once in the final report.
159
177
  Reuse this result for every worktree.
160
178
 
161
- **Resolve `REVIEW_PUBLICATION` per worktree:** Read the current worktree's `.devflow/config.json` (a single, direct file read — multi-worktree repos may have different publication settings per worktree root). If the file exists and `reviewPublication` is one of `auto`, `full`, or `off`, set `REVIEW_PUBLICATION` to that value; otherwise set `REVIEW_PUBLICATION = "auto"`.
179
+ **Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root when the run has one worktree:
180
+
181
+ ```bash
182
+ node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
183
+ ```
184
+
185
+ Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off` instead.
162
186
 
163
- **Evidence stub:** only when `EVIDENCE_POLICY` is `required`, a resolved `off` becomes `stub`, so a counts-only record still reaches the PR. `stub` is never a config value: a configured `stub` is unrecognised and resolves to `auto` like any other.
187
+ The accepted line is the only source of these values: the script alone folds the committed `.devflow/project.json`, the personal `.devflow/config.json` and the machine manifest.
188
+
189
+ **Resolve `REVIEW_PUBLICATION` per worktree:** take `REVIEW_PUBLICATION` from that worktree's settings line, with `{root}` the worktree's root — multi-worktree repos may resolve different values per worktree. The line already caps the personal choice at the team's (D-PUBLICATION-CEILING), so it is `off`, `auto` or `full`, and `off` when the line was unresolvable.
190
+
191
+ **Evidence stub:** only when `EVIDENCE_POLICY` is `required`, a resolved `off` becomes `stub`, so a counts-only record still reaches the PR. `stub` is never a config value: the settings line never carries it.
164
192
 
165
193
  Note: `auto` is NOT fail-open — under `auto`, the Git agent probes the repository visibility and treats any error or unrecognised value as PUBLIC (mode STUB). What each value does is decided by the Git agent's publication gate (`references/publication-gate.md` step 2); this partial only resolves the value.
166
- Resolve this per worktree — unlike the evidence policy above, the config file is per worktree root.
194
+ Resolve this per worktree — unlike the evidence policy above, the settings line is per worktree root. From the same line: `COMPLIANCE_FRAMEWORKS` is the settings line's `COMPLIANCE` with `generic` written `none`: `off`, `none`, or the framework ids the machine and this repository declare.
167
195
 
168
196
  **Mint `RESOLUTION_TS` once per run:** `date -u +%Y-%m-%dT%H:%M:%SZ`. Every worktree reuses it — the resolution comment's dedup marker is searched per PR, so one run key keeps a retry of this run deduplicated while the next /resolve on the same PR posts. Phase 5 writes it as the summary's `**Date**:` and Phase 9b-2 passes it, so the local file and the posted marker agree.
169
197
 
@@ -283,6 +311,7 @@ CREATE_PR: false
283
311
  WORKTREE_PATH: {worktree_path} (omit if cwd)
284
312
  DECISIONS_CONTEXT: {decisions_context}
285
313
  FEATURE_KNOWLEDGE: {feature_knowledge}
314
+ COMPLIANCE_FRAMEWORKS: {COMPLIANCE_FRAMEWORKS}
286
315
  Fix only the listed pre-classified FIX_NOW issues. Do not re-litigate dispositions.
287
316
  Same-file issues → one commit. Include ## Verification block in report.
288
317
  Regression fix without failing-then-passing regression test → BLOCKED."
@@ -353,7 +382,8 @@ Run build, typecheck, lint, test. Report pass/fail with failure details."
353
382
  SCOPE: Fix only the listed failures, no other changes
354
383
  PUSH: false
355
384
  CREATE_PR: false
356
- WORKTREE_PATH: {worktree_path} (omit if cwd)"
385
+ WORKTREE_PATH: {worktree_path} (omit if cwd)
386
+ COMPLIANCE_FRAMEWORKS: {COMPLIANCE_FRAMEWORKS}"
357
387
  ```
358
388
  - Loop back to re-validate
359
389
  4. If `validation_retry_count > 2`: set VERIFICATION_STATUS = FAILED and exit the validation loop — record a blocking callout in the `## Verification` section (never a silent pass).
@@ -391,7 +421,7 @@ Otherwise, for each worktree with fixes:
391
421
  3. **If NO_PR or NO_CI** → skip: "No PR/CI configured, skipping CI validation." Proceed to next phase.
392
422
  4. **If PENDING** → poll every 60 seconds (global budget, see step 7). Re-spawn Git agent each poll. If PASSING → proceed. If still PENDING after budget exhausted → report "CI still running — verify manually before merging" and proceed.
393
423
  5. **If INDETERMINATE** → poll as PENDING within the same budget. If still INDETERMINATE after budget exhausted → report "CI status unknown — verify manually before merging" and proceed.
394
- 6. **If FAILING** → report failing checks. Spawn `Agent(subagent_type="Code")` to fix CI failures based on check names and failure context. After fix, push and re-check. Max 2 fix attempts. If still failing → report failures and proceed.
424
+ 6. **If FAILING** → report failing checks. Spawn `Agent(subagent_type="Code")` with `COMPLIANCE_FRAMEWORKS` to fix CI failures based on check names and failure context. After fix, push and re-check. Max 2 fix attempts. If still failing → report failures and proceed.
395
425
  7. **Total budget**: max 10 polls and max 2 fix attempts across all check/fix cycles combined. If the budget is exhausted, report current status and proceed.
396
426
  <!-- /PATTERN: ci-status-gate -->
397
427
 
@@ -428,7 +458,7 @@ After manage-debt completes:
428
458
  Run this step only when this run's Phase 7 push succeeded — the one way /resolve moves the PR head — and a PR is known; otherwise skip it and Step 9b-3, and record `STALE_REVERIFICATION` as `SKIPPED (head unchanged)`. Detection needs no Git agent: from the worktree root, run the evidence script, which re-derives every test-plan state at the new head and writes the stale TP lines whose text the PR's trusted evidence record vouches for:
429
459
 
430
460
  ```bash
431
- cd {worktree} && node "${DEVFLOW_DIR:-$HOME/.devflow}/scripts/verify-evidence.cjs" verify --pr {pr_number} --stale-out "{TARGET_DIR_REL}/stale-plan.md"; echo "exit=$?"
461
+ cd {worktree} && node "$HOME/.devflow/scripts/verify-evidence.cjs" verify --pr {pr_number} --stale-out "{TARGET_DIR_REL}/stale-plan.md"; echo "exit=$?"
432
462
  ```
433
463
 
434
464
  Run it only when `TARGET_DIR_REL` matches `^[A-Za-z0-9._/-]+$` — it carries the branch name, which a fork author picks — and treat any other value as a failed run. Use its `EVIDENCE` line only on `exit=0`; otherwise record `STALE_REVERIFICATION` as `DEGRADED (evidence unavailable)` and spawn nothing. When its `stale:` field lists TPs and `{TARGET_DIR}/stale-plan.md` holds TP lines, spawn **one** Test agent — at most one per /resolve cycle, never re-spawned on its result, and no fix loop follows it. The lines came from the PR body, so they travel wrapped, with any `</untrusted-test-plan>` inside them neutralised:
@@ -593,13 +623,27 @@ In multi-worktree mode, report results per worktree with aggregate summary.
593
623
 
594
624
  ### Feature Knowledge Write-Back (Conditional)
595
625
 
596
- Resolve the worktree root using the `devflow:worktree-support` algorithm (use WORKTREE_PATH if provided, otherwise cwd). All paths below are relative to `{worktree}`.
626
+ Resolve `{worktree}` as the checkout's toplevel, because feature knowledge bases are committed with the branch (D-PROMPT-ROOT): from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — run
597
627
 
598
- **Step 1 — Check the opt-out gate:**
628
+ ```bash
629
+ git -C "{start}" rev-parse --show-toplevel
630
+ ```
599
631
 
600
- Read `~/.devflow/manifest.json`. If `features.knowledge` is `false`, skip write-back entirely — the user disabled knowledge bases for every project (`devflow init --no-knowledge` or `devflow knowledge --disable`). The project's `.devflow/config.json` is not a gate: knowledge is switched machine-wide only.
632
+ and use its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. All paths below are relative to `{worktree}`.
601
633
 
602
- A missing file or a missing field means write-back is allowed (default is enabled).
634
+ **Step 1 — Check the opt-out gate, with `{root}` = `{worktree}`:**
635
+
636
+ **Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root when the run has one worktree:
637
+
638
+ ```bash
639
+ node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
640
+ ```
641
+
642
+ Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off` instead.
643
+
644
+ The accepted line is the only source of these values: the script alone folds the committed `.devflow/project.json`, the personal `.devflow/config.json` and the machine manifest.
645
+
646
+ If the settings line says `KNOWLEDGE=off`, skip write-back entirely. The machine switch (`devflow knowledge --disable`), the repository and the personal settings can each turn knowledge off, and none can turn it back on (D-FEATURES-NARROW-ONLY). The fail-closed line says `KNOWLEDGE=off` too, so an unresolvable line skips write-back.
603
647
 
604
648
  **Step 2 — Evaluate whether write-back is warranted:**
605
649
 
@@ -638,6 +682,10 @@ The frontmatter in KNOWLEDGE.md is the source of truth — index.md is only a ca
638
682
  After writing, commit the two files to the current worktree branch yourself by running git via your Bash tool (do not use a script). Stage ONLY .devflow/features/index.md and .devflow/features/{slug}/KNOWLEDGE.md, then commit just those paths with a docs(knowledge): message. Do NOT push, do NOT force, do NOT stage anything else. Follow your Commit Protocol — it is non-blocking, so if any git step fails, report KB_COMMIT and finish normally."
639
683
  ```
640
684
 
685
+ **Step 4 — Surface an uncommitted knowledge base:**
686
+
687
+ When the Knowledge agent reports `KB_COMMIT: skipped (detached HEAD)`, the files were written but deliberately not committed — a commit on a detached HEAD becomes unreachable once HEAD moves. Tell the user in the workflow's final report, in one line, that the knowledge base was written but not committed, and name the uncommitted paths the agent listed, so they can commit them on a branch before the worktree is removed. Never commit them yourself.
688
+
641
689
  **Failure handling**: Non-blocking. If the Knowledge agent fails, log the failure and continue — the workflow outcome is not affected by write-back success.
642
690
 
643
691
  ## Architecture
@@ -24,16 +24,28 @@ Detect changed files and build context:
24
24
  4. Build TASK_DESCRIPTION from recent commit messages or branch name
25
25
  ### Load DECISIONS_CONTEXT
26
26
 
27
- Resolve the worktree root using the `devflow:worktree-support` algorithm (use WORKTREE_PATH if provided, otherwise cwd). All paths below are relative to `{worktree}`.
27
+ The decisions ledger belongs to the repository, not to one checkout: in a linked worktree it lives in the main worktree, and a session started in a subdirectory reads the copy at the repository root. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
28
+
29
+ ```bash
30
+ git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
31
+ ```
32
+
33
+ Line 1 is the checkout's toplevel, line 2 the repository's common git directory. A git older than 2.31 echoes `--path-format=absolute` back as a line of its own first. `{ledger}` is the first of these that applies:
34
+
35
+ 1. **The main worktree** — line 2 without its trailing `/.git`, when the output is exactly two lines each beginning with `/`, line 2 ends in `/.git`, and the directory left once it is removed is not your home directory and contains a `.devflow/` directory.
36
+ 2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
37
+ 3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
38
+
39
+ This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT), so you read the index the Learning agent writes.
28
40
 
29
41
  **Step 1 — Read the pre-rendered index:**
30
42
 
31
- Attempt to read `{worktree}/.devflow/learning/index.md`.
43
+ Attempt to read `{ledger}/.devflow/learning/index.md`.
32
44
 
33
45
  - If the file exists and contains non-empty content: use that content as `DECISIONS_CONTEXT`.
34
46
  - If the file is absent or empty: set `DECISIONS_CONTEXT` to `(none)`.
35
47
 
36
- **No subprocess, no `.cjs` script.** This is a single direct file read — the index is written at render time by `render-decisions.cjs` alongside `decisions.md`/`pitfalls.md`.
48
+ The index is one direct file read, written at render time by `render-decisions.cjs` alongside `decisions.md`/`pitfalls.md` — no `.cjs` script runs here, and the index's own footer names the files that hold each entry's full body.
37
49
 
38
50
  **Step 2 — Apply decisions using `devflow:apply-decisions`:**
39
51
 
@@ -43,7 +55,13 @@ Pass `DECISIONS_CONTEXT` to Scrutinize agent — the compact index lists active
43
55
 
44
56
  ### Load Feature Knowledge
45
57
 
46
- Resolve the worktree root using the `devflow:worktree-support` algorithm (use WORKTREE_PATH if provided, otherwise cwd). All paths below are relative to `{worktree}`.
58
+ Resolve `{worktree}` as the checkout's toplevel, because feature knowledge bases are committed with the branch (D-PROMPT-ROOT): from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — run
59
+
60
+ ```bash
61
+ git -C "{start}" rev-parse --show-toplevel
62
+ ```
63
+
64
+ and use its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. All paths below are relative to `{worktree}`.
47
65
 
48
66
  **Step 1 — Read the index cache:**
49
67
 
@@ -78,7 +96,7 @@ Concatenate the selected KNOWLEDGE.md files under slug headers:
78
96
 
79
97
  If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set `FEATURE_KNOWLEDGE` to `(none)`.
80
98
 
81
- **No subprocess, no git calls, no `.cjs` script.** This entire step is direct file reads — 1 index read (or N frontmatter reads on fallback), bounded by KB count.
99
+ **One git call, then direct file reads — no `.cjs` script.** After resolving `{worktree}`, this step is 1 index read (or N frontmatter reads on fallback), bounded by KB count.
82
100
 
83
101
  Pass `FEATURE_KNOWLEDGE` to Scrutinize agent.
84
102
 
@@ -165,13 +183,27 @@ Display summary:
165
183
 
166
184
  ### Feature Knowledge Write-Back (Conditional)
167
185
 
168
- Resolve the worktree root using the `devflow:worktree-support` algorithm (use WORKTREE_PATH if provided, otherwise cwd). All paths below are relative to `{worktree}`.
186
+ Resolve `{worktree}` as the checkout's toplevel, because feature knowledge bases are committed with the branch (D-PROMPT-ROOT): from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — run
169
187
 
170
- **Step 1 — Check the opt-out gate:**
188
+ ```bash
189
+ git -C "{start}" rev-parse --show-toplevel
190
+ ```
171
191
 
172
- Read `~/.devflow/manifest.json`. If `features.knowledge` is `false`, skip write-back entirely — the user disabled knowledge bases for every project (`devflow init --no-knowledge` or `devflow knowledge --disable`). The project's `.devflow/config.json` is not a gate: knowledge is switched machine-wide only.
192
+ and use its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. All paths below are relative to `{worktree}`.
173
193
 
174
- A missing file or a missing field means write-back is allowed (default is enabled).
194
+ **Step 1 — Check the opt-out gate, with `{root}` = `{worktree}`:**
195
+
196
+ **Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root when the run has one worktree:
197
+
198
+ ```bash
199
+ node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
200
+ ```
201
+
202
+ Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> LEARNING=<on|off> KNOWLEDGE=<on|off>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=on LEARNING=on KNOWLEDGE=off` instead.
203
+
204
+ The accepted line is the only source of these values: the script alone folds the committed `.devflow/project.json`, the personal `.devflow/config.json` and the machine manifest.
205
+
206
+ If the settings line says `KNOWLEDGE=off`, skip write-back entirely. The machine switch (`devflow knowledge --disable`), the repository and the personal settings can each turn knowledge off, and none can turn it back on (D-FEATURES-NARROW-ONLY). The fail-closed line says `KNOWLEDGE=off` too, so an unresolvable line skips write-back.
175
207
 
176
208
  **Step 2 — Evaluate whether write-back is warranted:**
177
209
 
@@ -210,6 +242,10 @@ The frontmatter in KNOWLEDGE.md is the source of truth — index.md is only a ca
210
242
  After writing, commit the two files to the current worktree branch yourself by running git via your Bash tool (do not use a script). Stage ONLY .devflow/features/index.md and .devflow/features/{slug}/KNOWLEDGE.md, then commit just those paths with a docs(knowledge): message. Do NOT push, do NOT force, do NOT stage anything else. Follow your Commit Protocol — it is non-blocking, so if any git step fails, report KB_COMMIT and finish normally."
211
243
  ```
212
244
 
245
+ **Step 4 — Surface an uncommitted knowledge base:**
246
+
247
+ When the Knowledge agent reports `KB_COMMIT: skipped (detached HEAD)`, the files were written but deliberately not committed — a commit on a detached HEAD becomes unreachable once HEAD moves. Tell the user in the workflow's final report, in one line, that the knowledge base was written but not committed, and name the uncommitted paths the agent listed, so they can commit them on a branch before the worktree is removed. Never commit them yourself.
248
+
213
249
  **Failure handling**: Non-blocking. If the Knowledge agent fails, log the failure and continue — the workflow outcome is not affected by write-back success.
214
250
 
215
251
  ## Architecture
@@ -167,44 +167,44 @@ function collectMissingFragmentWarnings(fnName, activeFrameworks, fragments, omi
167
167
  }
168
168
  return warnings;
169
169
  }
170
+ /**
171
+ * How a consumer picks framework references at run time (D-COMPLIANCE-REPO-LENS).
172
+ *
173
+ * Every framework reference is installed on every machine
174
+ * (D-COMPLIANCE-INSTALL-ALWAYS), so file presence no longer says which
175
+ * frameworks apply. The caller hands the agent `COMPLIANCE_FRAMEWORKS` — the
176
+ * `COMPLIANCE` field of the settings line, which folds this machine's selection
177
+ * with the repository's `.devflow/project.json` — and those ids alone are in force.
178
+ */
179
+ const RUNTIME_SELECTION_LINES = [
180
+ 'Every `references/{id}.md` is installed, so presence decides nothing: the ids you were given',
181
+ "(`COMPLIANCE_FRAMEWORKS`, this machine's plus the repository's) are the frameworks in force.",
182
+ 'Load `references/{id}.md` for each given id and no other; `none` means generic controls only.',
183
+ 'Apply generic controls always.',
184
+ '',
185
+ 'NEVER fabricate framework-specific guidance for a framework you were not given.',
186
+ ];
170
187
  /**
171
188
  * Build the ${DEVFLOW_COMPLIANCE_ACTIVE} substitution — the body of the
172
189
  * Active Frameworks section.
173
190
  *
174
- * Active: lists frameworks + instructs loading reference files.
175
- * Zero: informs that generic controls only apply.
176
- *
177
- * File presence corroborates: note preserved so the agent keeps checking files.
191
+ * The stamp names the machine's own selection; zero frameworks is the neutral
192
+ * stamp a compliance-off machine's skill carries. Either way the section ends in
193
+ * RUNTIME_SELECTION_LINES, because the frameworks a run applies are the ids its
194
+ * caller passes, not the stamp.
178
195
  *
179
196
  * C5: a framework with no fragment still appears here — only its mapping row,
180
197
  * checklist item and reference row are omitted.
181
198
  *
182
- * Frameworks the registry cannot label are dropped entirely: neither the label nor the
183
- * `references/{id}.md` path is emitted (see resolveRegistryFrameworks).
199
+ * Frameworks the registry cannot label are dropped entirely: no label is emitted
200
+ * (see resolveRegistryFrameworks).
184
201
  */
185
202
  function buildActiveSection(activeFrameworks) {
186
203
  const resolved = resolveRegistryFrameworks(activeFrameworks);
187
- if (resolved.length === 0) {
188
- return [
189
- 'No framework-specific reference files are active. Apply generic controls only.',
190
- '',
191
- 'NEVER fabricate framework-specific guidance for absent `references/{id}.md` files.',
192
- 'If no reference file is present for a framework, apply generic controls only.',
193
- ].join('\n');
194
- }
195
- const labels = resolved.map(fw => fw.label);
196
- const refList = resolved.map(fw => `\`references/${fw.id}.md\``).join(' and ');
197
- return [
198
- `**Active: ${labels.join(', ')}.**`,
199
- '',
200
- `Load ${refList} for framework-specific controls. Apply generic controls always.`,
201
- '',
202
- 'File presence in the installed skill directory is the authoritative signal: if a',
203
- '`references/{id}.md` file is absent, treat that framework as inactive regardless of',
204
- 'this list.',
205
- '',
206
- 'NEVER fabricate framework-specific guidance for absent `references/{id}.md` files.',
207
- ].join('\n');
204
+ const stamp = resolved.length === 0
205
+ ? 'The machine declares no framework.'
206
+ : `**Machine frameworks: ${resolved.map(fw => fw.label).join(', ')}.**`;
207
+ return [stamp, '', ...RUNTIME_SELECTION_LINES].join('\n');
208
208
  }
209
209
  /**
210
210
  * Build the ${DEVFLOW_COMPLIANCE_MAPPING} substitution — the ENTIRE Framework