devflow-kit 3.4.0 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/README.md +12 -8
  3. package/dist/agents/code.md +39 -182
  4. package/dist/agents/{diagnose.md → debug.md} +4 -4
  5. package/dist/agents/design.md +0 -1
  6. package/dist/agents/fix.md +165 -0
  7. package/dist/agents/git.md +31 -693
  8. package/dist/agents/{scrutinize.md → harden.md} +9 -6
  9. package/dist/agents/knowledge.md +8 -2
  10. package/dist/agents/refactor.md +133 -0
  11. package/dist/agents/research.md +6 -0
  12. package/dist/agents/review.md +0 -4
  13. package/dist/agents/skim.md +4 -0
  14. package/dist/agents/triage.md +8 -1
  15. package/dist/cli/agents-view/render.js +1 -1
  16. package/dist/cli/commands/behavior-prompts.js +77 -0
  17. package/dist/cli/commands/behavior.js +123 -0
  18. package/dist/cli/commands/flags.js +8 -2
  19. package/dist/cli/commands/init-seed.js +7 -3
  20. package/dist/cli/commands/init.js +75 -8
  21. package/dist/cli/commands/learning.js +12 -12
  22. package/dist/cli/commands/legacy-hooks.js +1 -1
  23. package/dist/cli/commands/rules.js +16 -0
  24. package/dist/cli/commands/tracker.js +112 -15
  25. package/dist/cli/commands/uninstall.js +111 -5
  26. package/dist/cli.js +2 -0
  27. package/dist/commands/bug-analysis.md +22 -18
  28. package/dist/commands/code-review.md +25 -29
  29. package/dist/commands/debug.md +36 -15
  30. package/dist/commands/dynamic-build.md +64 -78
  31. package/dist/commands/dynamic-plan.md +18 -14
  32. package/dist/commands/dynamic-profile.md +8 -6
  33. package/dist/commands/dynamic-tickets.md +19 -15
  34. package/dist/commands/explore.md +14 -14
  35. package/dist/commands/implement.md +122 -225
  36. package/dist/commands/plan.md +32 -47
  37. package/dist/commands/release.md +12 -7
  38. package/dist/commands/research.md +26 -15
  39. package/dist/commands/resolve.md +53 -92
  40. package/dist/commands/self-review.md +42 -42
  41. package/dist/core/agent-frontmatter.js +101 -0
  42. package/dist/core/agent-models.js +47 -11
  43. package/dist/core/compliance-compose.js +6 -4
  44. package/dist/core/{learning-tuning-config.js → curate-tuning-config.js} +14 -14
  45. package/dist/core/feature-switch.js +23 -2
  46. package/dist/core/flags.js +111 -0
  47. package/dist/core/learning-queue-cleanup.js +1 -1
  48. package/dist/core/manifest.js +11 -3
  49. package/dist/core/mds-variants.js +68 -26
  50. package/dist/core/migrations.js +63 -44
  51. package/dist/core/plugins.js +49 -70
  52. package/dist/core/project-paths.js +3 -7
  53. package/dist/core/proxy-log.js +1 -1
  54. package/dist/core/proxy-state.js +1 -1
  55. package/dist/core/tracker.js +120 -2
  56. package/dist/hud/codex-usage.js +247 -0
  57. package/dist/hud/components/codex-quota.js +37 -0
  58. package/dist/hud/components/usage-quota.js +1 -1
  59. package/dist/hud/config.js +1 -0
  60. package/dist/hud/index.js +16 -3
  61. package/dist/hud/render.js +3 -1
  62. package/dist/learning-off/agents/code.md +37 -180
  63. package/dist/learning-off/agents/{diagnose.md → debug.md} +4 -4
  64. package/dist/learning-off/agents/design.md +0 -1
  65. package/dist/learning-off/agents/fix.md +161 -0
  66. package/dist/learning-off/agents/{scrutinize.md → harden.md} +9 -6
  67. package/dist/learning-off/agents/knowledge.md +8 -2
  68. package/dist/learning-off/agents/refactor.md +129 -0
  69. package/dist/learning-off/agents/research.md +6 -0
  70. package/dist/learning-off/agents/review.md +0 -4
  71. package/dist/learning-off/agents/skim.md +4 -0
  72. package/dist/learning-off/agents/triage.md +8 -1
  73. package/dist/learning-off/commands/bug-analysis.md +12 -12
  74. package/dist/learning-off/commands/code-review.md +14 -22
  75. package/dist/learning-off/commands/debug.md +24 -8
  76. package/dist/learning-off/commands/dynamic-build.md +58 -74
  77. package/dist/learning-off/commands/dynamic-plan.md +12 -10
  78. package/dist/learning-off/commands/dynamic-profile.md +2 -2
  79. package/dist/learning-off/commands/dynamic-tickets.md +13 -11
  80. package/dist/learning-off/commands/explore.md +3 -7
  81. package/dist/learning-off/commands/implement.md +110 -217
  82. package/dist/learning-off/commands/plan.md +21 -39
  83. package/dist/learning-off/commands/release.md +7 -4
  84. package/dist/learning-off/commands/research.md +16 -9
  85. package/dist/learning-off/commands/resolve.md +42 -85
  86. package/dist/learning-off/commands/self-review.md +30 -34
  87. package/dist/skills/git/references/learn-conventions.md +27 -3
  88. package/dist/skills/git/references/pr/check-ci-status.md +19 -0
  89. package/dist/skills/git/references/pr/check-merge-readiness.md +21 -0
  90. package/dist/skills/git/references/pr/fetch-review-threads.md +30 -0
  91. package/dist/skills/git/references/pr/post-resolution-summary.md +18 -0
  92. package/dist/skills/git/references/pr/post-review-summary.md +20 -0
  93. package/dist/skills/git/references/pr/resolve-review-threads.md +28 -4
  94. package/dist/skills/git/references/pr/update-pr-evidence.md +17 -6
  95. package/dist/skills/git/references/pr/validate-branch.md +26 -0
  96. package/dist/skills/git/references/tracker/github/associate-release.md +24 -0
  97. package/dist/skills/git/references/tracker/github/backlink-shipped-issues.md +31 -1
  98. package/dist/skills/git/references/tracker/github/create-release.md +30 -1
  99. package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +89 -2
  100. package/dist/skills/git/references/tracker/github/ensure-traceable-issue.md +16 -1
  101. package/dist/skills/git/references/tracker/github/fetch-issue.md +36 -1
  102. package/dist/skills/git/references/tracker/github/fetch-issues-batch.md +47 -1
  103. package/dist/skills/git/references/tracker/github/gather-release-evidence.md +25 -0
  104. package/dist/skills/git/references/tracker/github/manage-debt.md +21 -1
  105. package/dist/skills/git/references/tracker/github/post-wave-report.md +15 -1
  106. package/dist/skills/git/references/tracker/github/setup-task.md +41 -1
  107. package/dist/skills/git/references/tracker/jira/associate-release.md +24 -0
  108. package/dist/skills/git/references/tracker/jira/backlink-shipped-issues.md +31 -1
  109. package/dist/skills/git/references/tracker/jira/create-release.md +30 -1
  110. package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +89 -2
  111. package/dist/skills/git/references/tracker/jira/ensure-traceable-issue.md +16 -1
  112. package/dist/skills/git/references/tracker/jira/fetch-issue.md +36 -1
  113. package/dist/skills/git/references/tracker/jira/fetch-issues-batch.md +47 -1
  114. package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +25 -0
  115. package/dist/skills/git/references/tracker/jira/manage-debt.md +21 -1
  116. package/dist/skills/git/references/tracker/jira/post-wave-report.md +15 -1
  117. package/dist/skills/git/references/tracker/jira/setup-task.md +41 -1
  118. package/dist/skills/git/references/tracker/linear/associate-release.md +24 -0
  119. package/dist/skills/git/references/tracker/linear/backlink-shipped-issues.md +31 -1
  120. package/dist/skills/git/references/tracker/linear/create-release.md +30 -1
  121. package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +89 -2
  122. package/dist/skills/git/references/tracker/linear/ensure-traceable-issue.md +16 -1
  123. package/dist/skills/git/references/tracker/linear/fetch-issue.md +36 -1
  124. package/dist/skills/git/references/tracker/linear/fetch-issues-batch.md +47 -1
  125. package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +25 -0
  126. package/dist/skills/git/references/tracker/linear/manage-debt.md +21 -1
  127. package/dist/skills/git/references/tracker/linear/post-wave-report.md +15 -1
  128. package/dist/skills/git/references/tracker/linear/setup-task.md +41 -1
  129. package/dist/targets/claude-code/agent-type-owner.js +164 -0
  130. package/dist/targets/claude-code/behavior-install.js +111 -0
  131. package/dist/targets/claude-code/installer.js +177 -77
  132. package/dist/targets/claude-code/learning-install.js +9 -1
  133. package/dist/targets/claude-code/tracker-install.js +33 -16
  134. package/dist/targets/claude-code/tracker-servers.js +107 -0
  135. package/package.json +4 -3
  136. package/src/assets/agents/_partials/_code.mds +109 -0
  137. package/src/assets/agents/code.mds +18 -222
  138. package/src/assets/agents/{learning.md → curate.md} +22 -72
  139. package/src/assets/agents/{diagnose.mds → debug.mds} +4 -4
  140. package/src/assets/agents/design.mds +0 -1
  141. package/src/assets/agents/evaluate.md +11 -5
  142. package/src/assets/agents/explore.md +58 -0
  143. package/src/assets/agents/fix.mds +113 -0
  144. package/src/assets/agents/git.mds +31 -693
  145. package/src/assets/agents/{scrutinize.mds → harden.mds} +9 -6
  146. package/src/assets/agents/knowledge.mds +8 -2
  147. package/src/assets/agents/{simplify.md → polish.md} +7 -4
  148. package/src/assets/agents/refactor.mds +81 -0
  149. package/src/assets/agents/research.mds +6 -0
  150. package/src/assets/agents/review.mds +0 -4
  151. package/src/assets/agents/skim.mds +4 -0
  152. package/src/assets/agents/synthesize.md +26 -352
  153. package/src/assets/agents/test.md +10 -2
  154. package/src/assets/agents/tracker.md +20 -7
  155. package/src/assets/agents/triage.mds +8 -1
  156. package/src/assets/agents/validate.md +5 -0
  157. package/src/assets/commands/_partials/_compliance.mds +36 -0
  158. package/src/assets/commands/_partials/_decisions.mds +26 -6
  159. package/src/assets/commands/_partials/_engine.mds +17 -17
  160. package/src/assets/commands/_partials/_evidence_policy.mds +0 -17
  161. package/src/assets/commands/_partials/_knowledge.mds +14 -9
  162. package/src/assets/commands/_partials/_preamble.mds +5 -3
  163. package/src/assets/commands/_partials/_roster.mds +6 -5
  164. package/src/assets/commands/_partials/_wave.mds +2 -2
  165. package/src/assets/commands/bug-analysis.mds +10 -10
  166. package/src/assets/commands/code-review.mds +12 -22
  167. package/src/assets/commands/debug.mds +24 -2
  168. package/src/assets/commands/dynamic-build.mds +34 -51
  169. package/src/assets/commands/dynamic-plan.mds +4 -3
  170. package/src/assets/commands/dynamic-tickets.mds +5 -4
  171. package/src/assets/commands/explore.mds +1 -1
  172. package/src/assets/commands/implement.mds +108 -201
  173. package/src/assets/commands/plan.mds +19 -44
  174. package/src/assets/commands/release.mds +8 -3
  175. package/src/assets/commands/research.mds +14 -7
  176. package/src/assets/commands/resolve.mds +37 -82
  177. package/src/assets/commands/self-review.mds +27 -27
  178. package/src/assets/mds/.mdsroot +4 -0
  179. package/src/assets/mds/git/_ops.mds +383 -0
  180. package/src/assets/mds/git/_ops_pr.mds +201 -0
  181. package/src/assets/mds/git/_ops_steps.mds +147 -0
  182. package/src/assets/mds/git/_pr.mds +45 -50
  183. package/src/assets/mds/git/_references.mds +6 -3
  184. package/src/assets/mds/tracker/_common.mds +5 -5
  185. package/src/assets/mds/tracker/_contract.mds +4 -3
  186. package/src/assets/mds/tracker/_github.mds +60 -14
  187. package/src/assets/mds/tracker/_jira.mds +60 -14
  188. package/src/assets/mds/tracker/_linear.mds +60 -14
  189. package/src/assets/mds/tracker/_steps.mds +10 -9
  190. package/src/assets/rules/behavior.md +6 -0
  191. package/src/assets/scripts/hooks/assets/orchestrator-charter.md +5 -3
  192. package/src/assets/scripts/hooks/capture-prompt +1 -1
  193. package/src/assets/scripts/hooks/capture-question +1 -1
  194. package/src/assets/scripts/hooks/capture-turn +1 -1
  195. package/src/assets/scripts/hooks/json-helper.cjs +2 -2
  196. package/src/assets/scripts/hooks/lib/learning-store.cjs +1 -1
  197. package/src/assets/scripts/hooks/lib/project-paths.cjs +4 -10
  198. package/src/assets/scripts/hooks/preamble +1 -1
  199. package/src/assets/scripts/hooks/session-start-context +58 -45
  200. package/src/assets/scripts/verify-evidence.cjs +726 -9
  201. package/src/assets/skills/agent-references/SKILL.md +37 -0
  202. package/src/assets/skills/agent-references/references/commands/implement-evidence-asks.md +35 -0
  203. package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +15 -0
  204. package/src/assets/skills/agent-references/references/curate/maintain.md +71 -0
  205. package/src/assets/skills/agent-references/references/synthesize/bug-analysis.md +71 -0
  206. package/src/assets/skills/agent-references/references/synthesize/design.md +36 -0
  207. package/src/assets/skills/agent-references/references/synthesize/exploration.md +38 -0
  208. package/src/assets/skills/agent-references/references/synthesize/planning.md +60 -0
  209. package/src/assets/skills/agent-references/references/synthesize/research.md +61 -0
  210. package/src/assets/skills/agent-references/references/synthesize/review.md +76 -0
  211. package/src/assets/skills/apply-decisions/SKILL.md +6 -4
  212. package/src/assets/skills/compliance/SKILL.md +1 -1
  213. package/src/assets/skills/docs-framework/SKILL.md +81 -84
  214. package/src/assets/skills/docs-framework/references/patterns.md +14 -25
  215. package/src/assets/skills/docs-framework/references/violations.md +7 -7
  216. package/src/assets/skills/gap-analysis/SKILL.md +0 -16
  217. package/src/assets/skills/gap-analysis/references/compliance.md +19 -0
  218. package/src/assets/skills/qa/SKILL.md +1 -1
  219. package/src/assets/skills/quality-gates/SKILL.md +7 -7
  220. package/src/assets/skills/quality-gates/references/report-template.md +7 -7
  221. package/dist/skills/git/references/pr/ensure-pr-ready.md +0 -24
