devflow-kit 3.12.1 → 3.13.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 (75) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/agents/architect.md +10 -9
  3. package/dist/agents/code.md +6 -6
  4. package/dist/agents/design.md +7 -7
  5. package/dist/agents/harden.md +6 -8
  6. package/dist/agents/review.md +5 -6
  7. package/dist/cli/commands/init-seed.js +5 -1
  8. package/dist/cli/commands/init.js +27 -19
  9. package/dist/cli/commands/tdd.js +230 -0
  10. package/dist/cli/commands/uninstall.js +2 -2
  11. package/dist/cli.js +2 -0
  12. package/dist/commands/implement.md +1 -1
  13. package/dist/commands/plan.md +23 -61
  14. package/dist/compliance-off/commands/implement.md +1 -1
  15. package/dist/compliance-off/commands/plan.md +23 -61
  16. package/dist/compliance-off/skills/git/references/tracker/github/ensure-pr-ready.md +1 -0
  17. package/dist/compliance-off/skills/git/references/tracker/jira/ensure-pr-ready.md +1 -0
  18. package/dist/compliance-off/skills/git/references/tracker/linear/ensure-pr-ready.md +1 -0
  19. package/dist/compliance-tdd-off/agents/triage.md +173 -0
  20. package/dist/core/assets.js +40 -33
  21. package/dist/core/curation-variants.js +191 -76
  22. package/dist/core/feature-switch.js +3 -2
  23. package/dist/core/installed-variants.js +45 -14
  24. package/dist/core/manifest.js +3 -0
  25. package/dist/core/mds-variants.js +13 -6
  26. package/dist/core/plugins.js +38 -9
  27. package/dist/curation-compliance-off/commands/implement.md +1 -1
  28. package/dist/curation-compliance-off/commands/plan.md +23 -61
  29. package/dist/curation-compliance-tdd-off/agents/triage.md +170 -0
  30. package/dist/curation-off/agents/architect.md +10 -9
  31. package/dist/curation-off/agents/code.md +6 -6
  32. package/dist/curation-off/agents/design.md +7 -7
  33. package/dist/curation-off/agents/harden.md +6 -8
  34. package/dist/curation-off/agents/review.md +5 -6
  35. package/dist/curation-off/commands/implement.md +1 -1
  36. package/dist/curation-off/commands/plan.md +23 -61
  37. package/dist/curation-tdd-off/agents/code.md +173 -0
  38. package/dist/curation-tdd-off/agents/triage.md +171 -0
  39. package/dist/skills/git/references/tracker/github/ensure-pr-ready.md +1 -0
  40. package/dist/skills/git/references/tracker/jira/ensure-pr-ready.md +1 -0
  41. package/dist/skills/git/references/tracker/linear/ensure-pr-ready.md +1 -0
  42. package/dist/targets/claude-code/agent-type-owner.js +20 -15
  43. package/dist/targets/claude-code/curation-install.js +120 -99
  44. package/dist/targets/claude-code/installer.js +26 -29
  45. package/dist/targets/claude-code/shipped-set.js +2 -3
  46. package/dist/tdd-off/agents/code.md +176 -0
  47. package/dist/tdd-off/agents/triage.md +174 -0
  48. package/dist/variant-axes.json +54 -27
  49. package/package.json +1 -1
  50. package/src/assets/agents/_partials/_design.mds +7 -7
  51. package/src/assets/agents/architect.mds +3 -2
  52. package/src/assets/agents/code.mds +19 -7
  53. package/src/assets/agents/harden.mds +6 -8
  54. package/src/assets/agents/plan.md +63 -0
  55. package/src/assets/agents/review.mds +5 -6
  56. package/src/assets/agents/triage.mds +4 -0
  57. package/src/assets/commands/implement.mds +1 -1
  58. package/src/assets/commands/plan.mds +22 -68
  59. package/src/assets/mds/git/_ops_steps.mds +1 -0
  60. package/src/assets/skills/agent-references/references/commands/plan-levels.md +3 -3
  61. package/src/assets/skills/agent-references/references/synthesize/planning.md +9 -9
  62. package/src/assets/skills/design-review/SKILL.md +9 -12
  63. package/src/assets/skills/design-review/references/anti-patterns.md +4 -1
  64. package/src/assets/skills/gap-analysis/SKILL.md +2 -2
  65. package/src/assets/skills/git/references/patterns.md +3 -0
  66. package/src/assets/skills/patterns/SKILL.md +2 -4
  67. package/src/assets/skills/quality-gates/SKILL.md +2 -2
  68. package/src/assets/skills/quality-gates/references/patterns.md +3 -3
  69. package/src/assets/skills/quality-gates/references/report-template.md +2 -2
  70. package/src/assets/skills/quality-gates/references/violations.md +5 -5
  71. package/src/assets/skills/test-driven-development/SKILL.md +5 -5
  72. package/src/assets/skills/test-driven-development/references/rationalization-prevention.md +1 -1
  73. package/src/assets/skills/testing/SKILL.md +9 -9
  74. package/src/assets/skills/testing/references/report-template.md +1 -1
  75. package/src/assets/skills/testing/references/violations.md +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,21 @@ All notable changes to Devflow will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.13.0] - 2026-11-04
