devflow-kit 3.10.0 → 3.12.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 (229) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/dist/agents/architect.md +87 -0
  3. package/dist/agents/code.md +21 -25
  4. package/dist/agents/debug.md +21 -49
  5. package/dist/agents/design.md +9 -43
  6. package/dist/agents/fix.md +15 -29
  7. package/dist/agents/git.md +19 -22
  8. package/dist/agents/harden.md +14 -19
  9. package/dist/agents/knowledge.md +11 -19
  10. package/dist/agents/refactor.md +9 -14
  11. package/dist/agents/research.md +11 -34
  12. package/dist/agents/review.md +22 -52
  13. package/dist/agents/skim.md +7 -17
  14. package/dist/agents/triage.md +7 -14
  15. package/dist/cli/commands/backup-session.js +131 -0
  16. package/dist/cli/commands/compliance.js +16 -3
  17. package/dist/cli/commands/curation.js +12 -4
  18. package/dist/cli/commands/init.js +36 -55
  19. package/dist/cli/commands/install-report.js +95 -0
  20. package/dist/cli/commands/legacy-sweep.js +140 -45
  21. package/dist/cli/commands/rules.js +50 -13
  22. package/dist/cli/commands/uninstall.js +62 -24
  23. package/dist/commands/bug-analysis.md +31 -62
  24. package/dist/commands/code-review.md +38 -87
  25. package/dist/commands/debug.md +32 -82
  26. package/dist/commands/dynamic-build.md +155 -211
  27. package/dist/commands/dynamic-plan.md +71 -93
  28. package/dist/commands/dynamic-profile.md +7 -155
  29. package/dist/commands/dynamic-tickets.md +65 -186
  30. package/dist/commands/explore.md +27 -70
  31. package/dist/commands/implement.md +98 -186
  32. package/dist/commands/plan.md +60 -107
  33. package/dist/commands/release.md +25 -91
  34. package/dist/commands/research.md +34 -103
  35. package/dist/commands/resolve.md +64 -128
  36. package/dist/commands/self-review.md +35 -99
  37. package/dist/compliance-off/agents/git.md +15 -18
  38. package/dist/compliance-off/agents/triage.md +7 -14
  39. package/dist/compliance-off/commands/bug-analysis.md +31 -62
  40. package/dist/compliance-off/commands/code-review.md +34 -82
  41. package/dist/compliance-off/commands/dynamic-build.md +149 -205
  42. package/dist/compliance-off/commands/dynamic-tickets.md +65 -186
  43. package/dist/compliance-off/commands/implement.md +94 -180
  44. package/dist/compliance-off/commands/plan.md +60 -107
  45. package/dist/compliance-off/commands/release.md +25 -90
  46. package/dist/compliance-off/commands/resolve.md +54 -128
  47. package/dist/compliance-off/skills/git/references/tracker/github/ensure-pr-ready.md +3 -3
  48. package/dist/compliance-off/skills/git/references/tracker/jira/ensure-pr-ready.md +3 -3
  49. package/dist/compliance-off/skills/git/references/tracker/linear/ensure-pr-ready.md +3 -3
  50. package/dist/core/compliance.js +14 -0
  51. package/dist/core/fs-atomic.js +5 -1
  52. package/dist/core/orphan-sweep.js +20 -2
  53. package/dist/core/path-set.js +15 -0
  54. package/dist/core/plugins.js +6 -5
  55. package/dist/core/reference-sweep.js +42 -25
  56. package/dist/core/retired-shipped-names.js +278 -0
  57. package/dist/curation-compliance-off/agents/triage.md +7 -13
  58. package/dist/curation-compliance-off/commands/bug-analysis.md +21 -41
  59. package/dist/curation-compliance-off/commands/code-review.md +25 -62
  60. package/dist/curation-compliance-off/commands/dynamic-build.md +142 -194
  61. package/dist/curation-compliance-off/commands/dynamic-tickets.md +54 -173
  62. package/dist/curation-compliance-off/commands/implement.md +86 -161
  63. package/dist/curation-compliance-off/commands/plan.md +51 -86
  64. package/dist/curation-compliance-off/commands/release.md +17 -78
  65. package/dist/curation-compliance-off/commands/resolve.md +45 -108
  66. package/dist/curation-off/agents/architect.md +81 -0
  67. package/dist/curation-off/agents/code.md +20 -23
  68. package/dist/curation-off/agents/debug.md +19 -47
  69. package/dist/curation-off/agents/design.md +8 -41
  70. package/dist/curation-off/agents/fix.md +14 -27
  71. package/dist/curation-off/agents/harden.md +13 -18
  72. package/dist/curation-off/agents/knowledge.md +9 -17
  73. package/dist/curation-off/agents/refactor.md +8 -12
  74. package/dist/curation-off/agents/research.md +9 -32
  75. package/dist/curation-off/agents/review.md +11 -40
  76. package/dist/curation-off/agents/skim.md +7 -17
  77. package/dist/curation-off/agents/triage.md +7 -13
  78. package/dist/curation-off/commands/bug-analysis.md +21 -41
  79. package/dist/curation-off/commands/code-review.md +29 -67
  80. package/dist/curation-off/commands/debug.md +24 -63
  81. package/dist/curation-off/commands/dynamic-build.md +148 -200
  82. package/dist/curation-off/commands/dynamic-plan.md +60 -80
  83. package/dist/curation-off/commands/dynamic-tickets.md +54 -173
  84. package/dist/curation-off/commands/explore.md +18 -50
  85. package/dist/curation-off/commands/implement.md +90 -167
  86. package/dist/curation-off/commands/plan.md +51 -86
  87. package/dist/curation-off/commands/release.md +17 -79
  88. package/dist/curation-off/commands/research.md +23 -81
  89. package/dist/curation-off/commands/resolve.md +55 -108
  90. package/dist/curation-off/commands/self-review.md +26 -78
  91. package/dist/skills/git/references/pr/update-pr-evidence.md +2 -1
  92. package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +3 -3
  93. package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +3 -3
  94. package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +3 -3
  95. package/dist/targets/claude-code/compliance-install.js +38 -13
  96. package/dist/targets/claude-code/compliance-off-files.js +5 -1
  97. package/dist/targets/claude-code/curation-install.js +77 -32
  98. package/dist/targets/claude-code/folder-swap.js +142 -0
  99. package/dist/targets/claude-code/install-backup.js +780 -0
  100. package/dist/targets/claude-code/installer.js +383 -192
  101. package/dist/targets/claude-code/legacy-skill-hashes.js +170 -0
  102. package/dist/targets/claude-code/linked-folder.js +5 -11
  103. package/dist/targets/claude-code/reference-converge.js +15 -2
  104. package/dist/targets/claude-code/rules-folder.js +34 -0
  105. package/dist/targets/claude-code/shipped-set.js +160 -0
  106. package/dist/targets/claude-code/workflow-folder-install.js +32 -12
  107. package/dist/variant-axes.json +5 -1
  108. package/package.json +1 -1
  109. package/src/assets/agents/_partials/_code.mds +3 -5
  110. package/src/assets/agents/_partials/_design.mds +86 -0
  111. package/src/assets/agents/architect.mds +41 -0
  112. package/src/assets/agents/code.mds +18 -20
  113. package/src/assets/agents/curate.md +26 -35
  114. package/src/assets/agents/debug.mds +21 -49
  115. package/src/assets/agents/design.mds +11 -114
  116. package/src/assets/agents/evaluate.md +6 -16
  117. package/src/assets/agents/explore.md +1 -2
  118. package/src/assets/agents/fix.mds +12 -24
  119. package/src/assets/agents/git.mds +20 -23
  120. package/src/assets/agents/harden.mds +14 -19
  121. package/src/assets/agents/knowledge.mds +10 -38
  122. package/src/assets/agents/polish.md +13 -39
  123. package/src/assets/agents/refactor.mds +6 -9
  124. package/src/assets/agents/research.mds +11 -34
  125. package/src/assets/agents/review.mds +12 -84
  126. package/src/assets/agents/skim.mds +7 -17
  127. package/src/assets/agents/synthesize.md +3 -21
  128. package/src/assets/agents/test.md +31 -32
  129. package/src/assets/agents/tracker.md +116 -229
  130. package/src/assets/agents/triage.mds +7 -26
  131. package/src/assets/agents/validate.md +1 -3
  132. package/src/assets/commands/_partials/_compliance.mds +2 -2
  133. package/src/assets/commands/_partials/_decisions.mds +17 -24
  134. package/src/assets/commands/_partials/_docs_root.mds +31 -10
  135. package/src/assets/commands/_partials/_engine.mds +34 -56
  136. package/src/assets/commands/_partials/_evidence_policy.mds +1 -1
  137. package/src/assets/commands/_partials/_factory.mds +10 -104
  138. package/src/assets/commands/_partials/_knowledge.mds +47 -51
  139. package/src/assets/commands/_partials/_plan_contract.mds +2 -2
  140. package/src/assets/commands/_partials/_preamble.mds +21 -21
  141. package/src/assets/commands/_partials/_publication.mds +3 -3
  142. package/src/assets/commands/_partials/_roster.mds +12 -13
  143. package/src/assets/commands/_partials/_settings.mds +6 -3
  144. package/src/assets/commands/_partials/_ticket_template.mds +3 -7
  145. package/src/assets/commands/_partials/_tracker.mds +10 -5
  146. package/src/assets/commands/_partials/_wave.mds +23 -32
  147. package/src/assets/commands/bug-analysis.mds +3 -7
  148. package/src/assets/commands/code-review.mds +12 -33
  149. package/src/assets/commands/debug.mds +5 -47
  150. package/src/assets/commands/dynamic-build.mds +48 -70
  151. package/src/assets/commands/dynamic-plan.mds +23 -42
  152. package/src/assets/commands/dynamic-profile.mds +7 -57
  153. package/src/assets/commands/dynamic-tickets.mds +9 -29
  154. package/src/assets/commands/explore.mds +5 -44
  155. package/src/assets/commands/implement.mds +75 -117
  156. package/src/assets/commands/plan.mds +27 -57
  157. package/src/assets/commands/release.mds +4 -62
  158. package/src/assets/commands/research.mds +7 -53
  159. package/src/assets/commands/resolve.mds +40 -87
  160. package/src/assets/commands/self-review.mds +5 -45
  161. package/src/assets/mds/git/_ops_pr.mds +1 -0
  162. package/src/assets/mds/git/_ops_steps.mds +4 -4
  163. package/src/assets/mds/git/_pr.mds +1 -1
  164. package/src/assets/rules/engineering.md +1 -1
  165. package/src/assets/rules/quality.md +2 -2
  166. package/src/assets/scripts/ci-wait.cjs +150 -18
  167. package/src/assets/scripts/hooks/assets/orchestrator-charter.md +3 -3
  168. package/src/assets/scripts/hooks/preamble +2 -3
  169. package/src/assets/scripts/pr-evidence.cjs +1 -0
  170. package/src/assets/scripts/resolve-evidence-policy.cjs +14 -13
  171. package/src/assets/scripts/resolve-root.cjs +186 -0
  172. package/src/assets/scripts/resolve-settings.cjs +14 -9
  173. package/src/assets/scripts/verify-evidence.cjs +355 -22
  174. package/src/assets/skills/accessibility/SKILL.md +28 -95
  175. package/src/assets/skills/agent-references/SKILL.md +2 -4
  176. package/src/assets/skills/agent-references/references/commands/implement-evidence-asks.md +1 -1
  177. package/src/assets/skills/agent-references/references/commands/implement-levels.md +4 -7
  178. package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +1 -1
  179. package/src/assets/skills/agent-references/references/commands/plan-levels.md +2 -2
  180. package/src/assets/skills/apply-decisions/SKILL.md +5 -6
  181. package/src/assets/skills/apply-feature-knowledge/SKILL.md +3 -13
  182. package/src/assets/skills/architecture/SKILL.md +29 -105
  183. package/src/assets/skills/boundary-validation/SKILL.md +27 -78
  184. package/src/assets/skills/complexity/SKILL.md +8 -104
  185. package/src/assets/skills/compliance/SKILL.md +9 -67
  186. package/src/assets/skills/consistency/SKILL.md +7 -107
  187. package/src/assets/skills/database/SKILL.md +7 -72
  188. package/src/assets/skills/dependencies/SKILL.md +9 -109
  189. package/src/assets/skills/dependencies/references/detection.md +10 -0
  190. package/src/assets/skills/dependency-research/SKILL.md +9 -63
  191. package/src/assets/skills/design-review/SKILL.md +1 -35
  192. package/src/assets/skills/docs-framework/SKILL.md +4 -47
  193. package/src/assets/skills/documentation/SKILL.md +7 -71
  194. package/src/assets/skills/documentation/references/patterns.md +1 -1
  195. package/src/assets/skills/documentation/references/violations.md +1 -1
  196. package/src/assets/skills/feature-knowledge/SKILL.md +19 -222
  197. package/src/assets/skills/feature-knowledge/references/new-kb.md +128 -0
  198. package/src/assets/skills/gap-analysis/SKILL.md +1 -31
  199. package/src/assets/skills/git/SKILL.md +2 -22
  200. package/src/assets/skills/go/SKILL.md +24 -113
  201. package/src/assets/skills/java/SKILL.md +12 -98
  202. package/src/assets/skills/patterns/SKILL.md +8 -93
  203. package/src/assets/skills/performance/SKILL.md +29 -88
  204. package/src/assets/skills/python/SKILL.md +22 -120
  205. package/src/assets/skills/qa/SKILL.md +16 -54
  206. package/src/assets/skills/qa/references/browser-testing.md +0 -24
  207. package/src/assets/skills/qa/references/sources.md +2 -2
  208. package/src/assets/skills/quality-gates/SKILL.md +13 -100
  209. package/src/assets/skills/react/SKILL.md +33 -95
  210. package/src/assets/skills/regression/SKILL.md +8 -73
  211. package/src/assets/skills/reliability/SKILL.md +11 -120
  212. package/src/assets/skills/research-codebase/SKILL.md +7 -49
  213. package/src/assets/skills/research-competitor/SKILL.md +4 -39
  214. package/src/assets/skills/research-external/SKILL.md +5 -43
  215. package/src/assets/skills/research-market/SKILL.md +5 -43
  216. package/src/assets/skills/research-technology/SKILL.md +8 -68
  217. package/src/assets/skills/review-methodology/SKILL.md +10 -56
  218. package/src/assets/skills/rust/SKILL.md +19 -109
  219. package/src/assets/skills/security/SKILL.md +39 -66
  220. package/src/assets/skills/software-design/SKILL.md +20 -105
  221. package/src/assets/skills/software-design/references/patterns.md +84 -2
  222. package/src/assets/skills/software-design/references/violations.md +1 -1
  223. package/src/assets/skills/test-driven-development/SKILL.md +32 -107
  224. package/src/assets/skills/test-driven-development/references/rationalization-prevention.md +33 -1
  225. package/src/assets/skills/testing/SKILL.md +35 -53
  226. package/src/assets/skills/typescript/SKILL.md +23 -102
  227. package/src/assets/skills/ui-design/SKILL.md +26 -74
  228. package/src/assets/skills/worktree-support/SKILL.md +4 -10
  229. package/dist/curation-off/commands/dynamic-profile.md +0 -214
