devflow-kit 3.7.0 → 3.8.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 (184) hide show
  1. package/CHANGELOG.md +359 -1
  2. package/README.md +11 -11
  3. package/dist/agents/code.md +2 -4
  4. package/dist/agents/design.md +1 -1
  5. package/dist/agents/fix.md +6 -7
  6. package/dist/agents/git.md +1 -1
  7. package/dist/agents/harden.md +1 -1
  8. package/dist/agents/refactor.md +2 -4
  9. package/dist/agents/review.md +4 -4
  10. package/dist/agents/skim.md +2 -2
  11. package/dist/agents/triage.md +2 -2
  12. package/dist/cli/commands/capture.js +1 -1
  13. package/dist/cli/commands/curation-move-io.js +102 -0
  14. package/dist/cli/commands/curation-move-step.js +374 -0
  15. package/dist/cli/commands/{learning.js → curation.js} +302 -99
  16. package/dist/cli/commands/gate-level-prompts.js +426 -0
  17. package/dist/cli/commands/gates.js +34 -11
  18. package/dist/cli/commands/init-seed.js +11 -8
  19. package/dist/cli/commands/init.js +240 -54
  20. package/dist/cli/commands/memory.js +2 -2
  21. package/dist/cli/commands/prompt-io.js +37 -0
  22. package/dist/cli/commands/uninstall.js +81 -9
  23. package/dist/cli.js +2 -2
  24. package/dist/commands/bug-analysis.md +24 -35
  25. package/dist/commands/code-review.md +32 -36
  26. package/dist/commands/debug.md +4 -4
  27. package/dist/commands/dynamic-build.md +25 -24
  28. package/dist/commands/dynamic-plan.md +4 -4
  29. package/dist/commands/dynamic-profile.md +4 -4
  30. package/dist/commands/dynamic-tickets.md +4 -4
  31. package/dist/commands/explore.md +5 -5
  32. package/dist/commands/implement.md +52 -81
  33. package/dist/commands/plan.md +5 -5
  34. package/dist/commands/release.md +4 -4
  35. package/dist/commands/research.md +5 -5
  36. package/dist/commands/resolve.md +28 -30
  37. package/dist/commands/self-review.md +4 -12
  38. package/dist/core/assets.js +20 -20
  39. package/dist/core/curate-tuning-config.js +5 -6
  40. package/dist/core/curation-move-notice.js +84 -0
  41. package/dist/core/curation-move-skip.js +36 -0
  42. package/dist/core/curation-move.js +35 -0
  43. package/dist/core/curation-queue-cleanup.js +134 -0
  44. package/dist/core/curation-store.js +98 -0
  45. package/dist/core/{learning-variants.js → curation-variants.js} +65 -41
  46. package/dist/core/echo-value.js +11 -5
  47. package/dist/core/evidence-policy.js +1 -1
  48. package/dist/core/feature-switch.js +95 -19
  49. package/dist/core/fs-atomic.js +1 -1
  50. package/dist/core/gate-level.js +10 -2
  51. package/dist/core/git.js +16 -14
  52. package/dist/core/ledger-root.js +82 -22
  53. package/dist/core/linked-path.js +4 -4
  54. package/dist/core/manifest-lock.js +238 -0
  55. package/dist/core/manifest.js +58 -14
  56. package/dist/core/migrations.js +1 -13
  57. package/dist/core/observations.js +2 -2
  58. package/dist/core/plugins.js +15 -15
  59. package/dist/core/pool.js +26 -0
  60. package/dist/core/project-paths.js +103 -34
  61. package/dist/core/queue-drain.js +2 -2
  62. package/dist/core/tracked-areas.js +35 -0
  63. package/dist/core/tracker.js +1 -1
  64. package/dist/{learning-off → curation-off}/agents/code.md +2 -4
  65. package/dist/{learning-off → curation-off}/agents/fix.md +6 -7
  66. package/dist/{learning-off → curation-off}/agents/refactor.md +2 -4
  67. package/dist/{learning-off → curation-off}/agents/review.md +3 -3
  68. package/dist/{learning-off → curation-off}/agents/triage.md +1 -1
  69. package/dist/{learning-off → curation-off}/commands/bug-analysis.md +20 -31
  70. package/dist/{learning-off → curation-off}/commands/code-review.md +29 -33
  71. package/dist/{learning-off → curation-off}/commands/debug.md +1 -1
  72. package/dist/{learning-off → curation-off}/commands/dynamic-build.md +22 -21
  73. package/dist/{learning-off → curation-off}/commands/explore.md +1 -1
  74. package/dist/{learning-off → curation-off}/commands/implement.md +49 -78
  75. package/dist/{learning-off → curation-off}/commands/plan.md +1 -1
  76. package/dist/{learning-off → curation-off}/commands/resolve.md +25 -27
  77. package/dist/{learning-off → curation-off}/commands/self-review.md +1 -9
  78. package/dist/hud/components/{learning-counts.js → curation-counts.js} +36 -17
  79. package/dist/hud/config.js +1 -1
  80. package/dist/hud/index.js +6 -6
  81. package/dist/hud/render.js +3 -3
  82. package/dist/skills/git/references/pr/validate-branch.md +8 -5
  83. package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +13 -5
  84. package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +13 -5
  85. package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +13 -5
  86. package/dist/targets/claude-code/{learning-install.js → curation-install.js} +85 -65
  87. package/dist/targets/claude-code/installer.js +15 -15
  88. package/dist/targets/claude-code/language-stamp.js +5 -5
  89. package/dist/targets/claude-code/post-install.js +2 -2
  90. package/dist/targets/claude-code/tracker-servers.js +1 -1
  91. package/package.json +3 -2
  92. package/src/assets/agents/_partials/_code.mds +11 -11
  93. package/src/assets/agents/code.mds +2 -2
  94. package/src/assets/agents/curate.md +8 -8
  95. package/src/assets/agents/debug.mds +6 -6
  96. package/src/assets/agents/design.mds +18 -18
  97. package/src/assets/agents/fix.mds +6 -5
  98. package/src/assets/agents/git.mds +1 -1
  99. package/src/assets/agents/harden.mds +7 -7
  100. package/src/assets/agents/knowledge.mds +23 -23
  101. package/src/assets/agents/refactor.mds +2 -2
  102. package/src/assets/agents/research.mds +15 -15
  103. package/src/assets/agents/review.mds +43 -43
  104. package/src/assets/agents/skim.mds +11 -11
  105. package/src/assets/agents/triage.mds +22 -22
  106. package/src/assets/agents/validate.md +13 -26
  107. package/src/assets/commands/_partials/_decisions.mds +13 -13
  108. package/src/assets/commands/_partials/_engine.mds +8 -8
  109. package/src/assets/commands/_partials/_knowledge.mds +29 -15
  110. package/src/assets/commands/_partials/_preamble.mds +4 -4
  111. package/src/assets/commands/_partials/_settings.mds +2 -2
  112. package/src/assets/commands/_partials/_wave.mds +7 -7
  113. package/src/assets/commands/bug-analysis.mds +37 -48
  114. package/src/assets/commands/code-review.mds +46 -50
  115. package/src/assets/commands/debug.mds +14 -14
  116. package/src/assets/commands/dynamic-build.mds +38 -37
  117. package/src/assets/commands/dynamic-plan.mds +22 -22
  118. package/src/assets/commands/dynamic-profile.mds +2 -2
  119. package/src/assets/commands/dynamic-tickets.mds +8 -8
  120. package/src/assets/commands/explore.mds +20 -20
  121. package/src/assets/commands/implement.mds +77 -98
  122. package/src/assets/commands/plan.mds +27 -27
  123. package/src/assets/commands/release.mds +12 -12
  124. package/src/assets/commands/research.mds +19 -19
  125. package/src/assets/commands/resolve.mds +56 -50
  126. package/src/assets/commands/self-review.mds +20 -20
  127. package/src/assets/mds/git/_ops.mds +3 -1
  128. package/src/assets/mds/git/_ops_pr.mds +1 -1
  129. package/src/assets/mds/git/_ops_steps.mds +10 -4
  130. package/src/assets/mds/git/_pr.mds +7 -4
  131. package/src/assets/rules/quality.md +1 -0
  132. package/src/assets/scripts/hooks/background-memory-update +2 -2
  133. package/src/assets/scripts/hooks/capture-prompt +12 -12
  134. package/src/assets/scripts/hooks/capture-question +11 -11
  135. package/src/assets/scripts/hooks/capture-turn +12 -12
  136. package/src/assets/scripts/hooks/{learning-lock → curation-lock} +2 -2
  137. package/src/assets/scripts/hooks/curation-move +293 -0
  138. package/src/assets/scripts/hooks/ensure-devflow-init +45 -13
  139. package/src/assets/scripts/hooks/ensure-proxy +4 -4
  140. package/src/assets/scripts/hooks/ensure-root-gitignore +4 -4
  141. package/src/assets/scripts/hooks/git-marker +81 -0
  142. package/src/assets/scripts/hooks/json-helper.cjs +134 -51
  143. package/src/assets/scripts/hooks/json-parse +1 -1
  144. package/src/assets/scripts/hooks/lib/curation-move.cjs +1582 -0
  145. package/src/assets/scripts/hooks/lib/{learning-store.cjs → curation-store.cjs} +242 -118
  146. package/src/assets/scripts/hooks/lib/decisions-format.cjs +3 -3
  147. package/src/assets/scripts/hooks/lib/mkdir-lock.cjs +24 -7
  148. package/src/assets/scripts/hooks/lib/project-paths.cjs +132 -39
  149. package/src/assets/scripts/hooks/lib/render-decisions.cjs +34 -22
  150. package/src/assets/scripts/hooks/lib/tracked-areas.cjs +259 -0
  151. package/src/assets/scripts/hooks/memory-worker +1 -1
  152. package/src/assets/scripts/hooks/pre-compact-memory +6 -16
  153. package/src/assets/scripts/hooks/queue-append +228 -103
  154. package/src/assets/scripts/hooks/resolve-project-root +2 -2
  155. package/src/assets/scripts/hooks/session-start-context +143 -69
  156. package/src/assets/scripts/hooks/session-start-memory +3 -43
  157. package/src/assets/scripts/lib/project-config.cjs +12 -5
  158. package/src/assets/scripts/resolve-base.cjs +1043 -0
  159. package/src/assets/scripts/resolve-settings.cjs +42 -18
  160. package/src/assets/skills/agent-references/SKILL.md +5 -2
  161. package/src/assets/skills/agent-references/references/commands/implement-levels.md +27 -0
  162. package/src/assets/skills/agent-references/references/commands/implement-revalidate.md +6 -4
  163. package/src/assets/skills/agent-references/references/commands/resolve-levels.md +24 -0
  164. package/src/assets/skills/apply-decisions/SKILL.md +1 -1
  165. package/src/assets/skills/docs-framework/SKILL.md +7 -7
  166. package/src/assets/skills/docs-framework/references/patterns.md +3 -4
  167. package/src/assets/skills/quality-gates/SKILL.md +1 -1
  168. package/src/assets/skills/worktree-support/references/roots.md +2 -2
  169. package/templates/lint-pack/.lint-pack.conf +86 -0
  170. package/templates/lint-pack/README.md +190 -0
  171. package/templates/lint-pack/lint-pack.sh +905 -0
  172. package/dist/core/learning-queue-cleanup.js +0 -27
  173. package/dist/core/learning-store.js +0 -61
  174. /package/dist/{learning-off → curation-off}/agents/debug.md +0 -0
  175. /package/dist/{learning-off → curation-off}/agents/design.md +0 -0
  176. /package/dist/{learning-off → curation-off}/agents/harden.md +0 -0
  177. /package/dist/{learning-off → curation-off}/agents/knowledge.md +0 -0
  178. /package/dist/{learning-off → curation-off}/agents/research.md +0 -0
  179. /package/dist/{learning-off → curation-off}/agents/skim.md +0 -0
  180. /package/dist/{learning-off → curation-off}/commands/dynamic-plan.md +0 -0
  181. /package/dist/{learning-off → curation-off}/commands/dynamic-profile.md +0 -0
  182. /package/dist/{learning-off → curation-off}/commands/dynamic-tickets.md +0 -0
  183. /package/dist/{learning-off → curation-off}/commands/release.md +0 -0
  184. /package/dist/{learning-off → curation-off}/commands/research.md +0 -0
