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.
- package/CHANGELOG.md +151 -0
- package/README.md +43 -12
- package/bin/cli.js +13 -2
- package/core/agents/review.md +23 -0
- package/core/commands/audit.md +9 -1
- package/core/commands/brainstorm.md +6 -0
- package/core/commands/build.md +93 -8
- package/core/commands/doctor.md +13 -8
- package/core/commands/drive.md +80 -0
- package/core/commands/fix.md +10 -5
- package/core/commands/review.md +94 -12
- package/core/commands/spec.md +20 -0
- package/core/commands/update-pipeline.md +6 -1
- package/core/hooks/gate.py +4 -4
- package/core/templates/decisions.template.md +42 -0
- package/core/templates/spec.template.md +4 -2
- package/core/templates/steps/init-pipeline/02-interview-gaps.md +1 -1
- package/core/templates/steps/init-pipeline/04-write-render.md +8 -4
- package/core/workflows/review.js +44 -2
- package/dashboard/dist/assets/{index-AFQnlfjO.css → index-BZ_LQlEj.css} +1 -1
- package/dashboard/dist/assets/index-DYyn4p93.js +43 -0
- package/dashboard/dist/index.html +2 -2
- package/dashboard/server/doctor.js +13 -3
- package/dashboard/server/index.js +7 -0
- package/dashboard/server/metrics.js +4 -4
- package/dashboard/server/usage.js +61 -0
- package/install.ps1 +12 -1
- package/install.sh +12 -2
- package/package.json +1 -1
- package/profile/PIPELINE.template.md +3 -3
- package/profile/SCHEMA.md +150 -12
- package/scripts/loop.sh +318 -0
- package/scripts/metrics/collect.mjs +11 -2
- package/scripts/preflight.sh +2 -2
- package/scripts/telemetry-send.sh +5 -2
- package/scripts/test-dashboard.mjs +22 -2
- package/scripts/test-gate.mjs +1 -2
- package/scripts/test-loop.mjs +227 -0
- package/scripts/test-metrics.mjs +12 -3
- package/scripts/test-workflows.mjs +28 -0
- package/scripts/validate-core.mjs +21 -6
- package/core/agents/smoke.md +0 -63
- package/core/commands/smoke.md +0 -55
- 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> → /
|
|
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>` |
|
|
220
|
-
| `/
|
|
221
|
-
| `/
|
|
222
|
-
| `/
|
|
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
|
|
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 → /
|
|
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: /
|
|
260
|
-
session 2: /
|
|
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 —
|
|
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 /
|
|
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
|
|
217
|
-
//
|
|
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
|
|
package/core/agents/review.md
CHANGED
|
@@ -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
|
```
|
package/core/commands/audit.md
CHANGED
|
@@ -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
|
>
|
package/core/commands/build.md
CHANGED
|
@@ -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.
|
|
20
|
-
|
|
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
|
|
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:
|
|
112
|
-
|
|
113
|
-
|
|
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.
|
package/core/commands/doctor.md
CHANGED
|
@@ -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`, `
|
|
38
|
-
each carry their `model:` line too (sonnet/haiku/
|
|
39
|
-
(`build`, `review`, `fix`, `
|
|
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 —
|
|
88
|
-
`
|
|
89
|
-
|
|
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
|
|
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.
|