@shenlee/devcrew 0.1.2 → 0.1.4

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 (53) hide show
  1. package/README.md +15 -7
  2. package/README.zh-CN.md +12 -7
  3. package/dist/packages/adapters/src/index.js +204 -10
  4. package/dist/packages/core/src/active-run.js +13 -1
  5. package/dist/packages/core/src/artifacts.js +14 -4
  6. package/dist/packages/core/src/config.js +88 -17
  7. package/dist/packages/core/src/index.js +1 -0
  8. package/dist/packages/core/src/lock.js +89 -0
  9. package/dist/packages/core/src/paths.js +10 -6
  10. package/dist/packages/core/src/store.js +40 -0
  11. package/dist/packages/core/src/types.js +4 -1
  12. package/dist/packages/core/src/validation.js +7 -1
  13. package/dist/packages/core/src/version.js +1 -1
  14. package/dist/packages/core/src/workflow.js +87 -12
  15. package/dist/packages/orchestrator/src/index.js +317 -18
  16. package/dist/packages/plugins/src/index.js +2 -32
  17. package/dist/packages/service/src/tools.js +117 -17
  18. package/docs/claude-code.md +18 -3
  19. package/docs/codex.md +22 -5
  20. package/docs/quickstart.md +1 -1
  21. package/docs/superpowers/plans/2026-07-13-safety-semantics.md +313 -0
  22. package/docs/superpowers/plans/2026-07-14-p0-remediation.md +213 -0
  23. package/docs/superpowers/plans/2026-07-14-reliability-recovery.md +208 -0
  24. package/docs/superpowers/plans/2026-07-14-structured-role-results.md +231 -0
  25. package/docs/superpowers/specs/2026-07-13-execution-boundaries-design.md +126 -0
  26. package/docs/superpowers/specs/2026-07-14-p0-remediation-design.md +52 -0
  27. package/docs/superpowers/specs/2026-07-14-reliability-recovery-design.md +92 -0
  28. package/docs/superpowers/specs/2026-07-14-structured-role-results-design.md +96 -0
  29. package/docs/workflow.md +28 -4
  30. package/package.json +1 -1
  31. package/packages/adapters/src/index.ts +250 -13
  32. package/packages/core/src/active-run.ts +13 -1
  33. package/packages/core/src/artifacts.ts +16 -4
  34. package/packages/core/src/config.ts +97 -18
  35. package/packages/core/src/index.ts +1 -0
  36. package/packages/core/src/lock.ts +104 -0
  37. package/packages/core/src/paths.ts +11 -6
  38. package/packages/core/src/store.ts +45 -1
  39. package/packages/core/src/types.ts +92 -2
  40. package/packages/core/src/validation.ts +10 -0
  41. package/packages/core/src/version.ts +1 -1
  42. package/packages/core/src/workflow.ts +101 -11
  43. package/packages/orchestrator/src/index.ts +349 -19
  44. package/packages/plugins/src/index.ts +2 -44
  45. package/packages/service/src/tools.ts +126 -15
  46. package/plugins/devcrew-codex/.codex-plugin/plugin.json +1 -1
  47. package/plugins/devcrew-codex/.mcp.json +1 -1
  48. package/plugins/devcrew-codex/skills/devcrew/SKILL.md +8 -7
  49. package/scripts/smoke-codex-plugin.mjs +1 -1
  50. package/plugins/devcrew-codex/agents/architect.toml +0 -12
  51. package/plugins/devcrew-codex/agents/implementer.toml +0 -12
  52. package/plugins/devcrew-codex/agents/pm.toml +0 -13
  53. package/plugins/devcrew-codex/agents/tester.toml +0 -12
