cohorte 1.4.0 → 1.6.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 (44) hide show
  1. package/CHANGELOG.md +151 -0
  2. package/README.md +43 -12
  3. package/bin/cli.js +13 -2
  4. package/core/agents/review.md +23 -0
  5. package/core/commands/audit.md +9 -1
  6. package/core/commands/brainstorm.md +6 -0
  7. package/core/commands/build.md +93 -8
  8. package/core/commands/doctor.md +13 -8
  9. package/core/commands/drive.md +80 -0
  10. package/core/commands/fix.md +10 -5
  11. package/core/commands/review.md +94 -12
  12. package/core/commands/spec.md +20 -0
  13. package/core/commands/update-pipeline.md +6 -1
  14. package/core/hooks/gate.py +4 -4
  15. package/core/templates/decisions.template.md +42 -0
  16. package/core/templates/spec.template.md +4 -2
  17. package/core/templates/steps/init-pipeline/02-interview-gaps.md +1 -1
  18. package/core/templates/steps/init-pipeline/04-write-render.md +8 -4
  19. package/core/workflows/review.js +44 -2
  20. package/dashboard/dist/assets/{index-AFQnlfjO.css → index-BZ_LQlEj.css} +1 -1
  21. package/dashboard/dist/assets/index-DYyn4p93.js +43 -0
  22. package/dashboard/dist/index.html +2 -2
  23. package/dashboard/server/doctor.js +13 -3
  24. package/dashboard/server/index.js +7 -0
  25. package/dashboard/server/metrics.js +4 -4
  26. package/dashboard/server/usage.js +61 -0
  27. package/install.ps1 +12 -1
  28. package/install.sh +12 -2
  29. package/package.json +1 -1
  30. package/profile/PIPELINE.template.md +3 -3
  31. package/profile/SCHEMA.md +150 -12
  32. package/scripts/loop.sh +318 -0
  33. package/scripts/metrics/collect.mjs +11 -2
  34. package/scripts/preflight.sh +2 -2
  35. package/scripts/telemetry-send.sh +5 -2
  36. package/scripts/test-dashboard.mjs +22 -2
  37. package/scripts/test-gate.mjs +1 -2
  38. package/scripts/test-loop.mjs +227 -0
  39. package/scripts/test-metrics.mjs +12 -3
  40. package/scripts/test-workflows.mjs +28 -0
  41. package/scripts/validate-core.mjs +21 -6
  42. package/core/agents/smoke.md +0 -63
  43. package/core/commands/smoke.md +0 -55
  44. package/dashboard/dist/assets/index-DLBzciIC.js +0 -43
package/CHANGELOG.md CHANGED
@@ -3,6 +3,157 @@
3
3
  Entries are shown by `/update-pipeline` ("What's new") after a core refresh. Keep them short,
4
4
  user-facing, most recent first. One `## <version> — <YYYY-MM-DD>` section per release.
5
5
 
