@pilotspace/add 1.8.0 → 1.10.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 (38) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/bin/cli.js +137 -2
  3. package/docs/16-releasing.md +2 -2
  4. package/docs/17-components.md +125 -0
  5. package/docs/appendix-c-glossary.md +8 -0
  6. package/package.json +2 -2
  7. package/skill/add/SKILL.md +90 -116
  8. package/skill/add/adopt.md +13 -34
  9. package/skill/add/advisor.md +9 -10
  10. package/skill/add/compact-foundation.md +21 -34
  11. package/skill/add/components.md +54 -0
  12. package/skill/add/confidence.md +9 -25
  13. package/skill/add/deltas.md +12 -28
  14. package/skill/add/design.md +26 -32
  15. package/skill/add/fold.md +26 -51
  16. package/skill/add/graduate.md +18 -54
  17. package/skill/add/intake.md +30 -34
  18. package/skill/add/loop.md +30 -34
  19. package/skill/add/phases/0-ground.md +6 -14
  20. package/skill/add/phases/0-setup.md +30 -81
  21. package/skill/add/phases/1-specify.md +7 -22
  22. package/skill/add/phases/2-scenarios.md +1 -3
  23. package/skill/add/phases/3-contract.md +8 -22
  24. package/skill/add/phases/4-tests.md +3 -6
  25. package/skill/add/phases/5-build.md +8 -22
  26. package/skill/add/phases/6-verify.md +14 -49
  27. package/skill/add/phases/7-observe.md +1 -3
  28. package/skill/add/phases/fast-lane.md +31 -0
  29. package/skill/add/release.md +36 -90
  30. package/skill/add/report-template.md +41 -126
  31. package/skill/add/run.md +89 -159
  32. package/skill/add/scope.md +40 -89
  33. package/skill/add/setup-review.md +10 -27
  34. package/skill/add/soul.md +17 -36
  35. package/skill/add/streams.md +90 -149
  36. package/tooling/add.py +804 -14
  37. package/tooling/templates/TASK.fast.md.tmpl +72 -0
  38. package/tooling/templates/TASK.md.tmpl +1 -1
package/skill/add/soul.md CHANGED
@@ -1,37 +1,26 @@
1
1
  # Self-improving the voice — how SOUL.md converges to the human
2
2
 
3
- `SOUL.md` is the AI's voice (tone · communication style · trust). It ships as a **proposed starter**
4
- and is **human-owned**; this doc is how it stops being write-once and starts converging to *this*
5
- human. It mirrors `deltas.md` (emit) + `fold.md` (confirm → rewrite), but a confirmed voice delta is
6
- consolidated into **SOUL.md**, not the foundation — because voice is not one of the five competencies.
3
+ `SOUL.md` is the AI's voice (Tone · Communication style · Trust). It ships as a **proposed starter** and is **human-owned**; this doc is how it starts converging to *this* human. It mirrors `deltas.md` (emit) + `fold.md` (confirm → rewrite), but a confirmed voice delta consolidates into **SOUL.md**, not the foundation — voice is not one of the five competencies.
7
4
 