@@ -37,8 +37,10 @@ import { probeTrackedArea } from '../../core/tracked-areas.js';
37
37
  import { restampInstalledCommands } from '../../targets/claude-code/language-stamp.js';
38
38
  import { installRenderedCharter, removeHandoffSentinel } from '../../targets/claude-code/charter-render.js';
39
39
  import { installCommandsAndAgents } from '../../targets/claude-code/installer.js';
40
+ import { BACKUP_ROOT_NAME, escapeName } from '../../targets/claude-code/install-backup.js';
40
41
  import { isUnrealFolder, newLinkReport, refuseUnrealFolder, refusedFolderStatement } from '../../targets/claude-code/linked-folder.js';
41
42
  import { formatReplacedLinksSummary } from './install-report.js';
43
+ import { judgeBareLegacySkill } from './legacy-sweep.js';
42
44
  /**
43
45
  * Where a retired repo-local install lives: `<gitRoot>/.claude` and `<gitRoot>/.devflow`.
44
46
  *
@@ -654,6 +656,9 @@ export function userContentPaths(devflowDir) {
654
656
  { relPath: 'skills', isDir: true, label: `skill shadows (${path.join(devflowDir, 'skills')})` },
655
657
  // Rule shadow overrides (~/.devflow/rules/{name}.md)
656
658
  { relPath: 'rules', isDir: true, label: `rule shadows (${path.join(devflowDir, 'rules')})` },
659
+ // The files an install moved out of the devflow folders because devflow did not ship them.
660
+ // They are the user's own files, so only a confirmed full wipe removes them.
661
+ { relPath: BACKUP_ROOT_NAME, isDir: true, label: `install backups (${path.join(devflowDir, BACKUP_ROOT_NAME)})` },
657
662
  // preference-profile.md — user-curated decision-preference profile
658
663
  { relPath: 'preference-profile.md', label: 'preference-profile.md' },
659
664
  // tracker/ — the inferred, hand-editable issue-tracker conventions, one file
@@ -921,7 +926,7 @@ export function installArtifactPaths(devflowDir) {
921
926
  * This function runs on the decline, cancel, non-interactive AND --keep-docs paths,
922
927
  * so an entry here is deleted even when the user answers "no" to the full wipe.
923
928
  * User-authored state (everything in `userContentPaths`: skill/rule shadows,
924
- * preference-profile.md, the tracker conventions with the legacy tracker.md and
929
+ * the install backups, preference-profile.md, the tracker conventions with the legacy tracker.md and
925
930
  * its backups, the global tuning file under both names, hud.json) is removed only by
926
931
  * the confirmed full-dir rm.
927
932
  * agent-models.json is an INSTALL ARTIFACT (stale per-agent overrides silently
@@ -1012,6 +1017,35 @@ export async function isDevFlowInstalled(claudeDir) {
1012
1017
  catch { /* skills dir absent or unreadable */ }