@@ -0,0 +1,213 @@
1
+ # P0 Verification and Review Remediation Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Prevent unverified apply patches from being promoted and send architecture-review findings back through implementation.
6
+
7
+ **Architecture:** Keep `verificationStatus` as the single source for testing-gate policy. Treat `failed` and `not_run` identically for blocking, but allow the existing persisted waiver to reopen either state. Reuse the existing testing-rejection recovery pattern for implementation-review findings, preserving the isolated worktree while returning the state machine to `execution/ready`.
8
+
9
+ **Tech Stack:** TypeScript, Node.js test runner, Git worktrees, existing DevCrew MCP/orchestrator APIs.
10
+
11
+ ---
12
+
13
+ ### Task 1: Block missing verification evidence
14
+
15
+ **Files:**
16
+ - Modify: `tests/orchestrator.test.ts:483-533`
17
+ - Modify: `packages/orchestrator/src/index.ts:241-253, 552-558`
18
+ - Modify: `packages/core/src/workflow.ts:297-314`
19
+
20
+ - [ ] **Step 1: Write failing no-verification tests**
21
+
22
+ Add a test after the failed-verification test that creates an apply fixture with
23
+ an empty `verifyCommands` list and no discoverable manifest. Advance it through
24
+ testing and assert the following:
25
+
26
+ ```ts
27
+ assert.equal(tested.verificationStatus, "not_run");
28
+ assert.equal(tested.gates.testing, "rejected");
29
+ assert.equal(tested.status, "awaiting_input");
30
+ await assert.rejects(
31
+ () => approveOrchestratedWorkflow({ cwd, runId: tested.runId, gate: "testing" }),
32
+ /not pending approval/i,
33
+ );
34
+ ```
35
+
36
+ In the same test, call `waiveOrchestratedVerification` with a non-empty reason,
37
+ assert `testing: pending` and `awaiting_approval`, then approve testing and
38
+ assert the reviewed file was promoted. Add a second assertion that directly
39
+ sets a persisted test fixture to `verificationStatus: "not_run"`, a pending
40
+ testing gate, and no waiver, then expects `approveOrchestratedWorkflow` to
41
+ throw `Verification must pass before promotion`.
42
+
43
+ - [ ] **Step 2: Run the focused test and verify RED**
44
+
45
+ Run:
46
+
47
+ ```bash
48
+ node --import tsx --test tests/orchestrator.test.ts
49
+ ```
50
+
51
+ Expected: the new test fails because `not_run` currently opens a pending gate
52
+ and the waiver operation rejects it.
53
+
54
+ - [ ] **Step 3: Implement the minimal verification policy**
55
+
56
+ In `setTestingGateFromVerification`, replace the `failed`-only branch with a
57
+ non-passed branch. Preserve the existing failed message and add a distinct
58
+ missing-evidence message:
59
+
60
+ ```ts
61
+ if (state.verificationStatus !== "passed") {
62
+ state.gates.testing = "rejected";
63
+ state.status = "awaiting_input";
64
+ state.feedback.push({
65
+ gate: "testing",
66
+ message: state.verificationStatus === "failed"
67
+ ? "Automated verification failed. Inspect the test report, revise the implementation, or record an explicit verification waiver with its reason."
68
+ : "No verification evidence was recorded. Configure or run validation, revise the implementation, or record an explicit verification waiver with its reason.",
69
+ createdAt: now(),
70
+ });
71
+ return;
72
+ }
73
+ ```
74
+
75
+ Update `waiveVerificationWorkflow` to accept either `failed` or `not_run` and
76
+ change its error message to mention failed or missing verification. In
77
+ `approveOrchestratedWorkflow`, replace the failed-only promotion check with:
78
+
79
+ ```ts
80
+ if (before.verificationStatus !== "passed" && !before.verificationWaiver) {
81
+ throw new Error("Verification must pass before promotion or have an explicit verification waiver");
82
+ }
83
+ ```
84
+
85
+ - [ ] **Step 4: Run focused tests and verify GREEN**
86
+
87
+ Run:
88
+
89
+ ```bash
90
+ node --import tsx --test tests/orchestrator.test.ts
91
+ ```
92
+
93
+ Expected: all orchestrator tests pass, including failed and missing
94
+ verification waiver paths.
95
+
96
+ - [ ] **Step 5: Commit the verification fix**
97
+
98
+ ```bash
99
+ git add packages/core/src/workflow.ts packages/orchestrator/src/index.ts tests/orchestrator.test.ts
100
+ git commit -m "fix: block promotion without verification evidence"
101
+ ```
102
+
103
+ ### Task 2: Return review findings to execution
104
+
105
+ **Files:**
106
+ - Modify: `tests/orchestrator.test.ts:365-421`
107
+ - Modify: `packages/orchestrator/src/index.ts:639-658`
108
+ - Modify: `docs/workflow.md:45-49`
109
+
110
+ - [ ] **Step 1: Write the failing review-remediation test**
111
+
112
+ Extend `architecture review blocks testing when it requires changes` after its
113
+ current rejection assertions. Call `answerOrchestratedWorkflow` with a
114
+ non-empty answer and assert:
115
+
116
+ ```ts
117
+ assert.equal(revised.phase, "execution");
118
+ assert.equal(revised.status, "ready");
119
+ assert.equal(revised.gates["implementation-review"], "not_started");
120
+ assert.equal(revised.executionWorkspace?.path, workspacePath);
121
+ ```
122
+
123
+ Then call `continueOrchestratedWorkflow` with a runner that records its phase
124
+ and assert the next executed role has `phase === "execution"` and
125
+ `role === "implementer"`, not `review`/`architect`.
126
+
127
+ - [ ] **Step 2: Run the focused test and verify RED**
128
+
129
+ Run:
130
+
131
+ ```bash
132
+ node --import tsx --test tests/orchestrator.test.ts
133
+ ```
134
+
135
+ Expected: the new assertions fail because `devcrew_answer` currently re-runs
136
+ the review phase.
137
+
138
+ - [ ] **Step 3: Implement the remediation transition**
139
+
140
+ Add this branch in `answerOrchestratedWorkflow` immediately after the existing
141
+ testing-rejection branch:
142
+
143
+ ```ts
144
+ if (
145
+ before.executionMode === "apply" &&
146
+ before.phase === "review" &&
147
+ before.gates["implementation-review"] === "rejected" &&
148
+ before.architectureReview?.decision === "changes_required"
149
+ ) {
150
+ state.phase = "execution";
151
+ state.status = "ready";
152
+ state.gates["implementation-review"] = "not_started";
153
+ return saveState(state);
154
+ }
155
+ ```
156
+
157
+ Do not clear `executionWorkspace`, `architectureReview`, feedback, or the
158
+ prior review artifact; they remain audit evidence and the next execution phase
159
+ will refresh the captured diff and create a new review.
160
+
161
+ - [ ] **Step 4: Update the workflow documentation**
162
+
163
+ Replace the current claim that feedback must be addressed before another review
164
+ with text stating that `devcrew_answer` returns the run to the isolated
165
+ `execution/ready` state and a later `devcrew_continue` performs the revised
166
+ implementation before a fresh architect review.
167
+
168
+ - [ ] **Step 5: Run focused tests and verify GREEN**
169
+
170
+ Run:
171
+
172
+ ```bash
173
+ node --import tsx --test tests/orchestrator.test.ts
174
+ ```
175
+
176
+ Expected: all orchestrator tests pass and the remediation test observes an
177
+ implementer execution before a subsequent review.
178
+
179
+ - [ ] **Step 6: Commit the remediation fix**
180
+
181
+ ```bash
182
+ git add docs/workflow.md packages/orchestrator/src/index.ts tests/orchestrator.test.ts
183
+ git commit -m "fix: return architecture findings to execution"
184
+ ```
185
+
186
+ ### Task 3: Full verification
187
+
188
+ **Files:**
189
+ - Verify: `packages/core/src/workflow.ts`
190
+ - Verify: `packages/orchestrator/src/index.ts`
191
+ - Verify: `tests/orchestrator.test.ts`
192
+
193
+ - [ ] **Step 1: Run the complete repository validation**
194
+
195
+ Run:
196
+
197
+ ```bash
198
+ npm run validate
199
+ ```
200
+
201
+ Expected: TypeScript compilation succeeds and every test passes.
202
+
203
+ - [ ] **Step 2: Inspect the final diff**
204
+
205
+ Run:
206
+
207
+ ```bash
208
+ git diff main...HEAD --check
209
+ git status --short
210
+ ```
211
+
212
+ Expected: no whitespace errors; only the two implementation commits and this
213
+ plan/spec commits are present on the branch.
@@ -0,0 +1,208 @@
1
+ # Configuration Integrity and Run Recovery Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Reject unsafe configuration, prevent concurrent MCP mutations from overwriting one another, and make interrupted runs explicitly abortable and recoverable.
6
+
7
+ **Architecture:** A strict version-1 parser validates `.devcrew/config.json` and keeps artifact paths inside the requester repository. A repository-wide atomic directory lock wraps MCP mutations while read-only calls remain available. Aborting is a persisted terminal state that preserves audit data; recovery only clears a confirmed stale lock and retries cleanup of a terminal run's residual worktree.
8
+
9
+ **Tech Stack:** TypeScript, Node.js `fs/promises`, Node test runner, Git worktrees, MCP tool registry.
10
+
11
+ ---
12
+
13
+ ### Task 1: Validate configuration and artifact paths
14
+
15
+ **Files:**
16
+ - Modify: `packages/core/src/config.ts`
17
+ - Modify: `tests/core.test.ts`
18
+
19
+ - [ ] **Step 1: Write failing configuration tests**
20
+
21
+ Add table-driven tests that write `.devcrew/config.json`, then call
22
+ `startWorkflow`. Cover an unknown top-level key, an unknown workflow key, an
23
+ unknown gate, a duplicate gate, an empty command, an absolute
24
+ `artifactDirectory`, and `../outside`. Each test asserts the error identifies
25
+ the invalid field. Add a valid custom artifact directory assertion so the
26
+ existing supported path remains accepted.
27
+
28
+ - [ ] **Step 2: Verify RED**
29
+
30
+ Run:
31
+
32
+ ```bash
33
+ node --import tsx --test tests/core.test.ts
34
+ ```
35
+
36
+ Expected: new invalid-config cases fail because `readConfig` currently merges
37
+ untyped JSON and `artifactDirectory` is only joined to `cwd`.
38
+
39
+ - [ ] **Step 3: Implement a strict version-1 parser**
40
+
41
+ In `config.ts`, parse JSON as `unknown`, require plain objects, reject keys
42
+ outside the documented schema, validate enum values from exported type
43
+ constants, and validate arrays as non-empty trimmed strings with no invalid
44
+ gate entries or duplicates. Resolve `workflow.artifactDirectory` against
45
+ `cwd`; reject absolute values and any resolved path whose relative path leaves
46
+ the repository. Return the normalized validated `DevCrewConfig`.
47
+
48
+ - [ ] **Step 4: Verify GREEN and commit**
49
+
50
+ Run:
51
+
52
+ ```bash
53
+ node --import tsx --test tests/core.test.ts
54
+ git add packages/core/src/config.ts tests/core.test.ts
55
+ git commit -m "fix: validate DevCrew configuration strictly"
56
+ ```
57
+
58
+ Expected: all core tests pass and invalid configuration fails before a run is
59
+ created.
60
+
61
+ ### Task 2: Add explicit repository mutation locks
62
+
63
+ **Files:**
64
+ - Create: `packages/core/src/lock.ts`
65
+ - Modify: `packages/core/src/paths.ts`
66
+ - Modify: `packages/core/src/index.ts`
67
+ - Modify: `packages/service/src/tools.ts`
68
+ - Modify: `tests/core.test.ts`
69
+ - Modify: `tests/service.test.ts`
70
+
71
+ - [ ] **Step 1: Write failing lock tests**
72
+
73
+ Add core tests that hold a repository lock while a second acquisition rejects
74
+ with a busy error, then release the first lock and acquire again. Create a
75
+ lock directory with metadata containing a non-running pid and assert normal
76
+ acquisition still refuses it while explicit stale-lock recovery removes it.
77
+ Add a service test that holds the lock, verifies `devcrew_status` still works,
78
+ and verifies a mutating `devcrew_approve` returns a structured busy error.
79
+
80
+ - [ ] **Step 2: Verify RED**
81
+
82
+ Run:
83
+
84
+ ```bash
85
+ node --import tsx --test tests/core.test.ts tests/service.test.ts
86
+ ```
87
+
88
+ Expected: imports fail because no repository lock API exists and MCP calls do
89
+ not serialize mutations.
90
+
91
+ - [ ] **Step 3: Implement lock primitives**
92
+
93
+ Add `repositoryLockPath`, then implement `withRepositoryLock(cwd, action)`
94
+ using atomic `mkdir`. Store `{ ownerId, pid, createdAt }` in `lock.json`,
95
+ remove only the held owner directory in `finally`, and reject existing locks
96
+ without waiting. Implement `recoverRepositoryLock(cwd)` to remove only a
97
+ missing/invalid/dead-local-process lock; it must reject a live owner and must
98
+ never run automatically.
99
+
100
+ - [ ] **Step 4: Wrap MCP mutation dispatch**
101
+
102
+ In `callDevCrewTool`, route start, answer, approve, reject, continue,
103
+ complete-execution, waive-verification, abort, and recovery cleanup through a
104
+ single lock wrapper. Resolve an omitted run id inside the lock. Keep status and
105
+ artifact calls unlocked. Ensure start creates its run and sets `active-run`
106
+ under one lock.
107
+
108
+ - [ ] **Step 5: Verify GREEN and commit**
109
+
110
+ Run:
111
+
112
+ ```bash
113
+ node --import tsx --test tests/core.test.ts tests/service.test.ts
114
+ git add packages/core/src/lock.ts packages/core/src/paths.ts packages/core/src/index.ts packages/service/src/tools.ts tests/core.test.ts tests/service.test.ts
115
+ git commit -m "fix: serialize DevCrew MCP mutations"
116
+ ```
117
+
118
+ Expected: concurrent writes return a structured busy error and reads remain
119
+ available.
120
+
121
+ ### Task 3: Persist terminal aborts and recover residual worktrees
122
+
123
+ **Files:**
124
+ - Modify: `packages/core/src/types.ts`
125
+ - Modify: `packages/core/src/active-run.ts`
126
+ - Modify: `packages/core/src/workflow.ts`
127
+ - Modify: `packages/orchestrator/src/index.ts`
128
+ - Modify: `packages/service/src/tools.ts`
129
+ - Modify: `docs/workflow.md`
130
+ - Modify: `tests/core.test.ts`
131
+ - Modify: `tests/orchestrator.test.ts`
132
+ - Modify: `tests/service.test.ts`
133
+
134
+ - [ ] **Step 1: Write failing abort and recovery tests**
135
+
136
+ Add a workflow test that aborts a nonterminal state with a reason, asserts
137
+ `status: "aborted"`, persisted reason/timestamp, and that continue/answer/
138
+ complete cannot resume it. Add an apply-worktree test that aborts after
139
+ execution, confirms the requester checkout is unchanged and the isolated
140
+ worktree is removed. Add a service test that `devcrew_abort` clears its active
141
+ run and that a repeated abort is idempotent. Add a recovery test for an
142
+ aborted state retaining a workspace reference: recovery cleans that worktree
143
+ and clears the reference without running a role.
144
+
145
+ - [ ] **Step 2: Verify RED**
146
+
147
+ Run:
148
+
149
+ ```bash
150
+ node --import tsx --test tests/core.test.ts tests/orchestrator.test.ts tests/service.test.ts
151
+ ```
152
+
153
+ Expected: tests fail because `aborted` is not a run status and no abort or
154
+ recovery tool exists.
155
+
156
+ - [ ] **Step 3: Implement terminal abort state**
157
+
158
+ Add `RunAbort` plus `RunStatus: "aborted"`; persist the first non-empty abort
159
+ reason and timestamp. Add `abortWorkflow` with terminal idempotency, and make
160
+ continuation return aborted runs unchanged. Add
161
+ `clearActiveRunIfMatches(cwd, runId)` so an abort never clears another run's
162
+ active pointer.
163
+
164
+ - [ ] **Step 4: Implement orchestration and MCP lifecycle tools**
165
+
166
+ Add `abortOrchestratedWorkflow` to persist abort audit state before attempting
167
+ worktree cleanup. On cleanup success clear `executionWorkspace`; on failure
168
+ leave it for recovery. Add `recoverOrchestratedWorkflow` that accepts only
169
+ terminal runs and retries this cleanup. Register `devcrew_abort` and
170
+ `devcrew_recover`, with schemas and structured errors, and apply the lock
171
+ rules from Task 2. Update `docs/workflow.md` with abort/recover semantics.
172
+
173
+ - [ ] **Step 5: Verify GREEN and commit**
174
+
175
+ Run:
176
+
177
+ ```bash
178
+ node --import tsx --test tests/core.test.ts tests/orchestrator.test.ts tests/service.test.ts
179
+ git add packages/core/src/types.ts packages/core/src/active-run.ts packages/core/src/workflow.ts packages/orchestrator/src/index.ts packages/service/src/tools.ts docs/workflow.md tests/core.test.ts tests/orchestrator.test.ts tests/service.test.ts
180
+ git commit -m "feat: add DevCrew abort and recovery controls"
181
+ ```
182
+
183
+ Expected: aborted runs retain audit evidence, cannot resume, clean their
184
+ worktrees when possible, and can explicitly retry residual cleanup.
185
+
186
+ ### Task 4: Full verification
187
+
188
+ **Files:**
189
+ - Verify: all modified files
190
+
191
+ - [ ] **Step 1: Run repository validation**
192
+
193
+ ```bash
194
+ npm run validate
195
+ ```
196
+
197
+ Expected: TypeScript build succeeds and every test passes.
198
+
199
+ - [ ] **Step 2: Inspect final state**
200
+
201
+ ```bash
202
+ git diff main...HEAD --check
203
+ git status --short
204
+ git log --oneline main..HEAD
205
+ ```
206
+
207
+ Expected: no whitespace errors, clean worktree, and only the design, plan,
208
+ and implementation commits on the branch.
@@ -0,0 +1,231 @@
1
+ # Structured Role Results Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Accept validated, versioned role-result envelopes while preserving Markdown-only SDK outputs and expose structured evidence through run state, artifacts, and MCP.
6
+
7
+ **Architecture:** The core package owns envelope types and state migration. The adapter recognizes one explicitly marked JSON block, validates role-specific data, and returns Markdown with the protocol block removed. The orchestrator uses the normalized result without changing gates; artifacts render a human-readable appendix, and MCP continues returning the persisted state.
8
+
9
+ **Tech Stack:** TypeScript strict mode, Node.js built-in test runner, `tsx`.
10
+
11
+ ---
12
+
13
+ ### Task 1: Define normalized envelope types and old-state migration
14
+
15
+ **Files:**
16
+ - Modify: `packages/core/src/types.ts:91-100`
17
+ - Modify: `packages/core/src/store.ts:24-70`
18
+ - Test: `tests/core.test.ts`
19
+
20
+ - [ ] **Step 1: Write the failing migration test**
21
+
22
+ Append this test to `tests/core.test.ts`:
23
+
24
+ ```ts
25
+ test("loadState marks pre-envelope role results as legacy", async () => {
26
+ const cwd = await tempProject();
27
+ const started = await startWorkflow({ cwd, host: "codex", mode: "feature", request: "Migrate roles" });
28
+ const path = runDir(cwd, started.runId);
29
+ const raw = JSON.parse(await readFile(join(path, "state.json"), "utf8")) as Record<string, unknown>;
30
+ raw.roles = [{ role: "pm", backend: "codex", summary: "old", markdown: "# Old", usedFallback: false }];
31
+ await writeFile(join(path, "state.json"), JSON.stringify(raw));
32
+
33
+ const role = (await loadState(cwd, started.runId)).roles[0] as unknown as { format?: string };
34
+ assert.equal(role.format, "legacy");
35
+ });
36
+ ```
37
+
38
+ - [ ] **Step 2: Verify it fails**
39
+
40
+ Run: `npm test -- --test-name-pattern="pre-envelope role"`
41
+
42
+ Expected: FAIL because `RoleResult.format` does not exist.
43
+
44
+ - [ ] **Step 3: Add the smallest normalized types and migration**
45
+
46
+ Add these exports in `packages/core/src/types.ts` and make `format` mandatory on `RoleResult`:
47
+
48
+ ```ts
49
+ export interface CommandEvidence {
50
+ command: string;
51
+ exitCode: number;
52
+ output?: string;
53
+ }
54
+
55
+ export interface RoleQuestion {
56
+ id: string;
57
+ prompt: string;
58
+ context?: string;
59
+ }
60
+
61
+ export interface StructuredRoleData {
62
+ schemaVersion: 1;
63
+ role: Exclude<RoleResult["role"], "conductor">;
64
+ summary: string;
65
+ risks: string[];
66
+ evidence: CommandEvidence[];
67
+ questions?: RoleQuestion[];
68
+ decisions?: string[];
69
+ reviewDecision?: ArchitectureReviewDecision;
70
+ changedFiles?: string[];
71
+ testCases?: Array<{ id: string; scenario: string; type: "happy" | "edge" | "failure" | "regression"; expected: string }>;
72
+ }
73
+ ```
74
+
75
+ In `loadState`, map each persisted role missing a valid `format` to `{ ...role, format: "legacy" }`, leaving all prior persisted fields intact.
76
+
77
+ - [ ] **Step 4: Verify it passes**
78
+
79
+ Run: `npm test -- --test-name-pattern="pre-envelope role"`
80
+
81
+ Expected: PASS.
82
+
83
+ - [ ] **Step 5: Commit**
84
+
85
+ ```bash
86
+ git add packages/core/src/types.ts packages/core/src/store.ts tests/core.test.ts
87
+ git commit -m "feat: normalize persisted role results"
88
+ ```
89
+
90
+ ### Task 2: Parse and validate the marked envelope in adapters
91
+
92
+ **Files:**
93
+ - Modify: `packages/adapters/src/index.ts:69-102,143-162,424-459`
94
+ - Test: `tests/adapters.test.ts`
95
+
96
+ - [ ] **Step 1: Write failing parser tests**
97
+
98
+ Export `parseRoleResultOutput` and add tests that call it with this valid PM output and each invalid variation:
99
+
100
+ ```ts
101
+ const output = `<!-- devcrew-role-result -->
102
+ \`\`\`json
103
+ {"schemaVersion":1,"role":"pm","summary":"Need scope","risks":[],"evidence":[],"questions":[{"id":"format","prompt":"Which formats?"}]}
104
+ \`\`\`
105
+ # Requirements
106
+
107
+ ## Functional Scope
108
+ `;
109
+ const result = parseRoleResultOutput("pm", "requirements", output);
110
+ assert.equal(result.format, "structured");
111
+ assert.deepEqual(result.questions, ["Which formats?"]);
112
+ assert.doesNotMatch(result.markdown, /devcrew-role-result/);
113
+ ```
114
+
115
+ Add separate `assert.throws` tests for malformed marked JSON, two marked blocks, `schemaVersion: 2`, role mismatch, duplicate/blank PM question IDs, and a non-integer command exit code. Add a Markdown-only test proving `format === "legacy"` and existing PM/review parsing remain unchanged.
116
+
117
+ - [ ] **Step 2: Verify they fail**
118
+
119
+ Run: `npm test -- --test-name-pattern="role result output"`
120
+
121
+ Expected: FAIL because `parseRoleResultOutput` is not exported.
122
+
123
+ - [ ] **Step 3: Implement the protocol parser and prompt contract**
124
+
125
+ Implement a parser that finds exactly one `<!-- devcrew-role-result -->` followed by a `json` fenced block. When no marker exists, return the original Markdown and `format: "legacy"`; when a marker exists, reject malformed or invalid data. Require all common fields, role-matching field sets, unique PM question IDs, nonempty strings, and integer command exit codes. Return the Markdown with only the marked block removed.
126
+
127
+ Add this exact prompt guidance before `Required Sections`:
128
+
129
+ ```ts
130
+ "Return this protocol block first:",
131
+ "<!-- devcrew-role-result -->",
132
+ "```json",
133
+ "{\"schemaVersion\":1,\"role\":\"<current role>\",\"summary\":\"...\",\"risks\":[],\"evidence\":[]}",
134
+ "```",
135
+ "Then return the required Markdown H2 sections. Do not include a second marked result block.",
136
+ ```
137
+
138
+ Replace direct Markdown extraction in `runRole` with the parser's normalized result. For legacy output, keep `extractOpenQuestions` and `extractArchitectureReviewDecision`; for structured output, derive those compatibility fields from validated structured data.
139
+
140
+ - [ ] **Step 4: Verify adapter tests pass**
141
+
142
+ Run: `npm test -- tests/adapters.test.ts`
143
+
144
+ Expected: PASS.
145
+
146
+ - [ ] **Step 5: Commit**
147
+
148
+ ```bash
149
+ git add packages/adapters/src/index.ts tests/adapters.test.ts
150
+ git commit -m "feat: parse structured role result envelopes"
151
+ ```
152
+
153
+ ### Task 3: Persist and render structured implementation and test evidence
154
+
155
+ **Files:**
156
+ - Modify: `packages/orchestrator/src/index.ts:317-344,456-481`
157
+ - Test: `tests/orchestrator.test.ts`
158
+
159
+ - [ ] **Step 1: Write failing workflow tests**
160
+
161
+ Add a structured PM runner result with a question and assert `awaiting_input`. Add an implementation result with `format: "structured"` and `structured.changedFiles` plus command evidence, then assert the persisted role retains them and `implementation-review.md` contains `## Structured Role Result` and the command/exit code. Add an analogous tester assertion for `test-report.md` risks and evidence.
162
+
163
+ - [ ] **Step 2: Verify they fail**
164
+
165
+ Run: `npm test -- --test-name-pattern="structured (PM|implementation|tester)"`
166
+
167
+ Expected: FAIL because artifacts do not render structured role data.
168
+
169
+ - [ ] **Step 3: Render the structured appendix without changing workflow evidence sources**
170
+
171
+ Add an orchestrator artifact helper used by `appendExecutionSections` that renders `state.roles.at(-1)?.structured` only when `format === "structured"`. It must show schema version, summary, changed files, command evidence, test cases, risks, and questions when present, escaping no data and preserving the role's Markdown body as the primary artifact.
172
+
173
+ Keep the existing captured Git diff and configured verification as authoritative promotion evidence. Structured implementation `changedFiles` and tester commands are supplemental role assertions, not a way to overwrite `state.changedFiles`, `state.implementationDiff`, or `state.verification`.
174
+
175
+ In the orchestrator, use structured PM question prompts for `pendingQuestions` and structured review decisions for `architectureReview`; preserve the existing compatibility fields so legacy runners and callers continue to work.
176
+
177
+ - [ ] **Step 4: Verify workflow tests pass**
178
+
179
+ Run: `npm test -- tests/orchestrator.test.ts`
180
+
181
+ Expected: PASS.
182
+
183
+ - [ ] **Step 5: Commit**
184
+
185
+ ```bash
186
+ git add packages/orchestrator/src/index.ts tests/orchestrator.test.ts
187
+ git commit -m "feat: render structured role evidence"
188
+ ```
189
+
190
+ ### Task 4: Surface format and results through MCP and complete regression checks
191
+
192
+ **Files:**
193
+ - Modify: `packages/service/src/tools.ts:215-320`
194
+ - Test: `tests/service.test.ts`
195
+ - Modify: `docs/codex.md`
196
+ - Modify: `docs/claude-code.md`
197
+
198
+ - [ ] **Step 1: Write the failing MCP test**
199
+
200
+ Start a workflow with a structured PM runner, invoke `devcrew_status`, and assert its text includes `role_format=structured` plus `structuredContent.state.roles.at(-1).structured.questions[0].id === "format"`. The test must use `callDevCrewTool`, not inspect the state file directly.
201
+
202
+ - [ ] **Step 2: Verify it fails**
203
+
204
+ Run: `npm test -- --test-name-pattern="MCP.*structured role"`
205
+
206
+ Expected: FAIL until the state summary exposes the normalized role format.
207
+
208
+ - [ ] **Step 3: Keep MCP state safe and document the migration**
209
+
210
+ Return the existing state object unchanged except for its newly persisted normalized role fields; do not create a second incompatible tool response shape. Extend `summarizeState` with `role_format=<legacy|structured|none>`.
211
+
212
+ Document the marker, schema version, legacy fallback rule, and the rule that malformed marked output is rejected rather than downgraded in both host guides.
213
+
214
+ - [ ] **Step 4: Verify the focused service test passes**
215
+
216
+ Run: `npm test -- tests/service.test.ts`
217
+
218
+ Expected: PASS.
219
+
220
+ - [ ] **Step 5: Run complete validation and inspect the patch**
221
+
222
+ Run: `npm run validate && npm test && git diff main...HEAD --check`
223
+
224
+ Expected: validation and all tests pass; whitespace check prints no output.
225
+
226
+ - [ ] **Step 6: Commit**
227
+
228
+ ```bash
229
+ git add packages/service/src/tools.ts tests/service.test.ts docs/codex.md docs/claude-code.md
230
+ git commit -m "docs: describe structured role result migration"
231
+ ```