8
- You (the AI) **emit** voice deltas as `open`. Only the **human** confirms one, and only a confirmed
9
- delta rewrites SOUL.md. **The human's confirm is the only writer** — you never self-approve a voice
10
- rewrite (rewriting someone's voice is theirs to approve, like a foundation consolidation).
5
+ You **emit** voice deltas as `open`. Only the **human** confirms one; **the human's confirm is the only writer** — you never self-approve a voice rewrite.
11
6
 
12
7
  ## What a voice delta is drawn from
13
8
 
14
- A voice delta is grounded in how the human actually shows up **in session**:
15
- - their **wordings** — the words they reach for, and the words they correct you on (they cross out a
16
- bit of jargon and write the plain word over it);
17
- - their **flow** — what they skip, what they double-check, where they want the summary before the detail.
9
+ A voice delta is grounded in how the human shows up **in session**:
10
+ - their **wordings** — the words they reach for, and the words they correct you on;
11
+ - their **flow** what they skip, what they double-check, where they want summary before detail.
18
12
 
19
- NOT from their private **memory** files or anything outside the working session — SOUL learns from what
20
- you observed together, never from reading a personal store.
13
+ NOT from their private **memory** files or anything outside the working session — SOUL learns only from what you observed together.
21
14
 
22
15
  ## The grammar (mirrors deltas.md)
23
16
 
24
- Each voice delta begins on its own tag line; the observation may wrap, and a required `(evidence: …)`
25
- clause closes it:
26
-
27
17
  ```
28
18
  - [VOICE · <status>] <observation about the voice> (evidence: <in-session pointer>)
29
19
  ```
30
20
 
31
- - `<status>` — `open` | `confirmed` | `declined`. A newly emitted delta is **`open`**.
32
21
  - `<observation>` — what the voice should become ("lead with the decision, not the preamble").
33
- - `(evidence: …)` **required**, non-empty: a moment in the session (a correction, a re-ask, a
34
- visible preference). No evidence it is a guess about the human, not a delta. Drop it.
22
+ - `<status>``open` | `confirmed` | `declined`. A newly emitted delta is **`open`**.
23
+ - `(evidence: …)` **required**, non-empty: a moment in the session (a correction, a re-ask, a visible preference). No evidence → drop it.
35
24
 
36
25
  ```
37
26
  - [VOICE · open] the human strips hedging from my drafts — cut "I think / it seems" and state it plainly
@@ -40,12 +29,9 @@ clause closes it:
40
29
 
41
30
  ## The loop — observe → confirm → rewrite
42
31
 
43
- 1. **Emit** (OBSERVE) — at a task's observe phase (or on demand), propose 0–N voice deltas as `open`
44
- from the session's wordings + flow. Surface them in the report; show-before-ask.
32
+ 1. **Emit** (OBSERVE) — propose 0–N voice deltas as `open` from wordings + flow. Surface in the report; show-before-ask.
45
33
  2. **Confirm** — the human accepts or declines each. **No SOUL.md write happens without this.**
46
- 3. **Rewrite** — on a confirmed delta, edit the routed SOUL.md section, then record the delta line
47
- (status `confirmed`) at the **top** of the "Voice deltas" ledger (**newest-first**, append-only — a
48
- declined delta flips to `declined` and stays in place, so "considered, chose not to" is auditable).
34
+ 3. **Rewrite** — on a confirmed delta, edit the routed SOUL.md section, record the delta line (`confirmed`) at the **top** of "Voice deltas" (**newest-first**, append-only — declined stays in place).
49
35
 
50
36
  ## Routing — every voice delta has a SOUL.md home
51
37
 
@@ -55,23 +41,18 @@ clause closes it:
55
41
  | how I *structure* what I say (summary-first, show-before-ask, length) | **## Communication style** |
56
42
  | what keeps the human's *trust* (gates, honesty, what I never do) | **## Trust** |
57
43
 
58
- The rewrite is surgical: refine or append the bullet the delta names; never silently rewrite the rest
59
- of the voice. Every confirmed delta also gets its line in **## Voice deltas** (newest-first).
44
+ The rewrite is surgical: refine or append the bullet the delta names; never silently rewrite the rest of the voice. Every confirmed delta also gets its line in **## Voice deltas** (newest-first).
60
45
 
61
- ## Reject codes (the AI is first check, the human the backstop)
46
+ ## Reject codes
62
47
 
63
48
  <reject_codes>
64
- - `unconfirmed_voice_rewrite` — a SOUL.md write was attempted without a recorded human confirm. The AI
65
- proposes; it never self-approves. Stop and get the confirm. (The identity-owned floor.)
49
+ - `unconfirmed_voice_rewrite` — a SOUL.md write was attempted without a recorded human confirm. The AI proposes; it never self-approves. Stop and get the confirm.
66
50
  - `no_open_voice_deltas` — nothing is `open`. The loop is a no-op; do not touch SOUL.md.
67
- - `unroutable_voice_delta` — the observation maps to no SOUL.md section (not tone/style/trust). Fix the
68
- delta or widen the routing before writing.
51
+ - `unroutable_voice_delta` — the observation maps to no SOUL.md section (not tone/style/trust). Fix the delta or widen the routing before writing.
69
52
  </reject_codes>
70
53
 
71
54
  ## Where it plugs in
72
55
 
73
- - **Emit**: `phases/7-observe.md` proposes voice deltas beside its competency/spec deltas.
74
- - **Target**: `SOUL.md` (scaffolded by setup) its "## Voice deltas" ledger holds the confirmed history.
75
- - **Kin**: `deltas.md` (competency learnings → foundation) and `fold.md` (the same propose→confirm→write
76
- discipline). This is the voice's version of that discipline; the engine stays judgment-free (no
77
- `add.py` command writes the voice).
56
+ - **Emit**: `phases/7-observe.md` proposes voice deltas beside competency/spec deltas.
57
+ - **Target**: `SOUL.md` — "## Voice deltas" ledger holds confirmed history.
58
+ - **Kin**: `deltas.md` + `fold.md` (same propose→confirm→write discipline). No `add.py` command writes the voice.
@@ -3,48 +3,41 @@
3
3
  Load this when a milestone has more than one task and you want to run them concurrently.
4
4
  **Default:** when a project confirms `parallel + auto` as its run mode at setup
5
5
  (`phases/0-setup.md` "Run mode"), parallel streaming is the project default — an **opt-out**, not
6
- the opt-in it once was; downgrade in one step (`add.py autonomy set conservative --project`, or just
7
- run tasks one at a time). A project that kept the conservative run mode still treats this rubric as
8
- the opt-in escape hatch. Either way it changes nothing below.
6
+ the opt-in it once was; downgrade in one step (`add.py autonomy set conservative --project`, or
7
+ just run tasks one at a time). A project that kept the conservative run mode still treats this
8
+ rubric as the opt-in escape hatch.
9
9
 
10
- It changes **no `add.py` code and no phase semantics**. It is a way *you, the
11
- orchestrator*, drive several tasks at once by reading the dependency DAG that
12
- `add.py status` already prints, and spawning one worker per ready task.
10
+ It changes **no `add.py` code and no phase semantics**. It is a way *you, the orchestrator*,
11
+ drive several tasks at once by reading the dependency DAG `add.py status` already prints and
12
+ spawning one worker per ready task.
13
13
 
14
14
  ## The honest frame — this is pipelining, not N× speed
15
15
 
16
- With **one human reviewer** you cannot beat `review_time × N_tasks` (the human-led
17
- decision points are serial — `docs/10-setup-and-stages.md:91`). So the win is **not throughput**:
18
- it is that the reviewer is **never blocked waiting on a build**. While the human reviews
19
- task A's frozen bundle, the builds for B·C·D run behind *their* frozen contracts. You hide
20
- build latency under human latency. Do not promise more than that.
16
+ With **one human reviewer** you cannot beat `review_time × N_tasks` (decision points are serial).
17
+ The win is that the reviewer is **never blocked waiting on a build**: builds for B·C·D run behind
18
+ *their* frozen contracts while the human reviews A. You hide build latency under human latency.
21
19
 
22
20
  ## The two queues
23
21
 
24
22
  Compute both from one `python3 .add/tooling/add.py status` — no new state:
25
23
 
26
- - **READY-QUEUE** — tasks in the active milestone where `phase ≠ done` **and** every
27
- `deps=` task already shows `gate=PASS`. These are the only tasks a worker may pick up.
28
- A task with unmet deps stays queued; a task finishing PASS unblocks its dependents on
29
- the next `status`.
30
- - **REVIEW-QUEUE** — the irreducibly serial part: the **bundle approval** (contract
31
- freeze) and any **Verify escalation**. One human, one queue. Present these one at a
32
- time, never in a batch the human will approve without reading.
24
+ - **READY-QUEUE** — tasks where `phase ≠ done` **and** every `deps=` task shows `gate=PASS`.
25
+ A task with unmet deps stays queued; a task finishing PASS unblocks its dependents.
26
+ - **REVIEW-QUEUE** the irreducibly serial part: the **bundle approval** (contract freeze) and
27
+ any **Verify escalation**. One human, one queue. Present these one at a time, never in a batch.
33
28
 
34
29
  ```
35
30
  add.py status ─► READY-QUEUE ──spawn workers──► builds run ──► REVIEW-QUEUE ──► done
36
- (deps=PASS?) (machine span) (concurrent) (decision points,
37
- strictly serial)
38
- └──────────────── a task gating PASS unblocks its dependents ──────────────┘
31
+ (deps=PASS?) (machine span) (concurrent) (decision points, serial)
32
+
33
+ └──────── a task gating PASS unblocks its dependents ──────────────────────────┘
39
34
  ```
40
35
 
41
36
  ## The DAG strategy — let the engine schedule the waves (`add.py waves`)
42
37
 
43
- Do **not** eyeball the READY-QUEUE by hand once a milestone has more than a couple of
44
- tasks the engine computes the whole schedule from the dependency DAG `status` already
45
- holds. `add.py waves` (read-only, writes nothing) groups the active milestone's not-done
46
- tasks into **topological waves**, names the **critical path**, and emits an advisory
47
- **tier hint** — exactly the inputs you need to fan out effectively:
38
+ Do **not** eyeball the READY-QUEUE by hand once a milestone has more than a couple of tasks.
39
+ `add.py waves` (read-only) groups not-done tasks into **topological waves**, names the **critical
40
+ path**, and emits an advisory **tier hint**:
48
41
 
49
42
  ```
50
43
  $ add.py waves
@@ -55,94 +48,67 @@ critical path: dag-scheduler → setup-run-mode (2 tasks)
55
48
  tier hint: top → dag-scheduler, setup-run-mode; mid → the rest
56
49
  ```
57
50
 
58
- Read the schedule as a strategy, not a command:
59
-
60
- - **Wave = a fan-out batch.** Every task in a wave has all its in-milestone deps already
61
- PASS, so the whole wave is spawnable at once (one worker per task, `isolation="worktree"`).
62
- Finish a wave, gate its tasks PASS, then `add.py waves` again the next wave is unblocked.
63
- - **Run the widest wave first.** It hides the most build latency under the human's review
64
- latency (the honest frame above): more concurrent builds while the reviewer reads one bundle.
65
- - **Spend your strongest model on the critical path.** The critical-path tasks gate the most
66
- downstream work, so a wrong-but-plausible result there is the costliest give them the
67
- **top** tier (`run.md` tiers); off-path tasks take **mid**. The tier hint is exactly this rule,
68
- applied to the graph. It is **advisory** — graph position is a proxy for scope difficulty, not a
69
- gate; override it when you know a task is harder than its position suggests.
70
- - **`--json`** (`{ milestone, waves, critical_path, critical_path_len, tiers, blocked }`) feeds a
71
- runner that spawns the wave programmatically. `blocked` lists any task whose dep can never be
72
- satisfied within this milestone (a cross-milestone dep) — surfaced, never silently dropped; a
73
- `dependency_cycle` is refused with the offending members named (no schedule exists).
74
-
75
- What `waves` does **not** change: the irreducible floor below still holds — one human approval
76
- per contract, builds overlap but the review queue stays serial. `waves` decides *order and model*,
77
- never *whether the human gate fires*.
51
+ - **Wave = a fan-out batch.** Every task in a wave has all in-milestone deps PASS, so the whole
52
+ wave is spawnable at once (`isolation="worktree"`). Finish a wave, gate tasks PASS, then
53
+ `add.py waves` again the next wave is unblocked.
54
+ - **Run the widest wave first** to hide the most build latency under human review latency.
55
+ - **Spend your strongest model on the critical path.** Critical-path tasks gate the most
56
+ downstream work; off-path tasks take **mid**. The tier hint is advisory override when you
57
+ know a task is harder than its position suggests.
58
+ - **`--json`** (`{ milestone, waves, critical_path, critical_path_len, tiers, blocked }`) feeds
59
+ a runner that spawns programmatically. `blocked` lists tasks whose dep cannot be satisfied
60
+ within this milestone; a `dependency_cycle` is refused with the offending members named.
78
61
 
79
- ## The autonomy level is the throttle (not a new flag)
62
+ The irreducible floor holds `waves` decides *order and model*, never *whether the human gate fires*.
80
63
 
81
- How much concurrency you actually get is set by each task's `autonomy:` header
82
- (`run.md`), not by this rubric:
64
+ ## The autonomy level is the throttle (not a new flag)
83
65
 
84
66
  | `autonomy` (TASK.md) | What serializes on the human | Concurrency |
85
67
  |----------------------|------------------------------|-------------|
86
- | `conservative` / `manual` | bundle approval **+** every Verify | pure pipelining — builds overlap, both gates queue (`manual` is the strict floor; same streams behaviour) |
68
+ | `conservative` / `manual` | bundle approval **+** every Verify | pure pipelining — builds overlap, both gates queue |
87
69
  | `auto` (default) | bundle approval **only**; Verify auto-PASSes on evidence | real concurrency — only the decision point + residue escalations queue |
88
- | `auto` but **high-risk** | refused → must lower to `conservative` / `manual` (`unguarded_high_risk_auto`) | back to pipelining, by design |
70
+ | `auto` but **high-risk** | refused → must lower (`unguarded_high_risk_auto`) | back to pipelining, by design |
89
71
 
90
- The irreducible floor is **one human approval per task at the contract decision point** — the decision point
91
- never drops to zero (`run.md:22`). That floor is correct; do not engineer around it.
72
+ The irreducible floor is **one human approval per task at the contract decision point** — that
73
+ floor never drops to zero (`run.md:22`). Do not engineer around it.
92
74
 
93
75
  ## Who writes what — the hard boundary
94
76
 
95
77
  <constraints>
96
- - **You (orchestrator)** own all shared writes: `MILESTONE.md`, and every
97
- `add.py advance <slug>` / `add.py gate <outcome> <slug>` call. **Always pass the explicit
98
- `<slug>`** `advance`/`gate`/`phase` all take an optional task slug and act on it
99
- (`add.py` `_resolve_task`); omitting it falls back to the single `active_task`, which
100
- races once more than one stream is live. Name the task every time. Workers never run these.
101
- - **A worker** owns only its own `.add/tasks/<slug>/` it builds `src/`, drives the
102
- tests green, gathers evidence, and writes `SUMMARY.md` + OBSERVE deltas. It touches
103
- **no sibling stream and no shared file**.
104
- - **Isolation**: spawn each worker with `isolation="worktree"` so concurrent builds
105
- cannot collide. The worktree is discarded on failure; the task resets to its last-good
106
- phase.
78
+ - **You (orchestrator)** own all shared writes: `MILESTONE.md`, and every `add.py advance <slug>` /
79
+ `add.py gate <outcome> <slug>` call. Always pass the explicit `<slug>` — **name the task every time** —
80
+ omitting it falls back to the single `active_task`, which races once more than one stream is live.
81
+ Workers never run these.
82
+ - **A worker** owns only its own `.add/tasks/<slug>/` it builds `src/`, drives tests green,
83
+ gathers evidence, and writes `SUMMARY.md` + OBSERVE deltas. It touches **no sibling stream and
84
+ no shared file** never write shared state (state.json, MILESTONE.md, a sibling's files).
85
+ - **Isolation**: spawn each worker with `isolation="worktree"` so concurrent builds cannot
86
+ collide. The worktree is discarded on failure; the task resets to its last-good phase.
107
87
  </constraints>
108
88
 
109
89
  ## Design for failure (required)
110
90
 
111
91
  - **Fresh worktree base (verify base == HEAD)** — create each worker's worktree from current
112
- `HEAD` **after** you commit the task's frozen specification bundle (spec · scenarios · contract · tests). A
113
- worktree forked from a stale base forces the worker to recreate the frozen artifacts by hand
114
- (the v10 dogfood hit exactly this). Before the worker starts, confirm `git -C <worktree>
115
- rev-parse HEAD` equals the orchestrator's `HEAD`; if it drifted, `git merge` the base in first.
116
- On a runner that creates each worktree **at spawn** from a pool (e.g. Claude Code), that pool can hand
117
- out a STALE base, so the pre-spawn `rev-parse` evidence cell is unsatisfiable. The `unverified_fork_base`
118
- check then **shifts** it never skips: the worker's **step-0** syncs to base (`git merge` the orchestrator's
119
- `HEAD`) and re-echoes `rev-parse HEAD`, which the orchestrator verifies at **merge-time**, before merge-back.
120
- The pre-spawn check stays the DEFAULT for fresh-`HEAD`-worktree runners; the merge-time path is the additive
121
- ALTERNATIVE for spawn-time runners never a replacement of the pre-spawn rule.
122
- **The engine executes this gate** (engine-merge-base-enforcement): run
123
- `python3 .add/tooling/add.py wave-verify` before the first merge-back it refuses a mismatched or
124
- pending echo (`unverified_fork_base`) and an off-template ledger (`wave_ledger_malformed`, fail-closed);
125
- `add.py check` is the standing monitor (red at `status: merging`, `fork_base_pending` WARN at `live`).
126
- - **Lease + timeout** — record which worker holds which task (in the wave ledger, below);
127
- if a worker dies, release the claim back to READY (re-spawn, do not assume partial work is sound).
128
- - **Failure isolates** — a worker that hits a STOP-and-escalate (below) blocks only its
129
- own task. Siblings keep running; the escalation joins the REVIEW-QUEUE.
92
+ `HEAD` **after** committing the task's frozen specification bundle. Confirm `git -C <worktree>
93
+ rev-parse HEAD` equals the orchestrator's `HEAD`; if drifted, `git merge` the base first.
94
+ On a pool-based runner (e.g. Claude Code) the pre-spawn check **shifts** to the worker's
95
+ **step-0**: sync to base and re-echo `rev-parse HEAD`, which the orchestrator verifies at
96
+ **merge-time**. The engine executes this gate (`engine-merge-base-enforcement`): run
97
+ `python3 .add/tooling/add.py wave-verify` before the first merge-back it refuses a
98
+ mismatched or pending echo (`unverified_fork_base`) and an off-template ledger
99
+ (`wave_ledger_malformed`, fail-closed); `add.py check` is the standing monitor.
100
+ - **Lease + timeout** record which worker holds which task (in the wave ledger); if a worker
101
+ dies, release the claim back to READY.
102
+ - **Failure isolates** a worker that hits a STOP-and-escalate blocks only its own task;
103
+ siblings keep running and the escalation joins the REVIEW-QUEUE.
130
104
  - **Circuit-breaker** — if N workers fail in a wave, stop fanning out and fall back to
131
105
  sequential. Repeated failure means the scope was wrong, not the parallelism.
132
106
 
133
107
  ## Wave ledger — the wave's resume point
134
108
 
135
- A single task resumes from `state.json`; a wave used to resume from nothing — the
136
- task lease fork-base autonomy merge-order mapping lived only in the orchestrator's
137
- chat context, and the v12-1 recurrence proved that discipline without an artifact fails
138
- (the base check existed in prose and never ran). The ledger fixes both: it is the file you
139
- re-orient from, and its evidence cells cannot be filled without executing the checks.
140
-
141
- **The file** — `.add/milestones/<m>/WAVE.md`, orchestrator-owned like `MILESTONE.md` and
142
- `state.json`. ONE live wave per milestone at a time; opening a second while one is live is
143
- refused (`wave_already_live`). **Workers never read WAVE.md** — the orchestrator copies the
144
- relevant mid-wave decisions into each worker's PROMPT.md at spawn/respawn, so the worker
145
- contract below stays unchanged and no worker widens into sibling state.
109
+ **The file** `.add/milestones/<m>/WAVE.md`, orchestrator-owned. ONE live wave per milestone;
110
+ opening a second while one is live is refused (`wave_already_live`). **Workers never read
111
+ WAVE.md** the orchestrator copies relevant decisions into each worker's PROMPT.md at spawn.
146
112
 
147
113
  ```markdown
148
114
  # WAVE.md — transient wave ledger (orchestrator-owned · one live wave per milestone)
@@ -162,48 +128,34 @@ base: <orchestrator HEAD at spawn — the sha every fork must equal>
162
128
  ```
163
129
 
164
130
  **Evidence cells, not ticks.** The fork-base cell holds the PASTED output of
165
- `git -C <worktree> rev-parse HEAD`, and it must equal `base:`. A tick is not evidence; a row
166
- you can only fill by running the command is the fresh-worktree-base check EXECUTING the
167
- v12-1 lesson (words-exist method-works) closed structurally. Spawning a worker whose roster
168
- row lacks that evidence is refused (`unverified_fork_base`). On a spawn-time pool runner this
169
- PRE-spawn paste is unsatisfiable (the pooled base is stale until the worker syncs), so the cell
170
- instead holds the worker's **step-0** post-sync echo (still `== base:`) and the `unverified_fork_base`
171
- refusal **shifts to merge-time**, before merge-back it shifts, it never lifts.
172
-
173
- **Lifecycle open consume → digest delete.** Open the ledger when the first worker
174
- spawns. The serial integration Verify consumes it (the merge order is read from it, one
175
- worktree at a time). At wave close, absorb the evidence digest wave base · roster→fork-base
176
- evidence · merge order · integration-Verify outcomeinto `MILESTONE.md` as an append-only
177
- `## Wave log` block (this is the integration-Verify *record*, previously homeless), and only
178
- then remove the file. Removing WAVE.md before the digest is absorbed is refused
179
- (`digest_not_absorbed`) — the proof the checks ran must outlive the file.
180
-
181
- **Resume rule.** On session start, a live WAVE.md is the wave's resume point: re-orient from
182
- the file — roster, bases, decisions, merge order — never from conversational memory.
131
+ `git -C <worktree> rev-parse HEAD` and must equal `base:`. Filling the row requires running the
132
+ command words-exist method-works. Spawning a worker whose roster row lacks that evidence is
133
+ refused (`unverified_fork_base`). On a pool runner the cell holds the worker's **step-0**
134
+ post-sync echo (still `== base:`) and the refusal **shifts to merge-time**.
135
+
136
+ **Lifecycle open consume digest delete.** Open when the first worker spawns. At wave
137
+ close, absorb the evidence digest — base · roster fork-base · merge order · integration-Verify
138
+ outcome — into `MILESTONE.md` as an append-only `## Wave log` block, then remove the file.
139
+ Removing WAVE.md before the digest is absorbed is refused (`digest_not_absorbed`).
140
+
141
+ **Resume rule.** On session start, a live WAVE.md is the wave's resume point: re-orient from the
142
+ file roster, bases, decisions, merge ordernever from conversational memory.
183
143
 
184
144
  ## Merge is serial — integration Verify
185
145
 
186
- Parallel build, **serial integration**. After workers return, you merge the worktrees
187
- one at a time and run the **integration** Verify — the concurrency / architecture / layering
188
- checks that `run.md:102` says automation cannot judge. Two green tasks in isolation can
189
- still conflict when merged; this step is where that surfaces. Never auto-pass it.
146
+ Parallel build, **serial integration**. After workers return, merge worktrees one at a time and
147
+ run the **integration** Verify — the concurrency / architecture / layering checks automation
148
+ cannot judge. Two green tasks in isolation can still conflict when merged. Never auto-pass it.
190
149
 
191
150
  Each worktree carries a full copy of `.add/`. Merge back **only** `src/`, `tests/`, and the
192
151
  worker's own `.add/tasks/<slug>/` (TASK.md · SUMMARY.md) — `.add/state.json`, `MILESTONE.md`,
193
- and the live `WAVE.md` stay orchestrator-owned, or a parallel merge will drag stale state back.
152
+ and the live `WAVE.md` stay orchestrator-owned.
194
153
 
195
154
  ## The worker contract — portable across coding agents
196
155
 
197
- A worker **is** the dynamic run (`run.md`) for one task. Keep two things separate:
198
-
199
- - **The contract** (below) the prompt. It is **agent-agnostic**: it names no vendor tool,
200
- no model, no spawn API. It is a durable ADD artifact, like the spec and the tests.
201
- - **The adapter** (next sections) — the thin, swappable mapping that tells *one* runner
202
- (Claude Code · Codex · opencode · pi-mono · any CLI agent) how to launch the contract.
203
-
204
- This split is the whole point: the same frozen contract runs on any agent; only the adapter
205
- changes. Fill every `{{...}}` per stream. The ADD-specific value is `<touch_boundary>` + the
206
- "return a verdict, never write shared state" rule — they are identical on every runner.
156
+ A worker **is** the dynamic run (`run.md`) for one task. The contract below is **agent-agnostic**:
157
+ no vendor tool, no model, no spawn API — a durable ADD artifact. The adapter (next sections) is
158
+ the thin, swappable mapping for one runner. Fill every `{{...}}` per stream.
207
159
 
208
160
  ```xml
209
161
  <!-- PROMPT.md — dropped into the worker's worktree, or passed inline. No runner-specific tokens. -->
@@ -227,7 +179,7 @@ Score confidence (0-1) on Completeness · Clarity · Practicality · Optimizatio
227
179
  Self-Eval; if any < 0.9, refine before returning.
228
180
  </persona>
229
181
 
230
- <touch_boundary> <!-- from run.md:56-73; the worker's contract, identical on every runner -->
182
+ <touch_boundary> <!-- from run.md; the worker's contract, identical on every runner -->
231
183
  MAY: rewrite code in src/ · drive tests green WITHOUT weakening them · gather verify evidence.
232
184
  MUST NOT: edit the frozen CONTRACT or locked scope · weaken/delete/skip any test ·
233
185
  touch §1–§3 bundle artifacts · write MILESTONE.md / state.json / any sibling stream.
@@ -235,7 +187,7 @@ STOP-and-escalate (return your findings; do not decide):
235
187
  • a discovered scope/contract gap → backward-correction, reopen Specify (principle 4)
236
188
  • any SECURITY finding → HARD-STOP, always
237
189
  • a concurrency/timing OR architecture/layering risk the tests cannot exercise
238
- • [include this bullet when autonomy is conservative OR manual — any lowered rung] the verify gate itself — STOP for the human
190
+ • [include this bullet when autonomy is conservative OR manual] the verify gate itself — STOP for the human
239
191
  Auto-PASS only if autonomy=auto AND: all tests green · coverage not decreased · no test weakened ·
240
192
  no contract edited · loops dry · completeness-critic clean · no residue above. Log it as
241
193
  auto-resolved, naming this run as owner — never forge a human signature.
@@ -247,9 +199,8 @@ Auto-PASS only if autonomy=auto AND: all tests green · coverage not decreased
247
199
  </context_files>
248
200
 
249
201
  <expertise>
250
- Adopt the persona above. If your runner supports specialist injection a Claude Code skill,
251
- a Codex/opencode system-prompt preamble, an agent profile load the one matching {{DOMAIN}}.
252
- If it does not, the persona IS your expertise.
202
+ If your runner supports specialist injection (a Claude Code skill, a system-prompt preamble, an
203
+ agent profile), load the one matching {{DOMAIN}}. Otherwise the persona above IS your expertise.
253
204
  </expertise>
254
205
 
255
206
  <tools>
@@ -259,8 +210,8 @@ ripgrep otherwise. Design every IO path for failure — timeouts, retries, rollb
259
210
 
260
211
  <return> <!-- the worker PROPOSES; the orchestrator RECORDS. A worker never runs add.py. -->
261
212
  End with a structured verdict AND write the same into SUMMARY.md in the task dir, then
262
- **commit SUMMARY.md + deltas.md** in the worktree (uncommitted worktree files survive only by
263
- harness courtesy — commit them so the serial-integration merge-back carries your report):
213
+ **commit SUMMARY.md + deltas.md** in the worktree (uncommitted files survive only by harness
214
+ courtesy — commit them so the serial-integration merge-back carries your report):
264
215
  { task, outcome: PASS|RISK-ACCEPTED|HARD-STOP|ESCALATE, evidence: <tests+coverage>,
265
216
  residue: [security|concurrency|architecture findings], deltas: [open lessons learned] }.
266
217
  Do NOT touch add.py or any shared file — the orchestrator gates on your verdict.
@@ -270,23 +221,20 @@ Do NOT touch add.py or any shared file — the orchestrator gates on your verdic
270
221
  ## Choosing the model — vendor-neutral tiers
271
222
 
272
223
  ADD picks a **tier** from the scope's nature; the adapter maps the tier to the runner's model id.
273
- The contract is identical whichever model runs it (the model is disposable, like the code):
274
224
 
275
225
  | Tier | When | Claude Code | Any other runner |
276
226
  |------|------|-------------|------------------|
277
227
  | **mid** | ordinary, well-tested scope; clear contract | `sonnet` | the runner's balanced model |
278
228
  | **top** | complex / ambiguous / cross-cutting / broad scope of impact | `opus` | the runner's strongest reasoning model |
279
229
 
280
- Two rules sit **above** model choice and never bend:
281
- - **High-risk a lowered rung (`conservative` or `manual`), regardless of model** (`run.md` high-risk guard). A
282
- stronger model does not buy back the human gate.
283
- - **Security residue always escalates** — no tier and no model auto-passes it.
230
+ Two rules sit **above** model choice: **high-risk a lowered rung (`conservative` or `manual`),
231
+ regardless of model** a stronger model does not buy back the human gate. And **security residue
232
+ always escalates** no tier auto-passes it.
284
233
 
285
234
  ## The spawn adapter — one thin mapping per runner
286
235
 
287
236
  ADD needs six capabilities from any runner. **Isolation is the one ADD owns itself** (a git
288
- worktree), so streams stay portable even on a runner with no native sandbox — ADD makes the
289
- worktree, then points the agent at that directory.
237
+ worktree), so streams stay portable even on a runner with no native sandbox.
290
238
 
291
239
  | ADD needs | Abstract | Claude Code (verified reference) | Any CLI agent — Codex · opencode · pi-mono · … |
292
240
  |-----------|----------|----------------------------------|-----------------------------------------------|
@@ -297,16 +245,9 @@ worktree, then points the agent at that directory.
297
245
  | domain expertise | skill / preamble | a Claude skill in `<expertise>` | a system-prompt / profile preamble |
298
246
  | return a verdict | structured | final message (optionally a schema) | stdout JSON the orchestrator parses |
299
247
 
300
- The **hint of `Task` spawn** is the Claude Code column — the worked reference. For any other
301
- agent the recipe is the same shape: `git worktree add` → point the agent CLI at that dir with
302
- the chosen model → it reads `PROMPT.md` → you parse its verdict.
303
-
304
248
  > **Honesty:** only the Claude Code column is verified. The CLI forms for Codex/opencode/pi-mono
305
- > are *illustrative shapes*, not confirmed flags — exact syntax differs per runner and version;
306
- > confirm with the `find-docs` skill. The portable, durable parts are the **contract** and the
307
- > **six-capability mapping**, never any one runner's flags.
249
+ > are *illustrative shapes* confirm exact syntax with the `find-docs` skill.
308
250
 
309
251
  When workers return, **you** record each outcome with the explicit slug — `add.py advance <slug>`
310
252
  as evidence lands, `add.py gate PASS|RISK-ACCEPTED|HARD-STOP <slug>` at verify — then re-read
311
- `status` to refill the READY-QUEUE. The worker proposes a verdict; the orchestrator records it.
312
- That split is exactly what lets a non-Claude worker take part without ever touching shared state.
253
+ `status` to refill the READY-QUEUE. The worker proposes; the orchestrator records.