1013
1018
  return false;
1014
1019
  }
1020
+ /** Why a bare legacy skill folder stays: its `SKILL.md` is a file that no release of devflow installed. */
1021
+ const KEPT_NOT_MADE = 'devflow did not make this folder';
1022
+ /** Why a bare legacy skill folder stays: there is no regular `SKILL.md`, the folder or file is a link, or a read failed. */
1023
+ const KEPT_UNDECIDED = 'devflow could not tell if it made this folder';
1024
+ /**
1025
+ * Sort the bare legacy skill folders that exist in `skillsDir` into those a full uninstall removes
1026
+ * and those it keeps. The skills folder is shared with Claude Code and other tools, so a bare name
1027
+ * (`python`, `plan`) does not prove that devflow made the folder. It is removed only when the check
1028
+ * `devflow init` uses finds a `SKILL.md` that a release installed (`judgeBareLegacySkill`). The dry
1029
+ * run and the removal both take this one list. A `devflow:` name is in the namespace of devflow, and
1030
+ * the prefixed pass removes it. Reads one file per folder at most. Never throws.
1031
+ */
1032
+ async function planBareLegacySkills(skillsDir) {
1033
+ const remove = [];
1034
+ const keep = [];
1035
+ for (const name of new Set(LEGACY_SKILL_NAMES)) {
1036
+ if (name.startsWith(SKILL_NAMESPACE))
1037
+ continue;
1038
+ const folder = path.join(skillsDir, name);
1039
+ const verdict = await judgeBareLegacySkill(folder, name);
1040
+ if (verdict === 'devflow')
1041
+ remove.push(folder);
1042
+ else if (verdict === 'other')
1043
+ keep.push({ folder, reason: KEPT_NOT_MADE });
1044
+ else if (verdict === 'unknown')
1045
+ keep.push({ folder, reason: KEPT_UNDECIDED });
1046
+ }
1047
+ return { remove, keep };
1048
+ }
1015
1049
  // ---------------------------------------------------------------------------