@@ -7,7 +7,7 @@ import color from 'picocolors';
7
7
  import { getInstallationPaths, getClaudeDirectory, getHomeDirectory, getManagedSettingsPath } from '../../targets/claude-code/claude-paths.js';
8
8
  import { getGitRoot } from '../../core/git.js';
9
9
  import { isSameLocation } from '../../core/same-location.js';
10
- import { DEVFLOW_PLUGINS, SKILL_NAMESPACE, getAllSkillNames, getAllAgentNames, getAllCommandNames, parsePluginSelection, resolveFeatureRedirect, prefixSkillName, unprefixSkillName, skillsOf, FEATURE_OWNED_SKILLS } from '../../core/plugins.js';
10
+ import { DEVFLOW_PLUGINS, SKILL_NAMESPACE, buildAssetMaps, getAllSkillNames, getAllAgentNames, getAllCommandNames, parsePluginSelection, resolveFeatureRedirect, prefixSkillName, unprefixSkillName, skillsOf, FEATURE_OWNED_SKILLS } from '../../core/plugins.js';
11
11
  import { readManifest, removeManifestPlugins } from '../../core/manifest.js';
12
12
  import { sweepOrphanedAssets, mdFileName, mdEntryName } from '../../core/orphan-sweep.js';
13
13
  import { LEGACY_SKILL_NAMES } from '../../targets/claude-code/legacy.js';
