devflow-kit 3.3.0 → 3.4.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 (138) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/agents/code.md +330 -0
  3. package/{src/assets → dist}/agents/design.md +1 -1
  4. package/{src/assets → dist}/agents/diagnose.md +1 -2
  5. package/dist/agents/git.md +29 -56
  6. package/{src/assets → dist}/agents/knowledge.md +4 -3
  7. package/{src/assets → dist}/agents/research.md +2 -2
  8. package/{src/assets → dist}/agents/review.md +8 -7
  9. package/{src/assets → dist}/agents/scrutinize.md +1 -1
  10. package/dist/agents/skim.md +148 -0
  11. package/{src/assets → dist}/agents/triage.md +1 -1
  12. package/dist/cli/commands/init.js +62 -0
  13. package/dist/cli/commands/learning.js +38 -3
  14. package/dist/cli/commands/uninstall.js +42 -1
  15. package/dist/commands/bug-analysis.md +30 -8
  16. package/dist/commands/code-review.md +141 -60
  17. package/dist/commands/debug.md +14 -12
  18. package/dist/commands/dynamic-build.md +37 -38
  19. package/dist/commands/dynamic-plan.md +30 -18
  20. package/dist/commands/dynamic-profile.md +27 -13
  21. package/dist/commands/dynamic-tickets.md +28 -14
  22. package/dist/commands/explore.md +15 -13
  23. package/dist/commands/implement.md +33 -28
  24. package/dist/commands/plan.md +37 -24
  25. package/dist/commands/release.md +69 -4
  26. package/dist/commands/research.md +33 -11
  27. package/dist/commands/resolve.md +35 -32
  28. package/dist/commands/self-review.md +36 -23
  29. package/dist/core/agent-models.js +43 -0
  30. package/dist/core/assets.js +55 -10
  31. package/dist/core/claude-md-audit.js +190 -0
  32. package/dist/core/feature-switch.js +20 -1
  33. package/dist/core/flags.js +28 -0
  34. package/dist/core/fs-atomic.js +8 -3
  35. package/dist/core/learning-variants.js +213 -0
  36. package/dist/core/manifest.js +62 -0
  37. package/dist/core/mds-variants.js +38 -1
  38. package/dist/core/plugins.js +71 -9
  39. package/{src/assets → dist/learning-off}/agents/code.md +6 -10
  40. package/dist/learning-off/agents/design.md +119 -0
  41. package/dist/learning-off/agents/diagnose.md +210 -0
  42. package/dist/learning-off/agents/knowledge.md +90 -0
  43. package/dist/learning-off/agents/research.md +149 -0
  44. package/dist/learning-off/agents/review.md +228 -0
  45. package/dist/learning-off/agents/scrutinize.md +117 -0
  46. package/{src/assets → dist/learning-off}/agents/skim.md +1 -8
  47. package/dist/learning-off/agents/triage.md +163 -0
  48. package/dist/learning-off/commands/bug-analysis.md +420 -0
  49. package/dist/learning-off/commands/code-review.md +525 -0
  50. package/dist/learning-off/commands/debug.md +294 -0
  51. package/dist/learning-off/commands/dynamic-build.md +1255 -0
  52. package/dist/learning-off/commands/dynamic-plan.md +424 -0
  53. package/dist/learning-off/commands/dynamic-profile.md +214 -0
  54. package/dist/learning-off/commands/dynamic-tickets.md +632 -0
  55. package/dist/learning-off/commands/explore.md +210 -0
  56. package/dist/learning-off/commands/implement.md +808 -0
  57. package/dist/learning-off/commands/plan.md +664 -0
  58. package/dist/learning-off/commands/release.md +310 -0
  59. package/dist/learning-off/commands/research.md +222 -0
  60. package/dist/learning-off/commands/resolve.md +837 -0
  61. package/dist/learning-off/commands/self-review.md +266 -0
  62. package/dist/skills/git/references/tracker/_contract.md +33 -0
  63. package/dist/skills/git/references/tracker/github/fetch-issue.md +2 -0
  64. package/dist/skills/git/references/tracker/github/fetch-issues-batch.md +2 -0
  65. package/dist/skills/git/references/tracker/github/gather-release-evidence.md +4 -0
  66. package/dist/skills/git/references/tracker/github/post-wave-report.md +2 -0
  67. package/dist/skills/git/references/tracker/github/setup-task.md +12 -0
  68. package/dist/skills/git/references/tracker/jira/associate-release.md +1 -1
  69. package/dist/skills/git/references/tracker/jira/fetch-issue.md +2 -0
  70. package/dist/skills/git/references/tracker/jira/fetch-issues-batch.md +2 -0
  71. package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +4 -0
  72. package/dist/skills/git/references/tracker/jira/post-wave-report.md +2 -0
  73. package/dist/skills/git/references/tracker/jira/setup-task.md +14 -2
  74. package/dist/skills/git/references/tracker/linear/associate-release.md +1 -1
  75. package/dist/skills/git/references/tracker/linear/fetch-issue.md +2 -0
  76. package/dist/skills/git/references/tracker/linear/fetch-issues-batch.md +2 -0
  77. package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +4 -0
  78. package/dist/skills/git/references/tracker/linear/post-wave-report.md +2 -0
  79. package/dist/skills/git/references/tracker/linear/setup-task.md +14 -2
  80. package/dist/targets/claude-code/installer.js +72 -36
  81. package/dist/targets/claude-code/language-stamp.js +185 -0
  82. package/dist/targets/claude-code/learning-install.js +489 -0
  83. package/package.json +1 -1
  84. package/src/assets/agents/code.mds +339 -0
  85. package/src/assets/agents/design.mds +149 -0
  86. package/src/assets/agents/diagnose.mds +225 -0
  87. package/src/assets/agents/evaluate.md +1 -3
  88. package/src/assets/agents/git.mds +29 -56
  89. package/src/assets/agents/knowledge.mds +125 -0
  90. package/src/assets/agents/research.mds +176 -0
  91. package/src/assets/agents/review.mds +286 -0
  92. package/src/assets/agents/scrutinize.mds +132 -0
  93. package/src/assets/agents/skim.mds +161 -0
  94. package/src/assets/agents/triage.mds +194 -0
  95. package/src/assets/agents/validate.md +8 -6
  96. package/src/assets/commands/_partials/_compliance.mds +5 -4
  97. package/src/assets/commands/_partials/_decisions.mds +31 -0
  98. package/src/assets/commands/_partials/_engine.mds +9 -1
  99. package/src/assets/commands/_partials/_knowledge.mds +25 -12
  100. package/src/assets/commands/_partials/_preamble.mds +33 -9
  101. package/src/assets/commands/_partials/_publication.mds +5 -4
  102. package/src/assets/commands/_partials/_settings.mds +13 -5
  103. package/src/assets/commands/_partials/_wave.mds +8 -0
  104. package/src/assets/commands/bug-analysis.mds +24 -2
  105. package/src/assets/commands/code-review.mds +147 -44
  106. package/src/assets/commands/debug.mds +17 -1
  107. package/src/assets/commands/dynamic-build.mds +33 -2
  108. package/src/assets/commands/dynamic-plan.mds +36 -6
  109. package/src/assets/commands/dynamic-profile.mds +9 -1
  110. package/src/assets/commands/dynamic-tickets.mds +16 -2
  111. package/src/assets/commands/explore.mds +27 -1
  112. package/src/assets/commands/implement.mds +41 -8
  113. package/src/assets/commands/plan.mds +47 -8
  114. package/src/assets/commands/{release.md → release.mds} +27 -24
  115. package/src/assets/commands/research.mds +28 -4
  116. package/src/assets/commands/resolve.mds +43 -2
  117. package/src/assets/commands/self-review.mds +30 -5
  118. package/src/assets/mds/tracker/_contract.mds +72 -0
  119. package/src/assets/mds/tracker/_github.mds +13 -2
  120. package/src/assets/mds/tracker/_jira.mds +17 -5
  121. package/src/assets/mds/tracker/_linear.mds +17 -5
  122. package/src/assets/mds/tracker/_mcp.mds +2 -2
  123. package/src/assets/mds/tracker/_steps.mds +97 -0
  124. package/src/assets/rules/context-economy.md +10 -0
  125. package/src/assets/rules/go.md +1 -0
  126. package/src/assets/rules/java.md +1 -0
  127. package/src/assets/rules/python.md +1 -0
  128. package/src/assets/rules/rust.md +1 -0
  129. package/src/assets/rules/typescript.md +1 -0
  130. package/src/assets/scripts/claude-md-audit.cjs +611 -0
  131. package/src/assets/scripts/hooks/assets/orchestrator-charter.md +1 -2
  132. package/src/assets/scripts/hooks/json-helper.cjs +13 -5
  133. package/src/assets/scripts/hooks/json-parse +34 -10
  134. package/src/assets/scripts/hooks/session-start-context +315 -7
  135. package/src/assets/skills/apply-decisions/SKILL.md +1 -1
  136. package/src/assets/skills/apply-feature-knowledge/SKILL.md +5 -5
  137. package/src/assets/skills/feature-knowledge/SKILL.md +43 -12
  138. package/src/assets/skills/quality-gates/SKILL.md +1 -1