6
+ ## 1.6.0 — 2026-08-01
7
+
8
+ > **Re-run `npx cohorte@latest update --global` (or `update`)** to pick up the readiness gate, the
9
+ > deferred-findings route, the resumable driver and the decision journal — the update *deletes* the
10
+ > shadowed `/loop` command and the long-dead `/cycle` from your install, it does not just stop
11
+ > shipping them. Existing specs keep working: the new front-matter fields are written on demand, and a
12
+ > spec without them simply isn't resumable yet. **`/loop <id>` is now `/drive <id>`.**
13
+
14
+ - **New — the readiness gate between `/spec` and `/build`.** `/build` §1.6 now scores the frozen spec
15
+ on **implementability** before authoring the contract and before dispatching anything: contract
16
+ shapes complete · every area owned by a surface · named dependencies actually exist · no ambiguity a
17
+ surface would have to guess at · design links present. The verdict goes to
18
+ `specs/reports/<id>.readiness.json` (`READY` · `RESERVATIONS` · `NOT-READY` + `gaps[]`).
19
+ **`NOT-READY` stops the build with zero agents spawned** — a spec that can't be built doesn't get
20
+ cheaper by being built on N surfaces in parallel — and sends you to `/spec`. `RESERVATIONS` never
21
+ blocks: each gap is inlined into the affected surface's dispatch as an assumption the implementer
22
+ applies *and* flags in its handoff. It costs **no extra agent**: the lead already holds the spec,
23
+ the profile and the reconciled surface list.
24
+ - **New — deferred findings: `/review` stops throwing away what isn't blocking.** The review agent
25
+ now returns a separate `## Deferred` section (max 10) for what is real but **out of this feature's
26
+ scope** — pre-existing code the diff never touched, adjacent debt the spec never claims to fix —
27
+ each line carrying its own out-of-scope reason. Deferred items count in no severity row, move no
28
+ verdict, are never cross-checked, and on **every** verdict get routed into
29
+ `specs/refactor-backlog.md` under the owning surface's `## <domain>` heading, tagged
30
+ `deferred:<id>`. So `/review` feeds `/refactor` for free instead of dropping everything
31
+ non-blocking on the floor. Never into `## Remediation`, which is what `/fix` re-dispatches. Not
32
+ deferrable, ever: anything the diff touched, any spec violation, any security issue on a path this
33
+ feature adds or calls. `/audit` now **carries open `deferred:` items over** when it rewrites the
34
+ backlog. The verdict JSON gains `deferred: <n>` (informational, outside `blocking`).
35
+ - **BREAKING — `/loop` is renamed `/drive`, because Claude Code shadowed it.** Claude Code ships its
36
+ own built-in `/loop` (run a prompt on a recurring interval), which won the name: typing
37
+ `/loop <id>` started the *interval runner* with the feature id as its prompt, so cohorte's driver
38
+ never ran — and the session, having never seen `loop.md`, reported a loop that did not exist. Same
39
+ command, same flags, same script (`pipeline/scripts/loop.sh` keeps its name — nothing about your
40
+ install paths changes): type **`/drive <id>`**. The update scrubs the old `commands/loop.md`, so a
41
+ stale shadowed copy can't linger.
42
+ - **`/drive` is resumable — the spec's status is the state machine.** The lifecycle is now
43
+ `draft → frozen → in-progress → in-review → shipped` plus `blocked`. Before every phase the driver
44
+ stamps `status: in-progress` + `loop_pass` + `loop_phase` into the spec's front-matter — plain
45
+ `awk`, a temp file and `mv`, **zero tokens** — and on exit a terminal `in-review` (clean) or
46
+ `blocked`. **`/drive <id> --resume`** then continues at the pass it reached instead of re-paying the
47
+ ones already made, whether the session died, the ceiling hit, or the fix stopped converging.
48
+ `--max` stays a ceiling on the *total* passes. New **exit 4** (`not implementable`) relays the
49
+ readiness gate's `NOT-READY`: the one loop outcome more passes cannot fix. The dashboard's specs
50
+ board gains In-progress and Blocked columns and shows `↻ pass 3 · /review` on the card; `/doctor`
51
+ names any spec left mid-loop.
52
+ - **Fixed — a dead subagent no longer reads as a clean one on the conversational path.** The
53
+ "a dead agent is never a clean result" doctrine existed since 1.3.4 — but only inside the
54
+ **workflows**. `/build`, `/review` and `/fix` had nothing: a subagent that dies (rate limit,
55
+ transport error, exhausted context) returns *nothing*, and nothing was indistinguishable from
56
+ "finished, nothing to report". Concretely, a dead **reviewer** produced zero findings ⇒
57
+ `blocking: 0` ⇒ verdict `SHIP` ⇒ `/drive` exit 0 ⇒ the human sent to `/ship` — a clean bill of
58
+ health on code no agent ever read. Now every fan-out phase does a **roll call** before integrating:
59
+ a silent surface is retried **once** alone (byte-identical prompt, so recovery costs one agent, not
60
+ a rebuild), then `/build` marks it `dead` and verifies the tree with that surface's own quiet
61
+ commands instead of speaking for the agent, `/review` lists it in the verdict's new `unreviewed[]`
62
+ and **refuses to score `SHIP`**, and `/fix` leaves every one of its items `- [ ]` (a dead agent
63
+ never ticks a box). `/build` also writes `specs/reports/<id>.build.json` with `dead[]`, and
64
+ `loop.sh` aborts on either signal with **exit 2** *before* reading `blocking` — because a dead
65
+ reviewer makes `blocking == 0` a statement about unread code. `unreviewed` is deliberately kept
66
+ out of `blocking`: faking a count there would corrupt the one field the driver contract rests on.
67
+ The metrics line is now written even when a surface died (`"<key>":"dead"`) — an incomplete batch
68
+ is exactly the batch worth recording.
69
+ - **Fixed — `/cycle` and its workflow were removed in 1.4.0 but no installer ever scrubbed them.**
70
+ Every install since has kept `commands/cycle.md` + `workflows/cycle.js` on disk, so a dead command
71
+ stayed listed and invokable — dispatching a workflow whose phases 1.5.0 then deleted. All three
72
+ installers now remove them (as they already did for `/smoke`), and CI **plants the orphans before
73
+ re-installing** instead of asserting their absence on a fresh scratch home, which is exactly the
74
+ blind spot that let this survive four releases.
75
+ - **Reconcile now tops up `specs/_template.md`.** It was seeded once at install and never refreshed,
76
+ so every repo kept the front-matter its core shipped with. `/update-pipeline` adds the missing
77
+ front-matter fields (never the body — the section list is yours).
78
+ - **New — `specs/_decisions.md`, the transverse decision journal.** `PIPELINE.md` is a *stack* profile;
79
+ it says nothing about what the project has **decided**, so every `/spec` re-discovered or
80
+ contradicted the same choices. The journal is deliberately tiny: **append-only, one line per
81
+ decision** (`- <date> · <area> · <decision> — because <reason> · <feature_id>`), reversal by a
82
+ superseding line rather than an edit. Written by `/spec` at freeze (typically 0–3 lines; zero is
83
+ normal) and by `/build` when it adds or splits a surface. Read by the **deciding** stages only —
84
+ `/brainstorm`, `/spec`, `/audit`. **Implementers and reviewers never load it:** they have the frozen
85
+ contract, and shipping them the rationale would cost `surfaces × dispatches` tokens per feature for
86
+ a fact they can't act on. That exclusion is what keeps it cheap enough to be worth having. The `_`
87
+ prefix means `/doctor`, the dashboard scanner and the kanban backfill already skip it.
88
+
89
+ ## 1.5.0 — 2026-08-01
90
+
91
+ > **Re-run `npx cohorte@latest update --global` (or `update`)** to pick up the collector and the
92
+ > `/smoke` removal — the update *deletes* the command and its agent from your install, it does not
93
+ > just stop shipping them. The new dashboard panel comes with `npx cohorte dashboard`.
94
+
95
+ - **New — `/loop <id>`: the review ⇄ fix cycle, run for you.** _(renamed `/drive` in 1.6.0 — see
96
+ there.)_ `/build` → `/review` → `/fix` →
97
+ `/review` … until a review reports **zero blocking findings** (a CRITICAL or a security issue —
98
+ a LOW nit never costs a pass), or the pass ceiling (`--max=N`, default 5), or two consecutive
99
+ reviews returning the *same* blocking findings, which means the fix is treading water and more
100
+ passes won't help. `--no-build` re-runs the loop on an already-built feature; `--rebuild` forces
101
+ a build. Every fix pass is committed (`loop(<id>): fix pass <i>`) — your way back after N
102
+ autonomous passes — and **no fix runs on the last pass**, since fixing without a review behind
103
+ it leaves unaudited code. Exit codes distinguish clean · ceiling · no verdict · non-convergent ·
104
+ usage, so a wrapper can tell "needs more passes" from "needs a human".
105
+ - **The loop does not run in your session — that's the whole design.** Each phase is a separate
106
+ `claude -p` child with its own fresh context, driven by the new shipped `loop.sh`; all child
107
+ output goes to `specs/reports/<id>.loop.log`, which the command is forbidden to read back. Your
108
+ session sees one line per phase and a three-line summary. A slash command cannot `/clear` itself,
109
+ so a conversational loop would pile the diff plus N review reports plus N contracts into a
110
+ history re-sent at input price every turn — it would cost more than the loop saves.
111
+ `disable-model-invocation: true`: an autonomous loop only ever starts because you asked.
112
+ - **`/review` now writes a machine-readable verdict** to `specs/reports/<id>.verdict.json` on every
113
+ run — verdict, finding counts by severity, per-surface breakdown, the normalized blocking items
114
+ and a stable `fingerprint` over them. It is the only contract between the pipeline and any
115
+ driver; no prose is parsed. `blocking` restates the reviewer's existing rule as a number
116
+ (CRITICAL + security, deduplicated), so `blocking == 0` ⟺ `SHIP`. The fingerprint hashes
117
+ *surface + file + problem* with the line number deliberately dropped — a fix that inserts lines
118
+ would otherwise change it every pass and the drift detection would never fire. A red preflight
119
+ writes a degraded `{"aborted":"preflight"}` verdict rather than nothing, so an abort is a
120
+ diagnosis instead of a silence.
121
+ - **BREAKING — `/smoke` and the `smoke` agent are removed.** The end-to-end run phase is gone:
122
+ the command, the agent, its preflight wiring, its telemetry phase and its documentation. The
123
+ loop is now `/brainstorm` → `/spec` → `/build` → `/review` → (`/fix` → `/review`)* → `/ship`,
124
+ with `/clear` safe between each. Nothing else depended on it; a `/smoke` in an old habit will
125
+ report an unknown command.
126
+ - **Nothing in the pipeline runs your app any more — that part is yours.** `/build` now closes by
127
+ telling you to exercise the feature by hand if it's worth it, and `/fix` says the same for
128
+ runtime failures. `/review` follows suit at the SHIP verdict: it ticks only what a stage
129
+ actually verified, and **leaves any DoD criterion that needs the app up open** (runtime flows,
130
+ a visual check against the design) unless you say you exercised it yourself and it held.
131
+ - **The preflight phase gate now gates `review` alone** (`gate.preflight.agents` defaults to
132
+ `[review]`). Existing profiles that list `smoke` keep working — the hook just never sees that
133
+ dispatch. `/doctor` compares against the new default, so re-run it after the update if it
134
+ flags gate drift.
135
+ - **Retired-phase data still renders.** Metrics files and dashboards carrying `phase: "smoke"`
136
+ keep their column, the transcript collector keeps attributing past `/smoke` runs to `/smoke`
137
+ instead of silently reclassifying them, and `telemetry-send.sh` still accepts the phase from a
138
+ stale install. Same treatment `/cycle` got in 1.4.0.
139
+ - **The cockpit now shows what a feature actually cost.** The dashboard's only metrics source
140
+ was `pipeline-metrics.jsonl`, written by the model itself — so it misses any run that ended
141
+ early and can never report tokens. On a real project it had captured 18 phase batches where
142
+ the transcripts hold 53 runs. The new **Cost & runtime** panel reads
143
+ `cohorte metrics` instead: per command, the number of runs, $ per run, $ total, tokens, wall
144
+ and active time, and the median number of subagents dispatched. That last column is the one
145
+ that makes a broken run obvious — a `/build` reporting 0 agents did no fan-out at all.
146
+ - **Both metrics sources are kept, because they answer different questions.** `pipeline-metrics.jsonl`
147
+ carries per-surface verdicts (`ok`, `REVISE:2`, `error`) that only the model knows and the
148
+ transcripts never contain; the collector carries money and time, which the model cannot report
149
+ and the transcripts record exactly. The two panels sit side by side and each says what it is
150
+ for. Neither replaces the other.
151
+ - **Fixed: discussing a command counted as running it.** An inline command mention was treated
152
+ as an invocation regardless of context, so a long message *about* `/review` billed that whole
153
+ conversation to `/review` — in cohorte's own repo it invented five `/cycle` runs out of a
154
+ design discussion. Inline mentions are now length-gated (an instruction is short; a discussion
155
+ is not); an explicit slash-command invocation is always counted.
156
+
6
157
  ## 1.4.0 — 2026-08-01