9
+
10
+ ### Added
11
+
12
+ - **`devflow tdd --enable | --disable | --status`** ([#758](https://github.com/dean0x/devflow/issues/758)). The switch is on by default. With it off, the installed Code agent has no test-first text and no `devflow:test-driven-development` preload, the installed Triage agent no longer says that the Code agent works test-first, and the skill is not installed; the other test rules stay. The switch changes only the installed files, through the same build variants and converge as `devflow curation` and `devflow compliance`; no spawn or settings line carries it. A plain re-init keeps it, and `devflow init --reset` turns it back on. With no install manifest the command records nothing and exits 1.
13
+
14
+ ### Changed
15
+
16
+ - **devflow ships a `Plan` agent that replaces Claude Code's built-in Plan** ([#756](https://github.com/dean0x/devflow/issues/756)). It runs on Opus at high effort, reads the code without editing it, names the lowest workable rung for each step, and never drops input validation, security checks, data-loss guards, fail-closed paths or the tests of these. `/plan` Phase 10 uses it, and so does plan mode when Claude Code delegates research to the Plan subagent. `init` skips it and warns when you already own a `Plan` agent, `uninstall` removes only devflow's copy, and `devflow agents --set plan --model <model>` changes its model.
17
+ - **`/plan` writes a lean artifact** ([#756](https://github.com/dean0x/devflow/issues/756)). The artifact keeps the acceptance criteria, the steps (each with its files, the callers and consumers to update, its Must lines and its rung), patterns, known limits and deferrals, PR guidance and the test plan, and drops the problem statement, scope, gap, integration, design-review and risk sections. Every accepted gap, design finding and risk becomes a Must line or a known limit. Phase 10 asks each Plan agent for one rung per step at every level, a revision replaces text and adds no section, and `/implement` hands the known limits to Evaluate, Test and a single Code agent, and the PR description lists them.
18
+ - **The Architect and design review ask for less** ([#756](https://github.com/dean0x/devflow/issues/756)). The Architect flags a plan step that sits above the lowest rung that meets the acceptance criteria, and an option, layer or config key that has no ask. Design review flags a missing retry, compensation step or cache only when the plan names a concrete case: an external call in the change, a stated or measured hot path, or a repeated delivery. Missing error handling at a trust boundary or for data loss stays a finding.
19
+ - **Code writes proportional tests, and review stops asking for speculative extras** ([#756](https://github.com/dean0x/devflow/issues/756)). Code writes one failing test first for each acceptance-criterion behaviour, adds an edge-case test only for a named case, and always tests trust boundaries, data loss, security and fail-closed paths. The testing, test-driven-development and quality-gates skills and the Harden agent ask for the same, and no prompt asks for the happy path, error cases and edge cases of every change. Review and the patterns skill ask for caching, retries, idempotency or compensation only when the diff shows a concrete case; a missing bound on an existing loop, retry or cache stays a finding. The test-first rule, the RED step and the bug-fix regression test stay.
20
+
21
+ ---
22
+
8
23
  ## [3.12.1] - 2026-11-01
9
24
 
10
25
  ### Fixed
@@ -2439,6 +2454,7 @@ devflow init
2439
2454
  ---
2440
2455
 
2441
2456
  [Unreleased]: https://github.com/dean0x/devflow/compare/v3.8.0...HEAD
2457
+ [3.13.0]: https://github.com/dean0x/devflow/compare/v3.12.1...v3.13.0
2442
2458
  [3.12.1]: https://github.com/dean0x/devflow/compare/v3.12.0...v3.12.1
2443
2459
  [3.12.0]: https://github.com/dean0x/devflow/compare/v3.11.0...v3.12.0
2444
2460
  [3.11.0]: https://github.com/dean0x/devflow/compare/v3.10.0...v3.11.0
@@ -18,17 +18,17 @@ tools:
18
18
 
19
19
  # Architect Agent
20
20
 
21
- You are a design analysis specialist. You detect anti-patterns in implementation plans.
21
+ You are a design analysis specialist.
22
22
 
23
23
  ## Input
24
24
 
25
25
  The orchestrator provides:
26
- - **Artifacts**: Design documents, specifications, issue bodies, or implementation plans to analyze
26
+ - **Artifacts**: Design documents, specifications, issue bodies or plans to analyze
27
27
 
28
- **Worktree Support**: If `WORKTREE_PATH` is provided, follow the `devflow:worktree-support` skill for path resolution. If omitted, use cwd.
28
+ **Worktree Support**: With `WORKTREE_PATH`, resolve paths by the `devflow:worktree-support` skill; without it, use cwd.
29
29
 
30
30
  - **DECISIONS_CONTEXT** (optional): Compact index of active ADR/PF entries for this repository (pre-rendered to `.devflow/curation/index.md` in its main worktree). `(none)` when absent. Use `devflow:apply-decisions` to Read full bodies on demand.
31
- - **FEATURE_KNOWLEDGE** (optional): Per KB, the Rules bullets most relevant to the feature, the KB path and a heading index, for pattern-aware gap analysis. Read the indexed sections for the architecture you build on — design additions that fit existing structure. Follow `devflow:apply-feature-knowledge`.
31
+ - **FEATURE_KNOWLEDGE** (optional): Per KB, the Rules bullets most relevant to the feature, the KB path and a heading index, for pattern-aware analysis. Read the indexed sections for the architecture you build on, so that additions fit it. Follow `devflow:apply-feature-knowledge`.
32
32
 
33
33
  ## Apply Decisions
34
34
 
@@ -37,13 +37,14 @@ Follow `devflow:apply-decisions` on the `DECISIONS_CONTEXT` index. A finding tha
37
37
  ## Responsibilities
38
38
 
39
39
  1. **Apply design review** — Scan the artifacts with all 6 rules of the preloaded `devflow:design-review` skill.
40
- 2. **Assess confidence (0-100%)** — For each finding, assess certainty. Report at 80%+, suggest at 60-79%, drop below 60%. 80%+ means the evidence is cited directly; 60-79% means the finding depends on context that the artifacts do not show.
41
- 3. **Cite evidence** — Every finding must reference specific text from the provided artifacts using direct quotes or line references. Never invent evidence that the artifacts do not hold.
42
- 4. **Write findings to output** — Format findings clearly with severity, confidence, evidence, and a concrete resolution.
40
+ 2. **Assess confidence (0-100%)** — Report a finding at 80%+ (evidence cited directly), suggest it at 60-79% (it depends on context the artifacts do not show), drop it below 60%.
41
+ 3. **Cite evidence** — Quote the artifacts or cite a line for every finding. Never invent evidence.
42
+ 4. **Write findings to output** — Give each finding a severity, confidence, evidence and a resolution.
43
+ 5. **Minimum lens** — Flag a step above the lowest rung that meets the acceptance criteria, and name that rung (not needed, reuse, standard library, installed dependency, one-line change, new code). Flag an option, layer or config key with no ask and no concrete case. Never flag a trust-boundary, security, data-loss or fail-closed guard, or its test.
43
44
 
44
45
  ## Plan writing
45
46
 
46
- When the prompt asks you to write an implementation plan, write it; the findings Output below does not apply. First run `d="${CLAUDE_CONFIG_DIR:-}"; case "$d" in /*) ;; *) d="$HOME/.claude" ;; esac; printf '%s\n' "$d"` in Bash and Read `<that directory>/skills/devflow:gap-analysis/SKILL.md`. Write the plan the prompt describes: close the gaps that skill names, avoid the 6 anti-patterns, and return the shape the prompt names.
47
+ When the prompt asks for an implementation plan, write it; the findings Output below does not apply. First run `d="${CLAUDE_CONFIG_DIR:-}"; case "$d" in /*) ;; *) d="$HOME/.claude" ;; esac; printf '%s\n' "$d"` in Bash and Read `<that directory>/skills/devflow:gap-analysis/SKILL.md`. Write the plan the prompt describes: close the gaps that skill names, avoid the 6 anti-patterns.
47
48
 
48
49
  ## Output
49
50
 
@@ -87,5 +88,5 @@ Report cap: final message at most about 1,500 tokens; longer material goes to a
87
88
 
88
89
  **Escalate to orchestrator:**
89
90
  - Context documents are missing or unreadable
90
- - Fundamental ambiguity that cannot be resolved without user input
91
+ - Ambiguity that only the user can resolve
91
92
  - Artifacts reference external systems not present in the provided context
@@ -42,7 +42,7 @@ You receive from orchestrator:
42
42
  - **PUSH** (optional): `true` (default) | `false` — when false, commit only; orchestrator owns push/CI gate
43
43
  - **DECISIONS_CONTEXT** (optional): Compact index of active ADR/PF entries
44
44
  - **BASE_BRANCH**: Branch this feature branch was created from
45
- - **EXECUTION_PLAN**: Synthesized plan with steps, files, tests
45
+ - **EXECUTION_PLAN**: Plan with steps, files, tests
46
46
  - **PATTERNS**: Codebase patterns to follow
47
47
  - **OPERATION** (optional): `implement` (default when absent) | `issue-fix` — selects operating mode; every spawn passes it as the first prompt line. Any other value returns BLOCKED, naming it, and changes nothing.
48
48
  - **ISSUES** (when OPERATION: issue-fix): FIX_NOW issues from the Triage agent
@@ -52,10 +52,10 @@ You receive from orchestrator:
52
52
  **Worktree Support**: With `WORKTREE_PATH`, resolve paths by the `devflow:worktree-support` skill; without it, use cwd.
53
53
 
54
54
  **Sequential execution context** (when chaining multiple Code agents):
55
- - **PRIOR_PHASE_SUMMARY**: Implementation summary from previous Code agent (see format below)
55
+ - **PRIOR_PHASE_SUMMARY**: Summary from the previous Code agent (format in Handoff)
56
56
  - **FILES_FROM_PRIOR_PHASE**: Files created that must be read and understood
57
57
  - **HANDOFF_REQUIRED**: true if another Code agent follows this one
58
- - **HANDOFF_FILE** (optional): Path to the branch-scoped handoff file: read the one section of the phase before yours, and append your own section when HANDOFF_REQUIRED=true
58
+ - **HANDOFF_FILE** (optional): Path to the branch-scoped handoff file (steps 1 and 6 below)
59
59
 
60
60
  ## Responsibilities
61
61
 
@@ -68,9 +68,9 @@ You receive from orchestrator:
68
68
 
69
69
  2. **Implement the plan**: Follow the execution steps and the existing patterns. Type everything. Use Result types if the codebase uses them.
70
70
 
71
- 3. **Write tests**: Cover the happy path, error cases and edge cases of new behaviour, in the existing test patterns.
71
+ 3. **Write tests**: Write one failing test first for each acceptance-criterion behaviour (else each behaviour your steps' Must lines name). Add an edge-case test only for a named, concrete case. Always test trust boundaries, data loss, security and fail-closed paths.
72
72
 
73
- 4. **Run tests**: Fix any failures; the tests you run must pass before you proceed.
73
+ 4. **Run tests**: Fix any failures; the tests you run must pass.
74
74
  **Gate ownership:** Run the targeted tests for your change in its TDD cycle, plus one affected-tests run after your last edit. In a fix mode, compile and run the named failing or regression tests. Never the full suite. Batch fixes: one build check per batch, not per edit. Only Validate runs the full suite.
75
75
 
76
76
  5. **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.
@@ -99,7 +99,7 @@ You fix the issues the Triage agent marked FIX_NOW. Do not re-litigate dispositi
99
99
 
100
100
  ## Handoff
101
101
 
102
- **If HANDOFF_REQUIRED=true**, end with the section you appended to `HANDOFF_FILE` (the orchestrator passes it on as PRIOR_PHASE_SUMMARY):
102
+ **If HANDOFF_REQUIRED=true**, end with the section you appended to `HANDOFF_FILE`:
103
103
 
104
104
  ```markdown
105
105
  ## Phase {N} Implementation Summary
@@ -27,12 +27,12 @@ You are a design analysis specialist. You detect gaps in design documents, speci
27
27
 
28
28
  The orchestrator provides:
29
29
  - **Focus**: Which aspect to analyze: completeness, architecture, security, performance, compliance, consistency, or dependencies
30
- - **Artifacts**: Design documents, specifications, issue bodies, or implementation plans to analyze
30
+ - **Artifacts**: Design documents, specifications, issue bodies or plans to analyze
31
31
 
32
- **Worktree Support**: If `WORKTREE_PATH` is provided, follow the `devflow:worktree-support` skill for path resolution. If omitted, use cwd.
32
+ **Worktree Support**: With `WORKTREE_PATH`, resolve paths by the `devflow:worktree-support` skill; without it, use cwd.
33
33
 
34
34
  - **DECISIONS_CONTEXT** (optional): Compact index of active ADR/PF entries for this repository (pre-rendered to `.devflow/curation/index.md` in its main worktree). `(none)` when absent. Use `devflow:apply-decisions` to Read full bodies on demand.
35
- - **FEATURE_KNOWLEDGE** (optional): Per KB, the Rules bullets most relevant to the feature, the KB path and a heading index, for pattern-aware gap analysis. Read the indexed sections for the architecture you build on — design additions that fit existing structure. Follow `devflow:apply-feature-knowledge`.
35
+ - **FEATURE_KNOWLEDGE** (optional): Per KB, the Rules bullets most relevant to the feature, the KB path and a heading index, for pattern-aware analysis. Read the indexed sections for the architecture you build on, so that additions fit it. Follow `devflow:apply-feature-knowledge`.
36
36
 
37
37
  ## Apply Decisions
38
38
 
@@ -41,9 +41,9 @@ Follow `devflow:apply-decisions` on the `DECISIONS_CONTEXT` index. A finding tha
41
41
  ## Responsibilities
42
42
 
43
43
  1. **Apply gap analysis** — Scan the provided artifacts with the detection patterns of the preloaded `devflow:gap-analysis` skill. Apply only the patterns for your assigned focus.
44
- 2. **Assess confidence (0-100%)** — For each finding, assess certainty. Report at 80%+, suggest at 60-79%, drop below 60%. 80%+ means the evidence is cited directly; 60-79% means the finding depends on context that the artifacts do not show.
45
- 3. **Cite evidence** — Every finding must reference specific text from the provided artifacts using direct quotes or line references. Never invent evidence that the artifacts do not hold.
46
- 4. **Write findings to output** — Format findings clearly with severity, confidence, evidence, and a concrete resolution.
44
+ 2. **Assess confidence (0-100%)** — Report a finding at 80%+ (evidence cited directly), suggest it at 60-79% (it depends on context the artifacts do not show), drop it below 60%.
45
+ 3. **Cite evidence** — Quote the artifacts or cite a line for every finding. Never invent evidence.
46
+ 4. **Write findings to output** — Give each finding a severity, confidence, evidence and a resolution.
47
47
 
48
48
  ## Output
49
49
 
@@ -87,5 +87,5 @@ Report cap: final message at most about 1,500 tokens; longer material goes to a
87
87
 
88
88
  **Escalate to orchestrator:**
89
89
  - Context documents are missing or unreadable
90
- - Fundamental ambiguity that cannot be resolved without user input
90
+ - Ambiguity that only the user can resolve
91
91
  - Artifacts reference external systems not present in the provided context
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: Harden
3
- description: Self-review after the Code agent. Checks the implementation against 9 quality pillars and fixes the issues.
3
+ description: Self-review after the Code agent. Checks 9 quality pillars and fixes the issues.
4
4
  model: opus
5
5
  effort: medium
6
6
  skills:
@@ -33,7 +33,7 @@ disallowedTools:
33
33
 
34
34
  # Harden Agent
35
35
 
36
- You evaluate the implementation against the 9 quality pillars and fix the issues you find.
36
+ You evaluate the implementation against the 9 quality pillars and fix the issues.
37
37
 
38
38
  ## Input Context
39
39
 
@@ -53,7 +53,7 @@ Follow the `devflow:apply-decisions` skill: check that the implementation is con
53
53
 
54
54
  ## Responsibilities
55
55
 
56
- 1. **Gather changes**: Read all files in FILES_CHANGED, together in one turn.
56
+ 1. **Gather changes**: Read all files in FILES_CHANGED.
57
57
 
58
58
  2. **Evaluate P0 pillars** (Design, Functionality, Security) and fix every issue.
59
59
 
@@ -61,11 +61,11 @@ Follow the `devflow:apply-decisions` skill: check that the implementation is con
61
61
 
62
62
  4. **Evaluate P1 pillars** (Complexity, Error Handling, Tests) and fix every issue.
63
63
 
64
- 5. **Evaluate P2** (Documentation): Fix if straightforward. Naming and Consistency belong to the Polish agent: report them as SKIP.
64
+ 5. **Evaluate P2** (Documentation): Fix if straightforward.
65
65
 
66
66
  6. **Commit fixes**: If any changes were made, create a commit with message "fix: address self-review issues".
67
67
 
68
- 7. **Report status**: Return the report below. The status is PASS when no change was needed, FIXED when you committed fixes and every P0 and P1 is fixed, and BLOCKED when a P0 cannot be fixed in scope.
68
+ 7. **Report status**: The status is PASS when no change was needed, FIXED when you committed fixes and every P0 and P1 is fixed, and BLOCKED when a P0 cannot be fixed in scope.
69
69
 
70
70
  **Gate ownership:** Run only a test file you added or changed, once. Only Validate runs the full suite.
71
71
 
@@ -79,8 +79,6 @@ Code-scanning runs in the Code agent; do not scan here.
79
79
 
80
80
  ## Output
81
81
 
82
- Return structured completion status:
83
-
84
82
  ```markdown
85
83
  ## Self-Review Report
86
84
 
@@ -119,4 +117,4 @@ Report cap: final message at most about 1,500 tokens; longer material goes to a
119
117
  - Security vulnerability that needs design reconsideration
120
118
  - Functionality issue that invalidates the implementation approach
121
119
 
122
- Fix every other fixable P0 and P1 issue yourself, missing tests for new code included.
120
+ Fix every other fixable P0 and P1 issue yourself, missing tests for an acceptance-criterion behaviour (else each behaviour the diff adds) or a trust-boundary, data-loss, security or fail-closed path included.
@@ -74,21 +74,21 @@ Follow `devflow:apply-decisions` on the `DECISIONS_CONTEXT` index. A finding tha
74
74
 
75
75
  ## Responsibilities
76
76
 
77
- 1. **Load focus skill**: Before any analysis, invoke the Skill tool: `Skill(skill="devflow:{FOCUS}")` (substituting your assigned focus area). If the Skill invocation fails, proceed with the review using your built-in knowledge — the focus skill provides additional detection patterns but is not required for a useful review.
77
+ 1. **Load focus skill**: Before any analysis, invoke the Skill tool: `Skill(skill="devflow:{FOCUS}")` (substituting your assigned focus area). If the Skill call fails, review without it.
78
78
  2. **Identify changed lines** - Read the diff from `DIFF_FILE` when passed, else run `git diff {DIFF_RANGE}`
79
79
  3. **Apply 3-category classification** - Sort issues by where they occur
80
80
  4. **Apply focus-specific analysis** - Use pattern skill detection rules from the loaded skill file
81
81
  5. **Assign severity** - CRITICAL, HIGH, MEDIUM, LOW based on impact
82
82
  6. **Assess confidence** - Assign 0-100% confidence to each finding (see Confidence Scale below)
83
- 7. **Filter by confidence** - Only report findings ≥80% in main sections; lower-confidence items go to Suggestions
83
+ 7. **Filter by confidence** - Report findings ≥80% in Blocking, Should-Fix and Pre-existing; 60-79% go to Suggestions; drop findings below 60%
84
84
  8. **Self-verify findings** — For each finding at ≥80% confidence (CRITICAL, HIGH, or MEDIUM):
85
85
  If the flagged lines are already visible in the diff output, skip the Read — the diff is
86
86
  sufficient for verification. Otherwise, Read the code at the flagged file:line as a
87
87
  ranged read of 30 lines either side, never the whole file. If the issue is already
88
88
  handled (guard clause, try/catch, validation present), downgrade to Suggestions or drop.
89
89
  If Read fails or line is out of range, retain finding at original confidence.
90
- 9. **Consolidate similar issues** - Group related findings to reduce noise (see Consolidation Rules)
91
- 10. **Generate report** - File:line references with suggested fixes
90
+ 9. **Consolidate similar issues** (see Consolidation Rules)
91
+ 10. **Generate report**
92
92
  11. **Determine merge recommendation** - Based on blocking issues
93
93
 
94
94
  ## Confidence Scale
@@ -102,13 +102,12 @@ Assess how certain you are that each finding is a real issue (not a false positi
102
102
  | 60-79% | Medium | Plausible issue, but depends on context you may not fully see |
103
103
  | < 60% | Low | Possible concern, but likely a matter of style or interpretation |
104
104
 
105
- **Threshold**: Only report findings with ≥80% confidence in Blocking, Should-Fix, and Pre-existing sections. Findings with 60-79% confidence go to the Suggestions section. Findings < 60% are dropped entirely.
106
-
107
105
  ## Consolidation Rules
108
106
 
109
107
  1. **Group similar issues** — If 3+ instances of the same pattern appear (e.g., "missing error handling" in multiple functions), consolidate into 1 finding listing all locations rather than N separate findings
110
108
  2. **Skip stylistic preferences** — Do not flag formatting, naming style, or code organization choices unless they violate explicit project conventions found in CLAUDE.md, .editorconfig, or linter configs
111
109
  3. **Skip issues in unchanged code** — Pre-existing issues in lines you did NOT change should only be reported if CRITICAL severity (security vulnerabilities, data loss risks)
110
+ 4. **Skip speculative asks** — In every focus, do not ask for caching, retries, idempotency or compensation unless the diff shows a concrete case (an external call, a stated or measured hot path, a repeated delivery). A missing bound on an existing loop, retry or cache stays a finding. A partial write that can lose data, a trust boundary and a fail-closed path need no case.
112
111
 
113
112
  ## Cross-Cycle Awareness
114
113
 
@@ -25,6 +25,7 @@ export const FEATURE_DEFAULTS = {
25
25
  rules: true,
26
26
  proxy: false,
27
27
  behavior: false,
28
+ tdd: true,
28
29
  compliance: { enabled: false, frameworks: [] },
29
30
  tracker: { provider: DEFAULT_TRACKER_PROVIDER },
30
31
  gateLevel: undefined,
@@ -48,6 +49,8 @@ export function resolveSeedFeatures(manifest) {
48
49
  const proxy = manifest?.features.proxy ?? FEATURE_DEFAULTS.proxy;
49
50
  // D-BEHAVIOR-OPT-IN: a manifest from before the switch has no key — it seeds the default (off).
50
51
  const behavior = manifest?.features.behavior ?? FEATURE_DEFAULTS.behavior;
52
+ // The tdd switch: a manifest from before it reads on (readManifest), so re-init keeps what the machine holds.
53
+ const tdd = manifest?.features.tdd ?? FEATURE_DEFAULTS.tdd;
51
54
  // Return a fresh object so callers never hold a reference to FEATURE_DEFAULTS.compliance.
52
55
  // Without the spread, `manifest?.features.compliance ?? FEATURE_DEFAULTS.compliance` returns
53
56
  // the module-level default by reference — downstream mutation would corrupt it process-wide.
@@ -65,7 +68,7 @@ export function resolveSeedFeatures(manifest) {
65
68
  // into the default, and init would then write the default over a value the
66
69
  // fold reads as the strictest level.
67
70
  const gateLevel = manifest?.features.gateLevel;
68
- return { ambient, memory, hud, knowledge, curation, rules, proxy, behavior, compliance, tracker, gateLevel };
71
+ return { ambient, memory, hud, knowledge, curation, rules, proxy, behavior, tdd, compliance, tracker, gateLevel };
69
72
  }
70
73
  /**
71
74
  * Resolve the flag record for the init seed.
@@ -326,6 +329,7 @@ export function applyCliToggles(base, toggles) {
326
329
  rules: toggles.rules ?? base.rules,
327
330
  proxy: toggles.proxy ?? base.proxy,
328
331
  behavior: toggles.behavior ?? base.behavior,
332
+ tdd: toggles.tdd ?? base.tdd,
329
333
  compliance: toggles.compliance ?? base.compliance,
330
334
  tracker: toggles.tracker ?? base.tracker,
331
335
  gateLevel: base.gateLevel,
@@ -54,6 +54,7 @@ import { formatTrackerSummary, shouldRunTrackerStep, runTrackerStep, buildClackT
54
54
  import { buildClackGateLevelPrompts, carriedGateLevel, formatGateLevelRow, formatGateLevelSummary, readStoredGateLevel, resolveGateLevelForInit, resolveGateLevelInitState, } from './gate-level-prompts.js';
55
55
  import { shouldRunAttributionStep, runAttributionStep, buildClackAttributionPrompts, applyAttributionAnswer, attributionSeedFrom, } from './attribution-prompts.js';
56
56
  import { convergeVariantAxes, describePostingLeft, installedVersionMatches, readRunningVersion } from '../../targets/claude-code/curation-install.js';
57
+ import { VARIANT_AXES, machineSwitches } from '../../core/curation-variants.js';
57
58
  import { POSTING_OFF_NOTICE, installRecordFor, postingNoticeDue, readInstalledVariants } from '../../core/installed-variants.js';
58
59
  import { auditAndRecordClaudeMd, formatClaudeMdAuditNote, formatClaudeMdAuditUnavailable, } from '../../core/claude-md-audit.js';
59
60
  import * as os from 'os';
@@ -594,6 +595,7 @@ export function buildHudOnlyManifest(existing, version, now, refusedGateLevel) {
594
595
  ambient: false, memory: false, hud: true, knowledge: false,
595
596
  curation: false, rules: false, flags: {}, proxy: false,
596
597
  behavior: false,
598
+ tdd: true,
597
599
  compliance: { enabled: false, frameworks: [] },
598
600
  // The exported default, not a literal — the one constant every other
599
601
  // module reads, so a moved default moves here too.
@@ -1099,6 +1101,10 @@ export const initCommand = new Command('init')
1099
1101
  // → false (FEATURE_DEFAULTS.behavior); re-inits and the Recommended path keep the prior
1100
1102
  // manifest value; only --behavior/--no-behavior and the Advanced wizard change it.
1101
1103
  let behaviorEnabled = seed.features.behavior;
1104
+ // tdd: a machine switch init only carries: the seed holds the prior manifest value (on when the
1105
+ // manifest has none, and under --reset), and no flag or wizard step changes it. `devflow tdd`
1106
+ // is the only command that changes the value; `init --reset` turns it back on.
1107
+ const tddEnabled = seed.features.tdd;
1102
1108
  // compliance: manifest-group (like proxy); seed from prior manifest value.
1103
1109
  // CLI override applied below in both Recommended and Advanced paths.
1104
1110
  let complianceEnabled = seed.features.compliance.enabled;
@@ -1836,6 +1842,15 @@ export const initCommand = new Command('init')
1836
1842
  hadComplianceRule = true;
1837
1843
  }
1838
1844
  catch { /* absent — no legacy artifact */ }
1845
+ // The SETTLED switches, after the flag, the prompt and the seed have all had their say
1846
+ // (D-LEARNING-VARIANT-INSTALL), never a raw seed or a repository's narrowing: built once here
1847
+ // and passed whole to the install, the converge and the install record, so the files installed
1848
+ // and the manifest written at the end of init cannot disagree about them.
1849
+ const switches = machineSwitches({
1850
+ curation: curationEnabled,
1851
+ compliance: { enabled: complianceEnabled },
1852
+ tdd: tddEnabled,
1853
+ });
1839
1854
  // Install via file copy
1840
1855
  let installReport;
1841
1856
  const installWarnings = [];
@@ -1850,14 +1865,9 @@ export const initCommand = new Command('init')
1850
1865
  rulesMap,
1851
1866
  isPartialInstall: !!options.plugin,
1852
1867
  spinner: s,
1853
- // The SETTLED switch, after the flag, the prompt and the seed have all had
1854
- // their say (D-LEARNING-VARIANT-INSTALL): the files installed here and the
1855
- // manifest written at the end of init cannot disagree about it.
1856
- curation: curationEnabled,
1857
- // The SETTLED compliance switch, never a raw seed or a repository's narrowing: the
1858
- // variant follows the machine switch alone, and with it off the install refuses
1859
- // before it writes a file when the variant files are not all there.
1860
- compliance: complianceEnabled,
1868
+ // With compliance off the install refuses before it writes a file when the variant
1869
+ // files are not all there.
1870
+ switches,
1861
1871
  trackerServers,
1862
1872
  // Non-fatal install notices with no other channel (skipped symlinks in the
1863
1873
  // generated reference tree, mode-normalisation failures) reach the user rather
@@ -1873,10 +1883,10 @@ export const initCommand = new Command('init')
1873
1883
  backupReport.print();
1874
1884
  process.exit(1);
1875
1885
  }
1876
- // The one converge for both switches (D-LEARNING-VARIANT-INSTALL, AC-27): the file copy
1886
+ // The one converge for every switch (D-LEARNING-VARIANT-INSTALL, AC-27): the file copy
1877
1887
  // above installed the variant of everything IT installed; on a `--plugin` install the
1878
1888
  // other plugins' files, already on disk, may still be another variant (this run may
1879
- // have flipped a switch), and the apply-decisions skill is removed here when the copy
1889
+ // have flipped a switch), and a skill an off switch gates is removed here when the copy
1880
1890
  // skipped it on a partial install. It also converges the compliance skill and rule, so
1881
1891
  // enabling or disabling compliance during init needs no separate devflow compliance run.
1882
1892
  // Rewrites only what is installed. Warn-not-abort: a failure is a warning here and the
@@ -1885,19 +1895,15 @@ export const initCommand = new Command('init')
1885
1895
  const variantConverge = await convergeVariantAxes({
1886
1896
  claudeDir,
1887
1897
  devflowDir,
1888
- manifest: {
1889
- features: {
1890
- curation: curationEnabled,
1891
- compliance: { enabled: complianceEnabled, frameworks: complianceFrameworks },
1892
- rules: rulesEnabled,
1893
- },
1894
- },
1898
+ switches,
1899
+ frameworks: complianceFrameworks,
1900
+ rulesEnabled,
1895
1901
  plugins: effectivePlugins,
1896
1902
  warn: (msg) => installWarnings.push(msg),
1897
1903
  backups,
1898
1904
  });
1899
1905
  if (verbose && variantConverge.converged) {
1900
- p.log.info(`Curation ${curationEnabled ? 'on' : 'off'}, compliance ${complianceEnabled ? 'on' : 'off'} variants: ` +
1906
+ p.log.info(`Variants (${VARIANT_AXES.map(axis => `${axis} ${switches[axis] ? 'on' : 'off'}`).join(', ')}): ` +
1901
1907
  `${variantConverge.commandsRewritten.length} command(s) and ${variantConverge.agentsRewritten.length} agent(s) ` +
1902
1908
  `rewritten, ${variantConverge.unchanged} already current`);
1903
1909
  }
@@ -2457,7 +2463,7 @@ export const initCommand = new Command('init')
2457
2463
  }
2458
2464
  // Write installation manifest for upgrade tracking (non-fatal — install already succeeded)
2459
2465
  const now = new Date().toISOString();
2460
- const installRecord = installRecordFor(variantConverge.converged, { curation: curationEnabled, compliance: complianceEnabled });
2466
+ const installRecord = installRecordFor(variantConverge.converged, switches);
2461
2467
  const manifestData = {
2462
2468
  version,
2463
2469
  // Resolved above, before the install, because the skills install set is
@@ -2485,6 +2491,8 @@ export const initCommand = new Command('init')
2485
2491
  // overridden by --behavior/--no-behavior and the Advanced wizard. The rule file was
2486
2492
  // converged above to match it.
2487
2493
  behavior: behaviorEnabled,
2494
+ // The tdd switch, carried from the prior manifest (on under --reset).
2495
+ tdd: tddEnabled,
2488
2496
  // Resolved compliance state — seeded from prior manifest, overridden by CLI flags
2489
2497
  // and Advanced wizard selection. convergeComplianceArtifacts was called above.
2490
2498
  // normalizeFrameworks: dedup + filter unknowns before persisting.
@@ -0,0 +1,230 @@
1
+ /**
2
+ * devflow tdd — the machine switch for the test-first text of the installed Code agent.
3
+ *
4
+ * `features.tdd` in ~/.devflow/manifest.json (absent = on) picks which installed files carry the
5
+ * TDD text: with it on, the Code agent preloads the test-driven-development skill and its test
6
+ * step says "write one failing test first"; with it off, the skill folder is not installed and the
7
+ * Code agent keeps its test rules (one test per behaviour, trust boundaries, data loss, security,
8
+ * fail-closed paths) without the test-first wording. Nothing reads the switch at run time: it only
9
+ * decides which files this machine installs.
10
+ *
11
+ * `--enable` and `--disable` write the switch under the manifest lock, then run the one converge
12
+ * for every variant axis (applyVariantToggle) and report. A converge that is skipped (no readable
13
+ * manifest, a version skew) or that does not finish clean exits non-zero; the switch write is not
14
+ * rolled back, so `devflow init` finishes the job. `--status` prints the switch, the gated skill
15
+ * and what the install record says the installed prompts hold.
16
+ *
17
+ * The core (applyTddChange, readTddStatus) returns a Result and prints nothing; the command action
18
+ * renders it. That keeps the business logic free of throws and of terminal output.
19
+ */
20
+ import { Command } from 'commander';
21
+ import * as p from '@clack/prompts';
22
+ import color from 'picocolors';
23
+ import { promises as fs } from 'fs';
24
+ import * as path from 'path';
25
+ import { isMachineFeatureOn, writeMachineFeature } from '../../core/feature-switch.js';
26
+ import { readGateManifest } from '../../core/gate-level.js';
27
+ import { readInstalledVariants, variantRecordStatus } from '../../core/installed-variants.js';
28
+ import { TDD_GATED_SKILLS, prefixSkillName } from '../../core/plugins.js';
29
+ import { getClaudeDirectory, getDevFlowDirectory } from '../../targets/claude-code/claude-paths.js';
30
+ import { applyVariantToggle, describePostingLeft, describeVariantConverge, readRunningVersion, } from '../../targets/claude-code/curation-install.js';
31
+ import { openBackupSessionOrFail, runWithBackupReport } from './backup-session.js';
32
+ /**
33
+ * The one action the flags ask for: null when none is given (the command prints its usage), an
34
+ * error when more than one is, because `--enable --disable` has no meaning.
35
+ */
36
+ export function resolveTddAction(options) {
37
+ const asked = [];
38
+ if (options.enable === true)
39
+ asked.push('enable');
40
+ if (options.disable === true)
41
+ asked.push('disable');
42
+ if (options.status === true)
43
+ asked.push('status');
44
+ if (asked.length > 1) {
45
+ return { ok: false, error: 'Use only one of --enable, --disable and --status.' };
46
+ }
47
+ return { ok: true, value: asked[0] ?? null };
48
+ }
49
+ const stateWord = (enabled) => (enabled ? 'on' : 'off');
50
+ /**
51
+ * Apply one change of the tdd switch: write the switch, then run the one converge for every axis,
52
+ * which records the installed variants after a clean run (applyVariantToggle does that last step).
53
+ *
54
+ * The switch comes first, so whatever the converge does next the machine's choice is on disk. A
55
+ * converge that is skipped, or that leaves a file or the skill unconverged, exits 1 and says that
56
+ * the switch stays recorded. Returns a result and never throws; the record of the backup session
57
+ * prints once, as the change returns, ahead of the messages.
58
+ */
59
+ export function applyTddChange(opts) {
60
+ return runWithBackupReport(opts.backups, () => applyChange(opts));
61
+ }
62
+ async function applyChange(opts) {
63
+ const { claudeDir, devflowDir, enabled, runningVersion, packageRoot, warn, backups } = opts;
64
+ const recorded = await writeMachineFeature(devflowDir, 'tdd', enabled);
65
+ if (!recorded.ok) {
66
+ return {
67
+ messages: [{ level: 'error', text: 'Devflow is not installed on this machine. Run `devflow init` first.' }],
68
+ exitCode: 1,
69
+ };
70
+ }
71
+ const recordedLine = { level: 'info', text: `The tdd switch is recorded as ${stateWord(enabled)}.` };
72
+ const outcome = await applyVariantToggle({
73
+ claudeDir,
74
+ devflowDir,
75
+ axis: 'tdd',
76
+ enabled,
77
+ runningVersion,
78
+ warn,
79
+ packageRoot,
80
+ backups,
81
+ });
82
+ switch (outcome.kind) {
83
+ case 'skipped':
84
+ return { messages: [recordedLine, { level: 'error', text: outcome.message }], exitCode: 1 };
85
+ case 'converged': {
86
+ if (!outcome.result.converged) {
87
+ return {
88
+ messages: [
89
+ recordedLine,
90
+ { level: 'error', text: 'The installed files were not all converged onto the tdd switch (see the warnings above). Run `devflow init` to finish.' },
91
+ ...describePostingLeft(outcome.result.posting).map((text) => ({ level: 'warn', text })),
92
+ ],
93
+ exitCode: 1,
94
+ };
95
+ }
96
+ const messages = [{
97
+ level: 'success',
98
+ text: enabled
99
+ ? 'TDD enabled: the Code agent and the test-driven-development skill carry the test-first rules.'
100
+ : 'TDD disabled: the test-first rules and the test-driven-development skill are not installed. ' +
101
+ 'The test rules for trust boundaries, data loss, security and fail-closed paths stay.',
102
+ }];
103
+ const changed = describeVariantConverge(outcome.result, 'tdd', enabled);
104
+ if (changed !== null)
105
+ messages.push({ level: 'info', text: `Installed prompts: ${changed}` });
106
+ return { messages, exitCode: 0 };
107
+ }
108
+ default: {
109
+ const unhandled = outcome;
110
+ return { messages: [{ level: 'error', text: `Unhandled toggle outcome ${JSON.stringify(unhandled)}` }], exitCode: 1 };
111
+ }
112
+ }
113
+ }
114
+ async function pathExists(file) {
115
+ try {
116
+ await fs.access(file);
117
+ return true;
118
+ }
119
+ catch {
120
+ return false;
121
+ }
122
+ }
123
+ /** Read the switch, the gated skill and the install record. Writes nothing. Never throws. */
124
+ export async function readTddStatus(opts) {
125
+ // The raw read heals nothing: readManifest would rewrite a manifest that holds a legacy key.
126
+ const read = await readGateManifest(opts.devflowDir);
127
+ if (read.kind !== 'object')
128
+ return { ok: false, error: 'not-installed' };
129
+ const enabled = isMachineFeatureOn(read.raw, 'tdd');
130
+ return {
131
+ ok: true,
132
+ value: {
133
+ enabled,
134
+ skillInstalled: await pathExists(path.join(opts.claudeDir, 'skills', prefixSkillName(TDD_GATED_SKILLS[0]))),
135
+ record: variantRecordStatus(readInstalledVariants(read.raw.installedVariants), 'tdd', enabled),
136
+ },
137
+ };
138
+ }
139
+ function recordLine(record) {
140
+ switch (record) {
141
+ case 'on':
142
+ return color.green('on');
143
+ case 'off':
144
+ return color.dim('off');
145
+ case 'mismatch':
146
+ return color.yellow('mismatch (run devflow init)');
147
+ case 'unknown':
148
+ return color.yellow('unknown (run devflow init)');
149
+ default: {
150
+ const unhandled = record;
151
+ return unhandled;
152
+ }
153
+ }
154
+ }
155
+ function logMessage(message) {
156
+ switch (message.level) {
157
+ case 'success':
158
+ p.log.success(message.text);
159
+ break;
160
+ case 'info':
161
+ p.log.info(message.text);
162
+ break;
163
+ case 'warn':
164
+ p.log.warn(message.text);
165
+ break;
166
+ case 'error':
167
+ p.log.error(message.text);
168
+ break;
169
+ default: {
170
+ const unhandled = message.level;
171
+ void unhandled;
172
+ break;
173
+ }
174
+ }
175
+ }
176
+ function renderStatus(result) {
177
+ if (!result.ok) {
178
+ p.log.error(`Devflow is not installed on this machine. Run ${color.cyan('devflow init')} first.`);
179
+ process.exitCode = 1;
180
+ return;
181
+ }
182
+ const { enabled, skillInstalled, record } = result.value;
183
+ p.log.info(`State: ${enabled ? color.green('enabled') : color.yellow('disabled')}`);
184
+ p.log.info(`Skill: ${skillInstalled ? color.green('installed') : color.dim('not installed')}`);
185
+ p.log.info(`Prompts: ${recordLine(record)}`);
186
+ }
187
+ export const tddCommand = new Command('tdd')
188
+ .description('Manage the test-first (TDD) text of the installed Code agent')
189
+ .option('--enable', 'Install the Code agent with the test-first rules and the test-driven-development skill')
190
+ .option('--disable', 'Install the Code agent without the test-first rules, and remove the test-driven-development skill')
191
+ .option('--status', 'Show whether the test-first text is on and what is installed')
192
+ .action(async (options) => {
193
+ const resolved = resolveTddAction(options);
194
+ if (!resolved.ok) {
195
+ p.log.error(resolved.error);
196
+ process.exitCode = 1;
197
+ return;
198
+ }
199
+ const action = resolved.value;
200
+ if (action === null) {
201
+ p.log.info('Usage: devflow tdd --enable | --disable | --status');
202
+ return;
203
+ }
204
+ const claudeDir = getClaudeDirectory();
205
+ const devflowDir = getDevFlowDirectory();
206
+ p.intro(color.cyan(action === 'status' ? 'TDD Status' : `${action === 'enable' ? 'Enable' : 'Disable'} TDD`));
207
+ if (action === 'status') {
208
+ renderStatus(await readTddStatus({ claudeDir, devflowDir }));
209
+ p.outro('');
210
+ return;
211
+ }
212
+ // The session comes before the first change. Without a shipped set the command changes nothing.
213
+ const backups = await openBackupSessionOrFail({ claudeDir, devflowDir });
214
+ if (backups === null)
215
+ return;
216
+ const applied = await applyTddChange({
217
+ claudeDir,
218
+ devflowDir,
219
+ enabled: action === 'enable',
220
+ runningVersion: await readRunningVersion(),
221
+ warn: (msg) => p.log.warn(msg),
222
+ backups,
223
+ });
224
+ for (const message of applied.messages)
225
+ logMessage(message);
226
+ if (applied.exitCode !== 0)
227
+ process.exitCode = applied.exitCode;
228
+ p.outro('');
229
+ });
230
+ //# sourceMappingURL=tdd.js.map