@@ -52,7 +52,19 @@ Read `.release/RELEASE-FLOW.md`:
52
52
 
53
53
  ### Phase 1b: Load Context
54
54
 
55
- **Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE
55
+ **Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES
56
+
57
+ **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:
58
+
59
+ ```bash
60
+ node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
61
+ ```
62
+
63
+ 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.
64
+
65
+ 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.
66
+
67
+ When the settings line says `LEARNING=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
56
68
 
57
69
  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`):
58
70
 
@@ -70,9 +82,62 @@ This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT
70
82
 
71
83
  Read `{ledger}/.devflow/learning/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
72
84
 
73
- Load feature knowledge: Attempt to read `.devflow/features/index.md` (the regenerable cache). If absent or empty, glob `.devflow/features/*/KNOWLEDGE.md` and read each file's YAML frontmatter (`name`, `description`, `directories`) as the relevance surface. Pick release-relevant KBs by matching their documented area against the release context. For each selected KB, read the full `KNOWLEDGE.md` — trust current code over KB content on any mismatch. Concatenate under slug headers and set `FEATURE_KNOWLEDGE` (or `(none)` if no KBs exist or none are relevant). No `index.json`, no subprocess, no `.cjs` script.
85
+ ### Load Feature Knowledge
86
+
87
+ 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
88
+
89
+ ```bash
90
+ git -C "{start}" rev-parse --show-toplevel
91
+ ```
92
+
93
+ 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}`.
94
+
95
+ **Step 1 — Read the index cache:**
96
+
97
+ Attempt to read `{worktree}/.devflow/features/index.md`. Each line follows the format:
98
+
99
+ ```
100
+ - **{slug}** — {areas} — {Use-when description}
101
+ ```
102
+
103
+ If `index.md` exists and contains at least one entry line, use it for relevance matching.
104
+
105
+ **Step 2 — Fallback: glob frontmatter (if `index.md` is absent or empty):**
106
+
107
+ Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read only its YAML frontmatter block (between the opening and closing `---` delimiters). The frontmatter fields `name`, `description`, and `directories` are the authoritative relevance surface — `index.md` is only a cache.
108
+
109
+ **Step 3 — Pick relevant KBs:**
110
+
111
+ Match the current task area and description against each index line (or frontmatter `description` + `directories` on fallback). Select entries whose documented area overlaps the current task. This is a relevance judgment — prefer specificity over breadth.
112
+
113
+ **Step 4 — Read each selected KB's Rules:**
114
+
115
+ For each selected entry, `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
116
+
117
+ 1. List its `##` headings with line numbers through Bash: `command grep -n '^## ' "{kb}"`. This only locates sections; the text of a KB comes from the Read view alone.
118
+ 2. Read the `## Rules` range (its line to the next heading) with the Read tool, using `offset` and `limit`, and choose the one to three bullets most relevant to the current task. The choice is yours, made per KB.
119
+ 3. If the KB has no `## Rules` section, choose one to three entries from its `## Anti-Patterns` or `## Gotchas` range the same way, and label them by that section's name instead of an ID.
120
+
121
+ When a KB contradicts the code you observe, **trust the code** — the code is the freshness mechanism; the KB may lag behind. A missing Rules section, a missing heading list and `(none)` are legitimate states, not errors.
122
+
123
+ **Step 5 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES:**
124
+
125
+ Write one block per selected KB. Paste each bullet verbatim from the Read view, never from a shell view. The path is relative to the checkout root; an agent resolves it under `WORKTREE_PATH` when one is provided.
126
+
127
+ ```
128
+ --- Feature knowledge: {slug} ---
129
+ KB: .devflow/features/{slug}/KNOWLEDGE.md
130
+ Rules:
131
+ - **KB-AP-2** {bullet text, verbatim}
132
+ - **KB-INV-1** {bullet text, verbatim}
133
+ Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
134
+ ```
135
+
136
+ A KB with no Rules section labels its entries `Rules ({section name}):` and gives them no ID. `FEATURE_KNOWLEDGE` is these blocks; `FEATURE_KNOWLEDGE_RULES` is the same blocks without the `Headings:` line. Both come from this one selection, and each spawn names the variable its recipient takes. If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set both to `(none)`.
137
+
138
+ **One git call, then direct reads — no `.cjs` script.** After resolving `{worktree}`, this step is 1 index read (or N frontmatter reads on fallback), plus one heading listing and one Rules read per selected KB, bounded by KB count.
74
139
 
75
- Pass both to all subsequent agents via their input contracts.
140
+ Pass `DECISIONS_CONTEXT` and `FEATURE_KNOWLEDGE` only to agents whose contract declares them; the Validate and Git agents this command spawns do not.
76
141
 
77
142
  ### Phase 1c: Resolve the Evidence Policy
78
143
 
@@ -230,7 +295,7 @@ On completion:
230
295
  │ └─ Read .release/RELEASE-FLOW.md (learned) or proceed to detect (fresh)
231
296
  │
232
297
  ├─ Phase 1b: Load Context
233
- │ └─ Load DECISIONS_CONTEXT and FEATURE_KNOWLEDGE for downstream agents
298
+ │ └─ Load DECISIONS_CONTEXT and FEATURE_KNOWLEDGE for the agents that declare them
234
299
  │
235
300
  ├─ Phase 2: Detect Release Process (first run only)
236
301
  │ └─ Tiered scan: package.json, CI workflows, git history
@@ -31,7 +31,7 @@ $ARGUMENTS
31
31
 
32
32
  ### Phase 1: Load Decisions (Orchestrator-Local)
33
33
 
34
- **Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE
34
+ **Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES
35
35
 
36
36
  **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
37
37
 
@@ -41,8 +41,20 @@ git -C "{start}" rev-parse --show-toplevel
41
41
 
42
42
  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.
43
43
 
44
+ **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:
45
+
46
+ ```bash
47
+ node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
48
+ ```
49
+
50
+ 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.
51
+
52
+ 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.
53
+
44
54
  ### Load DECISIONS_CONTEXT
45
55
 
56
+ When the settings line says `LEARNING=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
57
+
46
58
  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`):
47
59
 
48
60
  ```bash
@@ -100,22 +112,32 @@ Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read on
100
112
 
101
113
  Match the current task area and description against each index line (or frontmatter `description` + `directories` on fallback). Select entries whose documented area overlaps the current task. This is a relevance judgment — prefer specificity over breadth.
102
114
 
103
- **Step 4 — Read selected KBs:**
115
+ **Step 4 — Read each selected KB's Rules:**
116
+
117
+ For each selected entry, `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
104
118
 
105
- For each selected entry, read `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md` in full. When the KB content contradicts the current code you observe, **trust the code** — the code is the freshness mechanism; the KB may lag behind.
119
+ 1. List its `##` headings with line numbers through Bash: `command grep -n '^## ' "{kb}"`. This only locates sections; the text of a KB comes from the Read view alone.
120
+ 2. Read the `## Rules` range (its line to the next heading) with the Read tool, using `offset` and `limit`, and choose the one to three bullets most relevant to the current task. The choice is yours, made per KB.
121
+ 3. If the KB has no `## Rules` section, choose one to three entries from its `## Anti-Patterns` or `## Gotchas` range the same way, and label them by that section's name instead of an ID.
106
122
 
107
- **Step 5 — Set FEATURE_KNOWLEDGE:**
123
+ When a KB contradicts the code you observe, **trust the code** — the code is the freshness mechanism; the KB may lag behind. A missing Rules section, a missing heading list and `(none)` are legitimate states, not errors.
108
124
 
109
- Concatenate the selected KNOWLEDGE.md files under slug headers:
125
+ **Step 5 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES:**
126
+
127
+ Write one block per selected KB. Paste each bullet verbatim from the Read view, never from a shell view. The path is relative to the checkout root; an agent resolves it under `WORKTREE_PATH` when one is provided.
110
128
 
111
129
  ```
112
130
  --- Feature knowledge: {slug} ---
113
- {full KNOWLEDGE.md content}
131
+ KB: .devflow/features/{slug}/KNOWLEDGE.md
132
+ Rules:
133
+ - **KB-AP-2** {bullet text, verbatim}
134
+ - **KB-INV-1** {bullet text, verbatim}
135
+ Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
114
136
  ```
115
137
 
116
- If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set `FEATURE_KNOWLEDGE` to `(none)`.
138
+ A KB with no Rules section labels its entries `Rules ({section name}):` and gives them no ID. `FEATURE_KNOWLEDGE` is these blocks; `FEATURE_KNOWLEDGE_RULES` is the same blocks without the `Headings:` line. Both come from this one selection, and each spawn names the variable its recipient takes. If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set both to `(none)`.
117
139
 
118
- **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.
140
+ **One git call, then direct reads — no `.cjs` script.** After resolving `{worktree}`, this step is 1 index read (or N frontmatter reads on fallback), plus one heading listing and one Rules read per selected KB, bounded by KB count.
119
141
 
120
142
  Use `FEATURE_KNOWLEDGE` **locally** for research framing. Pass to each Research agent in Phase 4.
121
143
 
@@ -138,7 +160,7 @@ Generate topic slug from the research question (kebab-case, lowercase, no articl
138
160
 
139
161
  Only if `codebase` type is in RESEARCH_PLAN.
140
162
 
141
- Spawn `Agent(subagent_type="Skim")` targeting codebase areas relevant to the research question.
163
+ Spawn `Agent(subagent_type="Skim")` with `LEARNING` from the settings line, targeting codebase areas relevant to the research question.
142
164
 
143
165
  Skip and set ORIENT_OUTPUT = "(none)" if `codebase` type is not in RESEARCH_PLAN.
144
166
 
@@ -152,7 +174,7 @@ Spawn 2-5 `Agent(subagent_type="Research")` agents **in a single message** (para
152
174
  Each Research agent receives:
153
175
  - `RESEARCH_TYPE`, `RESEARCH_QUESTION`, `OUTPUT_PATH` from RESEARCH_PLAN
154
176
  - `DECISIONS_CONTEXT`: From Phase 1
155
- - `FEATURE_KNOWLEDGE`: From Phase 1
177
+ - `FEATURE_KNOWLEDGE`: `{feature_knowledge}` from Phase 1
156
178
  - `ORIENT_OUTPUT`: Only for `codebase` type
157
179
  - `WORKTREE_PATH`: If in a worktree context
158
180
 
@@ -183,7 +205,7 @@ If external research was skipped due to tool unavailability: inform user.
183
205
 
184
206
  ### Phase 7: Feature Knowledge Creation (Conditional)
185
207
 
186
- **Requires:** RESEARCH_SUMMARY, DECISIONS_CONTEXT
208
+ **Requires:** RESEARCH_SUMMARY
187
209
  **Produces:** FEATURE_KNOWLEDGE_STATUS (created | skipped)
188
210
 
189
211
  1. If `codebase` type was not in RESEARCH_PLAN → skip
@@ -85,10 +85,22 @@ Set `TARGET_DIR` to the selected review or bug-analysis directory path, and `TAR
85
85
 
86
86
  #### Step 0d: Load Project Decisions
87
87
 
88
- **Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, EVIDENCE_POLICY, ISSUE_REQUIRED, APPLY_CONVENTIONS, REQUIRE_NON_AUTHOR_APPROVAL, REVIEW_PUBLICATION, RESOLUTION_TS
88
+ **Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES, EVIDENCE_POLICY, ISSUE_REQUIRED, APPLY_CONVENTIONS, REQUIRE_NON_AUTHOR_APPROVAL, REVIEW_PUBLICATION, RESOLUTION_TS
89
+
90
+ **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:
91
+
92
+ ```bash
93
+ node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
94
+ ```
95
+
96
+ 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.
97
+
98
+ 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.
89
99
 
90
100
  ### Load DECISIONS_CONTEXT
91
101
 
102
+ When the settings line says `LEARNING=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
103
+
92
104
  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
105
 
94
106
  ```bash
@@ -146,22 +158,32 @@ Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read on
146
158
 
147
159
  Match the current task area and description against each index line (or frontmatter `description` + `directories` on fallback). Select entries whose documented area overlaps the current task. This is a relevance judgment — prefer specificity over breadth.
148
160
 
149
- **Step 4 — Read selected KBs:**
161
+ **Step 4 — Read each selected KB's Rules:**
162
+
163
+ For each selected entry, `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
164
+
165
+ 1. List its `##` headings with line numbers through Bash: `command grep -n '^## ' "{kb}"`. This only locates sections; the text of a KB comes from the Read view alone.
166
+ 2. Read the `## Rules` range (its line to the next heading) with the Read tool, using `offset` and `limit`, and choose the one to three bullets most relevant to the current task. The choice is yours, made per KB.
167
+ 3. If the KB has no `## Rules` section, choose one to three entries from its `## Anti-Patterns` or `## Gotchas` range the same way, and label them by that section's name instead of an ID.
150
168
 
151
- For each selected entry, read `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md` in full. When the KB content contradicts the current code you observe, **trust the code** — the code is the freshness mechanism; the KB may lag behind.
169
+ When a KB contradicts the code you observe, **trust the code** — the code is the freshness mechanism; the KB may lag behind. A missing Rules section, a missing heading list and `(none)` are legitimate states, not errors.
152
170
 
153
- **Step 5 — Set FEATURE_KNOWLEDGE:**
171
+ **Step 5 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES:**
154
172
 
155
- Concatenate the selected KNOWLEDGE.md files under slug headers:
173
+ Write one block per selected KB. Paste each bullet verbatim from the Read view, never from a shell view. The path is relative to the checkout root; an agent resolves it under `WORKTREE_PATH` when one is provided.
156
174
 
157
175
  ```
158
176
  --- Feature knowledge: {slug} ---
159
- {full KNOWLEDGE.md content}
177
+ KB: .devflow/features/{slug}/KNOWLEDGE.md
178
+ Rules:
179
+ - **KB-AP-2** {bullet text, verbatim}
180
+ - **KB-INV-1** {bullet text, verbatim}
181
+ Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
160
182
  ```
161
183
 
162
- If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set `FEATURE_KNOWLEDGE` to `(none)`.
184
+ A KB with no Rules section labels its entries `Rules ({section name}):` and gives them no ID. `FEATURE_KNOWLEDGE` is these blocks; `FEATURE_KNOWLEDGE_RULES` is the same blocks without the `Headings:` line. Both come from this one selection, and each spawn names the variable its recipient takes. If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set both to `(none)`.
163
185
 
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.
186
+ **One git call, then direct reads — no `.cjs` script.** After resolving `{worktree}`, this step is 1 index read (or N frontmatter reads on fallback), plus one heading listing and one Rules read per selected KB, bounded by KB count.
165
187
 
166
188
  Pass `FEATURE_KNOWLEDGE` to the Triage agent in Phase 2.
167
189
 
@@ -176,17 +198,7 @@ Accept the output only when it is exactly two lines: `exit=0` last and, before i
176
198
  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.
177
199
  Reuse this result for every worktree.
178
200
 
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.
186
-
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.
201
+ **Resolve `REVIEW_PUBLICATION` per worktree:** take `REVIEW_PUBLICATION` from that worktree's settings line — the line resolved above for `{root}`, the worktree's root, by the settings block when this run has not yet resolved that 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
202
 
191
203
  **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.
192
204
 
@@ -384,6 +396,7 @@ Run build, typecheck, lint, test. Report pass/fail with failure details."
384
396
  PUSH: false
385
397
  CREATE_PR: false
386
398
  WORKTREE_PATH: {worktree_path} (omit if cwd)
399
+ DECISIONS_CONTEXT: {decisions_context}
387
400
  COMPLIANCE_FRAMEWORKS: {COMPLIANCE_FRAMEWORKS}"
388
401
  ```
389
402
  - Loop back to re-validate
@@ -432,7 +445,7 @@ Phase 7 has pushed already, so this is a no-op unless the head moved since. `exi
432
445
  3. **If NO_PR or NO_CI** → skip: "No PR/CI configured, skipping CI validation." Proceed to next phase.
433
446
  4. **If PENDING** and fewer than 3 waits have run → wait again (step 1). After the third wait → report "CI still running — verify manually before merging" and proceed.
434
447
  5. **If INDETERMINATE** and fewer than 3 waits have run → wait again (step 1). After the third wait → report "CI status unknown — verify manually before merging" and proceed.
435
- 6. **If FAILING** and fewer than 2 fixes have run → report the failing checks from the line. Spawn `Agent(subagent_type="Code")` whose prompt opens with `OPERATION: ci-fix`, with `COMPLIANCE_FRAMEWORKS`, `CI_FAILURES` and `PUSH: false`; `CI_FAILURES` holds the failing-check names from the line and nothing else, because the Code agent fetches the full names and reads the logs itself and this command reads none. After a fix, push with the command above and, if a wait remains, wait again (step 1); a failed push records `TRACEABILITY: DEGRADED (ci push failed)`, reports "CI status unknown — verify manually before merging" and stops waiting. After the second fix still FAILING → report the failing checks and proceed.
448
+ 6. **If FAILING** and fewer than 2 fixes have run → report the failing checks from the line. Spawn `Agent(subagent_type="Code")` whose prompt opens with `OPERATION: ci-fix`, with `COMPLIANCE_FRAMEWORKS`, `CI_FAILURES`, `DECISIONS_CONTEXT` and `PUSH: false`; `CI_FAILURES` holds the failing-check names from the line and nothing else, because the Code agent fetches the full names and reads the logs itself and this command reads none. After a fix, push with the command above and, if a wait remains, wait again (step 1); a failed push records `TRACEABILITY: DEGRADED (ci push failed)`, reports "CI status unknown — verify manually before merging" and stops waiting. After the second fix still FAILING → report the failing checks and proceed.
436
449
  7. **Budget**: at most 3 waits and 2 fixes in all, per worktree. When one is spent, report the current status and proceed.
437
450
  <!-- /PATTERN: ci-status-gate -->
438
451
 
@@ -642,17 +655,7 @@ git -C "{start}" rev-parse --show-toplevel
642
655
 
643
656
  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}`.
644
657
 
645
- **Step 1 — Check the opt-out gate, with `{root}` = `{worktree}`:**
646
-
647
- **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:
648
-
649
- ```bash
650
- node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
651
- ```
652
-
653
- 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.
654
-
655
- 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.
658
+ **Step 1 — Check the opt-out gate, with `{root}` = `{worktree}`:** take the settings line resolved above for that root, resolving it with the settings block when this run has not yet.
656
659
 
657
660
  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.
658
661
 
@@ -682,7 +685,7 @@ Write the knowledge base to:
682
685
  Then update the index cache by performing a read-modify-write on:
683
686
  {worktree}/.devflow/features/index.md
684
687
 
685
- Index line format: `- **{slug}** — {areas} — {Use-when description}`
688
+ Index line format: `- **{slug}** — {areas} — {Use-when description}` — at most 300 characters, the description at most 220; reword a longer one, never cut it.
686
689
 
687
690
  If the line for this slug already exists in index.md, replace it. If it does not exist, append it. If index.md does not exist, create it with just this line.
688
691
 
@@ -14,7 +14,7 @@ Run Simplify agent and Scrutinize agent sequentially on changed files for post-i
14
14
 
15
15
  ### Phase 0: Context Gathering
16
16
 
17
- **Produces:** FILES_CHANGED, TASK_DESCRIPTION, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, HEAD_BEFORE
17
+ **Produces:** FILES_CHANGED, TASK_DESCRIPTION, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES, HEAD_BEFORE
18
18
 
19
19
  Detect changed files and build context:
20
20
 
@@ -23,8 +23,21 @@ Detect changed files and build context:
23
23
  3. If no changes found, report "No changes to review" and exit
24
24
  4. Build TASK_DESCRIPTION from recent commit messages or branch name
25
25
  5. Record `HEAD_BEFORE` (`git rev-parse HEAD`) now, before Simplify runs — Phase 3 compares against it
26
+
27
+ **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:
28
+
29
+ ```bash
30
+ node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
31
+ ```
32
+
33
+ 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.
34
+
35
+ 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.
36
+
26
37
  ### Load DECISIONS_CONTEXT
27
38
 
39
+ When the settings line says `LEARNING=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
40
+
28
41
  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`):
29
42
 
30
43
  ```bash
@@ -82,26 +95,36 @@ Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read on
82
95
 
83
96
  Match the current task area and description against each index line (or frontmatter `description` + `directories` on fallback). Select entries whose documented area overlaps the current task. This is a relevance judgment — prefer specificity over breadth.
84
97
 
85
- **Step 4 — Read selected KBs:**
98
+ **Step 4 — Read each selected KB's Rules:**
86
99
 
87
- For each selected entry, read `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md` in full. When the KB content contradicts the current code you observe, **trust the code** — the code is the freshness mechanism; the KB may lag behind.
100
+ For each selected entry, `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
88
101
 
89
- **Step 5 — Set FEATURE_KNOWLEDGE:**
102
+ 1. List its `##` headings with line numbers through Bash: `command grep -n '^## ' "{kb}"`. This only locates sections; the text of a KB comes from the Read view alone.
103
+ 2. Read the `## Rules` range (its line to the next heading) with the Read tool, using `offset` and `limit`, and choose the one to three bullets most relevant to the current task. The choice is yours, made per KB.
104
+ 3. If the KB has no `## Rules` section, choose one to three entries from its `## Anti-Patterns` or `## Gotchas` range the same way, and label them by that section's name instead of an ID.
90
105
 
91
- Concatenate the selected KNOWLEDGE.md files under slug headers:
106
+ When a KB contradicts the code you observe, **trust the code** — the code is the freshness mechanism; the KB may lag behind. A missing Rules section, a missing heading list and `(none)` are legitimate states, not errors.
107
+
108
+ **Step 5 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES:**
109
+
110
+ Write one block per selected KB. Paste each bullet verbatim from the Read view, never from a shell view. The path is relative to the checkout root; an agent resolves it under `WORKTREE_PATH` when one is provided.
92
111
 
93
112
  ```
94
113
  --- Feature knowledge: {slug} ---
95
- {full KNOWLEDGE.md content}
114
+ KB: .devflow/features/{slug}/KNOWLEDGE.md
115
+ Rules:
116
+ - **KB-AP-2** {bullet text, verbatim}
117
+ - **KB-INV-1** {bullet text, verbatim}
118
+ Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
96
119
  ```
97
120
 
98
- If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set `FEATURE_KNOWLEDGE` to `(none)`.
121
+ A KB with no Rules section labels its entries `Rules ({section name}):` and gives them no ID. `FEATURE_KNOWLEDGE` is these blocks; `FEATURE_KNOWLEDGE_RULES` is the same blocks without the `Headings:` line. Both come from this one selection, and each spawn names the variable its recipient takes. If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set both to `(none)`.
99
122
 
100
- **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.
123
+ **One git call, then direct reads — no `.cjs` script.** After resolving `{worktree}`, this step is 1 index read (or N frontmatter reads on fallback), plus one heading listing and one Rules read per selected KB, bounded by KB count.
101
124
 
102
- Pass `FEATURE_KNOWLEDGE` to Scrutinize agent.
125
+ Pass `FEATURE_KNOWLEDGE_RULES` to Scrutinize agent.
103
126
 
104
- **Extract:** FILES_CHANGED (list), TASK_DESCRIPTION (string), DECISIONS_CONTEXT (string, optional), FEATURE_KNOWLEDGE (string, optional), HEAD_BEFORE (40-hex SHA)
127
+ **Extract:** FILES_CHANGED (list), TASK_DESCRIPTION (string), DECISIONS_CONTEXT (string, optional), FEATURE_KNOWLEDGE (string, optional), FEATURE_KNOWLEDGE_RULES (string, optional), HEAD_BEFORE (40-hex SHA)
105
128
 
106
129
  ### Phase 1: Simplify agent (Code Refinement)
107
130
 
@@ -129,7 +152,7 @@ Agent(subagent_type="Scrutinize", run_in_background=false):
129
152
  "TASK_DESCRIPTION: {task_description}
130
153
  FILES_CHANGED: {files_changed}
131
154
  DECISIONS_CONTEXT: {decisions_context}
132
- FEATURE_KNOWLEDGE: {feature_knowledge}
155
+ FEATURE_KNOWLEDGE: {feature_knowledge_rules}
133
156
  Evaluate against 9-pillar framework. Fix P0/P1 issues. Return structured report.
134
157
  Follow devflow:apply-decisions to scan DECISIONS_CONTEXT and Read full ADR/PF bodies on demand. Skip if (none).
135
158
  Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE. Skip if (none)."
@@ -195,17 +218,7 @@ git -C "{start}" rev-parse --show-toplevel
195
218
 
196
219
  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}`.
197
220
 
198
- **Step 1 — Check the opt-out gate, with `{root}` = `{worktree}`:**
199
-
200
- **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:
201
-
202
- ```bash
203
- node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
204
- ```
205
-
206
- 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.
207
-
208
- 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.
221
+ **Step 1 — Check the opt-out gate, with `{root}` = `{worktree}`:** take the settings line resolved above for that root, resolving it with the settings block when this run has not yet.
209
222
 
210
223
  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.
211
224
 
@@ -235,7 +248,7 @@ Write the knowledge base to:
235
248
  Then update the index cache by performing a read-modify-write on:
236
249
  {worktree}/.devflow/features/index.md
237
250
 
238
- Index line format: `- **{slug}** — {areas} — {Use-when description}`
251
+ Index line format: `- **{slug}** — {areas} — {Use-when description}` — at most 300 characters, the description at most 220; reword a longer one, never cut it.
239
252
 
240
253
  If the line for this slug already exists in index.md, replace it. If it does not exist, append it. If index.md does not exist, create it with just this line.
241
254
 
@@ -599,6 +599,49 @@ export async function loadShippedAgentDefaults(dirs = agentSourceDirs(), opts) {
599
599
  }
600
600
  return defaults;
601
601
  }
602
+ // ---------------------------------------------------------------------------
603
+ // carryAgentOverrides — the frontmatter a converge keeps
604
+ // ---------------------------------------------------------------------------
605
+ /**
606
+ * D-AGENT-OVERRIDE-CARRY: the text a prompt converge installs for an agent is the
607
+ * variant `source` wearing the installed copy's `model:` and `effort:`.
608
+ *
609
+ * Those two lines are the only frontmatter keys reapplyAgentMapping manages, and
610
+ * `devflow agents` and the proxy put their values there. A converge that installed
611
+ * the bare variant would write every overridden agent back to its shipped model
612
+ * and effort and leave reapplyAgentMapping to restore it: a window with default
613
+ * models, and a no-op converge that rewrites everything. Carrying the two lines
614
+ * keeps that window shut, so a copy already holding the right variant and its
615
+ * overrides compares byte-equal and is not touched.
616
+ *
617
+ * The carry is an optimisation, never the authority: reapplyAgentMapping reads
618
+ * agent-models.json and decides what the installed frontmatter must say. It
619
+ * agrees with the carry whenever the installed copy was last written by it, and
620
+ * where they disagree the later reapply wins. Both go through
621
+ * rewriteAgentFrontmatter, so the model-name charset guard, the first-block scope
622
+ * and the EOL handling are the ones the reapply uses.
623
+ *
624
+ * `source` is returned unchanged when there is nothing safe to carry: either side
625
+ * has no well-formed frontmatter, the installed copy has no model, its model
626
+ * fails the model-name charset or its effort is not an EFFORT_LEVELS member. An
627
+ * installed copy with no `effort:` line carries no effort (a mapping effort of
628
+ * `inherit` yields exactly that).
629
+ *
630
+ * Pure function — no I/O.
631
+ */
632
+ export function carryAgentOverrides(source, installed) {
633
+ const model = readFrontmatterModel(installed);
634
+ const effort = readFrontmatterEffort(installed);
635
+ if (!model.ok || !effort.ok || model.value === '')
636
+ return source;
637
+ if (effort.value !== '' && !isEffortLevel(effort.value))
638
+ return source;
639
+ const carried = rewriteAgentFrontmatter(source, {
640
+ model: model.value,
641
+ effort: effort.value === '' ? null : effort.value,
642
+ });
643
+ return carried.ok ? carried.value.content : source;
644
+ }
602
645
  /**
603
646
  * Idempotent convergence function: walk every installed agent file and
604
647
  * rewrite frontmatter model/effort to match the effective mapping.
@@ -1,16 +1,21 @@
1
1
  import { join } from 'path';
2
2
  import { getPackageRoot } from './paths.js';
3
3
  import { SKILL_REFS_OUTPUT_DIR } from './mds-variants.js';
4
+ import { LEARNING_OFF_OUTPUT_DIR } from './learning-variants.js';
4
5
  /**
5
6
  * Flat skills source directory: src/assets/skills/{name}/
6
7
  * All plugins' skills live here directly (no per-plugin subdirectory).
8
+ *
9
+ * @param root - Package root to resolve against. Injectable so a caller working
10
+ * on a temp tree (the learning converge) reads the skill source from the same
11
+ * root as the rest of its sources.
7
12
  */