7
158
 
8
159
  > **Re-run `npx cohorte@latest update --global` (or `update`)** — the workflow fixes only apply
package/README.md CHANGED
@@ -20,7 +20,7 @@ then one command per project (`/init-pipeline`) adapts it to that project's stac
20
20
  **stateless agents** that only communicate through a frozen contract:
21
21
 
22
22
  ```
23
- /brainstorm → /spec → (design) → /build <id> → /smoke → /review → (/fix) → /ship
23
+ /brainstorm → /spec → (design) → /build <id> → /review → (/fix) → /ship
24
24
  ```
25
25
 
26
26
  ## How it works — three layers
@@ -131,7 +131,8 @@ design system), **interviews** you for the gaps, and **generates**:
131
131
  symbols instead of grep-and-reading whole files; `graphify` or `none` also available via the
132
132
  profile's `retrieval.provider`)
133
133
  - `scripts/new-feature.sh` + `remove-feature.sh` — parallel worktree isolation (if you enable it)
134
- - `specs/_template.md`
134
+ - `specs/_template.md` (and, on first decision, `specs/_decisions.md` — the project's one-line-per-decision
135
+ journal, read by `/brainstorm`, `/spec` and `/audit` so features stop re-litigating settled ground)
135
136
 
136
137
  Sanity-check `PIPELINE.md`, commit it, and run `/brainstorm`.
137
138
 