@@ -20,7 +20,7 @@ import { removeContextHook } from './context.js';
20
20
  import { applyProxyTeardownToSettings } from './proxy.js';
21
21
  import { readProxyState, proxyJsonExists } from '../../core/proxy-state.js';
22
22
  import { hudCacheDir } from '../../core/cache.js';
23
- import { TRACKER_ATTEMPTS_NAMES, TRACKER_CLAIM_FILE, TRACKER_CONVENTIONS_DIR, TRACKER_ENABLED_FILE, TRACKER_LEGACY_ATTEMPTS_FILE, TRACKER_LEGACY_CONVENTIONS_FILE, TRACKER_PROVIDER_IDS, TRACKER_STAGED_PREFIX, } from '../../core/tracker.js';
23
+ import { effectiveTrackerServers, TRACKER_ATTEMPTS_NAMES, TRACKER_CLAIM_FILE, TRACKER_CONVENTIONS_DIR, TRACKER_ENABLED_FILE, TRACKER_LEGACY_ATTEMPTS_FILE, TRACKER_LEGACY_CONVENTIONS_FILE, TRACKER_PROVIDER_IDS, TRACKER_STAGED_PREFIX, } from '../../core/tracker.js';
24
24
  import { CLAUDE_MD_AUDIT_STAMP_FILE, CLAUDE_MD_AUDIT_STAMP_TMP_PREFIX } from '../../core/claude-md-audit.js';
25
25
  import { revertExternalAgents } from '../../core/agent-models.js';
26
26
  import { detectShell, getProfilePath } from '../../core/safe-delete.js';
@@ -32,6 +32,7 @@ import { stripDevflowTeammateModeFromJson } from '../../core/teammate-mode-clean
32
32
  import { getPackageRoot, isContainedIn } from '../../core/paths.js';
33
33
  import { firstSymbolicLink } from '../../core/linked-path.js';
34
34
  import { restampInstalledCommands } from '../../targets/claude-code/language-stamp.js';