@@ -1,26 +1,26 @@
1
1
  /**
2
- * Learning-variant installer for the Claude Code target.
2
+ * Curation-variant installer for the Claude Code target.
3
3
  *
4
- * D-LEARNING-VARIANT-INSTALL: the install follows the machine's learning switch
5
- * (`features.learning` in ~/.devflow/manifest.json) and nothing else. When the
6
- * switch is off, every command and agent that has a learning-off variant
7
- * (dist/learning-off/{commands,agents}, built by D-LEARNING-VARIANTS) is installed
4
+ * D-LEARNING-VARIANT-INSTALL: the install follows the machine's curation switch
5
+ * (`features.curation` in ~/.devflow/manifest.json) and nothing else. When the
6
+ * switch is off, every command and agent that has a curation-off variant
7
+ * (dist/curation-off/{commands,agents}, built by D-LEARNING-VARIANTS) is installed
8
8
  * from it, and the apply-decisions skill is not installed, so the decisions text
9
9
  * reaches no prompt and the skill has no reader. When the switch is on, the
10
- * learning-on files and the skill are installed. Three pieces carry it:
10
+ * curation-on files and the skill are installed. Three pieces carry it:
11
11
  *
12
12
  * - the source order (src/core/assets.ts commandSourceDirs / agentSourceDirs):
13
- * with learning off the learning-off directory is consulted first, then the
13
+ * with curation off the curation-off directory is consulted first, then the
14
14
  * normal order, so a host with no arm installs its one file as before;
15
- * - the skill condition (LEARNING_GATED_SKILLS in src/core/plugins.ts):
16
- * installViaFileCopy leaves the skill out when learning is off;
17
- * - {@link convergeLearningVariants}, below: the converge that makes an
15
+ * - the skill condition (CURATION_GATED_SKILLS in src/core/plugins.ts):
16
+ * installViaFileCopy leaves the skill out when curation is off;
17
+ * - {@link convergeCurationVariants}, below: the converge that makes an
18
18
  * ALREADY-installed tree match the switch, run by `devflow init` after the
19
- * file copy and by `devflow learning --enable/--disable` after the switch is
20
- * written ({@link applyLearningToggle}).
19
+ * file copy and by `devflow curation --enable/--disable` after the switch is
20
+ * written ({@link applyCurationToggle}).
21
21
  *
22
22
  * The converge, decided in turn:
23
- * - Its roster is the files that exist under dist/learning-off, not a list typed
23
+ * - Its roster is the files that exist under dist/curation-off, not a list typed
24
24
  * here: the build owns which hosts have an arm, so a new arm is converged with
25
25
  * no edit to this file.
26
26
  * - It rewrites only files that are ALREADY installed. A `--plugin` install
@@ -42,34 +42,34 @@
42
42
  * the skill is resolved through the installer's own resolveSkillSource. Only
43
43
  * skills and rules have shadows; commands and agents have none, so there is
44
44
  * nothing for an off variant to collide with. A shadow of apply-decisions
45
- * under learning off is DORMANT in the same sense as one for a deselected
45
+ * under curation off is DORMANT in the same sense as one for a deselected
46
46
  * skill: kept in ~/.devflow/skills, never installed, never deleted, and
47
- * applied again the moment learning comes back on.
47
+ * applied again the moment curation comes back on.
48
48
  * - Version skew: the variants in this package were built with this version.
49
49
  * When the manifest records another version, the installed files are not the
50
- * ones this package would rewrite, so {@link applyLearningToggle} skips the
50
+ * ones this package would rewrite, so {@link applyCurationToggle} skips the
51
51
  * converge and says to run `devflow init`.
52
52
  * - An agent's installed `model:` and `effort:` are carried into the variant before
53
53
  * the byte comparison (D-AGENT-OVERRIDE-CARRY, see {@link withInstalledState}),
54
54
  * so the overrides `devflow agents` and the proxy put there are never written
55
55
  * back to the shipped values and a no-op converge writes no agent.
56
- * {@link applyLearningToggle} still runs reapplyAgentMapping straight after a
56
+ * {@link applyCurationToggle} still runs reapplyAgentMapping straight after a
57
57
  * converge that rewrote an agent: it reads agent-models.json and is the authority.
58
58
  *
59
59
  * D-LEARNING-PRELOAD-MACHINE-ONLY (amended): the apply-decisions preload follows
60
60
  * the machine switch only, never a repository's narrowing, because a repository
61
- * can narrow learning off on a machine where it is on and the installed agents are
62
- * machine-wide. Met by the variant: the learning-off agent files do not preload
63
- * the skill (no install-time frontmatter rewrite exists), and the learning-on files
61
+ * can narrow curation off on a machine where it is on and the installed agents are
62
+ * machine-wide. Met by the variant: the curation-off agent files do not preload
63
+ * the skill (no install-time frontmatter rewrite exists), and the curation-on files
64
64
  * keep the preload and their run-time gate for a narrowed repository. A repo
65
- * `project.json` with `learning: false` on a learning-on machine therefore changes
65
+ * `project.json` with `curation: false` on a curation-on machine therefore changes
66
66
  * nothing installed.
67
67
  *
68
68
  * I/O orchestration in src/targets/; the pure selection rules stay in src/core/.
69
69
  */