@@ -216,10 +217,10 @@ it in `.claude/pipeline/VERSION` and bundled repos in their committed `pipeline.
216
217
  | `/init-pipeline` | Detect stack → interview → generate the profile + agents. Run once per project. |
217
218
  | `/brainstorm` | Interactive persona panel that pressure-tests a feature idea. |
218
219
  | `/spec` | Freeze the feature spec + contract into `specs/<id>.md` (UI features also get a standalone design brief at `specs/design/<id>.md`). Also applies review returns. |
219
- | `/build <id>` | Lead authors the contract, then dispatches one implementer per surface in parallel. |
220
- | `/smoke <id>` | Run the feature for real: infra up, contract endpoints, UI flows, design conformance. |
221
- | `/review <id>` | Read-only review agents (one per touched surface, parallel) audit the diff vs the spec. |
222
- | `/fix <id>` | Apply a review/smoke report: remediation into the spec, re-dispatch only the surfaces with findings. |
220
+ | `/build <id>` | Readiness gate on the frozen spec, then the lead authors the contract and dispatches one implementer per surface in parallel. |
221
+ | `/review <id>` | Read-only review agents (one per touched surface, parallel) audit the diff vs the spec; out-of-scope findings go to the refactor backlog. |
222
+ | `/fix <id>` | Apply a review report: remediation into the spec, re-dispatch only the surfaces with findings. |
223
+ | `/drive <id>` | Autonomous `/build → /review/fix /review …` until no blocking finding is left (see below). |
223
224
  | `/ship <id>` | Release agent commits, pushes, opens the PR; watches CI; proposes worktree teardown. |
224
225
  | `/audit [path]` | Prioritized refactor backlog for existing code. |
225
226
  | `/refactor <domain>` | Apply the backlog for one surface, TDD-first. |
@@ -230,12 +231,12 @@ it in `.claude/pipeline/VERSION` and bundled repos in their committed `pipeline.
230
231
  ### Run the loop cheaply — `/clear` between stages
231
232
 
232
233
  Every command reloads all the state it needs **from disk** — the frozen spec, the contract, the diff, the
233
- Remediation checkboxes, the freshness stamp, and the last `/review`·`/smoke` report (staged to a gitignored
234
+ Remediation checkboxes, the freshness stamp, and the last `/review` report (staged to a gitignored
234
235
  `specs/reports/<id>.md`). Nothing essential lives in the conversation. So the loop is **`/clear`-safe at
235
236
  every boundary**:
236
237
 
237
238
  ```
238
- /spec → /clear → /build → /clear → /smoke → /clear → /review → /clear → /fix → /clear → /review → /ship
239
+ /spec → /clear → /build → /clear → /review → /clear → /fix → /clear → /review → /ship
239
240
  ```
240
241
 
241
242
  `/clear`-ing between stages sheds the accumulated main-thread context, which is the single biggest token
@@ -243,6 +244,36 @@ lever: long sessions (>150k) are expensive even when cached. Each command tells
243
244
  safe to clear. If you'd rather stay in one session, `/compact` mid-task does the lighter version. (Claude
244
245
  can't fire `/clear` itself — it's a client-side command; the pipeline just makes it always safe to type.)
245
246
 