35
+ import { installCommandsAndAgents } from '../../targets/claude-code/installer.js';
35
36
  /**
36
37
  * Where a retired repo-local install lives: `<gitRoot>/.claude` and `<gitRoot>/.devflow`.
37
38
  *
@@ -488,7 +489,7 @@ export function userContentPaths(devflowDir) {
488
489
  const name = `${TRACKER_LEGACY_CONVENTIONS_FILE}.${id}.bak`;
489
490
  return { relPath: name, label: `${name} (previous issue tracker conventions)` };
490
491
  }),
491
- // learning.json — global learning agent tuning config
492
+ // learning.json — global curate agent tuning config
492
493
  { relPath: 'learning.json', label: 'learning.json' },
493
494
  // hud.json — user HUD enable/disable preference and display config
494
495
  { relPath: 'hud.json', label: 'hud.json (HUD configuration)' },
@@ -885,6 +886,89 @@ export async function runDryRunPhase(opts) {
885
886
  }
886
887
  }
887
888
  }
889
+ /**
890
+ * After a selective uninstall removed a retired agent file, write the current commands
891
+ * and agents of the plugins that stay installed.
892
+ *
893
+ * A retired agent file only exists on a machine that ran an older release. That
894
+ * release's commands, for the plugins that stay, still spawn the retired name, and the
895
+ * agents that replaced it are not installed. Removing the file without this step would
896
+ * leave those plugins unable to spawn their agents until the next full `devflow init`.
897
+ *
898
+ * Writes only commands and agents, through the same copy path `devflow init` uses
899
+ * ({@link installCommandsAndAgents}). It does not touch the hooks, the scripts or
900
+ * settings.json, so the notice tells the user to run `devflow init` for those.
901
+ *
902
+ * Never runs in a legacy local scope (D-CLI-NO-SYMLINK): a repository can commit a command
903
+ * file as a symbolic link, and the copy writes through it. The folder guard below does not
904
+ * check files. `devflow init` can not update a legacy local install either, so the warning
905
+ * tells the user to remove it in full.
906
+ *
907
+ * Skipped, with a warning, when there is no readable manifest or it lists no known plugin (the
908
+ * retained set would be a guess), or when a folder is behind a link the caller's guard
909
+ * refuses. Those warnings name `devflow init` as the remedy. When the copy fails, it stops
910
+ * at the first failure: files it wrote before then stay, and the warning names the same
911
+ * remedy. Never throws: an uninstall must finish.
912
+ * Agent model lines are reverted again after the copy, as the selective phase does before
913
+ * its removal, so a freshly written agent carries no external-model line. Like the
914
+ * selective phase, it prints the warnings of that revert only with `verbose`.
915
+ */
916
+ export async function refreshRetainedCommandsAndAgents(opts) {
917
+ const { claudeDir, devflowDir, retained, retiredAgents } = opts;
918
+ const scope = opts.scope ?? 'user';
919
+ const verbose = opts.verbose ?? false;
920
+ const mayChange = opts.mayChange ?? changeAnything;
921
+ const agentsDir = path.join(claudeDir, 'agents', 'devflow');
922
+ const commandsDir = path.join(claudeDir, 'commands', 'devflow');
923
+ const retired = `Removed the agent file(s) of an older Devflow release: ${retiredAgents.join(', ')}.`;
924
+ const remedy = 'Run `devflow init` to update the commands, agents, hooks and scripts of the plugins that stay installed.';
925
+ if (retained.length === 0)
926
+ return;
927
+ if (scope === 'local') {
928
+ p.log.warn(`${retired} Devflow does not rewrite files in a legacy local install, so the remaining commands can still name the removed agents. Remove the legacy local install in full with \`devflow uninstall --scope local\`.`);
929
+ return;
930
+ }
931
+ // readManifest returns null for a missing file and for one it can not parse or validate.
932
+ const manifest = await readManifest(devflowDir).catch(() => null);
933
+ if (manifest === null) {
934
+ p.log.warn(`${retired} There is no readable manifest, so Devflow did not rewrite the remaining files. ${remedy}`);
935
+ return;
936
+ }
937
+ if (manifest.plugins.length === 0) {
938
+ p.log.warn(`${retired} The manifest lists no plugins, so Devflow did not rewrite the remaining files. ${remedy}`);
939
+ return;
940
+ }
941
+ // resolveInstalledPlugins falls back to the whole registry when no manifest name resolves, so
942
+ // the retained set would hold plugins that were never installed.
943
+ if (!manifest.plugins.some(name => DEVFLOW_PLUGINS.some(plugin => plugin.name === name))) {
944
+ p.log.warn(`${retired} The manifest lists no known plugin, so Devflow did not rewrite the remaining files. ${remedy}`);
945
+ return;
946
+ }
947
+ if (!(await mayChange(agentsDir)) || !(await mayChange(commandsDir))) {
948
+ p.log.warn(`${retired} A linked folder blocks the rewrite. ${remedy}`);
949
+ return;
950
+ }
951
+ try {
952
+ await installCommandsAndAgents({
953
+ plugins: retained,
954
+ agentsMap: buildAssetMaps(retained).agentsMap,
955
+ claudeDir,
956
+ learning: manifest.features.learning,
957
+ trackerServers: effectiveTrackerServers(manifest.features.tracker),
958
+ warn: (msg) => p.log.warn(msg),
959
+ });
960
+ }
961
+ catch (err) {
962
+ p.log.warn(`${retired} Devflow could not write the current commands and agents (${err instanceof Error ? err.message : String(err)}). ${remedy}`);
963
+ return;
964
+ }
965
+ try {
966
+ await revertExternalAgents({ installDir: agentsDir, devflowDir, onWarning: (msg) => { if (verbose)
967
+ p.log.warn(msg); } });
968
+ }
969
+ catch { /* the revert is best effort, as in the selective phase */ }
970
+ p.log.info(`${retired} Devflow wrote the current commands and agents of the plugins that stay installed. Run \`devflow init\` to update the hooks and scripts.`);
971
+ }
888
972
  /**
889
973
  * SELECTIVE PHASE (per scope): revert agent model overrides, remove the
890
974
  * selected plugins' assets, and clean up the ambient hook if the ambient
@@ -919,7 +1003,23 @@ export async function runSelectivePhaseForScope(opts) {
919
1003
  }
920
1004
  catch { /* agents dir absent or revert failed — non-fatal */ }
921
1005
  }
922
- await removeSelectedPlugins(claudeDir, selectedPlugins, verbose, installedPlugins, mayChange);
1006
+ const sweeps = await removeSelectedPlugins(claudeDir, selectedPlugins, verbose, installedPlugins, mayChange);
1007
+ // A retired agent file means the install is from an older release, and the commands of the
1008
+ // plugins that stay installed still spawn the name that was just removed. Write their
1009
+ // current commands and agents so the install stays whole. Runs before the language stamp
1010
+ // below, which then restamps the command this wrote.
1011
+ if (sweeps.agents.removed.length > 0) {
1012
+ const removed = new Set(selectedPlugins.map(sp => sp.name));
1013
+ await refreshRetainedCommandsAndAgents({
1014
+ claudeDir,
1015
+ devflowDir,
1016
+ retained: installedPlugins.filter(plugin => !removed.has(plugin.name)),
1017
+ retiredAgents: sweeps.agents.removed,
1018
+ scope,
1019
+ verbose,
1020
+ mayChange,
1021
+ });
1022
+ }
923
1023
  // D-LANGUAGE-FOCUS-STAMP: re-stamp the installed /code-review from the selection that REMAINS.
924
1024
  // A language plugin owns a skill and no command, so removing it deletes the skill while its
925
1025
  // name would stay on the stamped line, and /code-review would spawn a focus whose skill is gone.
@@ -1627,6 +1727,9 @@ export async function removeAllDevFlow(claudeDir, devflowScriptsDir, verbose, ma
1627
1727
  * A folder `mayChange` refuses is not swept at all (D-CLI-NO-SYMLINK,
1628
1728
  * legacyLocalChangeGuard). An entry in a swept folder that is itself a link is
1629
1729
  * only unlinked: `fs.rm` never follows the link it is given.
1730
+ *
1731
+ * Returns what each sweep removed and failed to remove, so a caller can tell that
1732
+ * a retired agent was removed (see {@link refreshRetainedCommandsAndAgents}).
1630
1733
  */
1631
1734
  export async function sweepDevflowNamespaces(claudeDir, verbose, mayChange = changeAnything) {
1632
1735
  const agentsDir = path.join(claudeDir, 'agents', 'devflow');
@@ -1656,6 +1759,7 @@ export async function sweepDevflowNamespaces(claudeDir, verbose, mayChange = cha
1656
1759
  p.log.warn(`Could not remove orphaned ${kind} "${failure.name}" (${reason}) — remove it manually`);
1657
1760
  }
1658
1761
  }
1762
+ return { agents: agentsSweep, commands: commandsSweep, skills: skillsSweep };
1659
1763
  }