70
70
  import { promises as fs } from 'fs';
71
71
  import * as path from 'path';
72
- import { agentSourceDirs, commandSourceDirs, learningOffDir, } from '../../core/assets.js';
72
+ import { agentSourceDirs, commandSourceDirs, curationOffDir, } from '../../core/assets.js';
73
73
  import { carryStampedTools } from '../../core/agent-frontmatter.js';
74
74
  import { carryAgentOverrides, reapplyAgentMapping } from '../../core/agent-models.js';
75
75
  import { describeEchoedValue } from '../../core/echo-value.js';
@@ -77,7 +77,7 @@ import { writeFileAtomicExclusive } from '../../core/fs-atomic.js';
77
77
  import { readManifest } from '../../core/manifest.js';
78
78
  import { getPackageRoot } from '../../core/paths.js';
79
79
  import { isProxyEnabled } from '../../core/proxy-state.js';
80
- import { DEVFLOW_PLUGINS, LEARNING_GATED_SKILLS, installedLanguageFocuses, prefixSkillName, skillsOf, } from '../../core/plugins.js';
80
+ import { DEVFLOW_PLUGINS, CURATION_GATED_SKILLS, installedLanguageFocuses, prefixSkillName, skillsOf, } from '../../core/plugins.js';
81
81
  import { copyDirectory, resolveSkillSource } from './installer.js';
82
82
  import { LANGUAGE_STAMPED_COMMANDS, stampForConverge } from './language-stamp.js';
83
83
  // ── Bounds ─────────────────────────────────────────────────────────────────
@@ -86,7 +86,7 @@ import { LANGUAGE_STAMPED_COMMANDS, stampForConverge } from './language-stamp.js
86
86
  * 9 agents; the bound exists so a directory that grew without limit cannot turn the
87
87
  * converge into an unbounded loop (every loop has an explicit bound).
88
88
  */
89
- export const MAX_LEARNING_ROSTER = 256;
89
+ export const MAX_CURATION_ROSTER = 256;
90
90
  /** Deepest skill-directory descent the tree comparison takes. */
91
91
  const MAX_SKILL_TREE_DEPTH = 4;
92
92
  /** A roster entry is a flat, lowercase, hyphenated markdown basename. */