8
- export function skillsDir() {
9
- return join(getPackageRoot(), 'src', 'assets', 'skills');
13
+ export function skillsDir(root = getPackageRoot()) {
14
+ return join(root, 'src', 'assets', 'skills');
10
15
  }
11
16
  /**
12
- * Flat agents source directory: src/assets/agents/{name}.md
13
- * All plugins' agents live here directly.
17
+ * Flat agents source directory: src/assets/agents/{name}.md, or {name}.mds for a
18
+ * generator host. All plugins' agents live here directly.
14
19
  *
15
20
  * @param root - Package root to resolve against. Injectable so a caller working
16
21
  * on a temp tree (the test harness) reads the layout from here rather than
@@ -35,17 +40,49 @@ export function scriptsDir() {
35
40
  }
36
41
  /**
37
42
  * Compiled commands directory: dist/commands/
38
- * Single lookup directory for installed commands — .mds compile output
39
- * plus verbatim hand-authored .md copies.
43
+ * Single lookup directory for installed commands: one compiled file per `.mds`
44
+ * command host in src/assets/commands/. A host that carries a learning arm also
45
+ * has a learning-off variant (see learningOffDir).
40
46
  */
41
47
  export function commandsDir() {
42
48
  return join(getPackageRoot(), 'dist', 'commands');
43
49
  }
50
+ /**
51
+ * Learning-off variant directory: dist/learning-off/{commands,agents}/
52
+ *
53
+ * Holds the learning-off variant of each prompt that carries a learning arm
54
+ * (D-LEARNING-VARIANTS), and only those. Absent until the build has run, so every
55
+ * reader tolerates its absence.
56
+ *
57
+ * The spelling comes from LEARNING_OFF_OUTPUT_DIR in learning-variants.ts, the
58
+ * build's own destination, rather than being retyped here.
59
+ *
60
+ * @param kind - Which prompt kind's variants.
61
+ * @param root - Package root to resolve against (see agentsDir).
62
+ */
63
+ export function learningOffDir(kind, root = getPackageRoot()) {
64
+ return join(root, ...LEARNING_OFF_OUTPUT_DIR.split('/'), kind);
65
+ }
66
+ /**
67
+ * Command source directories, MOST-PREFERRED FIRST.
68
+ *
69
+ * D-LEARNING-VARIANT-INSTALL: with learning off the learning-off variant comes
70
+ * first, so a host with an arm installs its off variant and a host with none falls
71
+ * through to the one compiled file; with learning on the order is the normal
72
+ * single-directory lookup.
73
+ *
74
+ * @param learning - The machine's settled learning switch.
75
+ * @param root - Package root to resolve against (see agentsDir).
76
+ */
77
+ export function commandSourceDirs(learning, root = getPackageRoot()) {
78
+ const normal = join(root, 'dist', 'commands');
79
+ return learning ? [normal] : [learningOffDir('commands', root), normal];
80
+ }
44
81
  /**
45
82
  * Compiled agents directory: dist/agents/{name}.md
46
83
  *
47
- * Output of the .mds generator hosts. The directory is absent until at least
48
- * one generator host exists, so every reader must tolerate its absence.
84
+ * Output of the .mds generator hosts. The directory is absent until the build has
85
+ * run, so every reader must tolerate its absence.
49
86
  *
50
87
  * @param root - Package root to resolve against (see agentsDir).
51
88
  */
@@ -87,9 +124,17 @@ export function compiledSkillRefsDir(root = getPackageRoot()) {
87
124
  * The non-empty tuple makes an empty list a compile error at every call site:
88
125
  * an empty list would survive a `??` default and resolve to nothing.
89
126
  *
127
+ * D-LEARNING-VARIANT-INSTALL: `learning: false` puts dist/learning-off/agents first,
128
+ * for the installer and the converge only. The default (learning on) is the order
129
+ * every other reader wants: the shipped defaults (model, effort) are the same in
130
+ * both variants, so loadShippedAgentDefaults and the test harness keep reading the
131
+ * learning-on tree.
132
+ *
90
133
  * @param root - Package root to resolve against (see agentsDir).
134
+ * @param learning - The machine's settled learning switch; on by default.
91
135
  */
92
- export function agentSourceDirs(root = getPackageRoot()) {
93
- return [compiledAgentsDir(root), agentsDir(root)];
136
+ export function agentSourceDirs(root = getPackageRoot(), learning = true) {
137
+ const normal = [compiledAgentsDir(root), agentsDir(root)];
138
+ return learning ? normal : [learningOffDir('agents', root), ...normal];
94
139
  }
95
140
  //# sourceMappingURL=assets.js.map