1660
1764
  /**
1661
1765
  * Remove only specific plugin assets (selective uninstall).
@@ -1665,6 +1769,8 @@ export async function sweepDevflowNamespaces(claudeDir, verbose, mayChange = cha
1665
1769
  * For skills: only remove skills that are NOT used by any remaining plugin.
1666
1770
  * Each removal passes `mayChange` first, which skips one a symbolic link would
1667
1771
  * redirect in a legacy local install (D-CLI-NO-SYMLINK, legacyLocalChangeGuard).
1772
+ *
1773
+ * Returns what the closing registry-diff sweep removed.
1668
1774
  */
1669
1775
  export async function removeSelectedPlugins(claudeDir, plugins, verbose, installedPlugins = DEVFLOW_PLUGINS, mayChange = changeAnything) {
1670
1776
  const { skills, agents, commands, rules } = computeAssetsToRemove(plugins, installedPlugins);
@@ -1734,6 +1840,6 @@ export async function removeSelectedPlugins(claudeDir, plugins, verbose, install
1734
1840
  // Removes any orphaned files whose names left the registry (retired, renamed,
1735
1841
  // or deleted from all plugins). Spans ALL plugins so assets belonging to
1736
1842
  // non-selected plugins are never swept.
1737
- await sweepDevflowNamespaces(claudeDir, verbose, mayChange);
1843
+ return sweepDevflowNamespaces(claudeDir, verbose, mayChange);
1738
1844
  }
1739
1845
  //# sourceMappingURL=uninstall.js.map
package/dist/cli.js CHANGED
@@ -19,6 +19,7 @@ import { safeDeleteCommand } from './cli/commands/safe-delete.js';
19
19
  import { proxyCommand } from './cli/commands/proxy.js';
20
20
  import { agentsCommand } from './cli/commands/agents.js';
21
21
  import { complianceCommand } from './cli/commands/compliance.js';
22
+ import { behaviorCommand } from './cli/commands/behavior.js';
22
23
  import { trackerCommand } from './cli/commands/tracker.js';
23
24
  const __filename = fileURLToPath(import.meta.url);
24
25
  const __dirname = dirname(__filename);
@@ -48,6 +49,7 @@ program.addCommand(safeDeleteCommand);
48
49
  program.addCommand(proxyCommand);
49
50
  program.addCommand(agentsCommand);
50
51
  program.addCommand(complianceCommand);
52
+ program.addCommand(behaviorCommand);
51
53
  program.addCommand(trackerCommand);
52
54
  // Handle no command (bare `devflow`) or unknown subcommand.
53
55
  // When Commander sees an unrecognised first argument it does not route to any
@@ -38,7 +38,7 @@ git -C "{start}" rev-parse --show-toplevel
38
38
  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.
39
39
 
40
40
  Render the test-plan block from `/implement`'s evidence file, and from nothing else:
41
- 1. `branch_slug` is `git branch --show-current` with every `/` replaced by `-`.
41
+ 1. `branch_slug` is `git -C "{worktree}" branch --show-current` with every `/` replaced by `-`.
42
42
  2. Only when `branch_slug` matches `^[A-Za-z0-9._-]{1,200}$` and the file exists, run (the path double-quoted):
43
43
 
44
44
  ```bash
@@ -195,19 +195,19 @@ The accepted line is the only source of these values: the script alone folds the
195
195
 
196
196
  When the settings line says `LEARNING=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
197
197
 
198
- 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`):
198
+ 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`):
199
199
 
200
200
  ```bash
201
201
  git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
202
202
  ```
203
203
 
204
- Line 1 is the checkout's toplevel, line 2 the repository's common git directory. A git older than 2.31 echoes `--path-format=absolute` back as a line of its own first. `{ledger}` is the first of these that applies:
204
+ 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:
205
205
 
206
206
  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.
207
207
  2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
208
208
  3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
209
209
 
210
- This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT), so you read the index the Learning agent writes.
210
+ This is the rule the learning hooks apply, so you read the index the Curate agent writes.
211
211
 
212
212
  **Step 1 — Read the pre-rendered index:**
213
213
 
@@ -216,11 +216,15 @@ Attempt to read `{ledger}/.devflow/learning/index.md`.
216
216
  - If the file exists and contains non-empty content: use that content as `DECISIONS_CONTEXT`.
217
217
  - If the file is absent or empty: set `DECISIONS_CONTEXT` to `(none)`.
218
218
 
219
- The index is one direct file read, written at render time by `render-decisions.cjs` alongside `decisions.md`/`pitfalls.md` — no `.cjs` script runs here, and the index's own footer names the files that hold each entry's full body.
219
+ The index is one direct file read, written at render time by `render-decisions.cjs` — no `.cjs` script runs here.
220
220
 
221
- **Step 2 — Apply decisions using `devflow:apply-decisions`:**
221
+ **Step 2 — Slice the index, then hand it on:**
222
222
 
223
- When `DECISIONS_CONTEXT` is not `(none)`, follow `devflow:apply-decisions` to scan the index, identify plausibly-relevant entries, Read full entry bodies on demand, and cite verbatim IDs in downstream agent prompts and reasoning.
223
+ When `DECISIONS_CONTEXT` is not `(none)`, hand it only to the agents whose contract declares it.
224
+
225
+ 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.
226
+
227
+ Those agents follow `devflow:apply-decisions`. A host that uses the index in its own thread says so in its own step.
224
228
 
225
229
  #### Feature Knowledge
226
230
 
@@ -246,7 +250,7 @@ If `index.md` exists and contains at least one entry line, use it for relevance
246
250
 
247
251
  **Step 2 — Fallback: glob frontmatter (if `index.md` is absent or empty):**
248
252
 
249
- 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.
253
+ Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read only its YAML frontmatter block (between the opening and closing `---` delimiters).
250
254
 
251
255
  **Step 3 — Pick relevant KBs:**
252
256
 
@@ -277,12 +281,12 @@ Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
277
281
 