@@ -96,12 +96,12 @@ const KINDS = ['commands', 'agents'];
96
96
  function installedFile(claudeDir, kind, fileName) {
97
97
  return path.join(claudeDir, kind, 'devflow', fileName);
98
98
  }
99
- /** The learning-ON source directories for a kind, most-preferred first. */
99
+ /** The curation-ON source directories for a kind, most-preferred first. */
100
100
  function onSourceDirs(kind, root) {
101
101
  return kind === 'commands' ? commandSourceDirs(true, root) : agentSourceDirs(root, true);
102
102
  }
103
103
  /**
104
- * The roster of one kind: the `.md` files under dist/learning-off/<kind>, sorted.
104
+ * The roster of one kind: the `.md` files under dist/curation-off/<kind>, sorted.
105
105
  *
106
106
  * `present` is false when the directory does not exist (the build has not run, or
107
107
  * only `build:cli` did), so the caller can say so instead of reporting a converge
@@ -110,18 +110,18 @@ function onSourceDirs(kind, root) {
110
110
  async function readRoster(kind, root, warn) {
111
111
  let entries;
112
112
  try {
113
- entries = await fs.readdir(learningOffDir(kind, root));
113
+ entries = await fs.readdir(curationOffDir(kind, root));
114
114
  }
115
115
  catch (err) {
116
116
  if (err.code === 'ENOENT')
117
117
  return { names: [], present: false };
118
- warn(`learning variants: cannot read the ${kind} variants — ${String(err)}`);
118
+ warn(`curation variants: cannot read the ${kind} variants — ${String(err)}`);
119
119
  return { names: [], present: false };
120
120
  }
121
121
  const names = entries.filter(entry => ROSTER_NAME_RE.test(entry)).sort();
122
- if (names.length > MAX_LEARNING_ROSTER) {
123
- warn(`learning variants: ${names.length} ${kind} variants exceed the bound of ${MAX_LEARNING_ROSTER}; converging the first ${MAX_LEARNING_ROSTER}`);
124
- return { names: names.slice(0, MAX_LEARNING_ROSTER), present: true };
122
+ if (names.length > MAX_CURATION_ROSTER) {
123
+ warn(`curation variants: ${names.length} ${kind} variants exceed the bound of ${MAX_CURATION_ROSTER}; converging the first ${MAX_CURATION_ROSTER}`);
124
+ return { names: names.slice(0, MAX_CURATION_ROSTER), present: true };
125
125
  }
126
126
  return { names, present: true };
127
127
  }
@@ -189,23 +189,23 @@ function withInstalledState(kind, fileName, source, installed, focuses) {
189
189
  * file is still tried.
190
190
  */