1016
1050
  // Phase runners — extracted from the action function for readability and
1017
1051
  // independent testability. Each covers one logical stage of the uninstall.
@@ -1029,9 +1063,10 @@ export async function isDevFlowInstalled(claudeDir) {
1029
1063
  * and the scripts directory inside devflowDir.
1030
1064
  * 2. ALL skill removal candidates (existence-filtered):
1031
1065
  * - Prefixed (devflow:name): live registry ∪ LEGACY_SKILL_NAMES.
1032
- * - Bare (name or devflow-name legacy): LEGACY_SKILL_NAMES ONLY.
1033
- * ~/.claude/skills/ is shared; bare dirs for live-registry skill names
1034
- * are by construction foreign to Devflow.
1066
+ * - Bare (name or devflow-name legacy): LEGACY_SKILL_NAMES ONLY, and only a
1067
+ * folder that devflow made (planBareLegacySkills). ~/.claude/skills/ is
1068
+ * shared; bare dirs for live-registry skill names are by construction
1069
+ * foreign to Devflow. A bare folder that stays is listed as `(kept: <reason>)`.
1035
1070
  * 3. manifest.json (removed separately in removeDevFlowInstallArtifacts).
1036
1071
  * 4. Every artifact path from installArtifactPaths(devflowDir) — the single
1037
1072
  * source of truth shared with the real removal loop.
@@ -1057,8 +1092,8 @@ export async function enumerateDryRunExtras(claudeDir, devflowDir, folderWorkflo
1057
1092
  // 2. Skills: enumerate ALL removal candidates that exist on disk.
1058
1093
  // Mirrors removeAllDevFlow's split-pass approach:
1059
1094
  // Prefixed: live registry ∪ LEGACY_SKILL_NAMES ∪ FEATURE_OWNED_SKILLS
1060
- // Bare: LEGACY_SKILL_NAMES only — shared skills/ dir; live-registry bare
1061
- // dirs are by construction foreign to Devflow.
1095
+ // Bare: LEGACY_SKILL_NAMES only, and only a folder that devflow made — shared
1096
+ // skills/ dir; live-registry bare dirs are by construction foreign to Devflow.
1062
1097
  // FEATURE_OWNED_SKILLS (compliance) is included so full uninstall removes
1063
1098
  // devflow:compliance even though it left the plugin registry (step 1.5).
1064
1099
  // The workflow skill folders (D-WORKFLOW-FOLDER-INSTALL) join through getAllSkillNames.
@@ -1072,14 +1107,10 @@ export async function enumerateDryRunExtras(claudeDir, devflowDir, folderWorkflo
1072
1107
  }
1073
1108
  catch { /* absent */ }
1074
1109
  }
1075
- for (const skillName of LEGACY_SKILL_NAMES) {
1076
- const barePath = path.join(skillsDir, skillName);
1077
- try {
1078
- await fs.access(barePath);
1079
- extras.push(barePath);
1080
- }
1081
- catch { /* absent */ }
1082
- }
1110
+ const bareSkills = await planBareLegacySkills(skillsDir);
1111
+ extras.push(...bareSkills.remove);
1112
+ for (const { folder, reason } of bareSkills.keep)
1113
+ extras.push(`${escapeName(folder)} (kept: ${reason})`);
1083
1114
  // 3. manifest.json — removed separately by removeDevFlowInstallArtifacts
1084
1115
  // (NOT in installArtifactPaths). List it here so the preview is complete.
1085
1116
  const manifestPath = path.join(devflowDir, 'manifest.json');
@@ -1422,9 +1453,11 @@ export async function runSelectivePhaseForScope(opts) {
1422
1453
  * @param opts.isTTY - Whether the session is interactive. Injected rather than
1423
1454
  * read from process.stdin so the prompt gate is an explicit input (matching
1424
1455
  * resolveDevflowDirCleanup) instead of an ambient global a test cannot control.
1456
+ * @param opts.confirm - The prompt for the full-dir wipe (default `p.confirm`).
1425
1457
  */
1426
1458
  export async function runFullPhaseForScope(opts) {
1427
1459
  const { scope, claudeDir, devflowDir, devflowScriptsDir, verbose, keepDocs, isTTY } = opts;
1460
+ const confirm = opts.confirm ?? p.confirm;
1428
1461
  // D-CLI-NO-SYMLINK: a legacy local install's removals and rewrites pass this first.
1429
1462
  const mayChange = scopeChangeGuard(scope, { claudeDir, devflowDir });
1430
1463
  // Revert GPT agent frontmatter before removing agents — ensures no orphaned
@@ -1482,7 +1515,7 @@ export async function runFullPhaseForScope(opts) {
1482
1515
  for (const item of userContent) {
1483
1516
  p.log.info(` ${item}`);
1484
1517
  }
1485
- const confirmFullCleanup = await p.confirm({
1518
+ const confirmFullCleanup = await confirm({
1486
1519
  message: `Remove entire ${devflowDir}? (includes the items listed above, plus logs and install metadata)`,
1487
1520
  initialValue: false,
1488
1521
  });
@@ -2005,10 +2038,11 @@ export async function removeAllDevFlow(claudeDir, devflowScriptsDir, verbose, ma
2005
2038
  // prefixSkillName() is idempotent for already-prefixed legacy entries.
2006
2039
  // FEATURE_OWNED_SKILLS (compliance) is included so full uninstall removes
2007
2040
  // devflow:compliance even though it left the plugin registry (step 1.5).
2008
- // Bare pass (name or devflow-name legacy): LEGACY_SKILL_NAMES ONLY.
2009
- // A bare dir whose name matches a live-registry skill is by construction
2010
- // foreign to Devflow (the devflow: namespace shipped in dcecda3, 2026-03-30).
2011
- // A bare 'compliance/' dir is also foreign (not in LEGACY_SKILL_NAMES).
2041
+ // Bare pass (name or devflow-name legacy): LEGACY_SKILL_NAMES ONLY, and only a folder
2042
+ // whose SKILL.md is a copy that a release of devflow installed (planBareLegacySkills).
2043
+ // Any other bare folder stays and is named. A bare dir whose name matches a
2044
+ // live-registry skill is by construction foreign to Devflow (the devflow: namespace
2045
+ // shipped in dcecda3, 2026-03-30). A bare 'compliance/' dir is also foreign (not in LEGACY_SKILL_NAMES).
2012
2046
  // The workflow skill folders (D-WORKFLOW-FOLDER-INSTALL) are in getAllSkillNames, so the folder is removed.
2013
2047
  const prefixedSkillNames = new Set([...getAllSkillNames(folderWorkflows), ...LEGACY_SKILL_NAMES, ...FEATURE_OWNED_SKILLS]);
2014
2048
  const skillsDir = path.join(claudeDir, 'skills');
@@ -2025,17 +2059,21 @@ export async function removeAllDevFlow(claudeDir, devflowScriptsDir, verbose, ma
2025
2059
  }
2026
2060
  catch { /* Skill doesn't exist */ }
2027
2061
  }
2028
- for (const skillName of LEGACY_SKILL_NAMES) {
2029
- // Remove bare variant — frozen legacy list only, never the live registry
2030
- const barePath = path.join(skillsDir, skillName);
2062
+ // Bare variant: frozen legacy list only, never the live registry, and only a folder that devflow made.
2063
+ const bareSkills = await planBareLegacySkills(skillsDir);
2064
+ for (const barePath of bareSkills.remove) {
2031
2065
  try {
2032
- await fs.stat(barePath);
2033
2066
  if (!(await mayChange(barePath)))
2034
2067
  continue;
2035
2068
  await fs.rm(barePath, { recursive: true, force: true });
2036
2069
  skillsRemoved++;
2037
2070
  }
2038
- catch { /* Skill doesn't exist */ }
2071
+ catch (error) {
2072
+ p.log.warn(`Could not remove ${escapeName(barePath)}: ${error}`);
2073
+ }
2074
+ }
2075
+ for (const { folder, reason } of bareSkills.keep) {
2076
+ p.log.info(`Kept ${escapeName(folder)}: ${reason}`);
2039
2077
  }
2040
2078
  if (skillsRemoved > 0 && verbose) {
2041
2079
  p.log.success(`Removed ${skillsRemoved} Devflow skill directories`);
@@ -1,10 +1,8 @@
1
1
  ---
2
- description: Proactive bug finding with static and semantic analysis — hunts real bugs in changed code before merge
2
+ description: Proactive bug finding in changed code before merge, with static and semantic analysis
3
3
  ---
4
4
  # Bug Analysis Command
5
5
 
6
- Run a proactive bug analysis on the current branch: static analysis tools and parallel semantic analyzers, synthesized into one bug report.
7
-
8
6
  ## Usage
9
7
 
10
8
  `/bug-analysis [--full] [--no-static]`: `--full` ignores incremental state; `--no-static` skips static analysis.
@@ -21,17 +19,19 @@ Run a proactive bug analysis on the current branch: static analysis tools and pa
21
19
  node "$HOME/.devflow/scripts/resolve-evidence-policy.cjs" 2>/dev/null; echo "exit=$?"
22
20
  ```
23
21
 
24
- 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.
22
+ 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. **Anything else** (including a script that cannot run) ⇒ use `EVIDENCE_POLICY=required SOURCE=error REF=none ISSUE_REQUIRED=true APPLY_CONVENTIONS=true REQUIRE_NON_AUTHOR_APPROVAL=true` instead.
25
23
 
26
24
  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.
27
25
 
28
- **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
26
+ **Docs root (D-DOCS-ROOT).** Every `.devflow/docs/` path is `{worktree}/.devflow/docs/…`. A repo-relative docs path handed to an agent travels with a `WORKTREE_PATH` naming its checkout.
27
+
28
+ Once per start directory (`WORKTREE_PATH` if provided, otherwise cwd), run from it:
29
29
 
30
30
  ```bash
31
- git -C "{start}" rev-parse --show-toplevel
31
+ node "$HOME/.devflow/scripts/resolve-root.cjs" "{start}"; echo "exit=$?"
32
32
  ```
33
33
 
34
- 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.
34
+ Accept only the three lines `WORKTREE=<absolute path>`, `LEDGER=<absolute path>` and `exit=0`, which set `{worktree}` and `{ledger}`. Otherwise both are the start directory.
35
35
 
36
36
  Render the test-plan block from `/implement`'s evidence file, and from nothing else:
37
37
  1. `branch_slug` is `git -C "{worktree}" branch --show-current` with every `/` replaced by `-`.
@@ -182,42 +182,33 @@ Set `STATIC_STATUS` to one `{tool}: {value}` per tool: `completed`, `not install
182
182
 
183
183
  #### Decisions Index
184
184
 
185
- **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 in a one-worktree run:
185
+ **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:
186
186
 
187
187
  ```bash
188
188
  node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
189
189
  ```
190
190
 
191
- 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> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — 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=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
191
+ 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> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — 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** (including a script that cannot run) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
192
192
 
193
193
  The accepted line is the only source of these values.
194
194
 
195
195
  ### Load DECISIONS_CONTEXT
196
196
 
197
- When the settings line says `CURATION=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
197
+ When the settings line says `CURATION=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, reading no index.
198
+
199
+ The decisions ledger belongs to the repository, not to one checkout: a linked worktree reads the main worktree's copy.
198
200
 
199
- The decisions ledger belongs to the repository, not to one checkout: a linked worktree reads the main worktree's copy, a subdirectory session the repository root's. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
201
+ Once per start directory (`WORKTREE_PATH` if provided, otherwise cwd), run from it:
200
202
 
201
203
  ```bash
202
- git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
204
+ node "$HOME/.devflow/scripts/resolve-root.cjs" "{start}"; echo "exit=$?"
203
205
  ```
204
206
 
205
- Line 1 is the checkout's toplevel, line 2 the 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 that applies:
206
-
207
- 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.
208
- 2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
209
- 3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
210
-
211
- This is the rule the curation hooks apply, so you read the index the Curate agent writes.
207
+ Accept only the three lines `WORKTREE=<absolute path>`, `LEDGER=<absolute path>` and `exit=0`, which set `{worktree}` and `{ledger}`. Otherwise both are the start directory.
212
208
 
213
- **Step 1 — Read the pre-rendered index:**
209
+ **Step 1 — Read the pre-rendered index** `{ledger}/.devflow/curation/index.md`. Its content is `DECISIONS_CONTEXT`; if it is absent or empty, `DECISIONS_CONTEXT` is `(none)`.
214
210
 
215
- Attempt to read `{ledger}/.devflow/curation/index.md`.
216
-
217
- - If the file exists and contains non-empty content: use that content as `DECISIONS_CONTEXT`.
218
- - If the file is absent or empty: set `DECISIONS_CONTEXT` to `(none)`.
219
-
220
- The index is one direct file read, written at render time by `render-decisions.cjs` — no `.cjs` script runs here.
211
+ The index is one direct file read.
221
212
 
222
213
  **Step 2 — Slice the index, then hand it on:**
223
214
 
@@ -225,51 +216,33 @@ When `DECISIONS_CONTEXT` is not `(none)`, hand it only to the agents whose contr
225
216
 
226
217
  Hand each agent that takes `DECISIONS_CONTEXT` a slice, not the whole index: the index lines whose title, scope or area touch the files and task it works on, verbatim, led by `(slice: N of M entries — full index: <absolute index path>)` and closed by the index footer. When unsure, include the line. Siblings over one diff share ONE slice.
227
218
 
228
- Those agents follow `devflow:apply-decisions`. A host that uses the index in its own thread says so in its own step.
229
-
230
219
  #### Feature Knowledge
231
220
 
232
221
  ### Load Feature Knowledge
233
222
 
234
- 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
223
+ Once per start directory (`WORKTREE_PATH` if provided, otherwise cwd), run from it:
235
224
 
236
225
  ```bash
237
- git -C "{start}" rev-parse --show-toplevel
226
+ node "$HOME/.devflow/scripts/resolve-root.cjs" "{start}"; echo "exit=$?"
238
227
  ```
239
228
 
240
- 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}`.
229
+ Accept only the three lines `WORKTREE=<absolute path>`, `LEDGER=<absolute path>` and `exit=0`, which set `{worktree}` and `{ledger}`. Otherwise both are the start directory.
241
230
 
242
- **Step 1 — Read the index cache:**
231
+ All paths below are relative to `{worktree}`.
243
232
 
244
- Attempt to read `{worktree}/.devflow/features/index.md`. Each line follows the format:
233
+ **Step 1 — Read the index cache** `{worktree}/.devflow/features/index.md`. Each line has the form `- **{slug}** — {areas} — {Use-when description}`. If `index.md` is absent or has no entry line, glob `{worktree}/.devflow/features/*/KNOWLEDGE.md` and read only the YAML frontmatter of each file, in one turn.
245
234
 
246
- ```
247
- - **{slug}** — {areas} — {Use-when description}
248
- ```
235
+ **Step 2 — Pick relevant KBs:** select the entries whose documented area overlaps the current task (index line, or frontmatter `description` and `directories` on fallback).
249
236
 
250
- If `index.md` exists and contains at least one entry line, use it for relevance matching.
237
+ **Step 3 — Read each selected KB's Rules.** `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
251
238
 
252
- **Step 2 — Fallback: glob frontmatter (if `index.md` is absent or empty):**
253
-
254
- Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read only its YAML frontmatter block (between the opening and closing `---` delimiters).
255
-
256
- **Step 3 — Pick relevant KBs:**
257
-
258
- 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.
259
-
260
- **Step 4 — Read each selected KB's Rules:**
261
-
262
- For each selected entry, `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
263
-
264
- 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.
265
- 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.
239
+ 1. List the `##` headings with line numbers of all selected KBs in one Bash call: `command grep -n '^## ' "{kb}" …`. With two or more paths, each line starts with its `{kb}:` path. This only locates sections; the text of a KB comes from the Read view alone.
240
+ 2. Read the `## Rules` range (its line to the next heading) with the Read tool, using `offset` and `limit`, all selected KBs in one turn, and choose the one to three bullets most relevant to the task.
266
241
  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.
267
242
 
268
- 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.
269
-
270
- **Step 5 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES:**
243
+ When a KB contradicts the code you observe, **trust the code**.
271
244
 
272
- 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.
245
+ **Step 4 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES.** 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.
273
246
 
274
247
  ```
275
248
  --- Feature knowledge: {slug} ---
@@ -280,9 +253,7 @@ Rules:
280
253
  Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
281
254
  ```
282
255
 
283
- 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)`.
284
-
285
- **One git call, then direct reads — no `.cjs` script.**
256
+ 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. 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)`.
286
257
 
287
258
  #### Plan Artifact
288
259
 
@@ -310,9 +281,7 @@ Pick the focus analyzers from `CHANGED_FILES` (Step 2b; do not re-run `git diff`
310
281
  **Produces:** ANALYZER_OUTPUTS
311
282
  **Requires:** DIFF_RANGE, ANALYSIS_DIR, ACTIVE_FOCUSES, STATIC_FINDINGS, ACCEPTANCE_RULES, PLAN_CONTEXT, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE
312
283
 
313
- Spawn ALL active Debug agents **in a single message** (parallel, NOT background):
314
-
315
- For each active focus, spawn:
284
+ Spawn one Debug agent for each active focus, all in a single message (parallel, not background):
316
285
  ```
317
286
  Agent(subagent_type="Debug", run_in_background=false):
318
287
  "Analyze focusing on {focus}.
@@ -391,7 +360,7 @@ Seven phases: Phase 1 to Phase 7.
391
360
  |------|----------|
392
361
  | Rebase invalidates `.last-analysis-head` SHA | `git cat-file -t` check fails → fallback to full diff |
393
362
  | Zero changed files in DIFF_RANGE with exit 0 | Stop: "No changes to analyze." |
394
- | `--full` flag | Bypass incremental detection (Step 2a), run full diff from base |
363
+ | `--full` flag | Step 2a takes the full-range path |
395
364
  | A scanner did not run or did not complete | Name the tool and why in `STATIC_FINDINGS`, not `(none)`; a tool that did not complete keeps the marker |
396
365
 
397
366
  ## Resolve Compatibility
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Comprehensive branch review using specialized sub-agents for PR readiness
2
+ description: Branch review by specialized agents for PR readiness
3
3
  ---
4
4
  # Code Review Command
5
5
 
@@ -7,12 +7,7 @@ Run a comprehensive code review of the current branch by spawning parallel revie
7
7
 
8
8
  ## Usage
9
9
 
10
- ```
11
- /code-review (review current branch — or all worktrees if multiple found)
12
- /code-review #42 (review specific PR)
13
- /code-review --full (force full-branch review, ignore previous review state)
14
- /code-review --path /path/to/worktree (review a specific worktree only)
15
- ```
10
+ `/code-review` (the current branch, or every reviewable worktree), `/code-review #42` (one PR), `--full` (ignore the previous review state), `--path <worktree>` (one worktree only).
16
11
 
17
12
  ## Phases
18
13
 
@@ -35,17 +30,17 @@ Run a comprehensive code review of the current branch by spawning parallel revie
35
30
 
36
31
  **Produces:** COMPLIANCE_ACTIVE, COMPLIANCE_FRAMEWORKS, GATE_LEVEL
37
32
 
38
- **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 in a one-worktree run:
33
+ **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:
39
34
 
40
35
  ```bash
41
36
  node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
42
37
  ```
43
38
 
44
- 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> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — 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=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
39
+ 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> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — 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** (including a script that cannot run) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
45
40
 
46
41
  The accepted line is the only source of these values.
47
42
 
48
- **Resolve the compliance lens** for each worktree root, from its settings line — the line resolved above for that root, by the settings block when this run has not yet resolved it (every framework reference is installed on every machine, so no file check decides it).
43
+ **Resolve the compliance lens** for each worktree root, from its settings line — the line resolved above for that root, by the settings block when this run has not yet resolved it (no file check decides it).
49
44
 
50
45
  **Set the compliance lens** from that 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.
51
46
 
@@ -62,7 +57,7 @@ Keep each worktree's values for every downstream phase.
62
57
  node "$HOME/.devflow/scripts/resolve-evidence-policy.cjs" 2>/dev/null; echo "exit=$?"
63
58
  ```
64
59
 
65
- 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.
60
+ 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. **Anything else** (including a script that cannot run) ⇒ use `EVIDENCE_POLICY=required SOURCE=error REF=none ISSUE_REQUIRED=true APPLY_CONVENTIONS=true REQUIRE_NON_AUTHOR_APPROVAL=true` instead.
66
61
 
67
62
  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.
68
63
 
@@ -178,11 +173,11 @@ MAX_REVIEW_CYCLES = 10
178
173
 
179
174
  For each reviewable worktree, call:
180
175
 
181
- **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.
176
+ **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. The line already caps the personal choice at the team's, so it is `off`, `auto` or `full`, and `off` when the line was unresolvable.
182
177
 
183
- **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.
178
+ **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.
184
179
 
185
- 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.
180
+ Note: `auto` does not fail open: 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.
186
181
 
187
182
  ### Phase 1: Analyze Changed Files
188
183
 
@@ -302,30 +297,21 @@ The core, database, dependencies, documentation and compliance focuses, and ever
302
297
 
303
298
  ### Load DECISIONS_CONTEXT
304
299
 
305
- When the settings line says `CURATION=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
300
+ When the settings line says `CURATION=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, reading no index.
301
+
302
+ The decisions ledger belongs to the repository, not to one checkout: a linked worktree reads the main worktree's copy.
306
303
 
307
- The decisions ledger belongs to the repository, not to one checkout: a linked worktree reads the main worktree's copy, a subdirectory session the repository root's. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
304
+ Once per start directory (`WORKTREE_PATH` if provided, otherwise cwd), run from it:
308
305
 
309
306
  ```bash
310
- git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
307
+ node "$HOME/.devflow/scripts/resolve-root.cjs" "{start}"; echo "exit=$?"
311
308
  ```
312
309
 
313
- Line 1 is the checkout's toplevel, line 2 the 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 that applies:
314
-
315
- 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.
316
- 2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
317
- 3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
318
-
319
- This is the rule the curation hooks apply, so you read the index the Curate agent writes.
310
+ Accept only the three lines `WORKTREE=<absolute path>`, `LEDGER=<absolute path>` and `exit=0`, which set `{worktree}` and `{ledger}`. Otherwise both are the start directory.
320
311
 
321
- **Step 1 — Read the pre-rendered index:**
312
+ **Step 1 — Read the pre-rendered index** `{ledger}/.devflow/curation/index.md`. Its content is `DECISIONS_CONTEXT`; if it is absent or empty, `DECISIONS_CONTEXT` is `(none)`.
322
313
 
323
- Attempt to read `{ledger}/.devflow/curation/index.md`.
324
-
325
- - If the file exists and contains non-empty content: use that content as `DECISIONS_CONTEXT`.
326
- - If the file is absent or empty: set `DECISIONS_CONTEXT` to `(none)`.
327
-
328
- The index is one direct file read, written at render time by `render-decisions.cjs` — no `.cjs` script runs here.
314
+ The index is one direct file read.
329
315
 
330
316
  **Step 2 — Slice the index, then hand it on:**
331
317
 
@@ -333,51 +319,33 @@ When `DECISIONS_CONTEXT` is not `(none)`, hand it only to the agents whose contr
333
319
 
334
320
  Hand each agent that takes `DECISIONS_CONTEXT` a slice, not the whole index: the index lines whose title, scope or area touch the files and task it works on, verbatim, led by `(slice: N of M entries — full index: <absolute index path>)` and closed by the index footer. When unsure, include the line. Siblings over one diff share ONE slice.
335
321
 
336
- Those agents follow `devflow:apply-decisions`. A host that uses the index in its own thread says so in its own step.
337
-
338
- This produces a compact index of active ADR/PF entries. Pass `DECISIONS_CONTEXT` to all Review agents as one shared slice, cut over the diff's files. Review agents use `devflow:apply-decisions` to Read full entry bodies on demand.
322
+ Pass `DECISIONS_CONTEXT` to all Review agents as one shared slice, cut over the diff's files.
339
323
 
340
324
  ### Load Feature Knowledge
341
325
 
342
- 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
326
+ Once per start directory (`WORKTREE_PATH` if provided, otherwise cwd), run from it:
343
327
 
344
328
  ```bash
345
- git -C "{start}" rev-parse --show-toplevel
329
+ node "$HOME/.devflow/scripts/resolve-root.cjs" "{start}"; echo "exit=$?"
346
330
  ```
347
331
 
348
- 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}`.
332
+ Accept only the three lines `WORKTREE=<absolute path>`, `LEDGER=<absolute path>` and `exit=0`, which set `{worktree}` and `{ledger}`. Otherwise both are the start directory.
349
333
 
350
- **Step 1 — Read the index cache:**
334
+ All paths below are relative to `{worktree}`.
351
335
 
352
- Attempt to read `{worktree}/.devflow/features/index.md`. Each line follows the format:
336
+ **Step 1 — Read the index cache** `{worktree}/.devflow/features/index.md`. Each line has the form `- **{slug}** — {areas} — {Use-when description}`. If `index.md` is absent or has no entry line, glob `{worktree}/.devflow/features/*/KNOWLEDGE.md` and read only the YAML frontmatter of each file, in one turn.
353
337
 
354
- ```
355
- - **{slug}** — {areas} — {Use-when description}
356
- ```
338
+ **Step 2 — Pick relevant KBs:** select the entries whose documented area overlaps the current task (index line, or frontmatter `description` and `directories` on fallback).
357
339
 
358
- If `index.md` exists and contains at least one entry line, use it for relevance matching.
340
+ **Step 3 — Read each selected KB's Rules.** `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
359
341
 
360
- **Step 2 — Fallback: glob frontmatter (if `index.md` is absent or empty):**
361
-
362
- Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read only its YAML frontmatter block (between the opening and closing `---` delimiters).
363
-
364
- **Step 3 — Pick relevant KBs:**
365
-
366
- 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.
367
-
368
- **Step 4 — Read each selected KB's Rules:**
369
-
370
- For each selected entry, `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
371
-
372
- 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.
373
- 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.
342
+ 1. List the `##` headings with line numbers of all selected KBs in one Bash call: `command grep -n '^## ' "{kb}" …`. With two or more paths, each line starts with its `{kb}:` path. This only locates sections; the text of a KB comes from the Read view alone.
343
+ 2. Read the `## Rules` range (its line to the next heading) with the Read tool, using `offset` and `limit`, all selected KBs in one turn, and choose the one to three bullets most relevant to the task.
374
344
  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.
375
345
 
376
- 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.
377
-
378
- **Step 5 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES:**
346
+ When a KB contradicts the code you observe, **trust the code**.
379
347
 
380
- 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.
348
+ **Step 4 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES.** 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.
381
349
 
382
350
  ```
383
351
  --- Feature knowledge: {slug} ---
@@ -388,9 +356,7 @@ Rules:
388
356
  Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
389
357
  ```
390
358
 
391
- 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)`.
392
-
393
- **One git call, then direct reads — no `.cjs` script.**
359
+ 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. 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)`.
394
360
 
395
361
  Pass `FEATURE_KNOWLEDGE` to all Review agents alongside `DECISIONS_CONTEXT`.
396
362
 
@@ -427,13 +393,11 @@ Spawn Review agents **in a single message**, one per focus in REVIEW_FOCUS_LIST
427
393
  | documentation | conditional | devflow:documentation | diff.patch |
428
394
  | compliance | diff-driven | devflow:compliance | diff.patch |
429
395
 
430
- Review agent count: `code` runs 8 core +1-12 at `full`, up to 2 fewer at `standard`, 3-4 at lean; a reduced class or a mix runs 2-6.
431
-
432
396
  **Set the compliance focus directive** from `COMPLIANCE_FRAMEWORKS`. `COMPLIANCE_FOCUS_DIRECTIVE` is this one line, with `<ids>` replaced by the value of `COMPLIANCE_FRAMEWORKS`; only the compliance focus's spawn carries it:
433
397
 
434
398
  > For this compliance focus, invoke Skill(skill="devflow:compliance") and load references/{id}.md only for the ids in <ids> (none: generic controls only); never fabricate guidance for a framework you were not given.
435
399
 
436
- Each Review agent invocation (all in one message, **NOT background**):
400
+ Each Review agent invocation:
437
401
  ```
438
402
  Agent(subagent_type="Review", run_in_background=false):
439
403
  "Review focusing on {focus}. Load the pattern skill via the Skill tool: Skill(skill="devflow:{focus}").
@@ -509,26 +473,13 @@ Per worktree, after successful completion:
509
473
 
510
474
  ```
511
475
  /code-review
512
- │
513
476
  ├─ Phase 0: Worktree Discovery & Pre-flight, Steps 0a-0f (Git agent per worktree, parallel)
514
477
  │ ├─ Step 0b: Resolve the compliance lens and gate level
515
- │
516
- ├─ Per worktree (SEQUENTIAL):
517
- │ │
518
- │ ├─ Phase 1: Analyze changed files
519
- │ │ ├─ Classify the diff (paths.txt → DIFF_CLASS)
520
- │ │ ├─ Choose the focuses
521
- │ │ └─ Write diff.patch and diff-{focus}.patch
522
- │ │
523
- │ ├─ Phase 2: Reviews (PARALLEL within worktree), one per REVIEW_FOCUS_LIST focus
524
- │ │ ├─ code: core (diff.patch), language (diff-{focus}.patch), conditional
525
- │ │ └─ docs-only / tests-only / lockfile-only: the reduced set (diff.patch)
526
- │ │
527
- │ ├─ Phase 3: Synthesis → Review Comment (SEQUENTIAL within worktree)
528
- │ │ ├─ Step 3a: Synthesize agent (mode: review, writes review-summary.md)
529
- │ │ └─ Step 3b: Git agent (post-review-summary)
530
- │ │
531
- │ └─ Phase 4: Write .last-review-head + display results
478
+ └─ Per worktree (SEQUENTIAL):
479
+ ├─ Phase 1: Classify the diff, choose the focuses, write diff.patch and diff-{focus}.patch
480
+ ├─ Phase 2: Reviews (PARALLEL): code, or docs-only / tests-only / lockfile-only (the reduced set)
481
+ ├─ Phase 3: Synthesize agent, then Git agent (post-review-summary)
482
+ └─ Phase 4: Write .last-review-head + display results
532
483
  ```
533
484
 
534
485
  ## Edge Cases
@@ -536,7 +487,7 @@ Per worktree, after successful completion:
536
487
  | Case | Handling |
537
488
  |------|----------|
538
489
  | `--full` in multi-worktree mode | Applies to all worktrees (global modifier). It sets the diff range, never the gate level |
539
- | Review comment already posted | Git agent matches its own marker on the `{cycle, timestamp}` pair → skip silently (D7) |
490
+ | Review comment already posted | Git agent skips it (D7) |
540
491
  | Docs-only diff | Its Step 1.1 set, narrowed by level |
541
492
  | Tests-only diff | Its Step 1.1 set, narrowed by level |
542
493
  | Lockfile-only diff | Its Step 1.1 set, narrowed by level |
@@ -557,4 +508,4 @@ Per worktree, after successful completion:
557
508
  2. **Parallel, not background** - Multiple agents in one message, but `run_in_background=false` so phases complete before proceeding
558
509
  3. **Git agent for git work** - All git operations go through Git agent, except the exceptions named in Principle 1; its writes print nothing
559
510
  4. **Honest reporting** - Display agent outputs directly
560
- 5. **Incremental by default** - Only review new changes unless `--full` specified
511
+ 5. **Fewest turns** - Send calls that need no output of each other in one message: the Step 0a listing with the Step 0b-ii script; at `standard` or `lean`, the Step 1.2b directory print with the Step 1.1 listing, and its Read with the `paths.txt` Read; the Phase 1b git calls, each under its own condition, with the Step 1.3 writes