278
282
  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)`.
279
283
 
280
- **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.
284
+ **One git call, then direct reads — no `.cjs` script.**
281
285
 
282
286
  #### Plan Artifact
283
287
 
284
- 1. List `{worktree}/.devflow/docs/design/*.md` — sort descending by filename (timestamps are naturally sortable), scan the 10 most recent
285
- 2. Read the most recent file if it exists
288
+ 1. List the design plans: `{worktree}/.devflow/docs/design/*.md` (a `/plan` artifact) and `{worktree}/.devflow/docs/design/*/*/*-plan.md` (a `/dynamic-plan` per-ticket plan). Sort by timestamp, newest first, and scan the 10 most recent. A `/plan` artifact's timestamp is the `YYYY-MM-DD_HHMM` before its `.md`; a per-ticket plan's is the name of its parent directory. Never sort by file name, which starts with an issue ID or a ticket slug. A per-ticket plan counts only when its `{ticket-slug}` (its file name without `-plan.md`) appears in the worktree's branch name
289
+ 2. Read the most recent file that carries an `## Acceptance Criteria` section
286
290
  3. Extract `## Acceptance Criteria` section → parse into table: `| ID | Criterion | Type | Testable Condition |`
287
291
  4. Set `PLAN_CONTEXT` to plan summary; `ACCEPTANCE_RULES` to the table
288
292
  5. If no plan files exist or section not found: `PLAN_CONTEXT=(none)`, `ACCEPTANCE_RULES=(none)`
@@ -306,11 +310,11 @@ Determine which focus analyzers to run using `CHANGED_FILES` (already computed i
306
310
  **Produces:** ANALYZER_OUTPUTS
307
311
  **Requires:** DIFF_RANGE, ANALYSIS_DIR, ACTIVE_FOCUSES, STATIC_FINDINGS, ACCEPTANCE_RULES, PLAN_CONTEXT, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE
308
312
 
309
- Spawn ALL active Diagnose agents **in a single message** (parallel, NOT background):
313
+ Spawn ALL active Debug agents **in a single message** (parallel, NOT background):
310
314
 
311
315
  For each active focus, spawn:
312
316
  ```
313
- Agent(subagent_type="Diagnose", run_in_background=false):
317
+ Agent(subagent_type="Debug", run_in_background=false):
314
318
  "Analyze focusing on {focus}.
315
319
  FOCUS: {focus}
316
320
  DIFF_COMMAND: git diff {DIFF_RANGE}
@@ -408,10 +412,10 @@ Run `/resolve` to process and fix these findings.
408
412
  │ └─ Detect active focuses (security + functional always; integration + usability conditional)
409
413
  │
410
414
  ├─ Phase 5: Bug Analysis (PARALLEL)
411
- │ ├─ Diagnose agent: security (+ STATIC_FINDINGS)
412
- │ ├─ Diagnose agent: functional
413
- │ ├─ Diagnose agent: integration (conditional)
414
- │ └─ Diagnose agent: usability (conditional)
415
+ │ ├─ Debug agent: security (+ STATIC_FINDINGS)
416
+ │ ├─ Debug agent: functional
417
+ │ ├─ Debug agent: integration (conditional)
418
+ │ └─ Debug agent: usability (conditional)
415
419
  │
416
420
  ├─ Phase 6: Synthesis
417
421
  │ └─ Synthesize agent (mode: bug-analysis)
@@ -448,7 +452,7 @@ Run `/resolve` after `/bug-analysis` to fix identified bugs. `/resolve` automati
448
452
  2. **Parallel, not background** — Analyzers spawn in one message with `run_in_background=false`
449
453
  3. **Static + semantic** — Two complementary tracks, each validates the other
450
454
  4. **Incremental by default** — Only analyze new changes unless `--full` specified
451
- 5. **Verify before reporting** — Diagnose agents self-verify every finding
455
+ 5. **Verify before reporting** — Debug agents self-verify every finding
452
456
  6. **Honest reporting** — Display risk level and counts directly from synthesis
453
457
 
454
458
  ## Phase Completion Checklist
@@ -22,9 +22,10 @@ Run a comprehensive code review of the current branch by spawning parallel revie
22
22
 
23
23
  **Produces:** WORKTREES
24
24
 
25
- 1. **Discover reviewable worktrees** using the `devflow:worktree-support` skill discovery algorithm:
26
- - Run `git worktree list --porcelain` → parse, filter (skip protected/detached/mid-rebase), dedup by branch, sort by recent commit
27
- - Invoke the `devflow:worktree-support` skill, then Read its `references/discovery.md` from the skill's base directory for the full 7-step algorithm; the canonical protected branch list stays in the skill
25
+ 1. **Discover reviewable worktrees**:
26
+ - Run `git worktree list --porcelain` and count the worktrees it lists
27
+ - **More than one listed:** Invoke the `devflow:worktree-support` skill, then Read its `references/discovery.md` from the skill's base directory for the full 7-step algorithm; the canonical protected branch list stays in the skill. Parse the list, filter (skip protected/detached/mid-rebase), dedup by branch, sort by recent commit
28
+ - **Exactly one listed:** load neither the skill nor the reference — that worktree is the only candidate, and Step 0c's Git agent validates its branch
28
29
  2. **If `--path` flag provided:** use only that worktree, skip discovery
29
30
  **`--path` validation**: Before proceeding, verify the path exists as a directory and appears in `git worktree list` output. If not: report error and stop.
30
31
  3. **If only 1 reviewable worktree** (the common case): proceed as single-worktree flow — zero behavior change
@@ -71,9 +72,9 @@ Set `EVIDENCE_POLICY`, `ISSUE_REQUIRED`, `APPLY_CONVENTIONS` and `REQUIRE_NON_AU
71
72
  **Requires:** WORKTREES
72
73
 
73
74
  Discover PR description guidance from plan artifact (per worktree):
74
- 1. List `{worktree}/.devflow/docs/design/*.md` files
75
- 2. Sort by timestamp in filename (descending -- timestamps are YYYY-MM-DD_HHMM, naturally sortable)
76
- 3. Read the most recent file, extract `## PR Description Guidance` section
75
+ 1. List the design plans: `{worktree}/.devflow/docs/design/*.md` (a `/plan` artifact) and `{worktree}/.devflow/docs/design/*/*/*-plan.md` (a `/dynamic-plan` per-ticket plan)
76
+ 2. Sort by timestamp, newest first, and scan the 10 most recent. A `/plan` artifact's timestamp is the `YYYY-MM-DD_HHMM` before its `.md`; a per-ticket plan's is the name of its parent directory. Never sort by file name, which starts with an issue ID or a ticket slug. A per-ticket plan counts only when its `{ticket-slug}` (its file name without `-plan.md`) appears in the worktree's branch name
77
+ 3. Read the most recent file that carries the section, extract `## PR Description Guidance` section
77
78
  4. If no plan files exist or section not found, set `PR_DESCRIPTION_GUIDANCE` to `(none)`
78
79
 
79
80
  Render the test-plan block (per worktree) from `/implement`'s evidence file, and from nothing else:
@@ -287,19 +288,19 @@ The core, database, dependencies, documentation and compliance focuses, and ever
287
288
 
288
289
  When the settings line says `LEARNING=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
289
290
 
290
- 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`):
291
+ 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`):
291
292
 
292
293
  ```bash
293
294
  git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
294
295
  ```
295
296
 
296
- Line 1 is the checkout's toplevel, line 2 the repository's common git directory. A git older than 2.31 echoes `--path-format=absolute` back as a line of its own first. `{ledger}` is the first of these that applies:
297
+ 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:
297
298
 
298
299
  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.
299
300
  2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
300
301
  3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
301
302
 
302
- This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT), so you read the index the Learning agent writes.
303
+ This is the rule the learning hooks apply, so you read the index the Curate agent writes.
303
304
 
304
305
  **Step 1 — Read the pre-rendered index:**
305
306
 
@@ -308,13 +309,17 @@ Attempt to read `{ledger}/.devflow/learning/index.md`.
308
309
  - If the file exists and contains non-empty content: use that content as `DECISIONS_CONTEXT`.
309
310
  - If the file is absent or empty: set `DECISIONS_CONTEXT` to `(none)`.
310
311
 
311
- The index is one direct file read, written at render time by `render-decisions.cjs` alongside `decisions.md`/`pitfalls.md` — no `.cjs` script runs here, and the index's own footer names the files that hold each entry's full body.
312
+ The index is one direct file read, written at render time by `render-decisions.cjs` — no `.cjs` script runs here.
312
313
 
313
- **Step 2 — Apply decisions using `devflow:apply-decisions`:**
314
+ **Step 2 — Slice the index, then hand it on:**
314
315
 
315
- When `DECISIONS_CONTEXT` is not `(none)`, follow `devflow:apply-decisions` to scan the index, identify plausibly-relevant entries, Read full entry bodies on demand, and cite verbatim IDs in downstream agent prompts and reasoning.
316
+ When `DECISIONS_CONTEXT` is not `(none)`, hand it only to the agents whose contract declares it.
316
317
 
317
- This produces a compact index of active ADR/PF entries. Pass `DECISIONS_CONTEXT` to all Review agents. Review agents use `devflow:apply-decisions` to Read full entry bodies on demand.
318
+ 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.
319
+
320
+ Those agents follow `devflow:apply-decisions`. A host that uses the index in its own thread says so in its own step.
321
+
322
+ 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.
318
323
 
319
324
  ### Load Feature Knowledge
320
325
 
@@ -338,7 +343,7 @@ If `index.md` exists and contains at least one entry line, use it for relevance
338
343
 
339
344
  **Step 2 — Fallback: glob frontmatter (if `index.md` is absent or empty):**
340
345
 
341
- 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.
346
+ Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read only its YAML frontmatter block (between the opening and closing `---` delimiters).
342
347
 
343
348
  **Step 3 — Pick relevant KBs:**
344
349
 
@@ -369,7 +374,7 @@ Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
369
374
 
370
375
  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)`.
371
376
 
372
- **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.
377
+ **One git call, then direct reads — no `.cjs` script.**
373
378
 
374
379
  Pass `FEATURE_KNOWLEDGE` to all Review agents alongside `DECISIONS_CONTEXT`.
375
380
 
@@ -408,6 +413,10 @@ Spawn Review agents **in a single message**, for the focus set `DIFF_CLASS` sele
408
413
 
409
414
  Review agent count: `code` runs 8 core, +1-12 added by Phase 1 (max 20 total per worktree); a reduced class or a mix runs 2-6.
410
415
 
416
+ **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:
417
+
418
+ > 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.
419
+
411
420
  Each Review agent invocation (all in one message, **NOT background**):
412
421
  ```
413
422
  Agent(subagent_type="Review", run_in_background=false):
@@ -421,7 +430,7 @@ DECISIONS_CONTEXT: {decisions_context}
421
430
  FEATURE_KNOWLEDGE: {feature_knowledge}
422
431
  PR_DESCRIPTION: <pr-description>{pr_description}</pr-description>
423
432
  PRIOR_RESOLUTIONS: <prior-resolution-summary>{prior_resolutions}</prior-resolution-summary>
424
- COMPLIANCE_FRAMEWORKS: {COMPLIANCE_FRAMEWORKS} (compliance focus only)
433
+ {COMPLIANCE_FOCUS_DIRECTIVE} (compliance focus only)
425
434
  If PRIOR_RESOLUTIONS is not (none), follow Cross-Cycle Awareness in review.md.
426
435
  Follow devflow:apply-decisions to scan the index and Read full ADR/PF bodies on demand.
427
436
  Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE — feature-specific patterns and anti-patterns inform findings.
@@ -517,21 +526,8 @@ In multi-worktree mode, report results per worktree.
517
526
 
518
527
  | Case | Handling |
519
528
  |------|----------|
520
- | No new commits since last review | Skip review, report: "No new commits since last review. Use --full for a full re-review." |
521
- | Rebase invalidates `.last-review-head` SHA | `git cat-file -t` check fails → fallback to full diff |
522
- | Same-minute review collision | `mkdir` fails → retry with seconds appended (`YYYY-MM-DD_HHMMSS`) |
523
- | Worktree in detached HEAD | Filtered out (no branch name → not reviewable) |
524
- | Worktree mid-rebase or mid-merge | Filtered out by status check |
525
- | Two worktrees on same branch | Deduplicate by branch — review once, use first worktree's path |
526
- | Worktree on protected branch | Filtered out (not reviewable) |
527
- | Worktree pre-flight fails | Report failure, continue with other worktrees |
528
529
  | `--full` in multi-worktree mode | Applies to all worktrees (global modifier) |
529
- | Many worktrees (5+) | Report count and proceed — user manages their worktree count |
530
530
  | Review comment already posted | Git agent matches its own marker on the `{cycle, timestamp}` pair → skip silently (D7); a re-review in the same cycle (different timestamp) posts its own comment. The marker's format belongs to the operation; this caller passes the pair and never restates the literal |
531
- | First review (no prior resolution) | PRIOR_RESOLUTIONS=(none), no convergence check |
532
- | fp_ratio denominator = 0 | fp_ratio = 0, no warning |
533
- | `--full` flag | Bypass incremental detection (Step 0d), still load PRIOR_RESOLUTIONS for cross-cycle awareness |
534
- | Parsing failure on resolution-summary.md | fp_ratio = 0, convergence tracking degraded (see Step 0e-ii) |
535
531
  | Concurrent sessions | Advisory only, each session computes independently |
536
532
  | Docs-only diff | `docs-only`: documentation, consistency, security on `diff.patch`; no language or conditional focus |
537
533
  | Tests-only diff | `tests-only`: testing, reliability, consistency, security on `diff.patch`; no language or conditional focus |
@@ -42,23 +42,31 @@ Accept the output only when it is exactly two lines: `exit=0` last and, before i
42
42
 
43
43
  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.
44
44
 
45
+ From the same line: `COMPLIANCE_FRAMEWORKS` is the settings line's `COMPLIANCE` with `generic` written `none`: `off`, `none`, or the framework ids the machine and this repository declare.
46
+
47
+ **Set the compliance directive** from `COMPLIANCE_FRAMEWORKS`. `COMPLIANCE_DIRECTIVE` is empty when `COMPLIANCE_FRAMEWORKS` is `off`: a spawn line that holds only `{COMPLIANCE_DIRECTIVE}` is then left out, so a lens-off spawn carries nothing about compliance. Otherwise `COMPLIANCE_DIRECTIVE` is this one line, with `<ids>` replaced by the value of `COMPLIANCE_FRAMEWORKS`:
48
+
49
+ > When the task touches regulated surface (data models, auth flows, logging/observability, payments, IaC, retention), 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.
50
+
51
+ Phase 7 passes `COMPLIANCE_DIRECTIVE` to the Code agent that implements the fix, on a line of its own.
52
+
45
53
  ### Load DECISIONS_CONTEXT
46
54
 
47
55
  When the settings line says `LEARNING=off`, set `DECISIONS_CONTEXT` to `(none)` and skip this step, locating no ledger and reading no index.
48
56
 
49
- 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`):
57
+ 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`):
50
58
 
51
59
  ```bash
52
60
  git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
53
61
  ```
54
62
 
55
- Line 1 is the checkout's toplevel, line 2 the repository's common git directory. A git older than 2.31 echoes `--path-format=absolute` back as a line of its own first. `{ledger}` is the first of these that applies:
63
+ 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:
56
64
 
57
65
  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.
58
66
  2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
59
67
  3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
60
68
 
61
- This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT), so you read the index the Learning agent writes.
69
+ This is the rule the learning hooks apply, so you read the index the Curate agent writes.
62
70
 
63
71
  **Step 1 — Read the pre-rendered index:**
64
72
 
@@ -67,11 +75,15 @@ Attempt to read `{ledger}/.devflow/learning/index.md`.
67
75
  - If the file exists and contains non-empty content: use that content as `DECISIONS_CONTEXT`.
68
76
  - If the file is absent or empty: set `DECISIONS_CONTEXT` to `(none)`.
69
77
 
70
- The index is one direct file read, written at render time by `render-decisions.cjs` alongside `decisions.md`/`pitfalls.md` — no `.cjs` script runs here, and the index's own footer names the files that hold each entry's full body.
78
+ The index is one direct file read, written at render time by `render-decisions.cjs` — no `.cjs` script runs here.
79
+
80
+ **Step 2 — Slice the index, then hand it on:**
71
81
 
72
- **Step 2 — Apply decisions using `devflow:apply-decisions`:**
82
+ When `DECISIONS_CONTEXT` is not `(none)`, hand it only to the agents whose contract declares it.
73
83
 
74
- When `DECISIONS_CONTEXT` is not `(none)`, follow `devflow:apply-decisions` to scan the index, identify plausibly-relevant entries, Read full entry bodies on demand, and cite verbatim IDs in downstream agent prompts and reasoning.
84
+ 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.
85
+
86
+ Those agents follow `devflow:apply-decisions`. A host that uses the index in its own thread says so in its own step.
75
87
 
76
88
  The orchestrator uses `DECISIONS_CONTEXT` locally when generating hypotheses (Phase 2) — prior pitfalls and decisions can suggest specific root causes to investigate. Follow `devflow:apply-decisions` to Read full entry bodies on demand. **Do NOT pass `DECISIONS_CONTEXT` to Explore investigators** — decisions context stays in the orchestrator; investigators examine code directly.
77
89
 
@@ -226,7 +238,20 @@ Produce the final report:
226
238
 
227
239
  Ask user via AskUserQuestion: "Want me to implement this fix?"
228
240
 
229
- - **YES** → Load `devflow:patterns` and `devflow:test-driven-development` skills, implement the fix, then spawn `Agent(subagent_type="Simplify")` on changed files.
241
+ - **YES** → implement the fix through the Code agent, never in this thread, then spawn `Agent(subagent_type="Polish")` on the changed files. /debug loads no feature knowledge, so the fix gets none:
242
+
243
+ ```
244
+ Agent(subagent_type="Code"):
245
+ "OPERATION: implement
246
+ TASK_ID: debug-{YYYY-MM-DD_HHMM}
247
+ TASK_DESCRIPTION: Implement the fix for this root cause: {bug description}
248
+ EXECUTION_PLAN: {Root Cause, Key Findings and Recommended Fix from Phase 6, with their file:line references}
249
+ PUSH: false
250
+ DECISIONS_CONTEXT: {decisions_context}
251
+ FEATURE_KNOWLEDGE: (none)
252
+ {COMPLIANCE_DIRECTIVE}"
253
+ ```
254
+
230
255
  - **NO** → Done. Report stands as documentation.
231
256
 
232
257
  ### Feature Knowledge Write-Back (Conditional)
@@ -261,21 +286,17 @@ FEATURE_SLUG: {slug derived from primary changed directory, kebab-case}
261
286
  FEATURE_NAME: {human-readable name}
262
287
  DIRECTORIES: {list of primary directories touched by this workflow}
263
288
  FILES_CHANGED: {list of files changed}
264
- DECISIONS_CONTEXT: {DECISIONS_CONTEXT if available, else (none)}
289
+ DECISIONS_CONTEXT: {the slice for these directories, else (none)}
265
290
 
266
291
  Write the knowledge base to:
267
292
  {worktree}/.devflow/features/{slug}/KNOWLEDGE.md
268
293
 
269
- Then update the index cache by performing a read-modify-write on:
294
+ Then update the index cache:
270
295
  {worktree}/.devflow/features/index.md
271
296
 
272
297
  Index line format: `- **{slug}** — {areas} — {Use-when description}` — at most 300 characters, the description at most 220; reword a longer one, never cut it.
273
298
 
274
- 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.
275
-
276
- The frontmatter in KNOWLEDGE.md is the source of truth — index.md is only a cache. Write the two files directly — no intermediate result JSON files, no external scripts.
277
-
278
- After writing, commit the two files to the current worktree branch yourself by running git via your Bash tool (do not use a script). Stage ONLY .devflow/features/index.md and .devflow/features/{slug}/KNOWLEDGE.md, then commit just those paths with a docs(knowledge): message. Do NOT push, do NOT force, do NOT stage anything else. Follow your Commit Protocol — it is non-blocking, so if any git step fails, report KB_COMMIT and finish normally."
299
+ Then commit the two files as your Commit Protocol directs."
279
300
  ```
280
301
 
281
302
  **Step 4 — Surface an uncommitted knowledge base:**
@@ -307,7 +328,7 @@ When the Knowledge agent reports `KB_COMMIT: skipped (detached HEAD)`, the files
307
328
  ├─ Phase 6: Root cause report with confidence level
308
329
  │
309
330
  ├─ Phase 7: Offer Fix
310
- │ └─ AskUserQuestion → implement fix + Simplify agent, or done
331
+ │ └─ AskUserQuestion → Code agent (fix) + Polish agent, or done
311
332
  │
312
333
  └─ Feature Knowledge Write-Back (Conditional)
313
334
  └─ Knowledge agent (if investigation surfaced durable cross-cutting knowledge)