191
191
  async function convergeFile(kind, fileName, opts) {
192
- const { claudeDir, learning, warn, root, focuses } = opts;
192
+ const { claudeDir, curation, warn, root, focuses } = opts;
193
193
  const target = installedFile(claudeDir, kind, fileName);
194
194
  const installed = await readIfPresent(target);
195
195
  if (installed === 'absent')
196
196
  return 'not-installed';
197
197
  if (installed === 'unreadable') {
198
- warn(`learning variants: cannot read the installed ${kind}/${fileName} (${target}) — left as it is`);
198
+ warn(`curation variants: cannot read the installed ${kind}/${fileName} (${target}) — left as it is`);
199
199
  return 'failed';
200
200
  }
201
- // Learning off: the variant is the roster file itself. Learning on: the normal
202
- // source order, which is where the learning-on file of that host lives.
203
- const candidates = learning
201
+ // Curation off: the variant is the roster file itself. Curation on: the normal
202
+ // source order, which is where the curation-on file of that host lives.
203
+ const candidates = curation
204
204
  ? onSourceDirs(kind, root).map(dir => path.join(dir, fileName))
205
- : [path.join(learningOffDir(kind, root), fileName)];
205
+ : [path.join(curationOffDir(kind, root), fileName)];
206
206
  const source = await firstReadable(candidates);
207
207
  if (source === undefined) {
208
- warn(`learning variants: no source for ${kind}/${fileName} (searched: ${candidates.join(', ')}) — left as it is`);
208
+ warn(`curation variants: no source for ${kind}/${fileName} (searched: ${candidates.join(', ')}) — left as it is`);
209
209
  return 'failed';
210
210
  }
211
211
  const wanted = withInstalledState(kind, fileName, source.bytes, installed, focuses);
@@ -219,7 +219,7 @@ async function convergeFile(kind, fileName, opts) {
219
219
  await writeFileAtomicExclusive(target, wanted.toString('utf-8'));
220
220
  }
221
221
  catch (err) {
222
- warn(`learning variants: could not rewrite ${kind}/${fileName} (${target}) — ${String(err)}`);
222
+ warn(`curation variants: could not rewrite ${kind}/${fileName} (${target}) — ${String(err)}`);
223
223
  return 'failed';
224
224
  }
225
225
  return 'rewritten';
@@ -288,7 +288,7 @@ async function pathExists(p) {
288
288
  * crash leaves behind must not look like a second skill to Claude Code.
289
289
  */
290
290
  async function swapInSkillDirectory(claudeDir, sourceDir, target) {
291
- const staging = path.join(claudeDir, `.devflow-learning-${process.pid}-${Date.now().toString(36)}.tmp`);
291
+ const staging = path.join(claudeDir, `.devflow-curation-${process.pid}-${Date.now().toString(36)}.tmp`);
292
292
  const backup = `${staging}.old`;
293
293
  try {
294
294
  await copyDirectory(sourceDir, staging);
@@ -310,16 +310,16 @@ async function swapInSkillDirectory(claudeDir, sourceDir, target) {
310
310
  await fs.rm(backup, { recursive: true, force: true }).catch(() => undefined);
311
311
  }
312
312
  }
313
- /** Converge the learning-gated skill directories. Never throws. */
313
+ /** Converge the curation-gated skill directories. Never throws. */
314
314
  async function convergeSkills(opts) {
315
- const { claudeDir, devflowDir, learning, plugins, warn } = opts;
315
+ const { claudeDir, devflowDir, curation, plugins, warn } = opts;
316
316
  const selected = skillsOf(plugins);
317
317
  let state = 'unchanged';
318
318
  // Every gated skill is converged: a failure on one must not skip the next.
319
- for (const skill of LEARNING_GATED_SKILLS) {
319
+ for (const skill of CURATION_GATED_SKILLS) {
320
320
  const target = path.join(claudeDir, 'skills', prefixSkillName(skill));
321
321
  try {
322
- if (!learning) {
322
+ if (!curation) {
323
323
  if (!(await pathExists(target)))
324
324
  continue;
325
325
  await fs.rm(target, { recursive: true });
@@ -338,7 +338,7 @@ async function convergeSkills(opts) {
338
338
  state = 'installed';
339
339
  }
340
340
  catch (err) {
341
- warn(`learning variants: could not converge the ${prefixSkillName(skill)} skill (${target}) — ${String(err)}`);
341
+ warn(`curation variants: could not converge the ${prefixSkillName(skill)} skill (${target}) — ${String(err)}`);
342
342
  state = 'failed';
343
343
  }
344
344
  }
@@ -347,21 +347,21 @@ async function convergeSkills(opts) {
347
347
  // ── Convergence ────────────────────────────────────────────────────────────
348
348
  /**
349
349
  * Make the installed commands, agents and apply-decisions skill match the
350
- * machine's learning switch.
350
+ * machine's curation switch.
351
351
  *
352
352
  * Never throws. A caller reads `converged`; it does not catch. A claudeDir that is
353
353
  * not absolute is reported the same way rather than thrown, because an install
354
354
  * must not die on it.
355
355
  */
356
- export async function convergeLearningVariants(opts) {
357
- const { claudeDir, learning, warn } = opts;
356
+ export async function convergeCurationVariants(opts) {
357
+ const { claudeDir, curation, warn } = opts;
358
358
  const empty = {
359
359
  converged: false, commandsRewritten: [], agentsRewritten: [], unchanged: 0, notInstalled: 0, skill: 'unchanged',
360
360
  };
361
361
  // Precondition, asserted in production code: a relative claudeDir would resolve
362
362
  // the install targets somewhere unexpected.
363
363
  if (!path.isAbsolute(claudeDir)) {
364
- warn(`learning variants: claudeDir is not an absolute path ("${claudeDir}") — skipping convergence`);
364
+ warn(`curation variants: claudeDir is not an absolute path ("${claudeDir}") — skipping convergence`);
365
365
  return empty;
366
366
  }
367
367
  const root = opts.packageRoot ?? getPackageRoot();
@@ -373,12 +373,12 @@ export async function convergeLearningVariants(opts) {
373
373
  for (const kind of KINDS) {
374
374
  const roster = await readRoster(kind, root, warn);
375
375
  if (!roster.present) {
376
- warn(`learning variants: no ${kind} variants under ${learningOffDir(kind, root)} — run \`npm run build:mds\`; installed ${kind} left as they are`);
376
+ warn(`curation variants: no ${kind} variants under ${curationOffDir(kind, root)} — run \`npm run build:mds\`; installed ${kind} left as they are`);
377
377
  failed = true;
378
378
  continue;
379
379
  }
380
380
  for (const fileName of roster.names) {
381
- const outcome = await convergeFile(kind, fileName, { claudeDir, learning, warn, root, focuses });
381
+ const outcome = await convergeFile(kind, fileName, { claudeDir, curation, warn, root, focuses });
382
382
  if (outcome === 'rewritten')
383
383
  rewritten[kind].push(fileName);
384
384
  else if (outcome === 'unchanged')
@@ -419,12 +419,12 @@ export async function readRunningVersion(packageRoot = getPackageRoot()) {
419
419
  *
420
420
  * The caller prints it only on a toggle: a run that moved nothing says nothing.
421
421
  */
422
- export function describeLearningConverge(result, learning) {
422
+ export function describeCurationConverge(result, curation) {
423
423
  const parts = [];
424
424
  const prompts = result.commandsRewritten.length + result.agentsRewritten.length;
425
425
  if (prompts > 0) {
426
426
  parts.push(`${result.commandsRewritten.length} command(s) and ${result.agentsRewritten.length} agent(s) ` +
427
- `rewritten for the learning-${learning ? 'on' : 'off'} variant`);
427
+ `rewritten for the curation-${curation ? 'on' : 'off'} variant`);
428
428
  }
429
429
  if (result.skill === 'installed')
430
430
  parts.push('the apply-decisions skill installed');
@@ -435,7 +435,7 @@ export function describeLearningConverge(result, learning) {
435
435
  /**
436
436
  * Whether the version the manifest records is the version of the running package.
437
437
  * Pure. An unknown running version (null) never matches: the installed files are then
438
- * not known to be the ones this package would write. Both callers, the learning
438
+ * not known to be the ones this package would write. Both callers, the curation
439
439
  * toggle and `init --hud-only`, ask this one question.
440
440
  */
441
441
  export function installedVersionMatches(installedVersion, runningVersion) {
@@ -447,14 +447,34 @@ export function installedVersionMatches(installedVersion, runningVersion) {
447
447
  * installed version is hand-editable file content, so it prints through
448
448
  * `describeEchoedValue`.
449
449
  */
450
- export function learningToggleSkew(installedVersion, runningVersion, learning) {
450
+ export function curationToggleSkew(installedVersion, runningVersion, curation) {
451
451
  if (installedVersionMatches(installedVersion, runningVersion))
452
452
  return null;
453
453
  return (`The installed prompts come from devflow ${describeEchoedValue(installedVersion)} and this CLI is ${runningVersion ?? 'of unknown version'}, ` +
454
- `so the learning-${learning ? 'on' : 'off'} variants were not applied. Run \`devflow init\` to apply them.`);
454
+ `so the curation-${curation ? 'on' : 'off'} variants were not applied. Run \`devflow init\` to apply them.`);
455
455
  }
456
456
  /**
457
- * What `devflow learning --enable/--disable` does after the switch is written:
457
+ * The version-skew line for a command that writes curation data, or null when the
458
+ * installed scripts are the ones this CLI would write. A hook of another version
459
+ * reads and creates a different ledger folder, so such a command writes nothing until
460
+ * `devflow init` has run. Apart from the toggle's own check (`curationToggleSkew`,
461
+ * which also names the prompt variants): this line is for configure and the other
462
+ * mutating subcommands. The installed version is hand-editable file content, so it
463
+ * prints through `describeEchoedValue`.
464
+ */
465
+ export async function installedScriptsSkew(devflowDir, packageRoot) {
466
+ const manifest = await readManifest(devflowDir);
467
+ if (manifest === null) {
468
+ return 'No readable install manifest, so the installed scripts are not known. Run `devflow init` first. Nothing was written.';
469
+ }
470
+ const running = await readRunningVersion(packageRoot);
471
+ if (installedVersionMatches(manifest.version, running))
472
+ return null;
473
+ return (`The installed scripts come from devflow ${describeEchoedValue(manifest.version)} and this CLI is ` +
474
+ `${running ?? 'of unknown version'}. Run \`devflow init\` first. Nothing was written.`);
475
+ }
476
+ /**
477
+ * What `devflow curation --enable/--disable` does after the switch is written:
458
478
  * converge the installed tree onto the new value, then reapply the saved agent
459
479
  * model and effort mapping.
460
480
  *
@@ -467,24 +487,24 @@ export function learningToggleSkew(installedVersion, runningVersion, learning) {
467
487
  *
468
488
  * Never throws.
469
489
  */
470
- export async function applyLearningToggle(opts) {
471
- const { claudeDir, devflowDir, learning, runningVersion, warn } = opts;
490
+ export async function applyCurationToggle(opts) {
491
+ const { claudeDir, devflowDir, curation, runningVersion, warn } = opts;
472
492
  const manifest = await readManifest(devflowDir);
473
493
  if (manifest === null) {
474
494
  return {
475
495
  kind: 'skipped',
476
496
  reason: 'no-manifest',
477
- message: 'No readable install manifest, so the learning variants were not applied. Run `devflow init`.',
497
+ message: 'No readable install manifest, so the curation variants were not applied. Run `devflow init`.',
478
498
  };
479
499
  }
480
- const skew = learningToggleSkew(manifest.version, runningVersion, learning);
500
+ const skew = curationToggleSkew(manifest.version, runningVersion, curation);
481
501
  if (skew !== null)
482
502
  return { kind: 'skipped', reason: 'version-skew', message: skew };
483
503
  const selection = new Set(manifest.plugins);
484
- const result = await convergeLearningVariants({
504
+ const result = await convergeCurationVariants({
485
505
  claudeDir,
486
506
  devflowDir,
487
- learning,
507
+ curation,
488
508
  plugins: DEVFLOW_PLUGINS.filter(plugin => selection.has(plugin.name)),
489
509
  warn,
490
510
  packageRoot: opts.packageRoot,
@@ -501,9 +521,9 @@ export async function applyLearningToggle(opts) {
501
521
  agentMappingReapplied = true;
502
522
  }
503
523
  catch (err) {
504
- warn(`learning variants: could not reapply the agent model mapping — ${String(err)}`);
524
+ warn(`curation variants: could not reapply the agent model mapping — ${String(err)}`);
505
525
  }
506
526
  }
507
527
  return { kind: 'converged', result, agentMappingReapplied };
508
528
  }
509
- //# sourceMappingURL=learning-install.js.map
529
+ //# sourceMappingURL=curation-install.js.map
@@ -1,7 +1,7 @@
1
1
  import { promises as fs } from 'fs';
2
2
  import { existsSync } from 'fs';
3
3
  import * as path from 'path';
4
- import { SKILL_NAMESPACE, buildAssetMaps, prefixSkillName, unprefixSkillName, getAllSkillNames, getAllAgentNames, getAllCommandNames, FEATURE_OWNED_SKILLS, resolveSkillInstallPlan, omitLearningGatedSkills } from '../../core/plugins.js';
4
+ import { SKILL_NAMESPACE, buildAssetMaps, prefixSkillName, unprefixSkillName, getAllSkillNames, getAllAgentNames, getAllCommandNames, FEATURE_OWNED_SKILLS, resolveSkillInstallPlan, omitCurationGatedSkills } from '../../core/plugins.js';
5
5
  import { skillsDir, agentSourceDirs, rulesDir, commandSourceDirs, scriptsDir, compiledSkillRefsDir } from '../../core/assets.js';
6
6
  import { getPackageRoot, isContainedIn } from '../../core/paths.js';
7
7
  import { sweepOrphanedAssets, mdFileName, mdEntryName } from '../../core/orphan-sweep.js';
@@ -1344,7 +1344,7 @@ async function firstExisting(candidates) {
1344
1344
  * installed in its place).
1345
1345
  *
1346
1346
  * The ONE spelling of that decision: the install loop and
1347
- * convergeLearningVariants both call it, so a skill the learning toggle installs
1347
+ * convergeCurationVariants both call it, so a skill the curation toggle installs
1348
1348
  * later is shadowed exactly as one the install installed.
1349
1349
  *
1350
1350
  * The shipped source is stat-checked FIRST, even under a valid shadow, so an
@@ -1438,8 +1438,8 @@ async function removeDeselectedSkills(skillsDir, names) {
1438
1438
  * the selective uninstall, which rewrites the files of the plugins that stay installed
1439
1439
  * after it removed a retired agent.
1440
1440
  *
1441
- * Commands come from dist/commands/{name}.md, or — with learning off — the learning-off
1442
- * variant dist/learning-off/commands/{name}.md when the host has one
1441
+ * Commands come from dist/commands/{name}.md, or — with curation off — the curation-off
1442
+ * variant dist/curation-off/commands/{name}.md when the host has one
1443
1443
  * (D-LEARNING-VARIANT-INSTALL; commandSourceDirs owns the order). A declared command
1444
1444
  * with no compiled source file is a hard error, not a skip.
1445
1445
  *
@@ -1458,9 +1458,9 @@ async function removeDeselectedSkills(skillsDir, names) {
1458
1458
  * known and leaves it alone.
1459
1459
  */
1460
1460
  export async function installCommandsAndAgents(opts) {
1461
- const { plugins, agentsMap, claudeDir, learning, trackerServers, warn } = opts;
1461
+ const { plugins, agentsMap, claudeDir, curation, trackerServers, warn } = opts;
1462
1462
  const commandsTarget = path.join(claudeDir, 'commands', 'devflow');
1463
- const commandDirs = commandSourceDirs(learning);
1463
+ const commandDirs = commandSourceDirs(curation);
1464
1464
  const commandsSourceNames = new Set();
1465
1465
  for (const plugin of plugins) {
1466
1466
  for (const cmd of plugin.commands) {
@@ -1473,8 +1473,8 @@ export async function installCommandsAndAgents(opts) {
1473
1473
  for (const name of commandsSourceNames) {
1474
1474
  const srcFile = await firstExisting(commandDirs.map(dir => path.join(dir, mdFileName(name))));
1475
1475
  if (srcFile === undefined) {
1476
- // The error names the learning-ON path: that file exists for every declared
1477
- // command, while a learning-off file exists only for a host with an arm.
1476
+ // The error names the curation-ON path: that file exists for every declared
1477
+ // command, while a curation-off file exists only for a host with an arm.
1478
1478
  throw new Error(`Command source not found for declared command "${name}": ${path.join(commandSourceDirs(true)[0], mdFileName(name))}. ` +
1479
1479
  `Ensure build:mds ran successfully before install.`);
1480
1480
  }
@@ -1482,8 +1482,8 @@ export async function installCommandsAndAgents(opts) {
1482
1482
  }
1483
1483
  }
1484
1484
  const agentsTarget = path.join(claudeDir, 'agents', 'devflow');
1485
- // Learning-aware (D-LEARNING-VARIANT-INSTALL). An injected list wins as given.
1486
- const agentDirs = opts.agentSourceDirs ?? agentSourceDirs(undefined, learning);
1485
+ // Curation-aware (D-LEARNING-VARIANT-INSTALL). An injected list wins as given.
1486
+ const agentDirs = opts.agentSourceDirs ?? agentSourceDirs(undefined, curation);
1487
1487
  const allAgentNames = new Set();
1488
1488
  for (const plugin of plugins) {
1489
1489
  for (const agent of plugin.agents) {
@@ -1524,7 +1524,7 @@ export async function installCommandsAndAgents(opts) {
1524
1524
  * Returns an InstallReport describing which shadows were applied and which were skipped.
1525
1525
  */
1526
1526
  export async function installViaFileCopy(options) {
1527
- const { plugins, claudeDir, devflowDir, skillsMap, agentsMap, rulesMap = new Map(), isPartialInstall, spinner, learning, trackerServers = TRACKER_MCP_SERVERS_DEFAULT, warn = () => { }, } = options;
1527
+ const { plugins, claudeDir, devflowDir, skillsMap, agentsMap, rulesMap = new Map(), isPartialInstall, spinner, curation, trackerServers = TRACKER_MCP_SERVERS_DEFAULT, warn = () => { }, } = options;
1528
1528
  const report = {
1529
1529
  shadowedSkills: [],
1530
1530
  shadowedRules: [],
@@ -1687,7 +1687,7 @@ export async function installViaFileCopy(options) {
1687
1687
  plugins: commandAgentPlugins,
1688
1688
  agentsMap: commandAgentMap,
1689
1689
  claudeDir,
1690
- learning,
1690
+ curation,
1691
1691
  trackerServers,
1692
1692
  agentSourceDirs: options.agentSourceDirs,
1693
1693
  warn,
@@ -1713,12 +1713,12 @@ export async function installViaFileCopy(options) {
1713
1713
  // A declared skill whose source directory is absent is a build/packaging failure
1714
1714
  // and throws rather than silently skipping (matches command pattern).
1715
1715
  //
1716
- // D-LEARNING-VARIANT-INSTALL: a learning-off machine skips the learning-gated
1716
+ // D-LEARNING-VARIANT-INSTALL: a curation-off machine skips the curation-gated
1717
1717
  // skills here. The pre-clean above walked the UNFILTERED map, so on a full
1718
1718
  // install a leftover copy is already gone; a partial install leaves removal to
1719
- // convergeLearningVariants, which init runs straight after this call.
1719
+ // convergeCurationVariants, which init runs straight after this call.
1720
1720
  spinner.message('Installing skills...');
1721
- for (const [skillName] of omitLearningGatedSkills(skillsMap, learning)) {
1721
+ for (const [skillName] of omitCurationGatedSkills(skillsMap, curation)) {
1722
1722
  const resolved = await resolveSkillSource(skillName, devflowDir);
1723
1723
  const skillTarget = path.join(claudeDir, 'skills', prefixSkillName(skillName));
1724
1724
  await copyDirectory(resolved.dir, skillTarget);
@@ -10,7 +10,7 @@
10
10
  * - The carrier is one line, `Installed language focuses: <list>`, shipped as `(none)` in
11
11
  * src/assets/commands/code-review.mds and found again by an anchored match, so a later run can
12
12
  * re-stamp a copy an earlier run stamped. It carries no MDS interpolation braces, and it sits outside
13
- * every learning arm, so both variants carry it. A separate stamped file would add a file to the
13
+ * every curation arm, so both variants carry it. A separate stamped file would add a file to the
14
14
  * install walk and the install goldens, which an in-place rewrite leaves unchanged.
15
15
  * - Only code-review.md carries it. /dynamic-build spawns every review focus and drops none (plan
16
16
  * decision 1), so it has no stamp, no reduced classes and no DIFF_FILE.
@@ -22,8 +22,8 @@
22
22
  * - `devflow uninstall --plugin` removes a language plugin's skill but no command, so its name would
23
23
  * stay in the stamped copy; the selective phase re-stamps from the plugins that remain, through
24
24
  * {@link restampInstalledCommands} like the install.
25
- * - Composition with the learning converge (D-LEARNING-VARIANT-INSTALL), pinned: the converge rewrites
26
- * installed command files from dist or dist/learning-off, and those files carry the shipped `(none)`
25
+ * - Composition with the curation converge (D-LEARNING-VARIANT-INSTALL), pinned: the converge rewrites
26
+ * installed command files from dist or dist/curation-off, and those files carry the shipped `(none)`
27
27
  * line. It therefore applies {@link carryLanguageStamp} inside its own write path, putting the stamp
28
28
  * it finds on the installed copy into the variant it writes ({@link stampForConverge}); a copy with no
29
29
  * list to carry, one installed before the stamp existed, is stamped from the converge's selection
@@ -83,7 +83,7 @@ export function applyLanguageStamp(content, focuses) {
83
83
  /**
84
84
  * `source` with its stamp line replaced by the one on `installed`.
85
85
  *
86
- * The learning converge's write path (see the header): the variant it installs keeps the list the
86
+ * The curation converge's write path (see the header): the variant it installs keeps the list the
87
87
  * install stamped. Returns `source` unchanged unless both sides hold exactly one stamp line and the
88
88
  * installed one is a well-formed list, so a damaged or hostile line is never copied into a fresh file.
89
89
  */
@@ -103,7 +103,7 @@ function carriableStampLine(installed) {
103
103
  return STAMP_VALUE_RE.test(from[0][0].slice(LANGUAGE_STAMP_PREFIX.length)) ? from[0][0] : null;
104
104
  }
105
105
  /**
106
- * The text the learning converge installs for a stamped command: `source` carrying the installed copy's
106
+ * The text the curation converge installs for a stamped command: `source` carrying the installed copy's
107
107
  * list ({@link carryLanguageStamp}) when the copy holds one, else `source` stamped with `focuses`, the
108
108
  * effective selection's list, exactly as the install stamps it.
109
109
  *
@@ -56,7 +56,7 @@ const DEVFLOW_POLICY_LINE = '!.devflow/policy.json';
56
56
  const DEVFLOW_PROJECT_LINE = '!.devflow/project.json';
57
57
  /**
58
58
  * The shared .devflow/ gitignore block. Everything under .devflow/ is local
59
- * (memory, learning, docs, locks) EXCEPT:
59
+ * (memory, curation, docs, locks) EXCEPT:
60
60
  * - Feature knowledge bases: index.md and every {slug}/KNOWLEDGE.md are tracked
61
61
  * + committed (the Knowledge agent commits them at workflow end).
62
62
  * - conventions.md: naming-convention authority written by the Git learn-conventions
@@ -78,7 +78,7 @@ const DEVFLOW_PROJECT_LINE = '!.devflow/project.json';
78
78
  * so the init-time path and the always-on hook path produce the same file.
79
79
  */
80
80
  const DEVFLOW_GITIGNORE_BLOCK_LINES = [
81
- '# Devflow runtime data — local by default (memory, learning, docs, locks).',
81
+ '# Devflow runtime data — local by default (memory, curation, docs, locks).',
82
82
  '# Shared via git: feature knowledge bases under .devflow/features/ (index.md and',
83
83
  '# every {slug}/KNOWLEDGE.md), .devflow/conventions.md (naming authority),',
84
84
  '# .devflow/policy.json (retired; presence only) and .devflow/project.json (team settings).',
@@ -17,7 +17,7 @@
17
17
  * a `--plugin` run that does not install Git leaves the installed, stamped copy alone.
18
18
  * 2. `convergeTrackerArtifacts` stamps Tracker as it writes it, and compares the STAMPED text
19
19
  * with the installed file, so a steady-state run reports `unchanged`.
20
- * 3. `convergeLearningVariants` (init, `devflow learning --enable/--disable`) carries the
20
+ * 3. `convergeCurationVariants` (init, `devflow curation --enable/--disable`) carries the
21
21
  * installed stamp onto the variant it writes (`carryStampedTools`), the way it carries
22
22
  * `model:` and `effort:`, so a variant switch keeps the list and a repeat run is byte-equal.
23
23
  * 4. `devflow tracker --servers` re-stamps the installed copies at once ({@link restampTrackerAgents}).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "devflow-kit",
3
- "version": "3.7.0",
4
- "description": "A meta-harness for Claude Code — turns a single coding agent into an engineering team: orchestration, parallel review, persistent memory, self-learning, and graph workflows",
3
+ "version": "3.8.0",
4
+ "description": "A meta-harness for Claude Code — turns a single coding agent into an engineering team: orchestration, parallel review, persistent memory, curated decisions, and graph workflows",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "devflow": "dist/cli.js"
@@ -12,6 +12,7 @@
12
12
  "!dist/**/*.d.ts",
13
13
  "src/assets/",
14
14
  "src/targets/claude-code/templates/",
15
+ "templates/lint-pack/",
15
16
  "README.md",
16
17
  "LICENSE",
17
18
  "CHANGELOG.md"
@@ -6,8 +6,10 @@ so the build skips it and it reaches an artifact only through the hosts that imp
6
6
  D-CODE-VARIANTS: a spawn runs exactly one mode, so one agent for every mode would pay for every
7
7
  mode's text and skills on every spawn. Each host carries its own mode sections, its own `OPERATION:`
8
8
  line and its own preload (D-CODE-PRELOADS); what every mode needs is written once here. The
9
- security-scan block lives in `commit_push()`, so every variant keeps it, and the Running
10
- commands block lives in `tail()`, so the three carry one byte-identical copy.
9
+ Commit and push line lives in `commit_push()`. It ends with one check of the staged diff of every
10
+ committed file for secrets or tokens in debug output, and the security-scan block follows it, so
11
+ every variant keeps both. The Running commands block lives in `tail()`, so the three carry one
12
+ byte-identical copy.
11
13
 
12
14
  D-NO-RUNTIME-SKILLS: no variant carries a mode-skill table, a `DOMAIN` input or an instruction
13
15
  to load a skill by language.
@@ -16,27 +18,27 @@ D-COMPLIANCE-INJECT: no variant names the compliance skill or takes a compliance
16
18
  injects the compliance directive into a spawn prompt only when the resolved lens is on, so a
17
19
  lens-off spawn pays nothing for it (the directive's home is `commands/_partials/_compliance.mds`).
18
20
 
19
- The hosts import this partial as an alias (`as code`) and call each define once. A learning arm
21
+ The hosts import this partial as an alias (`as code`) and call each define once. A curation arm
20
22
  inside a define is split by the build like an arm in a host: the markers sit on lines of their own.
21
23
 
22
24
  @define input_core():
23
- - **TASK_ID**: Unique identifier (e.g., "task-2025-01-15_1430")
25
+ - **TASK_ID**: Unique identifier
24
26
  - **TASK_DESCRIPTION**: What to do
25
27
  - **PUSH** (optional): `true` (default) | `false` — when false, commit only; orchestrator owns push/CI gate
26
- <!-- learning:on -->
28
+ <!-- curation:on -->
27
29
  - **DECISIONS_CONTEXT** (optional): Compact index of active ADR/PF entries.
28
30
  When provided, use `devflow:apply-decisions` to Read full bodies on demand.
29
- <!-- learning:end -->
31
+ <!-- curation:end -->
30
32
  @end
31
33
 
32
34
  @define decisions_orient():
33
- <!-- learning:on -->
35
+ <!-- curation:on -->
34
36
  - If `DECISIONS_CONTEXT` is provided, follow `devflow:apply-decisions` on it. An absent key or `(none)` means no decisions context. State every decision or pitfall you apply in words in code, comments, tests and commit messages, never by its ID.
35
- <!-- learning:end -->
37
+ <!-- curation:end -->
36
38
  @end
37
39
 
38
40
  @define commit_push():
39
- **Commit and push**: Create atomic commits with clear messages. Reference TASK_ID. Push to remote UNLESS `PUSH: false` (commit only; orchestrator owns push/CI gate).
41
+ **Commit and push**: Create atomic commits with clear messages. Reference TASK_ID. Push to remote UNLESS `PUSH: false`. Before you commit, check the staged diff of every file you commit: no secrets or tokens in logs or debug output.
40
42
  **Security scan (conditional):** Only when this session offers a code-scanning tool. Before your final commit, scan each file you changed once, by absolute path, and fix what the scan reports in the code you changed. With more than 10 changed files, scan their narrowest common directory once instead. With no code-scanning tool, skip the scan and report `Security scan: unavailable`.
41
43
  @end
42
44
 
@@ -64,8 +66,6 @@ Run builds, typechecks, lints and tests in the foreground, each with an explicit
64
66
 
65
67
  ## Output
66
68
 
67
- Return structured completion status:
68
-
69
69
  ```markdown
70
70
  ## Implementation Report: {TASK_ID}
71
71
 
@@ -19,9 +19,9 @@ skills:
19
19
  - devflow:test-driven-development
20
20
  - devflow:worktree-support
21
21
  - devflow:apply-feature-knowledge
22
- <!-- learning:on -->
22
+ <!-- curation:on -->
23
23
  - devflow:apply-decisions
24
- <!-- learning:end -->
24
+ <!-- curation:end -->
25
25
  disallowedTools:
26
26
  - Agent
27
27
  - SendMessage