5-phase-workflow 2.0.6 → 2.1.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.
package/bin/install.js CHANGED
@@ -388,6 +388,11 @@ function getWorkflowManagedFiles() {
388
388
  'verification-agent.md'
389
389
  ],
390
390
 
391
+ // Workflows: Claude Code only (Workflow tool). Not installed for Codex.
392
+ workflows: [
393
+ '5-implement.js'
394
+ ],
395
+
391
396
  // Skills: specific skill directories
392
397
  skills: [
393
398
  'configure-docs-index',
@@ -451,6 +456,13 @@ function getFileManifest() {
451
456
  manifest.push(`agents/${agent}`);
452
457
  }
453
458
 
459
+ // Workflows are files (Claude Code only)
460
+ if (managed.workflows) {
461
+ for (const wf of managed.workflows) {
462
+ manifest.push(`workflows/${wf}`);
463
+ }
464
+ }
465
+
454
466
  // Skills are directories
455
467
  for (const skill of managed.skills) {
456
468
  manifest.push(`skills/${skill}`);
@@ -557,8 +569,20 @@ This skill was authored for Claude Code. Map these tool references:
557
569
  | \`Glob\` | \`glob\` / \`list_directory\` |
558
570
  | \`Grep\` | \`grep\` / \`search\` |
559
571
  | \`TaskCreate/TaskUpdate\` | Track progress internally |
572
+ | \`Workflow\` | Not available — run the command's prose fallback loop instead |
560
573
  | \`EnterPlanMode\` | Not available — use structured output instead |
561
574
 
575
+ ## Model Mapping (single source of truth)
576
+ When a skill, plan, or \`state.json\` component names a model, map it to Codex as:
577
+
578
+ | Named model | Codex model | reasoning_effort |
579
+ |-------------|-------------|------------------|
580
+ | \`haiku\` (or unset) | \`gpt-5.4-mini\` | \`low\` |
581
+ | \`sonnet\` | \`gpt-5.4\` | \`medium\` |
582
+ | Explore / explorer agent | \`gpt-5.4-mini\` (\`agent_type: explorer\`) | \`low\` |
583
+
584
+ This table is authoritative — skill bodies do not repeat per-call model mappings.
585
+
562
586
  ## Codex Token Budget
563
587
  - Default to \`gpt-5.4-mini\` with \`reasoning_effort: low\` for exploration, orchestration, simple implementation, and mechanical file edits.
564
588
  - Use \`gpt-5.4\` with \`reasoning_effort: medium\` only for complex logic, cross-module behavior, security-sensitive changes, data migrations, final verification with meaningful logic review, or retries after failure.
@@ -696,6 +720,25 @@ function selectiveUpdate(targetPath, sourcePath) {
696
720
  log.success('Updated agents/ (workflow files only)');
697
721
  }
698
722
 
723
+ // Update workflow scripts (Claude Code only — Workflow tool)
724
+ if (managed.workflows && managed.workflows.length > 0) {
725
+ const workflowsSrc = path.join(sourcePath, 'workflows');
726
+ const workflowsDest = path.join(targetPath, 'workflows');
727
+ if (!fs.existsSync(workflowsDest)) {
728
+ fs.mkdirSync(workflowsDest, { recursive: true });
729
+ }
730
+ for (const wf of managed.workflows) {
731
+ const src = path.join(workflowsSrc, wf);
732
+ const dest = path.join(workflowsDest, wf);
733
+ if (fs.existsSync(src)) {
734
+ fs.copyFileSync(src, dest);
735
+ } else {
736
+ log.warn(`Workflow source missing, skipped: ${wf}`);
737
+ }
738
+ }
739
+ log.success('Updated workflows/ (workflow files only)');
740
+ }
741
+
699
742
  // Update specific skills
700
743
  const skillsSrc = path.join(sourcePath, 'skills');
701
744
  const skillsDest = path.join(targetPath, 'skills');
@@ -1059,8 +1102,8 @@ function performFreshInstall(targetPath, sourcePath, isGlobal) {
1059
1102
  log.success(`Created ${targetPath}`);
1060
1103
  }
1061
1104
 
1062
- // Copy directories
1063
- const dirs = ['commands', 'agents', 'skills', 'hooks', 'templates', 'references'];
1105
+ // Copy directories (workflows is Claude Code only; performCodexFreshInstall never copies it)
1106
+ const dirs = ['commands', 'agents', 'workflows', 'skills', 'hooks', 'templates', 'references'];
1064
1107
  for (const dir of dirs) {
1065
1108
  const src = path.join(sourcePath, dir);
1066
1109
  const dest = path.join(targetPath, dir);
@@ -1668,6 +1711,17 @@ function uninstall() {
1668
1711
  }
1669
1712
  log.success('Removed workflow agents (preserved user-created agents)');
1670
1713
 
1714
+ // Remove only workflow-managed workflow scripts (Claude Code only)
1715
+ if (managed.workflows) {
1716
+ for (const wf of managed.workflows) {
1717
+ const wfPath = path.join(targetPath, 'workflows', wf);
1718
+ if (fs.existsSync(wfPath)) {
1719
+ fs.unlinkSync(wfPath);
1720
+ }
1721
+ }
1722
+ log.success('Removed workflow scripts');
1723
+ }
1724
+
1671
1725
  // Remove only workflow-managed skills
1672
1726
  for (const skill of managed.skills) {
1673
1727
  const skillPath = path.join(targetPath, 'skills', skill);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "5-phase-workflow",
3
- "version": "2.0.6",
3
+ "version": "2.1.0",
4
4
  "description": "A dev-workflow for Claude Code and Codex",
5
5
  "bin": {
6
6
  "foifi": "bin/install.js"
@@ -21,7 +21,7 @@ You follow the plan, state entry, and existing codebase patterns. You do not wid
21
21
 
22
22
  ## Simplicity
23
23
 
24
- Write the minimum that satisfies the component. Before writing code, stop at the first step that solves it: does it need to exist (YAGNI) → standard library native platform/framework feature already-installed dependency a single clear expression → minimum viable implementation. Add no new dependency for this. Do not add abstractions for single-use code, flexibility that was not requested, or error handling for impossible scenarios. Follow `Simplicity First` in the project `AGENTS.md`. This sharpens "smallest coherent change" — it never widens scope.
24
+ Write the minimum that satisfies the component (the "smallest coherent change"): prefer the standard library, a native framework feature, or an already-installed dependency over anything new. Add no new dependency, no abstraction for single-use code, no unrequested flexibility, and no error handling for impossible cases. Follow `Simplicity First` in the project `AGENTS.md`.
25
25
 
26
26
  End with exactly:
27
27
 
@@ -40,12 +40,10 @@ Keep the result block concise. Do not include command logs, diffs, or long expla
40
40
 
41
41
  ## Deviation Rules
42
42
 
43
- | Trigger | Action |
44
- |---------|--------|
45
- | Missing import, type mismatch, lint failure caused by your change | Fix and note in deviations |
46
- | Existing nearby convention contradicts the plan | Follow the convention and note it |
47
- | Required dependency or package is absent | Stop and report |
48
- | Database/schema/auth/API contract change not listed in plan | Stop and report |
49
- | Verify command fails from pre-existing unrelated failures | Report the exact evidence |
43
+ **Fix and note** in deviations: imports, type mismatches, or lint you caused; a nearby existing convention that contradicts the plan (follow the convention).
44
+
45
+ **Stop and report** as failed: a required dependency/package is absent; a database/schema/auth/API contract change not in the plan.
46
+
47
+ **Report the exact evidence, but do not mark the component failed**, when verify fails only from pre-existing unrelated issues (your change is complete and correct; record the failure as a deviation so verification can treat it as pre-existing).
50
48
 
51
49
  Do not make more than three attempts on the same failing issue.
@@ -20,7 +20,6 @@ Turn the human-readable component checklist in `plan.md` into execution state th
20
20
  - Tests normally run after the components they validate.
21
21
  - Choose `model: "haiku"` by default for simple mechanical work, localized UI changes, tests, docs, config edits, and single-file changes.
22
22
  - Choose `model: "sonnet"` only for complex logic, cross-module behavior, security/auth, data migrations, public API contracts, or work likely to require reasoning.
23
- - For Codex installs, `haiku` maps to `gpt-5.4-mini` with low reasoning and `sonnet` maps to `gpt-5.4` with medium reasoning.
24
23
  - Pick `patternRefs` from `Existing Patterns to Follow`, `codebase-scan.md`, or nearby existing files found with Glob/Grep. Prefer one primary reference; use a second only when it adds a distinct convention. Include line ranges or symbols when known so executors avoid reading whole files.
25
24
  - Pick `verifyCommands` from `.5/config.json`, the scan, package scripts, and target-specific checks. Prefer narrow checks first, then project-level build/test.
26
25
  - Preserve user decisions exactly. Exclude `[DEFERRED]` work.
@@ -48,7 +48,7 @@ Update `state.json`:
48
48
  "verificationResults": {
49
49
  "completeness": "passed|partial|failed",
50
50
  "infrastructure": "passed|failed",
51
- "acceptanceCriteria": "passed|partial|failed|skipped",
51
+ "acceptanceCriteria": "satisfied/total",
52
52
  "quality": "passed|partial|failed",
53
53
  "commands": [
54
54
  {
@@ -1,99 +1,97 @@
1
1
  ---
2
2
  name: 5:implement
3
- description: Executes a unified plan by spawning step-orchestrator-agent, per-step executor agents, and verification-agent.
4
- allowed-tools: Agent, Read, Write, Glob, Grep, Bash, TaskCreate, TaskUpdate, TaskList
3
+ description: Executes a unified plan. Uses the Workflow tool when available (parallel waves, schema-validated agents); otherwise runs an equivalent prose loop. Codex always uses the prose loop.
4
+ allowed-tools: Agent, Read, Write, Glob, Grep, Bash, Workflow, TaskCreate, TaskUpdate, TaskList
5
5
  user-invocable: true
6
6
  argument-hint: [feature-name]
7
7
  ---
8
8
 
9
9
  <role>
10
- You are an Implementation Orchestrator. You keep your context lean, delegate all code edits, and use `.5/features/{name}/state.json` as source of truth.
11
- You do NOT write source code yourself.
10
+ You are an Implementation Orchestrator. Keep your context lean, delegate all code edits, and use `.5/features/{name}/state.json` as the durable source of truth for cross-session resume. You do NOT write source code yourself.
12
11
  </role>
13
12
 
14
13
  # Implement
15
14
 
16
- ## Process
15
+ ## Step 1: Load Artifacts & Decide Path
17
16
 
18
- ### Step 1: Load Artifacts
19
-
20
- Read `.5/features/{feature-name}/state.json` first if it exists.
21
-
22
- Then read only the artifacts needed for the current path:
17
+ Read `.5/features/{feature-name}/state.json` first if it exists. Then read only what the current path needs:
23
18
 
24
19
  - Resume existing state: `.5/config.json` if needed for baseline, verification, or auto-commit.
25
20
  - New state or restart: `plan.md`, `codebase-scan.md` if it exists, and `.5/config.json` if it exists.
26
- - Final verification: `plan.md`, `state.json`, `.5/config.json` if present, and `codebase-scan.md` only if verification needs missing context.
27
21
 
28
- If `plan.md` is missing, stop and ask the user to run `/5:plan` first, then rerun `/5:implement {feature-name}` with the created feature folder name.
22
+ If `plan.md` is missing, stop and ask the user to run `/5:plan` first, then rerun `/5:implement {feature-name}`.
29
23
 
30
- If state exists:
24
+ State machine, if state exists:
31
25
 
32
- - `completed`: tell the user it is already implemented and verification already ran.
33
- - `in-progress`: resume from `currentStep`.
26
+ - `completed`: tell the user it is already implemented and verified; stop.
27
+ - `in-progress`: resume from `currentStep` (only run components not in `completedComponents`).
34
28
  - `failed`: ask whether to resume or restart.
35
29
 
36
- ### Step 2: Orchestrate Plan Into State
30
+ A plan is **compact** when `plan.md` frontmatter has `planFormat: compact` (1-2 components, no data migration, no security/auth change, no public API change).
37
31
 
38
- If state does not exist or restart was requested, spawn `step-orchestrator-agent`.
32
+ Remove `.5/.planning-active` once you have a valid plan to execute.
39
33
 
40
- In Codex, use `model: gpt-5.4-mini` and `reasoning_effort: low` for this agent unless the plan contains complex cross-module logic, security-sensitive work, or data migrations.
34
+ ## Step 2: Establish Baseline
41
35
 
42
- Prompt:
43
-
44
- ```text
45
- Read `.claude/agents/step-orchestrator-agent.md` for your role and output contract.
36
+ Run build/test commands from `.5/config.json` (or an explicit baseline block in `state.json`). Skip commands set to `none`. If `state.json.baseline` already records the same commands for this run/resume, reuse it.
46
37
 
47
- Feature: {feature-name}
48
- Plan: .5/features/{feature-name}/plan.md
49
- Codebase scan: .5/features/{feature-name}/codebase-scan.md
50
- Config: .5/config.json if present
38
+ Record compact results in `state.json.baseline` (command, status, one-line summary). Append full history to `state-events.jsonl`. If baseline fails, warn and continue; verification treats those as pre-existing.
51
39
 
52
- Create `.5/features/{feature-name}/state.json`.
53
- Derive steps, dependencies, model choices, pattern references, verify commands, and executor prompts from the clean plan.
54
- Keep steps minimal: group independent components in parallel; split only for real data/order dependencies or same-file conflicts.
40
+ ```json
41
+ {"type":"command","timestamp":"{ISO}","step":0,"component":null,"status":"passed|failed|skipped","summary":"one line","details":{"command":"{command}","phase":"baseline"}}
55
42
  ```
56
43
 
57
- Read back `state.json` and verify:
44
+ ## Step 3: Run
45
+
46
+ **If the `Workflow` tool is available, use the Workflow engine (preferred).** It moves orchestration into deterministic JS, fires parallel components concurrently, and returns schema-validated results — fewer tokens than driving the loop turn-by-turn.
58
47
 
59
- - `status` is `in-progress`
60
- - `steps` is non-empty
61
- - each pending component has `step`, `mode`, `model`, `patternRefs` or legacy `patternFiles`, and `verifyCommands`
48
+ 1. Build `args` for the workflow:
62
49
 
63
- Remove `.5/.planning-active` after state is valid.
50
+ ```json
51
+ {
52
+ "feature": "{feature-name}",
53
+ "paths": {"plan": ".5/features/{feature-name}/plan.md", "scan": ".5/features/{feature-name}/codebase-scan.md", "config": ".5/config.json"},
54
+ "isCompact": true,
55
+ "components": [{"name": "...", "action": "create|modify|delete|rename", "file": "...", "sourceFile": null, "description": "...", "dependsOn": []}],
56
+ "baseline": [{"command": "...", "status": "passed|failed|skipped", "summary": "one line"}],
57
+ "resume": null
58
+ }
59
+ ```
64
60
 
65
- ### Step 3: Establish Baseline
61
+ - For a **compact** plan, set `isCompact: true` and parse `components` from the plan's Component Checklist (the workflow builds a trivial single step with no orchestrator agent).
62
+ - For a **full** plan, set `isCompact: false` and omit `components` — the workflow's orchestrate phase derives steps itself.
63
+ - `baseline` is the array you recorded in Step 2 (or `[]`); the workflow's verifier treats those failures as pre-existing and reuses passing results instead of rerunning them.
64
+ - `resume` is `null` for a fresh run. To resume, pass `{"completedComponents": [...], "steps": [...], "pendingComponents": [...]}` copied verbatim from the existing `state.json`, so the workflow reuses the original steps rather than re-deriving them (re-derivation is non-deterministic and could rename components, breaking resume matching).
65
+ - The workflow reads the config **file** at `paths.config` itself; do not pass build/test/commit settings inline — baseline (Step 2) and auto-commit (Step 5) are run by this command, not the workflow.
66
66
 
67
- Run build/test commands from `.5/config.json` by default. If `state.json` defines an explicit baseline command block, prefer that block. Skip commands explicitly set to `none`.
67
+ 2. Call `Workflow({name: "5-implement", args})`.
68
+ 3. When it returns, **persist its result** (Step 4): write the returned `steps`, `components`, and `verification` into `state.json`, and **merge** (never replace) the returned `completedComponents` and per-component `results` into the existing arrays — a resumed run reports only the components it ran this invocation, so earlier-session history must be preserved. Append events to `state-events.jsonl`. The workflow does not touch the filesystem itself.
69
+ 4. Auto-commit per step (Step 5), then report (Step 6).
68
70
 
69
- If `state.json.baseline` already records the same commands for the current run or resume, reuse it instead of rerunning baseline.
71
+ > Cross-session resume stays durable via `state.json`, but the Workflow path persists **only after the workflow returns** — if a run is interrupted mid-way, this session's progress is not yet saved. On the next `/5:implement`, resume reconciles against the persisted `completedComponents` (only components recorded there are skipped), so re-running a partially-applied step is possible; the executor's smallest-coherent-change contract makes a re-touch safe but not free. Workflow's own in-session resume is a bonus; you are the one who persists state after it returns.
70
72
 
71
- Record compact command results in `state.json.baseline`: command, status, and a one-line summary only. Append full command history to `state-events.jsonl`. If baseline fails, warn and continue; later verification should treat those failures as pre-existing.
73
+ **Otherwise, run the prose loop (fallback).** It produces the same `state.json` outcome:
72
74
 
73
- Command event shape:
75
+ ### 3a. Orchestrate into state
74
76
 
75
- ```json
76
- {"type":"command","timestamp":"{ISO}","step":0,"component":null,"status":"passed|failed|skipped","summary":"one line","details":{"command":"{command}","phase":"baseline"}}
77
- ```
77
+ - **Compact plan:** build `state.json` inline from the Component Checklist — one step, `mode: "parallel"` unless components share a file or have a dependency (then `sequential`), `model: "haiku"`. **Do not spawn `step-orchestrator-agent`.**
78
+ - **Full plan:** spawn `step-orchestrator-agent` with `plan.md`, `codebase-scan.md`, and config; it writes `state.json` with steps, dependencies, model choices, `patternRefs` (line ranges/symbols), and verify commands.
78
79
 
79
- ### Step 4: Execute Steps
80
+ Verify `state.json`: `status: in-progress`, non-empty `steps`, each pending component has `step`, `mode`, `model`, `patternRefs` (or legacy `patternFiles`), and `verifyCommands`.
80
81
 
81
- For each step from `currentStep`:
82
+ ### 3b. Execute steps in waves
82
83
 
83
- 1. Pre-check dependencies: every dependency component must be completed; every file created/modified by previous completed components must still exist.
84
- 2. Create/update progress tasks for the step.
85
- 3. Spawn executor agents:
86
- - Use one agent per component when `mode` is `parallel`.
87
- - Use one agent at a time when `mode` is `sequential` or when components touch the same file.
88
- - Give each executor the inline contract below instead of making it read `.claude/agents/step-executor-agent.md`.
89
- - In Codex, map each component model before spawning:
90
- - `haiku` -> `model: gpt-5.4-mini`, `reasoning_effort: low`
91
- - `sonnet` -> `model: gpt-5.4`, `reasoning_effort: medium`
92
- - missing model -> `model: gpt-5.4-mini`, `reasoning_effort: low`
93
- 4. Give each executor only its component block from `state.json`, relevant global notes, required pattern references, verify commands, and this inline contract:
84
+ For each step from `currentStep`, skipping components already in `completedComponents`:
85
+
86
+ 1. Pre-check: every dependency component is completed and its files still exist.
87
+ 2. Update progress tasks for the step.
88
+ 3. Spawn executors:
89
+ - **Parallel step: emit all of the step's executor Agent calls in a single message so they run concurrently.**
90
+ - Sequential step (same-file or dependency): one executor at a time.
91
+ - Give each executor only its component block, required `patternRefs`, verify commands, and the inline contract below — do not make it read `step-executor-agent.md`. (For legacy `patternFiles`, tell it to read only the smallest relevant sections.)
94
92
 
95
93
  ```text
96
- Implement exactly the assigned component. Read only listed patternRefs ranges/symbols and the target file. Make the smallest coherent change, run assigned verify commands, and stop for missing dependencies, unplanned auth/schema/API changes, or unclear product decisions.
94
+ Implement exactly the assigned component. Read only listed patternRefs ranges/symbols and the target file. Make the smallest coherent change, run assigned verify commands, and stop (STATUS: failed) for missing dependencies, unplanned auth/schema/API changes, or unclear product decisions. If verify fails only from pre-existing unrelated issues, report it under DEVIATIONS with the exact evidence and keep STATUS: success — your change is complete. Do not make more than three attempts on the same failing issue.
97
95
 
98
96
  End with:
99
97
  ---RESULT---
@@ -106,97 +104,50 @@ ERROR: none | {error description}
106
104
  ---END---
107
105
  ```
108
106
 
109
- If a component has legacy `patternFiles`, tell the executor to read only the smallest relevant sections.
110
- 5. Parse only the `---RESULT---` block from each response.
111
- 6. Update `completedComponents`, `recentFailures`, `pendingComponents`, `currentStep`, `latestCommandResults`, and `lastUpdated`.
112
- - Append `component_result`, `retry`, and `command` events to `state-events.jsonl`.
113
- - Keep only the most recent compact summaries in `state.json`.
114
- 7. Read back state after every write and verify the expected fields changed.
115
-
116
- Retry failed components up to two times. Upgrade retries to `sonnet`; in Codex this means `model: gpt-5.4`, `reasoning_effort: medium`. Never fix code in the orchestrator context.
117
-
118
- Component and retry event shapes:
107
+ 4. Parse only the `---RESULT---` block from each executor.
108
+ 5. **Once per wave** (not per component), update `completedComponents`, `recentFailures`, `pendingComponents`, `currentStep`, `latestCommandResults`, `lastUpdated`, and append `component_result` / `retry` / `command` events to `state-events.jsonl`. Trust the executor's report do not re-read files you did not change to confirm them.
119
109
 
120
110
  ```json
121
111
  {"type":"component_result","timestamp":"{ISO}","step":1,"component":"{name}","status":"success|failed","summary":"one line","details":{"filesCreated":[],"filesModified":[],"verify":"passed|failed|skipped"}}
122
112
  {"type":"retry","timestamp":"{ISO}","step":1,"component":"{name}","status":"failed","summary":"retry reason","details":{"attempt":2,"model":"sonnet"}}
123
113
  ```
124
114
 
125
- ### Step 5: Auto-commit Completed Step
126
-
127
- After each step completes successfully, check `.5/config.json` for `git.autoCommit`.
115
+ Retry failed components up to twice, escalating to `sonnet`. Never fix code in the orchestrator context.
128
116
 
129
- If `git.autoCommit` is `true`:
117
+ ### 3c. Verify
130
118
 
131
- 1. Stage only files owned by components completed in this step:
132
- - `file` for create/modify/delete targets.
133
- - both `sourceFile` and `file` for rename targets.
134
- - files reported in executor `FILES_CREATED` and `FILES_MODIFIED`.
135
- 2. Do not stage unrelated working tree changes.
136
- 3. Build the commit message from `git.commitMessage.pattern`:
137
- - Replace `{ticket-id}` with `state.ticket` or an empty string.
138
- - Replace `{short-description}` with `step {number}: {step-name}`.
139
- - Trim redundant whitespace and punctuation if ticket ID is empty.
140
- 4. Commit the staged files.
141
- 5. Append a detailed entry to `state-events.jsonl` and a compact latest entry to `state.json.latestCommitResults`:
119
+ - **Fast path:** when every component reported `success` with `verify` `passed` or `skipped`, and no component was planned as **or escalated to** `sonnet` (i.e. a mechanical change), verify inline run the configured build/test once (reuse fresh baseline/component results), set the verification fields directly, and skip `verification-agent`.
120
+ - **Otherwise:** spawn `verification-agent` with `plan.md`, `state.json`, and config (and `codebase-scan.md` only if needed). It reuses fresh `baseline`/component/`latestCommandResults` instead of rerunning identical passing commands, then updates `state.json` verification fields and returns:
142
121
 
143
- ```json
144
- {
145
- "type": "commit",
146
- "timestamp": "{ISO-timestamp}",
147
- "step": 1,
148
- "component": null,
149
- "status": "committed|skipped|failed",
150
- "summary": "{commit-message-or-reason}",
151
- "details": {
152
- "commit": "{sha-or-null}",
153
- "files": ["path/to/file"],
154
- "error": null
155
- }
156
- }
122
+ ```text
123
+ ---VERIFICATION---
124
+ STATUS: passed | partial | failed
125
+ COMPLETENESS: passed | partial | failed
126
+ INFRASTRUCTURE: passed | failed
127
+ ACCEPTANCE_CRITERIA: satisfied/total
128
+ QUALITY: passed | partial | failed
129
+ ERRORS: none | {summary}
130
+ ---END_VERIFICATION---
157
131
  ```
158
132
 
159
- If there are no changed files for the step, skip the commit and record `status: "skipped"`. If commit fails, record `status: "failed"` and continue to final verification; do not retry by staging broader paths.
160
-
161
- If `git.autoCommit` is missing or `false`, do not commit.
133
+ ## Step 4: Persist Verification Result
162
134
 
163
- ### Step 6: Final Verification
135
+ Set `state.json` `status` to `completed` when verification passed; otherwise `failed`, and tell the user to fix the reported issues and rerun `/5:implement {feature-name}` to resume.
164
136
 
165
- After all steps complete, spawn `verification-agent`.
137
+ ## Step 5: Auto-commit
166
138
 
167
- In Codex, use `model: gpt-5.4-mini` and `reasoning_effort: low` when all component verification passed and the change is mechanical. Use `model: gpt-5.4` and `reasoning_effort: medium` when components touched complex logic, security/auth, data migrations, public APIs, or any component verification failed or was skipped.
139
+ If `.5/config.json` `git.autoCommit` is `true`, commit once per completed step:
168
140
 
169
- Prompt:
141
+ 1. Stage only files owned by that step's components: `file` for create/modify/delete, both `sourceFile` and `file` for rename, plus the executor's reported `FILES_CREATED`/`FILES_MODIFIED`. Do not stage unrelated changes.
142
+ 2. Build the message from `git.commitMessage.pattern`, replacing `{ticket-id}` with `state.ticket` (or empty) and `{short-description}` with `step {number}: {step-name}`; trim redundant whitespace/punctuation when the ticket is empty.
143
+ 3. Commit, and record a compact entry in `state.json.latestCommitResults` plus a detailed `commit` event:
170
144
 
171
- ```text
172
- Read `.claude/agents/verification-agent.md` for your role and output contract.
173
-
174
- Verify feature `{feature-name}` using:
175
- - .5/features/{feature-name}/plan.md
176
- - .5/features/{feature-name}/state.json
177
- - .5/config.json if present
178
- - .5/features/{feature-name}/codebase-scan.md only if plan/state are insufficient to judge acceptance criteria, patterns, or risks
179
-
180
- Verify that the implementation is complete and correct, the project builds, tests run, everything from the plan is implemented, and tests are written for the implemented feature where appropriate.
181
- Reuse `state.json.baseline`, component `VERIFY` outcomes, and `latestCommandResults` when they are fresh enough to prove the final status. Do not rerun identical build/test commands unless relevant files changed after the last recorded successful run.
182
- Update `.5/features/{feature-name}/state.json` verification fields.
183
- Do not write a verification report.
184
- Do not implement fixes.
145
+ ```json
146
+ {"type":"commit","timestamp":"{ISO}","step":1,"component":null,"status":"committed|skipped|failed","summary":"{message-or-reason}","details":{"commit":"{sha-or-null}","files":["path"],"error":null}}
185
147
  ```
186
148
 
187
- Parse only the `---VERIFICATION---` block from the response.
188
-
189
- If final verification passes, set state `status` to `completed`. If it fails or is partial, set `status` to `failed` and tell the user to fix the reported issues, then rerun `/5:implement {feature-name}` to resume verification.
190
-
191
- ### Step 7: Report
192
-
193
- Report:
149
+ No changed files `status: "skipped"`. Commit error → `status: "failed"`, continue; do not retry with broader paths. If `git.autoCommit` is missing/`false`, do not commit.
194
150
 
195
- - Completed component count
196
- - Failed component count
197
- - Verification status
198
- - Path to `state.json`
199
- - Auto-commit count and any failed commit attempts, if `git.autoCommit` is true
200
- - Failed commands, missing tests, or unmet acceptance criteria, if any
151
+ ## Step 6: Report
201
152
 
202
- Stop.
153
+ Report: completed/failed component counts, verification status, path to `state.json`, auto-commit count and any failures, and any failed commands, missing tests, or unmet acceptance criteria. Then stop.
@@ -81,7 +81,7 @@ Do not ask technical follow-ups yet.
81
81
 
82
82
  If `.5/index/` exists, check the `Generated:` timestamp in `.5/index/README.md`. If the index is more than one day old, run `.5/index/rebuild-index.sh` to refresh it before spawning the Explore agent.
83
83
 
84
- Spawn one Explore agent. In Codex, use `agent_type: explorer`, `model: gpt-5.4-mini`, and `reasoning_effort: low`.
84
+ Spawn one Explore agent.
85
85
 
86
86
  ```text
87
87
  Analyze the codebase for a unified workflow plan.
@@ -0,0 +1,328 @@
1
+ export const meta = {
2
+ name: '5-implement',
3
+ description: 'Execute a unified plan: derive steps, run executors in parallel waves, verify. Claude Code only; Codex uses the prose loop.',
4
+ whenToUse: 'Invoked by the /5:implement command when the Workflow tool is available. Reads args from the command, returns final state for the command to persist to state.json.',
5
+ phases: [
6
+ { title: 'Orchestrate', detail: 'derive steps + components (agent for non-trivial plans, inline for compact)' },
7
+ { title: 'Execute', detail: 'one executor agent per component; parallel components fire together per step' },
8
+ { title: 'Verify', detail: 'inline when all passed + mechanical, else one verification agent' }
9
+ ]
10
+ }
11
+
12
+ // ─────────────────────────────────────────────────────────────────────────────
13
+ // Contract note: the executor / orchestrator / verifier prompts below are the
14
+ // inline, schema-validated form of src/agents/*-agent.md. Those .md files remain
15
+ // the canonical human-readable contract; keep these prompts in sync with them.
16
+ //
17
+ // This script has NO filesystem access. It orchestrates agents and RETURNS the
18
+ // final state object. The /5:implement command (which has Write) persists
19
+ // state.json + state-events.jsonl and runs auto-commit after this returns.
20
+ // ─────────────────────────────────────────────────────────────────────────────
21
+
22
+ const RESULT_SCHEMA = {
23
+ type: 'object',
24
+ additionalProperties: false,
25
+ required: ['status', 'verify'],
26
+ properties: {
27
+ status: { enum: ['success', 'failed'] },
28
+ filesCreated: { type: 'array', items: { type: 'string' } },
29
+ filesModified: { type: 'array', items: { type: 'string' } },
30
+ verify: { enum: ['passed', 'failed', 'skipped'] },
31
+ deviations: { type: 'string', description: 'none or a brief list' },
32
+ error: { type: 'string', description: 'none or an error description' }
33
+ }
34
+ }
35
+
36
+ const VERIFICATION_SCHEMA = {
37
+ type: 'object',
38
+ additionalProperties: false,
39
+ required: ['status', 'completeness', 'infrastructure', 'quality'],
40
+ properties: {
41
+ status: { enum: ['passed', 'partial', 'failed'] },
42
+ completeness: { enum: ['passed', 'partial', 'failed'] },
43
+ infrastructure: { enum: ['passed', 'failed'] },
44
+ acceptanceCriteria: { type: 'string', description: 'satisfied/total, e.g. "3/3"' },
45
+ quality: { enum: ['passed', 'partial', 'failed'] },
46
+ commands: {
47
+ type: 'array',
48
+ items: {
49
+ type: 'object',
50
+ additionalProperties: false,
51
+ required: ['command', 'status'],
52
+ properties: {
53
+ command: { type: 'string' },
54
+ status: { enum: ['passed', 'failed', 'skipped'] },
55
+ summary: { type: 'string' }
56
+ }
57
+ }
58
+ },
59
+ failures: { type: 'array', items: { type: 'string' } }
60
+ }
61
+ }
62
+
63
+ const STATE_SCHEMA = {
64
+ type: 'object',
65
+ additionalProperties: false,
66
+ required: ['steps', 'pendingComponents'],
67
+ properties: {
68
+ steps: {
69
+ type: 'array',
70
+ items: {
71
+ type: 'object',
72
+ additionalProperties: false,
73
+ required: ['number', 'name', 'mode', 'components'],
74
+ properties: {
75
+ number: { type: 'integer' },
76
+ name: { type: 'string' },
77
+ mode: { enum: ['parallel', 'sequential'] },
78
+ model: { enum: ['haiku', 'sonnet'] },
79
+ components: { type: 'array', items: { type: 'string' } }
80
+ }
81
+ }
82
+ },
83
+ pendingComponents: {
84
+ type: 'array',
85
+ items: {
86
+ type: 'object',
87
+ additionalProperties: false,
88
+ required: ['name', 'action', 'step', 'mode', 'model', 'file'],
89
+ properties: {
90
+ name: { type: 'string' },
91
+ action: { enum: ['create', 'modify', 'delete', 'rename'] },
92
+ step: { type: 'integer' },
93
+ mode: { enum: ['parallel', 'sequential'] },
94
+ model: { enum: ['haiku', 'sonnet'] },
95
+ file: { type: 'string' },
96
+ sourceFile: { type: ['string', 'null'] },
97
+ description: { type: 'string' },
98
+ dependsOn: { type: 'array', items: { type: 'string' } },
99
+ patternRefs: {
100
+ type: 'array',
101
+ items: {
102
+ type: 'object',
103
+ additionalProperties: false,
104
+ required: ['file'],
105
+ properties: {
106
+ file: { type: 'string' },
107
+ read: { type: 'string' },
108
+ reason: { type: 'string' }
109
+ }
110
+ }
111
+ },
112
+ verifyCommands: { type: 'array', items: { type: 'string' } },
113
+ notes: { type: 'array', items: { type: 'string' } }
114
+ }
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ // ── Prompt builders ──────────────────────────────────────────────────────────
121
+
122
+ function orchestratorPrompt(a) {
123
+ return `You are a Step Orchestrator. Read these files and RETURN execution state as structured output. Do NOT write any file.
124
+
125
+ Feature: ${a.feature}
126
+ Plan: ${a.paths.plan}
127
+ Codebase scan: ${a.paths.scan} (read only if present)
128
+ Config: ${a.paths.config} (read only if present)
129
+
130
+ Turn the lean component checklist in the plan into steps + components:
131
+ - Group independent components into one step with mode "parallel"; use "sequential" only when components touch the same file, one imports another, or there is an explicit dependency.
132
+ - Prefer fewer steps. Tests run after the components they validate.
133
+ - model "haiku" by default (mechanical, UI, tests, docs, config, single-file). model "sonnet" only for complex logic, cross-module, security/auth, migrations, or public API.
134
+ - 1-2 high-signal patternRefs per component with line ranges or symbols so executors avoid whole-file reads.
135
+ - verifyCommands: narrowest relevant check first, then project build/test.
136
+ - Exclude [DEFERRED] work. Represent every other component once. dependsOn must reference existing component names.
137
+
138
+ Return an object matching the schema (steps[] and pendingComponents[]).`
139
+ }
140
+
141
+ function executorPrompt(c, a, opts) {
142
+ const refs = (c.patternRefs || []).map(r => ` - ${r.file}${r.read ? ` (${r.read})` : ''}${r.reason ? ` — ${r.reason}` : ''}`).join('\n') || ' - none'
143
+ const verify = (c.verifyCommands || []).join(' && ') || 'infer the narrowest relevant test/build command'
144
+ const retry = opts && opts.retry
145
+ ? '\nThis is a RETRY of a failed attempt — read the error context carefully and correct the root cause.'
146
+ : ''
147
+ return `You are a Step Executor. Implement EXACTLY this component and nothing more.${retry}
148
+
149
+ Component: ${c.name}
150
+ Action: ${c.action}
151
+ Target file: ${c.file}${c.sourceFile ? `\nSource file (rename from): ${c.sourceFile}` : ''}
152
+ Intent: ${c.description || ''}
153
+
154
+ Read only these pattern references (ranges/symbols), plus the target file for modify/rename:
155
+ ${refs}
156
+
157
+ Rules: smallest coherent change; mirror existing naming/exports/layout/tests; follow any local skill or rule; add no new dependency; no abstraction or error handling beyond what the intent requires. Fix mechanical issues you cause (imports, types, lint). STOP and report failed for missing dependencies, unplanned auth/schema/API/contract changes, or unclear product decisions. If verify fails only from pre-existing unrelated issues, report that as a deviation with the exact evidence — do not mark the component failed. Do not make more than three attempts on the same failing issue.
158
+
159
+ Then run: ${verify}
160
+
161
+ Return structured output: status, filesCreated, filesModified, verify, deviations (none or brief), error (none or description). Keep it concise — no logs or diffs unless failed.`
162
+ }
163
+
164
+ function verifyPrompt(a, results, resumeDone) {
165
+ const ran = results.flatMap(s => s.items.map(i =>
166
+ ` step ${s.step} ${i.component.name}: ${i.result ? i.result.status : 'no result'} (verify ${i.result ? i.result.verify : '?'})${i.escalated ? ' [escalated to sonnet]' : ''}`))
167
+ const prior = [...(resumeDone || [])]
168
+ .filter(n => !results.some(s => s.items.some(i => i.component.name === n)))
169
+ .map(n => ` ${n}: completed in a prior session`)
170
+ const summary = [...ran, ...prior].join('\n') || ' (no components ran this invocation)'
171
+ const baseline = (a.baseline && a.baseline.length)
172
+ ? a.baseline.map(b => ` ${b.command || b.details && b.details.command || '?'}: ${b.status}${b.summary ? ` — ${b.summary}` : ''}`).join('\n')
173
+ : ' (none recorded)'
174
+ return `You are a Verification Agent. Verify only; do not implement fixes.
175
+
176
+ Feature: ${a.feature}
177
+ Plan: ${a.paths.plan}
178
+ Config: ${a.paths.config} (read only if present)
179
+
180
+ Baseline (pre-change) command results — treat any failure listed here as PRE-EXISTING, not caused by this change:
181
+ ${baseline}
182
+
183
+ Component results:
184
+ ${summary}
185
+
186
+ Checks: completeness (every planned component done, acceptance criteria addressed); files exist for create/modify, rename moved correctly, delete removed; build + test pass (reuse the baseline and component results above when they already prove status — rerun only the commands whose inputs changed, not identical passing ones); correctness (inspect changed files, not just existence); quality (logic-bearing changes have tests when a test framework exists). Prefer changed files over broad scanning.
187
+
188
+ Return structured output: status, completeness, infrastructure, acceptanceCriteria ("satisfied/total"), quality, commands[], failures[].`
189
+ }
190
+
191
+ // ── Helpers ──────────────────────────────────────────────────────────────────
192
+
193
+ // Build a single trivial step in JS for compact plans (no orchestrator agent).
194
+ function compactSteps(components) {
195
+ const norm = components.map((c, i) => ({
196
+ name: c.name,
197
+ action: c.action || 'modify',
198
+ step: 1,
199
+ mode: 'parallel',
200
+ model: c.model || 'haiku',
201
+ file: c.file,
202
+ sourceFile: c.sourceFile || null,
203
+ description: c.description || '',
204
+ dependsOn: c.dependsOn || [],
205
+ patternRefs: c.patternRefs || [],
206
+ verifyCommands: c.verifyCommands || [],
207
+ notes: []
208
+ }))
209
+ // If two components write the same file or one depends on another, fall back to sequential.
210
+ const files = norm.map(c => c.file)
211
+ const fileConflict = new Set(files).size !== files.length
212
+ const hasDep = norm.some(c => c.dependsOn && c.dependsOn.length)
213
+ const mode = (fileConflict || hasDep) ? 'sequential' : 'parallel'
214
+ norm.forEach(c => { c.mode = mode })
215
+ const stepModel = norm.some(c => c.model === 'sonnet') ? 'sonnet' : 'haiku'
216
+ return {
217
+ steps: [{ number: 1, name: 'implement', mode, model: stepModel, components: norm.map(c => c.name) }],
218
+ pendingComponents: norm
219
+ }
220
+ }
221
+
222
+ async function runStep(step, components, a) {
223
+ const stepComps = components.filter(c => step.components.includes(c.name))
224
+ if (!stepComps.length) return { step: step.number, name: step.name, mode: step.mode, items: [] }
225
+
226
+ let waveResults
227
+ if (step.mode === 'parallel' && stepComps.length > 1) {
228
+ // Fire every parallel component together — true concurrency, one wave.
229
+ waveResults = await parallel(stepComps.map(c => () =>
230
+ agent(executorPrompt(c, a), { label: `exec:${c.name}`, phase: 'Execute', model: c.model || 'haiku', schema: RESULT_SCHEMA })
231
+ .then(result => ({ component: c, result }))
232
+ .catch(() => ({ component: c, result: null }))))
233
+ } else {
234
+ waveResults = []
235
+ for (const c of stepComps) {
236
+ const result = await agent(executorPrompt(c, a), { label: `exec:${c.name}`, phase: 'Execute', model: c.model || 'haiku', schema: RESULT_SCHEMA })
237
+ .catch(() => null)
238
+ waveResults.push({ component: c, result })
239
+ }
240
+ }
241
+
242
+ // Retry failed OR crashed (null) components up to twice, escalating to sonnet.
243
+ // A crashed agent (null result) is retried too — an infra error should not be
244
+ // treated more harshly than a clean structured failure.
245
+ for (const wr of waveResults) {
246
+ let attempt = 1
247
+ while ((wr.result == null || wr.result.status === 'failed') && attempt <= 2) {
248
+ log(`retry ${wr.component.name} (attempt ${attempt + 1}) on sonnet`)
249
+ wr.escalated = true
250
+ const retried = await agent(executorPrompt(wr.component, a, { retry: true }),
251
+ { label: `retry:${wr.component.name}`, phase: 'Execute', model: 'sonnet', schema: RESULT_SCHEMA }).catch(() => null)
252
+ if (retried) wr.result = retried
253
+ attempt++
254
+ }
255
+ }
256
+
257
+ return { step: step.number, name: step.name, mode: step.mode, items: waveResults }
258
+ }
259
+
260
+ // ── Main ─────────────────────────────────────────────────────────────────────
261
+
262
+ const a = args || {}
263
+ const resume = a.resume || {}
264
+ const resumeDone = new Set(resume.completedComponents || [])
265
+
266
+ phase('Orchestrate')
267
+ let plan
268
+ if (Array.isArray(resume.steps) && resume.steps.length && Array.isArray(resume.pendingComponents) && resume.pendingComponents.length) {
269
+ // Resume: reuse the steps/components derived in the original run (stored in state.json).
270
+ // Re-deriving via the orchestrator agent is non-deterministic and could rename components,
271
+ // breaking name-based resume matching — so never re-orchestrate on resume.
272
+ log(`resume: reusing ${resume.steps.length} prior step(s); ${resumeDone.size} component(s) already complete`)
273
+ plan = { steps: resume.steps, pendingComponents: resume.pendingComponents }
274
+ } else if (a.isCompact && Array.isArray(a.components) && a.components.length) {
275
+ log(`compact plan: ${a.components.length} component(s), no orchestrator agent`)
276
+ plan = compactSteps(a.components)
277
+ } else {
278
+ plan = await agent(orchestratorPrompt(a), { label: 'orchestrate', phase: 'Orchestrate', schema: STATE_SCHEMA })
279
+ }
280
+ const steps = plan.steps
281
+ const components = plan.pendingComponents
282
+
283
+ phase('Execute')
284
+ const results = []
285
+ for (const step of steps) {
286
+ const remaining = components.filter(c => step.components.includes(c.name) && !resumeDone.has(c.name))
287
+ if (!remaining.length) { log(`step ${step.number} already complete (resume), skipping`); continue }
288
+ const stepResult = await runStep({ ...step, components: remaining.map(c => c.name) }, components, a)
289
+ results.push(stepResult)
290
+ }
291
+
292
+ phase('Verify')
293
+ const allItems = results.flatMap(s => s.items)
294
+ const allPassed = allItems.length > 0 && allItems.every(i => i.result && i.result.status === 'success' && i.result.verify !== 'failed')
295
+ // Non-mechanical when a component was planned as sonnet OR needed a sonnet retry to pass —
296
+ // either signals reasoning-level work that warrants the full verification agent.
297
+ const usedSonnet = components.some(c => (c.model || 'haiku') === 'sonnet') || allItems.some(i => i.escalated)
298
+ let verification
299
+ if (allPassed && !usedSonnet) {
300
+ log('all components passed + mechanical (no sonnet, no escalation) — inline verify, no verification agent')
301
+ verification = { status: 'passed', completeness: 'passed', infrastructure: 'passed', acceptanceCriteria: 'n/a', quality: 'passed', commands: [], failures: [], inline: true }
302
+ } else {
303
+ if (!allItems.length) log('no components ran this invocation (resume) — verifying the already-completed feature against the plan')
304
+ verification = await agent(verifyPrompt(a, results, resumeDone), {
305
+ label: 'verify', phase: 'Verify', model: usedSonnet ? 'sonnet' : 'haiku', schema: VERIFICATION_SCHEMA
306
+ })
307
+ }
308
+
309
+ // Union prior + newly-succeeded so the command can MERGE (not replace) completed history on resume.
310
+ const newlyCompleted = allItems.filter(i => i.result && i.result.status === 'success').map(i => i.component.name)
311
+ const completedComponents = [...new Set([...resumeDone, ...newlyCompleted])]
312
+
313
+ // Returned to the /5:implement command, which persists state.json + state-events.jsonl and auto-commits.
314
+ // steps + components are returned so a later resume can pass them back (deterministic, no re-orchestration).
315
+ return {
316
+ feature: a.feature,
317
+ steps,
318
+ components,
319
+ completedComponents,
320
+ results: results.map(s => ({
321
+ step: s.step,
322
+ name: s.name,
323
+ mode: s.mode,
324
+ items: s.items.map(i => ({ component: i.component.name, file: i.component.file, sourceFile: i.component.sourceFile, escalated: !!i.escalated, result: i.result }))
325
+ })),
326
+ verification,
327
+ status: verification.status === 'passed' ? 'completed' : 'failed'
328
+ }