247
+ ### Let it run itself — `/drive`
248
+
249
+ ```
250
+ /drive feat-x # /build, then /review ⇄ /fix until clean (max 5 passes)
251
+ /drive feat-x --no-build # already built — just re-run the /review ⇄ /fix loop
252
+ /drive feat-x --max=8
253
+ /drive feat-x --resume # continue a run that died / hit the ceiling, at the pass it reached
254
+ ```
255
+
256
+ It stops when `/review` reports **zero blocking findings** (a CRITICAL or a security issue — a LOW
257
+ nit never costs a pass), at the pass ceiling, as soon as two consecutive reviews return the same
258
+ blocking findings (the fix is treading water and more passes won't help), or immediately if `/build`'s
259
+ readiness gate says the frozen spec **cannot be built** — that one needs `/spec`, not passes. **Each
260
+ fix pass is committed** (`loop(<id>): fix pass <i>`) — that's your way back after N autonomous passes —
261
+ and **no fix runs on the last pass**, since fixing without a review behind it leaves unaudited code.
262
+
263
+ **It's resumable.** Before each phase the driver stamps `status: in-progress` + `loop_pass` +
264
+ `loop_phase` into the spec's front-matter (plain `awk`, zero tokens), and a terminal `in-review` or
265
+ `blocked` on exit. So `--resume` continues at pass 3 instead of re-paying passes 1 and 2 — and the spec
266
+ itself tells you, `/doctor` and the dashboard where the loop got to.
267
+
268
+ **The loop does not run in your session.** Each phase is a separate `claude -p` child with its own
269
+ fresh context, driven by `pipeline/scripts/loop.sh`; all of their output goes to
270
+ `specs/reports/<id>.loop.log`, which the command is forbidden to read back. Your session sees one
271
+ line per phase and a three-line summary. That's the whole design: a slash command can't `/clear`
272
+ itself, so a conversational loop would pile the diff plus N review reports plus N contracts into a
273
+ history that is re-sent at input price every turn — it would cost more than the loop saves. The
274
+ machine contract is `specs/reports/<id>.verdict.json`, which `/review` now writes on every run; no
275
+ prose is ever parsed.
276
+
246
277
  ### Run features in parallel — one session per feature
247
278
 
248
279
  With `isolation.enabled`, every feature already gets its own worktree, ports, and database
@@ -256,8 +287,8 @@ The pattern:
256
287
  ```
257
288
  session 1 (main checkout): /spec feat-a → /build feat-a (agents run…)
258
289
  session 2 (main checkout): /spec feat-b → /build feat-b (agents run…)
259
- session 1: /smoke feat-a → /review feat-a → /ship feat-a
260
- session 2: /smoke feat-b → …
290
+ session 1: /review feat-a → /ship feat-a
291
+ session 2: /review feat-b → …
261
292
  ```
262
293
 
263
294
  Rules that make it safe:
@@ -266,7 +297,7 @@ Rules that make it safe:
266
297
  (`specs/<id>.md`, `<contract.path>/<id>.*`, `specs/reports/<id>*`), so sessions never share state —
267
298
  but a single session interleaving two features accumulates both in its context, paying for both.
268
299
  - **Disjoint surfaces per feature are guaranteed** (each worktree is a full checkout), and each
269
- feature's DB/ports come from its slot — `/smoke` runs collide on neither.
300
+ feature's DB/ports come from its slot — two features' dev servers collide on neither.
270
301
  - **The contract package is the one shared tree.** Two features editing
271
302
  `<contract.path>/<their-own-id>.<ext>` never conflict (one file per feature); merge order only
272
303
  matters if a later feature *imports* an earlier one's contract — ship the dependency first.
@@ -331,7 +362,7 @@ bin/cli.js # the npm CLI: install / update / dashboard / version (c
331
362
  install.sh # script installer (fresh + --update) for no-Node environments
332
363
  install.ps1 # same installer for Windows PowerShell (fresh + -Update)
333
364
  core/ # copied verbatim into ~/.claude (global) or <project>/.claude (bundled)
334
- agents/ # implementer.template.md (rendered per surface) + review / release / smoke / profile-reader
365
+ agents/ # implementer.template.md (rendered per surface) + review / release / profile-reader
335
366
  commands/ # init-pipeline + the pipeline commands + /update-pipeline
336
367
  hooks/ # gate.py (destructive-command gate; branch-aware; preflight phase gate)
337
368
  templates/ # handoff / brainstorm-return / design-brief / review-feedback / pr-body / spec
package/bin/cli.js CHANGED
@@ -213,8 +213,8 @@ function copyFixedAgents() {
213
213
  fs.mkdirSync(path.join(dest, 'agents'), { recursive: true });
214
214
  // Every agent in core/agents/ EXCEPT the *.template.md ones, which /init-pipeline renders
215
215
  // per-surface. Until 1.2.6 this was a hardcoded ['review.md', 'release.md'] that never grew
216
- // the `smoke.md` the shell installers copy, so `npx cohorte install` shipped the /smoke
217
- // command with no `smoke` agent to dispatch — the run reported /smoke as not installed.
216
+ // the agents the shell installers copy, so `npx cohorte install` shipped a command with no
217
+ // agent to dispatch — the run reported the command as not installed.
218
218
  // Reading the directory needs no list to keep in sync with the shell installers.
219
219
  const agentDir = path.join(src, 'core', 'agents');
220
220
  for (const f of fs.readdirSync(agentDir)) {
@@ -224,6 +224,17 @@ function copyFixedAgents() {
224
224
  // 0.1.19 split the bi-mode questionnaire-researcher into research-agent + questionnaire-architect;
225
225
  // copy-over never deletes, so scrub the retired agent lest a dead subagent_type linger.
226
226
  fs.rmSync(path.join(dest, 'agents', 'questionnaire-researcher.md'), { force: true });
227
+ // 1.5.0 removed the /smoke phase; copy-over never deletes, so scrub the orphan agent+command.
228
+ fs.rmSync(path.join(dest, 'agents', 'smoke.md'), { force: true });
229
+ fs.rmSync(path.join(dest, 'commands', 'smoke.md'), { force: true });
230
+ // 1.4.0 removed /cycle and its workflow — and no installer ever scrubbed them, so every
231
+ // install since has kept offering a command that dispatches a workflow whose phases were
232
+ // later deleted. A dead command is worse than a missing one: the model can still fire it.
233
+ fs.rmSync(path.join(dest, 'commands', 'cycle.md'), { force: true });
234
+ fs.rmSync(path.join(dest, 'workflows', 'cycle.js'), { force: true });
235
+ // 1.6.0 renamed /loop → /drive: Claude Code's own built-in /loop shadowed ours, so a leftover
236
+ // commands/loop.md is a command the user can never reach — scrub it rather than leave a decoy.
237
+ fs.rmSync(path.join(dest, 'commands', 'loop.md'), { force: true });
227
238
  scrubResearchQuestionnaire();
228
239
  }
229
240
 
@@ -81,6 +81,24 @@ domain** (same finding-line shape) instead of a SHIP/REVISE/BLOCK verdict.
81
81
  - Any **security vulnerability** ⇒ verdict **BLOCK**.
82
82
  - No CRITICAL and no security issue ⇒ verdict **SHIP**.
83
83
 
84
+ ## Deferred — real, but not this feature's problem
85
+
86
+ A finding is **deferred** when it is genuinely true and genuinely **out of this feature's scope**:
87
+ pre-existing code the staged diff did not touch, adjacent debt the spec never claims to fix, a
88
+ convention violation that predates this work. Deferring is not softening — it is naming the right
89
+ owner. The lead routes deferred findings to `specs/refactor-backlog.md` (they feed `/refactor`), so
90
+ they are **never lost and never cost a fix loop**.
91
+
92
+ - **Deferred findings are separate from your findings list** and count in **no** severity row: the
93
+ severity table drives the verdict, and a deferred item must never force one.
94
+ - **Deferrable:** a problem entirely in lines/files the diff did not change, whose fix is not required
95
+ by any acceptance criterion of this spec.
96
+ - **NOT deferrable, ever:** anything the diff touched or introduced; any spec violation; any
97
+ **security** issue on a path this feature adds, calls or modifies (a pre-existing hole this feature
98
+ now exposes to new traffic is this feature's problem). When in doubt, it is a finding, not a deferral.
99
+ - Cap the deferred list at **10 lines**, worst first; each carries its own out-of-scope reason so the
100
+ lead can route it without re-reading anything.
101
+
84
102
  ## Your return — the REVIEW REPORT, exactly this shape
85
103
 
86
104
  Every finding must be **self-sufficient for a stateless agent**: `file:line` · severity ·
@@ -110,6 +128,11 @@ Verdict: <SHIP | REVISE | BLOCK>
110
128
  - **[<SEVERITY>]** `<file>:<line>` · <spec-violation|quality|security> · <problem> → **Fix:** <concrete change>
111
129
  (order by severity; "None." if none; max 20 lines, one per finding, no code excerpts)
112
130
 
131
+ ## Deferred
132
+
133
+ - **[<SEVERITY>]** `<file>:<line>` · <quality|security> · <problem> → **Fix:** <concrete change> · out of scope: <why this feature does not own it>
134
+ (real but out of this feature's scope — see §Deferred; worst first; "None." if none; max 10 lines)
135
+
113
136
  ## Notes
114
137
  (ONLY the RBAC / mobile-first assessment when the profile enables them; omit the section otherwise)
115
138
  ```
@@ -7,7 +7,9 @@ argument-hint: [path or domain, default = whole repo]
7
7
  You are the **lead**. Audit **$ARGUMENTS** (default: whole repo) to drive it to a clean base. Read +
8
8
  analyze only — no fixes (those go through `/refactor`).
9
9
 
10
- > Read `PIPELINE.md` §`commands` (the mechanical gates), `surfaces`, and §Conventions.
10
+ > Read `PIPELINE.md` §`commands` (the mechanical gates), `surfaces`, and §Conventions — plus
11
+ > `specs/_decisions.md` §Live if it exists (SCHEMA.md §Decisions): those standing decisions are part
12
+ > of the rulebook you audit against, and code that contradicts one is a finding like any other.
11
13
  >
12
14
  > **Workflow variant** (opt-in — SCHEMA.md §Workflows): on Claude Code ≥ 2.1.154 with workflows
13
15
  > enabled, the human can ask to "run the audit workflow" (`<core>/workflows/audit.js` — one auditor
@@ -39,5 +41,11 @@ from your instructions), grouped by domain (one group per surface + shared). —
39
41
  Merge mechanical + convention findings into one prioritized backlog and **write
40
42
  `specs/refactor-backlog.md`**, grouped by domain, each item:
41
43
  `- [ ] <SEVERITY> · <file:line> · <rule|tdd|lint|format|type|security> · <concrete fix>`
44
+
45
+ **Carry over the deferred items** before overwriting: `grep -n 'deferred:' specs/refactor-backlog.md`
46
+ and re-emit every **open** (`- [ ]`) match verbatim under its domain, tag included. Those lines were
47
+ put there by `/review` §3.5 — a real finding a feature deliberately did not own — and an audit that
48
+ blindly overwrites the file is the one way they silently disappear. Already-ticked (`- [x]`) ones are
49
+ done: drop them.
42
50
  Print a short summary (counts per domain + top items). Tell the human: refactor a domain with
43
51
  `/refactor <domain>`.
@@ -11,6 +11,12 @@ at Finish, when a board is configured.
11
11
  > Read `PIPELINE.md` §Personas (the panel) and §`rbac` first. If `rbac.enabled`, the panel must
12
12
  > pressure-test the idea so it serves **every** role, not just admins.
13
13
  >
14
+ > Also read `specs/_decisions.md` §Live if it exists (SCHEMA.md §Decisions) — one line per standing
15
+ > decision. The panel argues about the idea, not about settled ground: a persona that proposes
16
+ > something a live line already decided must be told so by another persona, and an idea that genuinely
17
+ > needs to overturn one must say which line, out loud, so the human decides it here rather than
18
+ > discovering the contradiction at `/spec`.
19
+ >
14
20
  > Template paths below (`.claude/templates/…`) resolve to `~/.claude/templates/…` when the core is
15
21
  > installed globally — read whichever exists.
16
22
  >
@@ -16,8 +16,11 @@ You are the **lead**. Build feature **$ARGUMENTS** from its frozen spec.
16
16
  ## 1. Load & check
17
17
 
18
18
  - Check the spec front-matter FIRST — `grep '^status:' specs/$ARGUMENTS.md` (or Read with a ~15-line
19
- limit) — before any full read. If missing or `status` not `frozen`/`in-review`, stop tell the human
20
- to run `/spec` first. Only then read the body, selectively: front-matter, §5 contract, the surface
19
+ limit) — before any full read. Buildable statuses are `frozen`, `in-review` and `in-progress` (the
20
+ last one means a `/drive` is or was driving this spec SCHEMA.md §Spec status). `blocked` means a
21
+ loop gave up here: say so, and route by the spec's `## Remediation` — open items ⇒ `/fix`, none ⇒
22
+ continue this build. Anything else (`draft`, missing, `shipped`) ⇒ stop and tell the human to run
23
+ `/spec` first. Only then read the body, selectively: front-matter, §5 contract, the surface
21
24
  task sections, and `## Remediation` (fall back to a full read if the spec doesn't follow the
22
25
  template's headings).
23
26
  - **Route check** — if `## Remediation` has open `- [ ]` items and none requires a contract change,
@@ -56,6 +59,59 @@ shared-code rule (shared trees get a single-owner surface; cross-slice shapes go
56
59
  This is the automatic path: you don't send the human back to `/init-pipeline`. If nothing new is needed,
57
60
  say so and continue. Dispatch (§3) then covers the reconciled surface list.
58
61
 
62
+ **Adding or splitting a surface is an architectural decision** — append ONE line for it to
63
+ `specs/_decisions.md` §Live (SCHEMA.md §Decisions; create from `.claude/templates/decisions.template.md`
64
+ if absent), area `surfaces`, e.g.
65
+ `- <date> · surfaces · <key> owns <path>, single owner of <what> — because <the boundary reason> · $ARGUMENTS`.
66
+ One `>>` in the Bash call you're already making. Nothing added ⇒ nothing to append.
67
+
68
+ ## 1.6 Readiness verdict — the gate before N dispatches
69
+
70
+ **Zero extra agents: you already hold the spec, the profile and the reconciled surface list.** The
71
+ whole point is that a bancal spec costs one verdict here instead of N implementers discovering it in
72
+ parallel. Judge the frozen contract on **implementability only** — never on whether the feature is a
73
+ good idea (that was `/brainstorm`), never by re-reading files you don't already need:
74
+
75
+ 1. **Contract completeness** (§5) — every endpoint/interface has method+path (or signature), auth,
76
+ request fields with types + validation, the success shape, and its error cases. A missing
77
+ **request or success shape** ⇒ `NOT-READY` (an implementer would invent it, and the other surface
78
+ would invent a different one). A missing **error case** ⇒ `RESERVATIONS`.
79
+ 2. **Surface coverage** — every §6 task maps to a surface in the reconciled list, and every contract
80
+ entry has an owner **on each side it names** (producer and consumer). A contract entry no surface
81
+ owns ⇒ `NOT-READY`.
82
+ 3. **Dependencies exist** — for the modules, packages, tables, env vars and shared helpers the spec
83
+ names as *pre-existing*: verify them in ONE Bash call (`test -f` / `grep -l` / a package-manifest
84
+ grep, output redirected — never a file read per name). Named as pre-existing but absent, and not
85
+ listed as created by this feature ⇒ `NOT-READY`.
86
+ 4. **Residual ambiguity** (§10) — an open question a surface would have to *guess* at: blocks a
87
+ contract decision ⇒ `NOT-READY`; merely narrows an implementation choice ⇒ `RESERVATIONS`.
88
+ 5. **Design gate** — a `uses_design` surface in scope with `design_files` still empty ⇒ `NOT-READY`
89
+ (this is §1's gate restated as a verdict, so an automated driver sees the same fact).
90
+
91
+ Write the machine-readable verdict to `specs/reports/$ARGUMENTS.readiness.json` (overwrite,
92
+ `mkdir -p specs/reports` first — the same gitignored buffer dir `/review` stages into, which may not
93
+ exist yet on a first build) — on **every** build, including `READY`. It is the only channel between this gate and a driver (`/drive`),
94
+ which parses no prose:
95
+
96
+ ```json
97
+ { "id": "$ARGUMENTS", "phase": "readiness", "ts": "<ISO>", "verdict": "RESERVATIONS",
98
+ "gaps": ["contract|POST /orders|no 409 case for a duplicate id"],
99
+ "surfaces": ["backend", "frontend"] }
100
+ ```
101
+
102
+ - **`gaps`** — one normalized string per gap, `<check>|<where>|<what is missing>`: `<check>` is
103
+ `contract` · `coverage` · `dependency` · `ambiguity` · `design`; `<where>` is the contract entry,
104
+ surface key or dependency name (no `:line` — it shifts on every edit); `<what>` is the gap, not the
105
+ fix. `READY` ⇒ `[]`.
106
+ - **`NOT-READY` ⇒ STOP: author no contract and spawn NO agent.** Print the gaps and send the human to
107
+ `/spec $ARGUMENTS` to patch the contract, then re-run `/build`. This abort is the whole point of the
108
+ step — a spec that cannot be built does not get cheaper by being built N times in parallel.
109
+ - **`RESERVATIONS` ⇒ continue.** It never blocks (a gate that stalls a sound build on a missing error
110
+ case would cost more human round-trips than it saves): inline each gap verbatim into the dispatch of
111
+ the surface it affects, as an explicit assumption the agent must implement *and* flag in its handoff,
112
+ and relay the list to the human in one line each.
113
+ - **`READY` ⇒ continue silently** — one line, no restatement.
114
+
59
115
  ## 2. Author the contract (lead-only — the single sync channel)
60
116
 
61
117
  _Only if `contract.enabled`._ From §5 of the spec, write/update the feature's contract file at
@@ -87,28 +143,57 @@ tree. For each surface in `surfaces`:
87
143
  > via `DesignSync get_file`, build mobile-first · or `none` (non-design surface, or a fix loop whose
88
144
  > open items are all non-visual)>. Open Remediation items for YOUR surface (self-contained — fix
89
145
  > exactly these, reading only the files they name; `none` ⇒ first build, implement the spec's tasks
90
- > for your surface): <the surface's open `- [ ]` lines verbatim, or `none`>."
146
+ > for your surface): <the surface's open `- [ ]` lines verbatim, or `none`>. Readiness gaps for YOUR
147
+ > surface (§1.6 `RESERVATIONS` — the spec is silent here: implement the stated assumption and flag what
148
+ > you assumed in your handoff): <that surface's `gaps` entries verbatim, or `none`>."
149
+
150
+ ## 3.5 Roll call — account for EVERY dispatch before integrating
151
+
152
+ A subagent can die: a rate limit mid-run, a transport error after retries, its own context exhausted.
153
+ When it does, it returns **nothing** — and nothing is byte-identical to "a clean surface with nothing
154
+ to report". Silence is not a green light; treat it as the failure it is (SCHEMA.md §Dead agents).
155
+
156
+ - **Roll call.** Every surface you dispatched in §3 must come back with a handoff in the format its
157
+ agent instructions define. Missing, empty, or truncated mid-sentence ⇒ that surface is **dead**.
158
+ - **Never infer success from silence,** and never speak for a dead agent — you did not see its work.
159
+ - **Retry that surface ONCE, alone.** Re-dispatch it with the byte-identical §3 prompt. The other
160
+ surfaces' work is already on disk and untouched, so this costs one agent, not a rebuild — and most
161
+ deaths are transient. Never retry a surface that *did* answer.
162
+ - **Died twice ⇒ stop guessing and look.** Run that surface's own quiet commands
163
+ (`<surface>.typecheck_cmd`, `lint_quiet_cmd`, `test_quiet_cmd`) with output redirected to
164
+ `specs/reports/$ARGUMENTS.<key>.deadcheck.txt`, then grep it — never into your context. Report the
165
+ three results plus which of the spec's tasks for that surface actually landed, checked against the
166
+ tree, not against a handoff you never got. Say plainly that the surface is **unverified**.
91
167
 
92
168
  ## 4. Integrate
93
169
 
94
170
  When all return, flag any contract mismatch or failing test from the handoffs; otherwise print one
95
171
  status line per surface (`<key> · tests pass/fail · <n> TODOs`) — do not restate handoff content.
172
+ A dead surface (§3.5) prints `<key> · DEAD — unverified` and **the batch is never reported as ok**.
96
173
  Append **ONE line for the batch** to the **main checkout's** `.claude/pipeline-metrics.jsonl` —
97
174
  NOT the worktree's, which dies at teardown while metrics must accumulate across features. Resolve
98
175
  it from anywhere: `$(dirname "$(git rev-parse --git-common-dir)")/.claude/pipeline-metrics.jsonl`
99
176
  (in the main checkout this resolves to itself). Create it if absent; it must be gitignored.
100
177
  Compute the elapsed time in the same Bash call
101
178
  (`echo "{...\"seconds\":$(($(date +%s)-<start epoch from §2>)),...}" >> …`):
102
- `{"ts":"<ISO date>","feature":"$ARGUMENTS","phase":"build","seconds":<wall-clock>,"surfaces":{"<key>":"ok|error",…}}`
179
+ `{"ts":"<ISO date>","feature":"$ARGUMENTS","phase":"build","seconds":<wall-clock>,"surfaces":{"<key>":"ok|error|dead",…}}`
180
+ — **write this line even when a surface died.** An incomplete batch is exactly the batch worth having
181
+ in the record; skipping the append to "wait until it's complete" silently deletes the evidence that
182
+ anything went wrong. In the same call write the machine-readable batch result to
183
+ `specs/reports/$ARGUMENTS.build.json` (overwrite) — the channel an automated driver reads, since it
184
+ never sees your chat:
185
+ `{"id":"$ARGUMENTS","phase":"build","ts":"<ISO>","surfaces":{"<key>":"ok|error|dead",…},"dead":["<key>",…]}`
103
186
  — this is the evidence SCHEMA.md §Specialization asks for before splitting a surface. In the same
104
187
  Bash call, chain the opt-in usage ping — **the shared form every phase command reuses**:
105
188
  `<core>/pipeline/scripts/telemetry-send.sh <phase> "$ARGUMENTS" <seconds> "<results>" || true`
106
189
  (`<core>` = `~/.claude` global / `.claude` bundled; here `<phase>` = `build`, `<results>` =
107
190
  `<ok,ok|error,…>`) — a silent no-op unless the human explicitly consented (SCHEMA.md §Telemetry);
108
- never ask about consent here. `/review`, `/fix` and `/smoke` chain the same line with their own
191
+ never ask about consent here. `/review` and `/fix` chain the same line with their own
109
192
  phase + results. The `|| true` swallows a **missing** script too, so a half-copied core goes
110
193
  silent rather than loud — `/doctor` check 1 is what catches that.
111
- Then tell the human: run `/smoke $ARGUMENTS` to exercise the feature end-to-end (or test by hand),
112
- then `/review $ARGUMENTS`. Do not run the app or migrations yourself here `/smoke` is the
113
- sanctioned path for that. **Recommend a `/clear` now** the spec, contract and diff are all on
194
+ Then tell the human: exercise the feature by hand if it's worth it, then run `/review $ARGUMENTS` —
195
+ unless a surface is dead, in which case say so first and let them decide whether to re-run `/build`
196
+ (a dead surface has no findings, so `/fix` has nothing to re-dispatch).
197
+ Do not run the app or migrations yourself here — building is not running.
198
+ **Recommend a `/clear` now** — the spec, contract and diff are all on
114
199
  disk, and the lead's history is re-sent at input price on every turn it survives.
@@ -21,7 +21,7 @@ fix only with the human's go-ahead (or hand them the command).
21
21
  commands' step files are present — `templates/steps/init-pipeline/` non-empty (a router whose
22
22
  `templates/steps/<cmd>/` dir is missing is a partial/stale install ⇒
23
23
  re-run install/update). **Shipped scripts present and executable** in `<core>/pipeline/scripts/`:
24
- `kanban-move.sh`, `telemetry-send.sh`, `preflight.sh`, `new-feature.sh.template`,
24
+ `kanban-move.sh`, `telemetry-send.sh`, `preflight.sh`, `loop.sh`, `new-feature.sh.template`,
25
25
  `remove-feature.sh.template` — ❌ any missing one. Every caller chains these with `|| true`, so an absent script is a **silent**
26
26
  no-op (no kanban card moves, no telemetry ping, no error anywhere) — this check is the only thing
27
27
  that sees it. Also flag ❌ a `VERSION` **newer than** the other `pipeline/` files (compare mtimes):
@@ -34,9 +34,9 @@ fix only with the human's go-ahead (or hand them the command).
34
34
  its `surfaces[].model` — ❌ if missing, mismatched, or a literal `<SURFACE_MODEL>` placeholder
35
35
  (all three silently fall back to inheriting the lead session's model — often Opus — on every
36
36
  dispatch); ⚠️ any `inherit` with the note that it bills at the lead's tier. The generic agents
37
- (`review.md`, `release.md`, `smoke.md`, `profile-reader.md` — repo or `~/.claude/agents/`) must
38
- each carry their `model:` line too (sonnet/haiku/sonnet/haiku). **Command pins:** every mechanical command file
39
- (`build`, `review`, `fix`, `smoke`, `ship`, `audit`, `refactor`, `doctor`, `align-ds`,
37
+ (`review.md`, `release.md`, `profile-reader.md` — repo or `~/.claude/agents/`) must
38
+ each carry their `model:` line too (sonnet/haiku/haiku). **Command pins:** every mechanical command file
39
+ (`build`, `review`, `fix`, `loop`, `ship`, `audit`, `refactor`, `doctor`, `align-ds`,
40
40
  `update-pipeline` — in `.claude/commands/` or `~/.claude/commands/`) carries `model: sonnet` in
41
41
  its frontmatter — ⚠️ if missing (the lead's orchestration turn then bills at the session model,
42
42
  e.g. Opus/Fable). `brainstorm`, `spec`, and `init-pipeline` are intentionally unpinned
@@ -84,11 +84,16 @@ fix only with the human's go-ahead (or hand them the command).
84
84
  End the check with ONE summary line, e.g.
85
85
  `workflows: available (opt-in — ask to "run the review workflow")` or
86
86
  `workflows: unavailable (<first failing prerequisite>) — conversational commands (the default)`.
87
- 9. **Specs & metrics.** Every `specs/*.md` front-matter `status` is a valid stage — excluding
88
- `_`-prefixed files and `specs/refactor-backlog.md`, which `/audit` writes as a backlog, not a
89
- spec, and which has no front-matter to check; `shipped` specs
87
+ 9. **Specs & metrics.** Every `specs/*.md` front-matter `status` is a valid stage — one of
88
+ `draft · frozen · in-progress · in-review · shipped · blocked` (SCHEMA.md §Spec status; the last two
89
+ are written by the `/drive` driver, so flagging them would report the pipeline's own state as a
90
+ defect) — excluding
91
+ `_`-prefixed files (the spec template and `specs/_decisions.md`, the decision journal) and
92
+ `specs/refactor-backlog.md`, which `/audit` writes as a backlog, not a
93
+ spec, and which has no front-matter to check. A spec left `in-progress`/`blocked` with
94
+ `loop_pass` > 0 is a loop that never finished ⇒ say so and name `/drive <id> --resume`. `shipped` specs
90
95
  with a live worktree flagged (see 6). `.claude/pipeline-metrics.jsonl` and `specs/reports/` (the
91
- `/review`·`/smoke` report buffer that lets a `/fix` survive a `/clear`) are gitignored. Metrics
96
+ `/review` report buffer that lets a `/fix` survive a `/clear`) are gitignored. Metrics
92
97
  belong to the **main checkout** — a `pipeline-metrics.jsonl` inside a live feature worktree is a
93
98
  stale-core sign (its lines die at teardown) ⇒ suggest appending its lines to the main checkout's
94
99
  file and deleting the stray.