cohorte 2.10.0 → 3.0.0-dev.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/README.md +7 -0
- package/assets/manifest.json +193 -0
- package/assets/migrations/config/README.md +12 -0
- package/assets/migrations/state/0001_init.sql +154 -0
- package/assets/prompts/README.md +11 -0
- package/assets/prompts/agents/fixer.md +7 -0
- package/assets/prompts/agents/implementer.md +12 -0
- package/assets/prompts/agents/reviewer.md +8 -0
- package/assets/prompts/agents/security-reviewer.md +7 -0
- package/assets/prompts/phases/build.md +5 -0
- package/assets/prompts/phases/review.md +5 -0
- package/assets/prompts/phases/test.md +5 -0
- package/assets/prompts/system.md +11 -0
- package/assets/schemas/agent-output.schema.json +225 -0
- package/assets/schemas/auth-status.schema.json +87 -0
- package/assets/schemas/command-result.schema.json +192 -0
- package/assets/schemas/commands.schema.json +952 -0
- package/assets/schemas/config.schema.json +2259 -0
- package/assets/schemas/doctor-report.schema.json +104 -0
- package/assets/schemas/events.schema.json +8514 -0
- package/assets/schemas/fake-script.schema.json +549 -0
- package/assets/schemas/inspect.schema.json +3133 -0
- package/assets/schemas/manifest.schema.json +79 -0
- package/assets/schemas/ownership.schema.json +52 -0
- package/assets/schemas/policy-verdict.schema.json +282 -0
- package/assets/schemas/project-model.schema.json +783 -0
- package/assets/schemas/project-status.schema.json +217 -0
- package/assets/schemas/reconcile-plan.schema.json +155 -0
- package/assets/schemas/run-diff.schema.json +177 -0
- package/assets/schemas/run-snapshot-manifest.schema.json +2104 -0
- package/assets/schemas/run-state.schema.json +1755 -0
- package/assets/schemas/runtime-capabilities.schema.json +1545 -0
- package/assets/schemas/sandbox-capabilities.schema.json +116 -0
- package/assets/schemas/skill.schema.json +87 -0
- package/assets/schemas/spec.schema.json +202 -0
- package/assets/schemas/tool-catalogue.schema.json +655 -0
- package/assets/schemas/trust-record.schema.json +38 -0
- package/assets/skills/README.md +9 -0
- package/assets/skills/inspect-surface.md +4 -0
- package/dist/agent-host.mjs +50 -0
- package/dist/agent-host.mjs.map +1 -0
- package/dist/bundle-manifest.json +102 -0
- package/dist/chunks/__host-DgGPyco9.mjs +18 -0
- package/dist/chunks/__host-DgGPyco9.mjs.map +1 -0
- package/dist/chunks/approve-Cv135UqI.mjs +19 -0
- package/dist/chunks/approve-Cv135UqI.mjs.map +1 -0
- package/dist/chunks/auth-BT5oVp76.mjs +132 -0
- package/dist/chunks/auth-BT5oVp76.mjs.map +1 -0
- package/dist/chunks/auth-D8rCVY33.mjs +84 -0
- package/dist/chunks/auth-D8rCVY33.mjs.map +1 -0
- package/dist/chunks/brainstorm-CU10T1tm.mjs +7 -0
- package/dist/chunks/brainstorm-CU10T1tm.mjs.map +1 -0
- package/dist/chunks/cancel-KV_cpsqS.mjs +15 -0
- package/dist/chunks/cancel-KV_cpsqS.mjs.map +1 -0
- package/dist/chunks/canonical-C8UxeEmB.mjs +57 -0
- package/dist/chunks/canonical-C8UxeEmB.mjs.map +1 -0
- package/dist/chunks/catalogue-BvwSrM_j.mjs +1549 -0
- package/dist/chunks/catalogue-BvwSrM_j.mjs.map +1 -0
- package/dist/chunks/compose-Cr0hP0qm.mjs +7303 -0
- package/dist/chunks/compose-Cr0hP0qm.mjs.map +1 -0
- package/dist/chunks/config-DefHA2Lw.mjs +96 -0
- package/dist/chunks/config-DefHA2Lw.mjs.map +1 -0
- package/dist/chunks/contract-B0ra2-bm.mjs +295 -0
- package/dist/chunks/contract-B0ra2-bm.mjs.map +1 -0
- package/dist/chunks/contract-vYbwYr0Y.mjs +123 -0
- package/dist/chunks/contract-vYbwYr0Y.mjs.map +1 -0
- package/dist/chunks/deny-ClTxSvHJ.mjs +15 -0
- package/dist/chunks/deny-ClTxSvHJ.mjs.map +1 -0
- package/dist/chunks/diff-Qw0II0sj.mjs +101 -0
- package/dist/chunks/diff-Qw0II0sj.mjs.map +1 -0
- package/dist/chunks/discover-30Ciya_0.mjs +20 -0
- package/dist/chunks/discover-30Ciya_0.mjs.map +1 -0
- package/dist/chunks/doctor-DfCrKpfT.mjs +222 -0
- package/dist/chunks/doctor-DfCrKpfT.mjs.map +1 -0
- package/dist/chunks/fix-D4Tj8RVA.mjs +18 -0
- package/dist/chunks/fix-D4Tj8RVA.mjs.map +1 -0
- package/dist/chunks/gc-BBXlBF5w.mjs +161 -0
- package/dist/chunks/gc-BBXlBF5w.mjs.map +1 -0
- package/dist/chunks/init-Okz4mlhW.mjs +30 -0
- package/dist/chunks/init-Okz4mlhW.mjs.map +1 -0
- package/dist/chunks/inspect-Buby4cQD.mjs +22 -0
- package/dist/chunks/inspect-Buby4cQD.mjs.map +1 -0
- package/dist/chunks/logs-Giq5sUau.mjs +25 -0
- package/dist/chunks/logs-Giq5sUau.mjs.map +1 -0
- package/dist/chunks/migrate-DRoFUg53.mjs +19 -0
- package/dist/chunks/migrate-DRoFUg53.mjs.map +1 -0
- package/dist/chunks/models-Btp6X2YZ.mjs +24 -0
- package/dist/chunks/models-Btp6X2YZ.mjs.map +1 -0
- package/dist/chunks/pause-BASBfKLO.mjs +16 -0
- package/dist/chunks/pause-BASBfKLO.mjs.map +1 -0
- package/dist/chunks/policy-DUIgzF3W.mjs +139 -0
- package/dist/chunks/policy-DUIgzF3W.mjs.map +1 -0
- package/dist/chunks/providers-Dx78imKj.mjs +19 -0
- package/dist/chunks/providers-Dx78imKj.mjs.map +1 -0
- package/dist/chunks/reconcile-BfD785gd.mjs +26 -0
- package/dist/chunks/reconcile-BfD785gd.mjs.map +1 -0
- package/dist/chunks/render-DyZr5Lgi.mjs +53 -0
- package/dist/chunks/render-DyZr5Lgi.mjs.map +1 -0
- package/dist/chunks/resume-GJQRb2Eb.mjs +15 -0
- package/dist/chunks/resume-GJQRb2Eb.mjs.map +1 -0
- package/dist/chunks/retry-CLrUem1H.mjs +15 -0
- package/dist/chunks/retry-CLrUem1H.mjs.map +1 -0
- package/dist/chunks/review-BDdjb6kB.mjs +17 -0
- package/dist/chunks/review-BDdjb6kB.mjs.map +1 -0
- package/dist/chunks/run-CgTWYlcd.mjs +82 -0
- package/dist/chunks/run-CgTWYlcd.mjs.map +1 -0
- package/dist/chunks/run-tool-C3rAv4XF.mjs +26 -0
- package/dist/chunks/run-tool-C3rAv4XF.mjs.map +1 -0
- package/dist/chunks/schema-C9QbUW4H.mjs +578 -0
- package/dist/chunks/schema-C9QbUW4H.mjs.map +1 -0
- package/dist/chunks/send-BdnJ85Nz.mjs +19 -0
- package/dist/chunks/send-BdnJ85Nz.mjs.map +1 -0
- package/dist/chunks/ship-DTuLGoaJ.mjs +19 -0
- package/dist/chunks/ship-DTuLGoaJ.mjs.map +1 -0
- package/dist/chunks/shutdown-BM92Iyv2.mjs +15 -0
- package/dist/chunks/shutdown-BM92Iyv2.mjs.map +1 -0
- package/dist/chunks/skip-DZG5kpcH.mjs +18 -0
- package/dist/chunks/skip-DZG5kpcH.mjs.map +1 -0
- package/dist/chunks/spec-Bq0P3jVh.mjs +20 -0
- package/dist/chunks/spec-Bq0P3jVh.mjs.map +1 -0
- package/dist/chunks/src-CId6kMsY.mjs +1689 -0
- package/dist/chunks/src-CId6kMsY.mjs.map +1 -0
- package/dist/chunks/src-CfAOde7C.mjs +5403 -0
- package/dist/chunks/src-CfAOde7C.mjs.map +1 -0
- package/dist/chunks/src-Cu3TxNob.mjs +783 -0
- package/dist/chunks/src-Cu3TxNob.mjs.map +1 -0
- package/dist/chunks/src-DcU4IXMe.mjs +117 -0
- package/dist/chunks/src-DcU4IXMe.mjs.map +1 -0
- package/dist/chunks/src-JxawBQBn.mjs +446 -0
- package/dist/chunks/src-JxawBQBn.mjs.map +1 -0
- package/dist/chunks/src-s7YRvk0t.mjs +2116 -0
- package/dist/chunks/src-s7YRvk0t.mjs.map +1 -0
- package/dist/chunks/status-SMjiOMYy.mjs +29 -0
- package/dist/chunks/status-SMjiOMYy.mjs.map +1 -0
- package/dist/chunks/tail-BuhT-2PH.mjs +25 -0
- package/dist/chunks/tail-BuhT-2PH.mjs.map +1 -0
- package/dist/chunks/update-BXIppsbi.mjs +16 -0
- package/dist/chunks/update-BXIppsbi.mjs.map +1 -0
- package/dist/cli.mjs +175 -0
- package/dist/cli.mjs.map +1 -0
- package/package.json +17 -32
- package/CHANGELOG.md +0 -1453
- package/bin/cli.js +0 -812
- package/bin/report.js +0 -141
- package/core/adapter/render.js +0 -389
- package/core/agents/implementer.template.md +0 -142
- package/core/agents/profile-reader.md +0 -50
- package/core/agents/release.md +0 -58
- package/core/agents/review.md +0 -179
- package/core/commands/cohorte-align-ds.md +0 -33
- package/core/commands/cohorte-audit.md +0 -58
- package/core/commands/cohorte-brainstorm.md +0 -70
- package/core/commands/cohorte-build.md +0 -219
- package/core/commands/cohorte-doctor.md +0 -170
- package/core/commands/cohorte-fix.md +0 -80
- package/core/commands/cohorte-fleet.md +0 -103
- package/core/commands/cohorte-init-pipeline.md +0 -31
- package/core/commands/cohorte-intake.md +0 -92
- package/core/commands/cohorte-patch.md +0 -118
- package/core/commands/cohorte-refactor.md +0 -59
- package/core/commands/cohorte-retro.md +0 -85
- package/core/commands/cohorte-review.md +0 -270
- package/core/commands/cohorte-ship.md +0 -122
- package/core/commands/cohorte-spec.md +0 -101
- package/core/commands/cohorte-update-pipeline.md +0 -134
- package/core/hooks/gate.py +0 -580
- package/core/runtimes/claude.json +0 -74
- package/core/runtimes/codex.json +0 -83
- package/core/runtimes/cursor.json +0 -76
- package/core/runtimes/gemini.json +0 -76
- package/core/runtimes/opencode.json +0 -73
- package/core/templates/agent-handoff.md +0 -34
- package/core/templates/brainstorm-return.md +0 -36
- package/core/templates/decisions.template.md +0 -42
- package/core/templates/design-brief.md +0 -44
- package/core/templates/patch.template.md +0 -86
- package/core/templates/pr-body.md +0 -25
- package/core/templates/review-feedback.md +0 -38
- package/core/templates/spec.template.md +0 -87
- package/core/templates/steps/init-pipeline/01-detect-stack.md +0 -44
- package/core/templates/steps/init-pipeline/02-interview-gaps.md +0 -55
- package/core/templates/steps/init-pipeline/03-draft-profile.md +0 -10
- package/core/templates/steps/init-pipeline/04-write-render.md +0 -115
- package/core/templates/steps/init-pipeline/05-report.md +0 -12
- package/core/workflows/audit.js +0 -240
- package/core/workflows/loop.js +0 -641
- package/core/workflows/refactor.js +0 -276
- package/core/workflows/review.js +0 -456
- package/install.ps1 +0 -103
- package/install.sh +0 -114
- package/lib/doctor.js +0 -504
- package/lib/runtime.js +0 -134
- package/lib/versions.js +0 -149
- package/lib/yaml.js +0 -129
- package/profile/PIPELINE.template.md +0 -251
- package/profile/SCHEMA.md +0 -698
- package/profile/cohorte.config.template.yaml +0 -43
- package/scripts/assert-gate-hook.mjs +0 -75
- package/scripts/kanban-move.sh +0 -313
- package/scripts/metrics/collect.mjs +0 -531
- package/scripts/metrics/prices.json +0 -42
- package/scripts/new-feature.sh.template +0 -98
- package/scripts/preflight.sh +0 -124
- package/scripts/remove-feature.sh.template +0 -56
- package/scripts/test-adapter.mjs +0 -368
- package/scripts/test-gate.mjs +0 -428
- package/scripts/test-kanban.mjs +0 -304
- package/scripts/test-lib.mjs +0 -310
- package/scripts/test-metrics.mjs +0 -156
- package/scripts/test-workflows.mjs +0 -758
- package/scripts/validate-core.mjs +0 -320
package/CHANGELOG.md
DELETED
|
@@ -1,1453 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
Entries are shown by `/cohorte-update-pipeline` ("What's new") after a core refresh. Keep them
|
|
4
|
-
short, user-facing, most recent first. One `## <version> — <YYYY-MM-DD>` section per release.
|
|
5
|
-
|
|
6
|
-
> Sections below 2.0.0 name commands **as they were at the time** (`/build`, `/drive`, `/loop`).
|
|
7
|
-
> They are history and are deliberately not rewritten — every command gained a `cohorte-` prefix
|
|
8
|
-
> in 2.0.0.
|
|
9
|
-
|
|
10
|
-
## 2.10.0 — 2026-08-24
|
|
11
|
-
|
|
12
|
-
- **The dashboard is gone.** The local web cockpit — the `cohorte dashboard` verb, the
|
|
13
|
-
dependency-free HTTP server, the Vite/React app and the prebuilt `dashboard/dist` that shipped
|
|
14
|
-
in every tarball — is removed, along with the fleet registry, kanban and usage readers that
|
|
15
|
-
only it consumed. It was a second surface for state the CLI already reports, with its own
|
|
16
|
-
build step, its own security posture (loopback-bound because its action endpoints executed
|
|
17
|
-
code: install, update, reset, and `/cohorte-init-pipeline`·`/cohorte-update-pipeline`·`/cohorte-audit`
|
|
18
|
-
through headless Claude), and its own drift to police. `cohorte doctor`, `cohorte specs` and
|
|
19
|
-
`cohorte metrics` answer the same questions from the shell, and `doctor` exits 1 on any bad
|
|
20
|
-
check, which the browser never could.
|
|
21
|
-
|
|
22
|
-
**What did not go with it:** the four modules those verbs actually run on — the JS port of
|
|
23
|
-
`/cohorte-doctor`, the runtime-layout resolver, the version prober and the block-YAML parser —
|
|
24
|
-
moved from `dashboard/server/` to **`lib/`**. `cohorte doctor` / `specs` / `version` behave
|
|
25
|
-
exactly as before, and so do the Francois extension's `--panel` payloads. Their test suite
|
|
26
|
-
moved with them (`scripts/test-dashboard.mjs` ⇒ `scripts/test-lib.mjs`, 54 assertions), minus
|
|
27
|
-
the cases that covered deleted code.
|
|
28
|
-
|
|
29
|
-
Fallout worth naming: the package no longer has a build step at all (`prepack` and
|
|
30
|
-
`build:dashboard` are gone, npm and CI no longer build a React app to publish), the tarball
|
|
31
|
-
drops from 88 files to 73, and `~/.claude/cohorte-dashboard.json` — the tracked-project list —
|
|
32
|
-
is now dead; delete it. `--port` / `--host` / `--open` and `COHORTE_DASHBOARD_PORT` /
|
|
33
|
-
`COHORTE_DASHBOARD_HOST` no longer exist; `cohorte dashboard` prints the usage and exits 2.
|
|
34
|
-
|
|
35
|
-
## 2.9.0 — 2026-08-22
|
|
36
|
-
|
|
37
|
-
- **`/cohorte-intake` — the door before the doors.** Work has always entered the pipeline
|
|
38
|
-
pre-distilled by a human: a ticket became a `/cohorte-patch` paste, an email became a
|
|
39
|
-
brainstorm idea, by hand. Intake does the distillation: paste anything that arrives and it
|
|
40
|
-
triages — bug ⇒ the exact structure patch interviews for (inferred repro steps labeled as
|
|
41
|
-
such); feature ⇒ a brainstorm seed whose open-questions list is the panel's agenda, with any
|
|
42
|
-
`_decisions.md` line it contradicts named; noise ⇒ says so and stops, because inventing a
|
|
43
|
-
spec from noise costs a whole pipeline run downstream. The distillate lands on disk and on
|
|
44
|
-
the kanban's Ideas column; freezing anything stays the human's move.
|
|
45
|
-
|
|
46
|
-
- **`/cohorte-retro` — the pipeline learns from its own findings.** Every review leaves
|
|
47
|
-
structured residue (verdict.json, the specs' Remediation history, the deferred backlog) that
|
|
48
|
-
nothing ever read back. Retro mines it for patterns — the same finding kind on the same
|
|
49
|
-
surface across features, a hotspot module, a recurring fix family — and turns each into ONE
|
|
50
|
-
rule-shaped §Conventions line the human ratifies. Adopted rules re-render the affected
|
|
51
|
-
surface agents (the conventions slice is baked at render time — a rule without a re-render
|
|
52
|
-
is one reviewers enforce and implementers never saw) and land in the decisions journal.
|
|
53
|
-
Findings → rules → the next build never produces the finding: cheaper than any number of
|
|
54
|
-
review rounds catching it.
|
|
55
|
-
|
|
56
|
-
- **`/cohorte-fleet` — parallel features get a flight controller.** The worktree isolation
|
|
57
|
-
existed; the coordination lived in your head. `plan` builds the feature×surface overlap
|
|
58
|
-
matrix from the specs themselves (contract dependencies ⇒ merge order; same-tree writes ⇒
|
|
59
|
-
serialize or drop one), provisions the worktrees, and prints one launch line per feature.
|
|
60
|
-
`status` is one row per feature ending in the single next action. `sync` does the post-merge
|
|
61
|
-
sweep everyone forgets — rebase every survivor, report conflicts verbatim to their owner's
|
|
62
|
-
session, and say out loud that a rebase invalidates the freshness stamp. What it will never
|
|
63
|
-
do is spawn the work headless: that is the retired 2.2.0 driver's grave, and each feature's
|
|
64
|
-
loop keeps running in its own supervised session.
|
|
65
|
-
|
|
66
|
-
- **`/cohorte-review --pr <num>` — the pipeline reviews incoming work.** Same reviewers, same
|
|
67
|
-
report, none of the pipeline's certifications: the PR is fetched into a throwaway worktree
|
|
68
|
-
(your checkout untouched), reviewed in audit mode (no spec to conform to), and a red
|
|
69
|
-
preflight makes the mechanical failures the review instead of wasting reviewers on code that
|
|
70
|
-
doesn't compile. Posting the report as a PR comment always asks first — it is outward-facing
|
|
71
|
-
— and declining leaves the report on disk as a complete outcome.
|
|
72
|
-
|
|
73
|
-
- **What a feature costs, finally on the dashboard.** The workflow paths now stamp an
|
|
74
|
-
approximate `tokens` field into their metrics lines from the runtime's own counter
|
|
75
|
-
(`budget.spent()` deltas — the figure a conversational lead cannot read), the loop's history
|
|
76
|
-
carries cost per round, and the dashboard shows `~Nk tok` per feature and per phase. Marks
|
|
77
|
-
are placed around the review child so build/fix deltas never double-count it; token-less
|
|
78
|
-
conversational lines aggregate as absent, never as "free".
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
## 2.8.0 — 2026-08-22
|
|
83
|
-
|
|
84
|
-
- **`/cohorte-loop` is back — as a workflow, which is the whole point.** The 2.2.0 driver was
|
|
85
|
-
retired because it spawned headless child processes it could not supervise: it stalled on a
|
|
86
|
-
permission prompt it could not see, read a missing `build.json` as an empty one, and had a
|
|
87
|
-
session killed mid-write with nothing noticing. `core/workflows/loop.js` runs
|
|
88
|
-
build → review → [fix → review]* for one feature inside the Workflow runtime instead — the
|
|
89
|
-
runtime holds control flow, a dead agent resolves to `null` rather than to silence, and there
|
|
90
|
-
is no prompt to stall on.
|
|
91
|
-
|
|
92
|
-
What it will not do is as designed as what it does: it *verifies* `/cohorte-build`'s outputs
|
|
93
|
-
(frozen spec, fresh `readiness.json`, the lead-authored contract) as preconditions and aborts —
|
|
94
|
-
naming the gap — on anything that is a human's call: a `NOT-READY` spec, a surface the profile
|
|
95
|
-
doesn't own, a blocking finding on the contract file itself. A dead reviewer's zero findings
|
|
96
|
-
can never read as ship (`unreviewed` is checked before `blocking`, in that order on purpose);
|
|
97
|
-
identical blocking findings two rounds running abort as treading water instead of burning the
|
|
98
|
-
remaining rounds; `maxRounds` (default 5) is the last net, never the first. State is four files
|
|
99
|
-
in `specs/reports/` — re-invoking resumes, and every file older than the spec is treated as
|
|
100
|
-
absent. There is **no** `core/commands/cohorte-loop.md` and `validate-core.mjs` now fails if
|
|
101
|
-
one appears: without the Workflow runtime the loop refuses explicitly rather than degrading to
|
|
102
|
-
a lead re-reasoning the fan-out every round at session prices. It stamps `in-progress` /
|
|
103
|
-
`in-review` / `blocked` on the spec — the driver states SCHEMA.md kept alive since 2.2.0 have
|
|
104
|
-
a producer again.
|
|
105
|
-
|
|
106
|
-
To serve it, the review workflow now writes the same `specs/reports/<id>.verdict.json` the
|
|
107
|
-
conversational `/cohorte-review` §3 guarantees (blocking count, normalized `blocking_items`,
|
|
108
|
-
sha256 fingerprint, the degraded `aborted: "preflight"` form) — one machine contract, two
|
|
109
|
-
producers.
|
|
110
|
-
|
|
111
|
-
- **A deny behind an ask was reachable with one click.** `gate.py` scanned command segments in
|
|
112
|
-
order and returned on the first match, so `git commit -m x && node ace migration:fresh`
|
|
113
|
-
surfaced only the benign `git commit` confirm — and the human's single "yes" ran the
|
|
114
|
-
hard-denied migration behind it. Deny patterns are now matched across the whole chain before
|
|
115
|
-
any ask is offered. Global installs pick this up with `cohorte update`; bundled repos via
|
|
116
|
-
`/cohorte-update-pipeline`.
|
|
117
|
-
|
|
118
|
-
- **The SHIP stamp is now earned, not implied.** The conversational `/cohorte-review` ticked the
|
|
119
|
-
DoD and wrote the freshness stamp on every SHIP — including one carrying HIGH findings, which
|
|
120
|
-
`/cohorte-ship`'s gates then happily certified, while the workflow variant refused the same
|
|
121
|
-
state. Both paths now agree: tick + stamp only when nothing above LOW survived; surviving
|
|
122
|
-
HIGH/MEDIUM routes to `/cohorte-fix` (or an explicit park) first.
|
|
123
|
-
|
|
124
|
-
- **A dozen bugs the release audit surfaced**, the sharper ones being: `cohorte install` seeded
|
|
125
|
-
`cohorte.config.yaml` under `~/.claude` even when `CLAUDE_CONFIG_DIR` pointed elsewhere — a
|
|
126
|
-
config no reader ever probed (CI now asserts the seed lands where the readers look);
|
|
127
|
-
the refactor workflow's retry round discarded the items its first verify had already cleared,
|
|
128
|
-
so the backlog re-dispatched finished work — and invoked with a bare `"backend"` it silently
|
|
129
|
-
refactored *every* big domain; the dashboard trusted the absolute paths in a committed
|
|
130
|
-
`runtimes.json`, going all-red on any cloned or moved checkout; `preflight.sh` fed a UTC
|
|
131
|
-
timestamp to a local-time `touch -t`, future-dating the throwaway index west of UTC (and an
|
|
132
|
-
all-empty command list stamped a green preflight that had verified nothing);
|
|
133
|
-
`new-feature.sh` branched worktrees off the *local* default branch its own fetch never
|
|
134
|
-
updated; a CRLF kanban board failed with "column not found" on a column that exists; and a
|
|
135
|
-
dead mechanical-gates agent read as "0 failures" in the audit workflow. Plus a sweep of doc
|
|
136
|
-
drift (the first-feature walkthrough skipped build *and* review; "Node-less" installers that
|
|
137
|
-
require Node; stale counts of agents, scripts and board columns).
|
|
138
|
-
|
|
139
|
-
- **The shell installers are now the thin delegators they already were.** Since 2.2.0 both
|
|
140
|
-
scripts handed everything to `bin/cli.js` and then carried ~300 lines of unreachable legacy
|
|
141
|
-
copy code below the hand-off — dead text that `validate-core`'s "does the installer copy X"
|
|
142
|
-
checks were vacuously matching, which is worse than no check: it reads as coverage. The dead
|
|
143
|
-
code is gone; the checks now assert CI's install dry-run postconditions — tests against the
|
|
144
|
-
copy that actually runs. Along the way: `sh install.sh` from inside a checkout silently
|
|
145
|
-
*cloned the remote* instead of installing the local tree (`$0` arrives with no slash and the
|
|
146
|
-
self-locate case missed it); both installers now refuse a Node older than 18 up front instead
|
|
147
|
-
of half-installing before `fs.cpSync` crashes; and the review agent's `tools:` names both
|
|
148
|
-
retrieval providers (`mcp__serena`, `mcp__graphify`) — one fixed agent file, shared across
|
|
149
|
-
projects, only the wired provider is live in a session, and graphify projects' reviewers were
|
|
150
|
-
silently cut off from their own index.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
## 2.7.0 — 2026-08-22
|
|
154
|
-
|
|
155
|
-
- **The metrics panel billed Sonnet 5 fifty percent over.** `prices.json` carried $3/$15 because
|
|
156
|
-
that was the rate scheduled to take effect on 2026-09-01. It never will: Anthropic made the
|
|
157
|
-
$2/$10 introductory rate the standard one. Every run costed since the entry was written reads
|
|
158
|
-
high, and the further back a run is, the more confidently wrong the number looks.
|
|
159
|
-
|
|
160
|
-
Sonnet 5 is now $2/$10, and the file says in prose why the increase must not be reinstated —
|
|
161
|
-
the next person to "correct" this back will at least have to argue with a comment first. Sonnet
|
|
162
|
-
4.6 and earlier stay at $3/$15: same tier, different price, and the longest-prefix lookup keeps
|
|
163
|
-
them apart on its own.
|
|
164
|
-
|
|
165
|
-
- **A concurrency ceiling that moved while the comments stood still.** `audit.js` described the
|
|
166
|
-
runtime as capping concurrent agents at "~16". It is 20, it is named
|
|
167
|
-
(`CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS`), and raising it raises the ceiling without changing this
|
|
168
|
-
script — the queue belongs to the runtime, and a queued domain was never a lost one. Comments
|
|
169
|
-
only; no dispatch logic moved.
|
|
170
|
-
|
|
171
|
-
- **The design brief was the one step the pipeline handed back to you.** `/cohorte-spec` freezes a
|
|
172
|
-
brief to `specs/design/<feature_id>.md` and then said, in effect, paste this somewhere else. With
|
|
173
|
-
`design.inline: true` it can instead hand that file to `/design`, which reads the codebase,
|
|
174
|
-
matches the existing UI style, and returns editable artboards without leaving the session.
|
|
175
|
-
|
|
176
|
-
The flag is off by default and degrades rather than fails: an unmet floor falls back to the
|
|
177
|
-
paste-it-yourself path with a note, never an error. It needs `provider: claude-design`, the new
|
|
178
|
-
`inline_design` runtime capability (Claude Code only), and a CLI ≥ 2.1.234 — a **higher floor than
|
|
179
|
-
workflows' 2.1.154**, which is why `/cohorte-doctor` grew a separate check `8b` instead of raising
|
|
180
|
-
the existing one. Raising the shared floor would have made every install between the two versions
|
|
181
|
-
read as broken while its workflows ran fine.
|
|
182
|
-
|
|
183
|
-
Understand what inline does and does not change: it changes who does the pasting. The brief is
|
|
184
|
-
still written to disk first and is still what `/cohorte-build` reads — artboards are an aid to the
|
|
185
|
-
human, not an input to the pipeline. And `/design` is a research preview that **does not save them
|
|
186
|
-
for you**, so check 8b says so on every run, including the runs where everything passes. An
|
|
187
|
-
artboard nobody exported dies with the session, and there is no way to notice afterwards.
|
|
188
|
-
|
|
189
|
-
- This release adds a runtime capability, a profile flag, and a command section: run
|
|
190
|
-
`/cohorte-update-pipeline` after updating.
|
|
191
|
-
|
|
192
|
-
## 2.6.0 — 2026-08-14
|
|
193
|
-
|
|
194
|
-
- **Two ways to type the same command, and one of them silently doesn't work.** The docs wrote
|
|
195
|
-
`npx cohorte install`, the Francois extension's manifest names a bare `cohorte` binary, and
|
|
196
|
-
nothing said why the two could not be the same string. They cannot: `npx` fetches a package
|
|
197
|
-
into a cache and runs it once, leaving nothing on `PATH`, and a Francois panel may only spawn
|
|
198
|
-
a **bare binary name resolved on `PATH`**. So the extension's requirement read like a
|
|
199
|
-
preference the rest of the documentation contradicted.
|
|
200
|
-
|
|
201
|
-
Every command is now written one way — `cohorte <verb>`, after `npm i -g cohorte` — across the
|
|
202
|
-
README, the docs, both shell installers, the CLI's own banners, the `/cohorte-doctor` fix
|
|
203
|
-
lines, and the `install` string `/cohorte-init-pipeline` writes into a repo's committed
|
|
204
|
-
`pipeline.json`. `npx cohorte@latest <verb>` still works and is still the right call for a
|
|
205
|
-
one-off on a machine you don't own; it is named once, as the escape hatch it is.
|
|
206
|
-
|
|
207
|
-
- **The cost of pinning, removed before it could bite.** `install` and `update` lay down the core
|
|
208
|
-
carried by the CLI that runs them. `npx cohorte@latest` made that self-correcting; a global
|
|
209
|
-
install does not, so `cohorte update` on a CLI left at an old version would re-lay an old core
|
|
210
|
-
and report success — an update that updates nothing.
|
|
211
|
-
|
|
212
|
-
Both verbs now compare themselves against the registry when they finish and print exactly what
|
|
213
|
-
to run (`npm i -g cohorte@latest`) when they are behind. It is never fatal, never blocks a
|
|
214
|
-
successful install, costs a 2.5s fetch with no `npm view` fallback, and stays silent on any
|
|
215
|
-
failure — an offline install pays 2.5 seconds and says nothing. `COHORTE_NO_VERSION_CHECK=1`
|
|
216
|
-
opts out; `CI` opts out already.
|
|
217
|
-
|
|
218
|
-
Nothing in the pipeline changed: no new agent, no gate, no template — this release needs no
|
|
219
|
-
`/cohorte-update-pipeline`.
|
|
220
|
-
|
|
221
|
-
## 2.5.0 — 2026-08-14
|
|
222
|
-
|
|
223
|
-
- **Everything the pipeline knew about your repo, it would only say to a coding agent.**
|
|
224
|
-
`/cohorte-doctor` reads the health of an install and `specs/*.md` holds the board, but both
|
|
225
|
-
answers cost a session: you opened Claude Code, ran a command, and read prose. There was no
|
|
226
|
-
way to ask "is this repo's pipeline sound?" from a shell script, a CI job, or anything that
|
|
227
|
-
isn't an LLM.
|
|
228
|
-
|
|
229
|
-
Two read-only commands now answer without an agent in the loop:
|
|
230
|
-
|
|
231
|
-
```sh
|
|
232
|
-
cohorte specs # the board: id · status · branch · title, from specs/*.md frontmatter
|
|
233
|
-
cohorte doctor # the /cohorte-doctor checks — exits 1 when any check is bad
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
`doctor` **exits 1 on any bad check**, so it drops into CI as-is. Both reuse the dashboard's
|
|
237
|
-
own readers, so the board, the dashboard and the CLI can never give three answers about one
|
|
238
|
-
repo. `--porcelain` gives one record per line with `U+001F` between fields — a spec title
|
|
239
|
-
with a space in it never misaligns a column — and `--json` gives the native document.
|
|
240
|
-
|
|
241
|
-
- **The pipeline, in Francois.** A third shape, `--panel` (on `specs`, `doctor` and `metrics`),
|
|
242
|
-
emits the payload a [Francois](https://github.com/antoine-gmnz/francois) extension panel
|
|
243
|
-
validates against. It exists for
|
|
244
|
-
[**francois-plugin-cohorte**](https://github.com/TheBidouilleAgency/francois-plugin-cohorte):
|
|
245
|
-
a manifest-only extension — no code, no binary — that renders the 30-day cost, the doctor
|
|
246
|
-
report and the spec board as three panels beside your sessions, on any project with a
|
|
247
|
-
`PIPELINE.md`.
|
|
248
|
-
|
|
249
|
-
```sh
|
|
250
|
-
npm i -g cohorte # a Francois extension may only spawn a
|
|
251
|
-
francois ext install TheBidouilleAgency/cohorte # bare binary on PATH — never npx, never a shell
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
This is the only Francois-aware surface in the package, and it is one flag wide. Nothing in
|
|
255
|
-
the pipeline itself changed: no new agent, no new gate, no template to re-render — this
|
|
256
|
-
release needs no `/cohorte-update-pipeline`.
|
|
257
|
-
|
|
258
|
-
## 2.4.0 — 2026-08-13
|
|
259
|
-
|
|
260
|
-
- **The pipeline froze *what* to build, never *how much*.** A spec pins the contract and the
|
|
261
|
-
acceptance criteria, so the feature was right — but nothing ever asked an implementer whether the
|
|
262
|
-
helper it was about to write already existed three files over, whether the stdlib shipped it, or
|
|
263
|
-
whether the abstraction it was wrapping had exactly one caller. The diff came out correct and
|
|
264
|
-
fatter than it needed to be, and every extra line was then paid twice: once at build, once again at
|
|
265
|
-
`/cohorte-review`, whose cost is linear in the diff it reads.
|
|
266
|
-
|
|
267
|
-
Implementers now walk a **minimality ladder** before inventing anything: does it need to exist at
|
|
268
|
-
all → already in this repo → stdlib/framework → native platform feature → an already-installed
|
|
269
|
-
dependency → a few inline lines → only then the minimum the contract requires. It governs the
|
|
270
|
-
**how**, never the **what** — a contract field, an acceptance criterion, a test, a validation or an
|
|
271
|
-
authz check is out of its reach, by construction. It is bounded to **one lookup per candidate**, so
|
|
272
|
-
it costs a symbol search and not an exploration, and a shortcut kept on purpose surfaces in the
|
|
273
|
-
handoff's `## TODO / not done` with its ceiling and its upgrade trigger, instead of rotting in a
|
|
274
|
-
comment.
|
|
275
|
-
|
|
276
|
-
The `review` agent gains the matching axis — over-engineering, tagged `delete:` / `stdlib:` /
|
|
277
|
-
`native:` / `yagni:` / `shrink:`, always naming the cheaper replacement. It is deliberately the
|
|
278
|
-
weakest thing in the report: **5 findings max, MEDIUM ceiling, never a CRITICAL, never a REVISE,
|
|
279
|
-
never a BLOCK**. A diff whose only findings are `complexity` ships, and they park in the backlog
|
|
280
|
-
like any other nit. Tests, fixtures and anything the contract mandates are out of bounds — coverage
|
|
281
|
-
is not bloat. In audit mode the axis widens to the whole target (10 per domain, biggest cut first,
|
|
282
|
-
closing with `net: -N lines, -M deps possible.`), and `/cohorte-audit` files them under a new
|
|
283
|
-
`complexity` backlog tag: the cheapest wins in the file, since deleting code needs no new test.
|
|
284
|
-
|
|
285
|
-
Doctrine adapted from [ponytail](https://github.com/dietrichgebert/ponytail) (MIT) — the decision
|
|
286
|
-
ladder and the finding tags are theirs; the subordination to the frozen contract and the
|
|
287
|
-
can't-block severity ceiling are what make them safe inside a gated pipeline.
|
|
288
|
-
|
|
289
|
-
Run `/cohorte-update-pipeline` to re-render your surface agents — the ladder lives in the
|
|
290
|
-
implementer template, so it only reaches your agents through a reconcile.
|
|
291
|
-
|
|
292
|
-
## 2.3.0 — 2026-08-12
|
|
293
|
-
|
|
294
|
-
- **A bug fix had to pretend to be a feature.** The only way into the pipeline was
|
|
295
|
-
`/cohorte-spec` — a section-by-section interview whose critical part is a frozen §5 contract, with
|
|
296
|
-
a ~300-line budget. For a `500` on an empty cart that is more work than the fix, so in practice you
|
|
297
|
-
left the pipeline and patched by hand: no frozen intent, no review, no trace.
|
|
298
|
-
|
|
299
|
-
`/cohorte-patch` is the bug-fix entry point. A **triage, not an interview** — repro, expected
|
|
300
|
-
behaviour, what must not change — it locates the cause itself and freezes
|
|
301
|
-
`specs/patch-<slug>.md` (`kind: patch`, ~60 lines). The **§4 regression test replaces §5 CONTRACT**
|
|
302
|
-
as the thing the diff is checked against.
|
|
303
|
-
|
|
304
|
-
Then nothing downstream is special-cased: a patch spec *is* a spec, so `/cohorte-build` →
|
|
305
|
-
`/cohorte-review` → `/cohorte-fix` → `/cohorte-ship` consume it unchanged, one `/clear` between
|
|
306
|
-
each — four short sessions instead of one thread re-sending its own triage history at input price
|
|
307
|
-
every turn. Only three places read `kind: patch`: build §1.6/§2 (judge the repro + test, author no
|
|
308
|
-
contract when §5 is `none`), the `review` agent (scope creep becomes a first-class finding), and
|
|
309
|
-
ship (branch off `vcs.patch_branch_prefix`, `patch` bump by default, `fix(<scope>)` commit).
|
|
310
|
-
|
|
311
|
-
A patch may span **several surfaces** — one bug, one repro, one spec. The single hard escalation:
|
|
312
|
-
a fix needing **new** contract surface area is a feature wearing a bug's clothes, and it is routed
|
|
313
|
-
to `/cohorte-spec` rather than letting two surfaces invent a shape independently.
|
|
314
|
-
|
|
315
|
-
- **Telemetry is gone — all of it.** The opt-in usage pings that shipped through 2.2.0 are removed
|
|
316
|
-
wholesale: the `telemetry-send.sh` sender, the per-phase pings in the six funnel commands, the
|
|
317
|
-
consent question in `/cohorte-init-pipeline`, the `telemetry:` block in the config template, the
|
|
318
|
-
`/cohorte-doctor` consent check, the collector contract in `SCHEMA.md`. Cohorte now sends nothing,
|
|
319
|
-
anywhere.
|
|
320
|
-
|
|
321
|
-
**Upgrading removes what is already on disk.** Copy-over never deletes, so an existing install
|
|
322
|
-
would otherwise keep an executable that still POSTs to the collector — all three installers
|
|
323
|
-
(`install.sh`, `install.ps1`, `npx cohorte`) now scrub it, and CI asserts its absence. And
|
|
324
|
-
`/cohorte-update-pipeline` deletes the leftover `telemetry:` block from
|
|
325
|
-
`~/.claude/cohorte.config.yaml`: nothing reads it any more, and an `enabled: true` left sitting in
|
|
326
|
-
a file you may open reads as though data were still leaving the machine.
|
|
327
|
-
|
|
328
|
-
The OpenTelemetry tip (Claude Code's own metrics export, a collector you point at yourself) is
|
|
329
|
-
gone from `SCHEMA.md` §Measuring cost and the token-economy guide too. `/cost` and
|
|
330
|
-
`pipeline-metrics.jsonl` remain — both entirely local.
|
|
331
|
-
|
|
332
|
-
`validate-core.mjs` gained a ratchet: any mention of telemetry or a usage ping under
|
|
333
|
-
`core/{commands,agents,templates,workflows}` now fails CI, so it cannot creep back in by copying an
|
|
334
|
-
old command file. The single exemption is `/cohorte-update-pipeline` — the command that *deletes*
|
|
335
|
-
the leftovers has to name them — and it is itself checked for never naming a ping, a sender or a
|
|
336
|
-
consent flow.
|
|
337
|
-
|
|
338
|
-
- **Kanban:** `/cohorte-patch` with no argument offers the **Ideas** column, `[patch]`-titled cards
|
|
339
|
-
first, and titles its own card `[patch] <title>` (join key `#patch-<slug>`). The `[<kind>]` prefix
|
|
340
|
-
stays a human convention — nothing parses it.
|
|
341
|
-
|
|
342
|
-
- **Profile:** new optional `vcs.patch_branch_prefix` (default `fix/`); `/cohorte-update-pipeline`
|
|
343
|
-
tops it up, and a profile without it falls back to the same default.
|
|
344
|
-
|
|
345
|
-
## 2.2.0 — 2026-08-12
|
|
346
|
-
|
|
347
|
-
- **The pipeline was Claude Code or nothing.** The doctrine — frozen spec, stateless surfaces, a
|
|
348
|
-
gate you cannot talk your way past — is not Claude-specific, but every artefact that carried it
|
|
349
|
-
was: `.claude/commands/*.md` with Claude frontmatter, `Task` dispatches, a PreToolUse hook. A
|
|
350
|
-
Codex or Cursor user could read the ideas and reimplement nothing.
|
|
351
|
-
|
|
352
|
-
`core/commands/` and `core/agents/` are now **runtime-neutral sources**, and the installer renders
|
|
353
|
-
them per coding agent — as slash commands, TOML commands, or **Codex skills**
|
|
354
|
-
(`.agents/skills/<name>/SKILL.md`, committed with the repo: custom prompts are deprecated *and*
|
|
355
|
-
user-scoped, so a teammate cloning the repo would have got the profile and none of the commands) —
|
|
356
|
-
for **Claude Code, Codex CLI, Cursor, Gemini CLI, OpenCode**
|
|
357
|
-
(`npx cohorte install --runtime=codex,cursor`, or `--all-runtimes`, or nothing and it detects and
|
|
358
|
-
asks). Rendering rewrites the surface — markdown + the frontmatter keys that runtime understands,
|
|
359
|
-
or TOML for Gemini — resolves every path through the tokens `<core>` / `<state>` / `<agents>` /
|
|
360
|
-
`<config>` / `<memory>`, and swaps the argument placeholder (`$ARGUMENTS`, `{{args}}`, or an
|
|
361
|
-
explicit note where the runtime substitutes nothing, as Cursor does).
|
|
362
|
-
|
|
363
|
-
The part that is not cosmetic: the prompts **branch on what the runtime can enforce**, and say so
|
|
364
|
-
in their own text rather than pretending.
|
|
365
|
-
|
|
366
|
-
**The gate really runs on four of the five.** `gate.py` is registered as a blocking hook in each
|
|
367
|
-
runtime's own format — `PreToolUse` in `settings.json` (Claude) and `.codex/hooks.json` (Codex),
|
|
368
|
-
`beforeShellExecution` in `.cursor/hooks.json`, `BeforeTool` in `.gemini/settings.json` — and
|
|
369
|
-
emits that runtime's envelope, selected by `--runtime <id>`. A verdict in the wrong shape is read
|
|
370
|
-
as *allow* by every one of them, so each dialect is covered by `scripts/test-gate.mjs` rather than
|
|
371
|
-
trusted. **Codex and Gemini have no confirmation tier**, so an `ask` verdict is escalated to
|
|
372
|
-
`deny` with the reason attached: the point of that tier is that a human sees the command first,
|
|
373
|
-
and a runtime that cannot ask cannot deliver it — the same rule unattended headless runs already
|
|
374
|
-
used. The phase gate also learned Gemini's shape, where a subagent arrives as a tool of its own
|
|
375
|
-
name rather than as `Task` + `subagent_type`. OpenCode extends via plugins, not hooks, so there
|
|
376
|
-
the commands call `gate.py --check` themselves: same verdicts, but advisory, and
|
|
377
|
-
`/cohorte-doctor` says so instead of reporting ✅.
|
|
378
|
-
|
|
379
|
-
**Subagents are real everywhere**, in four different file formats — markdown + frontmatter for
|
|
380
|
-
Claude, Cursor, Gemini and OpenCode, TOML with the body under `developer_instructions` for Codex.
|
|
381
|
-
Read-only enforcement for the reviewer is derived from the source agent's tool list and re-emitted
|
|
382
|
-
as each runtime spells it (`readonly: true`, `sandbox_mode = "read-only"`); where there is no
|
|
383
|
-
equivalent, the rendered reviewer carries an explicit instruction that read-only is on it, and
|
|
384
|
-
why. Model pins do **not** travel: the profile names Anthropic aliases, which are meaningless
|
|
385
|
-
elsewhere, so agents inherit the runtime's own model selection.
|
|
386
|
-
|
|
387
|
-
**Real subagents are a requirement, not a capability to degrade around.** A sequential-persona
|
|
388
|
-
fallback shipped mid-development and was removed before release: it asked the lead to simulate the
|
|
389
|
-
isolation boundary by discipline — adopt one agent file, do that surface, drop it — which is not
|
|
390
|
-
the same guarantee, and no supported runtime ever took the branch. A runtime declaring
|
|
391
|
-
`subagents: false` is now refused at install with a named error rather than rendered into a
|
|
392
|
-
pipeline whose central promise is silently absent.
|
|
393
|
-
|
|
394
|
-
- **`/cohorte-loop` is removed, on every runtime including Claude Code.** The autonomous
|
|
395
|
-
build→review→fix driver was the one part of the pipeline tied to a single vendor's headless CLI —
|
|
396
|
-
it spawned `claude -p` children through two shell scripts, a detached `screen` session, a
|
|
397
|
-
`caffeinate` assertion and a resume protocol stamped into spec front-matter. That is a lot of
|
|
398
|
-
surface, on the platform-specific end of the codebase, for a phase the human-driven cycle already
|
|
399
|
-
covers at a cost the loop was mostly there to hide.
|
|
400
|
-
|
|
401
|
-
Gone with it: `scripts/loop.sh`, `scripts/loop-detach.sh`, their test suite, and the
|
|
402
|
-
`loop_pass`/`loop_phase` front-matter fields (dropped from the spec template; still *read* by the
|
|
403
|
-
dashboard so a spec left mid-flight by an older core still explains itself). The installer scrubs
|
|
404
|
-
the command and both scripts on upgrade, in every runtime's layout — copy-over never deletes, and
|
|
405
|
-
a surviving command file is a decoy the model can still fire against a core that no longer ships
|
|
406
|
-
its driver.
|
|
407
|
-
|
|
408
|
-
**The file contract stays.** `verdict.json`, `readiness.json` and `build.json` are still written
|
|
409
|
-
on every run, and the `in-progress`/`blocked` spec statuses stay valid: they are what anything
|
|
410
|
-
automating the cycle from outside reads and writes. Removing the built-in driver does not remove
|
|
411
|
-
the ability to drive it — it removes cohorte's opinion about how.
|
|
412
|
-
|
|
413
|
-
Layout: each runtime gets its own rendered core (`.cohorte/<id>/`), because the same template
|
|
414
|
-
resolves differently per capability — but the **project state is shared** (`.cohorte/`:
|
|
415
|
-
gate-config, preflight stamp, metrics), so a repo driven from two agents cannot disagree with
|
|
416
|
-
itself about what is gated or what has been verified. The user config is shared too; the shipped
|
|
417
|
-
scripts probe `~/.claude` then `~/.cohorte`, so one kanban board and one telemetry consent.
|
|
418
|
-
|
|
419
|
-
**Claude Code is unchanged** — same paths, same frontmatter, same hook, and `scripts/test-adapter.mjs`
|
|
420
|
-
asserts that as a regression test alongside the per-runtime output. `install.sh` / `install.ps1`
|
|
421
|
-
now delegate to the Node CLI: there is no shell renderer, and a raw copy would install prompts
|
|
422
|
-
full of unresolved markers that look installed and instruct the model wrongly.
|
|
423
|
-
|
|
424
|
-
- **A config dir with a space in it broke every tool call in the session.** The gate-hook
|
|
425
|
-
registration quoted the script path only on Windows, so a `CLAUDE_CONFIG_DIR` under
|
|
426
|
-
`~/Library/Application Support/…` — where a desktop host naturally puts it — produced
|
|
427
|
-
`python3 /Users/x/Library/Application Support/…/gate.py`. The shell split that, python reported
|
|
428
|
-
`can't open file '/Users/x/Library/Application'`, and *every* Bash and Task call failed —
|
|
429
|
-
including the ones needed to undo it. Quoted on every platform now, in both the global
|
|
430
|
-
registration and the per-runtime one, with a test that installs into a path containing a space
|
|
431
|
-
and asserts the quoting plus that a re-install still reconciles its own entry instead of
|
|
432
|
-
stacking a second.
|
|
433
|
-
|
|
434
|
-
- **`CLAUDE_CONFIG_DIR` was only half honoured.** The runtime registry declares Claude's paths as
|
|
435
|
-
`~/.claude`, and the adapter resolved them from the homedir — so with the variable set, the core
|
|
436
|
-
was written to the real `~/.claude` while the hook was registered in the overridden dir. A
|
|
437
|
-
scratch or CI install silently wrote into the user's actual global core. `resolvePaths` now
|
|
438
|
-
takes a re-rooting override, and the test asserts the core, the commands and the hook all land
|
|
439
|
-
in the override with nothing written to the home default.
|
|
440
|
-
|
|
441
|
-
- **The dashboard reported a healthy non-Claude install as broken.** Every path it checked was
|
|
442
|
-
`.claude/…`, so a repo driven from Cursor came back "no pipeline core installed", "surface with
|
|
443
|
-
no rendered agent", "artifacts not gitignored", "gate.py not registered" — four findings, all
|
|
444
|
-
false. A false red is worse than no check: it sends someone fixing what is not broken. The
|
|
445
|
-
server now resolves paths from `runtimes.json` (`dashboard/server/runtime.js`), reads the gate
|
|
446
|
-
registration in each runtime's own envelope, names artifacts against the right state dir, reads
|
|
447
|
-
the metrics sink from every state dir in play, skips workflows where there is no engine instead
|
|
448
|
-
of reporting them missing, and the reset action backs up every runtime's directory rather than
|
|
449
|
-
leaving the others behind for the fresh install to land beside.
|
|
450
|
-
|
|
451
|
-
- **`SCHEMA.md` is the agents' rulebook, read at run time — and it still hardcoded `.claude`.**
|
|
452
|
-
It ships to `<core>/pipeline/`, so on a non-Claude install it was telling agents to write
|
|
453
|
-
rendered agents and read the gate config in a directory that runtime never looks at. It and
|
|
454
|
-
`PIPELINE.template.md` now use the same `<core>`/`<state>`/`<agents>`/`<config>` tokens as the
|
|
455
|
-
commands, and the installer resolves their capability conditionals like any other prompt.
|
|
456
|
-
|
|
457
|
-
- **The preflight stamp could green code that had changed.** Both sides of the content digest seed
|
|
458
|
-
a throwaway git index from the real one, for its stat cache — but the copy is stamped `now`, and
|
|
459
|
-
git trusts an entry's cached stat data whenever the entry predates the index file. A file edited
|
|
460
|
-
in the same second as the preflight, at an unchanged size, therefore read as clean: the gate let
|
|
461
|
-
a `review` dispatch through onto code the preflight never verified. Both `gate.py` and
|
|
462
|
-
`preflight.sh` now backdate the copy by 5 s, which forces a content check for anything touched
|
|
463
|
-
inside that window and leaves the fast path intact for every older file.
|
|
464
|
-
|
|
465
|
-
## 2.1.0 — 2026-08-09
|
|
466
|
-
|
|
467
|
-
- **A repo that gates merges on a per-feature release note shipped red PRs, and the flow reported
|
|
468
|
-
success.** Changesets' `changeset` job fails any PR that touches product code without a
|
|
469
|
-
`.changeset/*.md`, but that requirement lives in the project's `CLAUDE.md` — which the ship flow
|
|
470
|
-
never reads. So `/cohorte-ship` committed, pushed, opened the PR and moved the kanban card to
|
|
471
|
-
**Shipped** while the PR was unmergeable, red on a job nobody was watching.
|
|
472
|
-
|
|
473
|
-
The profile gains a `release_notes` block (`enabled`, `tool`, `dir`/`filename`,
|
|
474
|
-
`anchor_package`, `language`, `forbid_levels`, `empty_cmd`, `ci_job`, `guidance` — SCHEMA.md
|
|
475
|
-
§Release notes), and `/cohorte-ship` gains **§2b**: the lead writes the note itself, next to the
|
|
476
|
-
`status: shipped` flip, so it lands *inside* the release commit rather than in a second one after
|
|
477
|
-
the PR is already open. The bump level is project policy, not a git ritual — the release agent is
|
|
478
|
-
now explicitly forbidden from authoring or editing a note, and only stages the one it is handed.
|
|
479
|
-
§4 verifies the note is in the commit; §5 routes a red `ci_job` back to §2b instead of through
|
|
480
|
-
`/cohorte-fix`, which would treat a missing note as a code finding.
|
|
481
|
-
|
|
482
|
-
Two things the block encodes that the tool itself does not: `forbid_levels`, for the `0.x` repo
|
|
483
|
-
where a `major` changeset silently jumps to `1.0.0` with no human deciding it, and the rule to
|
|
484
|
-
**ask** rather than guess between two defensible levels — a wrong bump is a published version
|
|
485
|
-
number, not a fixable draft. `empty_cmd` covers the honest no-op, for a PR that must move no
|
|
486
|
-
version at all.
|
|
487
|
-
|
|
488
|
-
- **Existing projects are asked, not defaulted.** `/cohorte-init-pipeline` detects a versioning tool
|
|
489
|
-
or note-enforcing CI job in Phase 1 and asks the anchor package, language and bump policy in Phase
|
|
490
|
-
2; `/cohorte-update-pipeline` treats `release_notes` as a genuine human decision during reconcile
|
|
491
|
-
rather than topping it up blind. No tool found ⇒ `enabled: false`, and §2b is a silent no-op.
|
|
492
|
-
|
|
493
|
-
## 2.0.2 — 2026-08-08
|
|
494
|
-
|
|
495
|
-
- **Kanban cards stopped moving mid-pipeline, and every stage still reported success.** The
|
|
496
|
-
stages only *described* the move — "move card `#<id>` → Building, no-op silently if no board" —
|
|
497
|
-
without saying where a board is even declared. Each phase runs in its own session after a
|
|
498
|
-
`/clear`, so the cheapest reading consistent with that instruction is "I see no board, so there
|
|
499
|
-
is none": a `/cohorte-ship` run announced "no kanban board configured", having opened neither
|
|
500
|
-
`~/.claude/cohorte.config.yaml` nor `PIPELINE.md`, and a feature that shipped and merged left
|
|
501
|
-
its card sitting in "Ready to build". Silence was indistinguishable from correctness, so this
|
|
502
|
-
went unnoticed across several features.
|
|
503
|
-
|
|
504
|
-
Resolution is not a judgment call, so it is no longer made by a judge. `kanban-move.sh auto <id>
|
|
505
|
-
<stage>` now reads the profile `name`, the config's `kanban.enabled` / `obsidian.vault_path` /
|
|
506
|
-
`boards[name]`, and maps the **stage key** (`ideas` … `shipped`) to that board's heading through
|
|
507
|
-
`boards[name].columns` → `kanban.columns` → a built-in default. Every stage calls exactly that,
|
|
508
|
-
and reports the line it printed: `moved #<id> -> <column>`, or `kanban: <reason>` naming the
|
|
509
|
-
missing link. Both exit 0 and they are not interchangeable. A board that *is* configured but
|
|
510
|
-
unmovable stays loud (exit 2 usage, exit 3 missing board / unknown column). Explicit board paths
|
|
511
|
-
and literal headings still work.
|
|
512
|
-
|
|
513
|
-
`validate-core` now fails any funnel command that moves a card without a literal
|
|
514
|
-
`kanban-move.sh auto …` call, or that omits the instruction not to conclude "no board" without
|
|
515
|
-
running it — the prose-only form is what regressed, so the prose-only form is what is banned.
|
|
516
|
-
New `scripts/test-kanban.mjs` (29 checks) pins the resolution table and the move semantics.
|
|
517
|
-
|
|
518
|
-
- **Renaming a project silently unlinks its board.** `kanban.boards` is keyed by the profile
|
|
519
|
-
`name`, so editing `name:` orphans the old entry and no lookup matches the new one — a genuine
|
|
520
|
-
"not configured", identical from the outside to never having had a board. `/cohorte-doctor`
|
|
521
|
-
gains check **7b**, which reports the resolved board (or the exact missing link) and flags an
|
|
522
|
-
orphaned entry as a rename; `/cohorte-update-pipeline` offers to re-key it instead of creating a
|
|
523
|
-
second board. New `kanban-move.sh --check` does the resolution alone, for both.
|
|
524
|
-
|
|
525
|
-
- **The gate judged `cd <other repo> && git commit` against the wrong checkout.** Branch-conditional
|
|
526
|
-
patterns resolved the branch at the payload cwd, but the tool's shell keeps no cwd between calls,
|
|
527
|
-
so agents write the `cd` into the command itself. A commit on a feature branch in another repo was
|
|
528
|
-
therefore refused as if it were on the default branch — and the refusal named a branch the command
|
|
529
|
-
was never going to run on, so no confirmation could lift it (in an unattended run, where `ask`
|
|
530
|
-
escalates to `deny`, it was a hard wall). The branch is now resolved per segment at the cwd that
|
|
531
|
-
segment actually runs in, cached so the common case is still one `git` call. Deliberately narrow:
|
|
532
|
-
a plain absolute/relative/quoted `cd`, never `cd -`, `$(…)`, variables or globs — anything
|
|
533
|
-
unresolvable keeps the previous cwd, which is the direction that keeps gating. `cd` never softens
|
|
534
|
-
the unconditional `deny`/`ask` tiers; 10 new cases in `test-gate.mjs` pin all of it.
|
|
535
|
-
|
|
536
|
-
- **`/cohorte-brainstorm` tags an Ideas card before moving it.** The join key is the `#<id>` tag,
|
|
537
|
-
and an Ideas card a human typed by hand has none — so the move found nothing, created a second
|
|
538
|
-
card, and stranded the original in Ideas. It now appends the tag first, located by `grep -n`,
|
|
539
|
-
never a full board read.
|
|
540
|
-
|
|
541
|
-
## 2.0.1 — 2026-08-03
|
|
542
|
-
|
|
543
|
-
Three fixes, one failure: an autonomous `/cohorte-loop` run that built 1 surface of 3, stamped
|
|
544
|
-
itself green, and then hung asking a human to approve its own pre-flight. All in `loop.sh` — no
|
|
545
|
-
repo files change, so `npx cohorte@latest update --global` (or `update`) is the whole migration.
|
|
546
|
-
|
|
547
|
-
- **Child sessions now run in `bypassPermissions`, not `acceptEdits`.** `acceptEdits` auto-approves
|
|
548
|
-
Write/Edit and *nothing else*, so the first `Bash` call no `allow` prefix in `settings.json`
|
|
549
|
-
covers raises a permission prompt — and a `claude -p` child has nobody to answer it. It stalls,
|
|
550
|
-
prints prose asking you to approve, and **exits 0**, which the driver scores as a clean phase.
|
|
551
|
-
That is the whole content of one observed run: the review child blocked on invoking
|
|
552
|
-
`preflight.sh` and the loop logged `▶ /cohorte-review … ok`. It is also backwards from what the
|
|
553
|
-
gate is built for — `hooks/gate.py` escalates every `ask` match to a hard **deny** under
|
|
554
|
-
`bypassPermissions` precisely because an unattended run cannot confirm. So the dangerous commands
|
|
555
|
-
from PIPELINE.md `gate` stay blocked deterministically, while typecheck/lint/tests/`git diff` stop
|
|
556
|
-
needing a human. `CLAUDE_FLAGS` still overrides it for a watched run.
|
|
557
|
-
|
|
558
|
-
- **A build phase that reported nothing is no longer treated as a build that found nothing.** The
|
|
559
|
-
driver checked `dead[]` in `specs/reports/<id>.build.json` but accepted the file being **absent** —
|
|
560
|
-
and a phase cut short never reaches the step that writes it, so there was no file to grep and no
|
|
561
|
-
surface to name while the child still exited 0. A 3-surface build that lost 2 of them mid-write
|
|
562
|
-
stamped `<id>.built` and sent reviewers at the result. A missing `build.json` after a build now
|
|
563
|
-
aborts as **exit 2**, naming the cause, and leaves no stamp so a re-run rebuilds.
|
|
564
|
-
|
|
565
|
-
- **`CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0` is exported for every child.** Print mode otherwise
|
|
566
|
-
*terminates* still-running background tasks at its ceiling ("Background tasks still running after
|
|
567
|
-
600s; terminating") — which is 25–40 min short of a real implementer batch, and killed the two
|
|
568
|
-
surfaces above mid-write. The phase is bounded by its own completion (and by the `caffeinate`
|
|
569
|
-
assertion the driver already holds), not by a stopwatch that fires inside the longest phase.
|
|
570
|
-
|
|
571
|
-
`test-loop.mjs` pins all three, including the fixture bug that hid the second one: its `ready`
|
|
572
|
-
build wrote no `build.json` either.
|
|
573
|
-
|
|
574
|
-
## 2.0.0 — 2026-08-03
|
|
575
|
-
|
|
576
|
-
> **Breaking: every command is renamed.** `/build` → `/cohorte-build`, `/review` →
|
|
577
|
-
> `/cohorte-review`, and so on for all 13. The driver, `/loop` → `/drive` in 1.6.0, is now
|
|
578
|
-
> **`/cohorte-loop`**. Re-run `npx cohorte@latest update --global` (or `update`): the update
|
|
579
|
-
> **deletes** the 13 unprefixed command files from your install rather than leaving them as
|
|
580
|
-
> decoys. Nothing inside your repo needs editing — `/build` in a spec or PIPELINE.md is prose,
|
|
581
|
-
> not a call site. Muscle memory is the only migration cost.
|
|
582
|
-
|
|
583
|
-
- **Every command now carries a `cohorte-` prefix, ending command shadowing for good.** A command
|
|
584
|
-
whose name collides with a Claude Code built-in is not overridden, it is **shadowed**: the
|
|
585
|
-
built-in answers the slash, our file is never read, and the session confidently reports on a run
|
|
586
|
-
that never happened. `/loop` did exactly that and went unnoticed until a user found the driver had
|
|
587
|
-
never started; `/doctor` was sitting on a watchlist waiting to do the same. 1.6.0 renamed one
|
|
588
|
-
name; this replaces the whole approach. `validate-core` now enforces the prefix structurally
|
|
589
|
-
instead of maintaining a blocklist that could only ever forbid the collisions we already knew
|
|
590
|
-
about. Telemetry **phase** names (`build`, `review`, `fix`, …) stay unprefixed — they are a wire
|
|
591
|
-
contract with the collector, and the retired bare command names are kept in the metrics
|
|
592
|
-
collector's retired list so months of existing transcripts stay attributed instead of silently
|
|
593
|
-
reclassifying to `(chat)`.
|
|
594
|
-
|
|
595
|
-
- **`/cohorte-loop` can now run for hours.** It previously ran the driver as one foreground Bash
|
|
596
|
-
call, which cannot work: a single call is capped at **600 s** and a build is 25–40 min, so it was
|
|
597
|
-
killed mid-`/cohorte-build`. Backgrounding it was worse — a backgrounded Bash call is **not
|
|
598
|
-
detached**, so the driver stayed in the calling session's process group and every Claude Code
|
|
599
|
-
restart, crash or laptop sleep took `loop.sh` and its `claude -p` children down with it, mid-write.
|
|
600
|
-
Observed on a real run: four teardowns in 45 minutes, each aborting both surface implementers and
|
|
601
|
-
leaving a half-built tree that read as `dead`. New `loop-detach.sh` puts the driver in its own
|
|
602
|
-
`screen` session so it outlives the launching process entirely, and `/cohorte-loop` polls a small
|
|
603
|
-
status file in ~9-minute waits. The driver's exit code — which the report table is keyed on —
|
|
604
|
-
survives as `__EXIT__ <code>` in that file.
|
|
605
|
-
|
|
606
|
-
- **`loop.sh` holds the machine awake for its whole run.** It re-execs itself under
|
|
607
|
-
`caffeinate -ims` on macOS, `systemd-inhibit` on Linux, because system sleep aborts every
|
|
608
|
-
in-flight `claude -p` request and the abort is byte-identical to "the agent returned nothing" —
|
|
609
|
-
the `dead` family the driver exists to catch. The inhibitor is **probed before the `exec`**, since
|
|
610
|
-
`exec` replaces the shell: one that exists but is refused (`systemd-inhibit` answers `Failed to
|
|
611
|
-
inhibit: Access denied` in a container, in CI, or in any seatless session) would otherwise make its
|
|
612
|
-
own failure the driver's exit code and the run would never start — GitHub's Linux runners turned
|
|
613
|
-
all 24 loop tests red exactly that way. Absent or refused both fall through to a no-op; an unheld
|
|
614
|
-
power assertion is a degraded run, not a failed one, and `test-loop.mjs` now pins both directions.
|
|
615
|
-
**This cannot prevent lid-close sleep** — no userspace assertion can on any platform; keep the
|
|
616
|
-
lid open or use clamshell mode.
|
|
617
|
-
|
|
618
|
-
- **Platform tiers, stated rather than assumed.** Detaching uses `screen` (macOS + Linux), else
|
|
619
|
-
`setsid` (Linux) — both escape the caller's process group, which is what actually matters. Git
|
|
620
|
-
Bash on Windows has neither, so it falls back to `nohup`, which ignores `SIGHUP` but does **not**
|
|
621
|
-
survive a teardown; `loop-detach.sh` prints that warning rather than degrading silently, and
|
|
622
|
-
points at running `loop.sh` from your own terminal instead. See the platform table in
|
|
623
|
-
`docs/reference/scripts.md`.
|
|
624
|
-
|
|
625
|
-
- **Fixed — the preflight stamp is keyed on the code, not on HEAD, and is never versioned.** The
|
|
626
|
-
stamp recorded the HEAD sha, which is the wrong key in both directions: the reviewed tree is
|
|
627
|
-
normally *dirty*, so committing the very code the preflight verified made the gate ask on a clean
|
|
628
|
-
tree, while an implementer editing files between preflight and dispatch invalidated nothing. Worse,
|
|
629
|
-
`.claude/preflight.ok` was never gitignored — once a release agent staged `.claude/`, the stamp
|
|
630
|
-
went into git describing the tree *before* its own commit, so it could never match again: every
|
|
631
|
-
review dispatch in that repo asked "HEAD moved" forever, and every new clone or worktree inherited
|
|
632
|
-
a green it never earned. The stamp is now `<epoch> <sha> <tree digest>`, where the digest is the
|
|
633
|
-
git tree id of the working tree (`.claude` and `specs` excluded, so the pipeline's own report,
|
|
634
|
-
metrics and DoD writes don't invalidate it), computed in a throwaway index that never touches
|
|
635
|
-
yours. Pre-2.0.0 two-field stamps still fall back to the HEAD comparison. `/cohorte-doctor` check 3
|
|
636
|
-
now fails hard on a tracked stamp, `/cohorte-update-pipeline` untracks it and fixes `.gitignore`
|
|
637
|
-
(§Reconcile step 8), and `test-gate.mjs` pins all of it — including "commit the verified code ⇒
|
|
638
|
-
still green" and "one edit ⇒ red".
|
|
639
|
-
|
|
640
|
-
- **`/cohorte-review` and `/cohorte-fix` now spell out the metrics path instead of delegating it.**
|
|
641
|
-
Both said "append a line to `pipeline-metrics.jsonl`" and pointed at `/cohorte-build` §4 for where
|
|
642
|
-
that file lives — a lead running from a feature worktree resolves the bare name against its own
|
|
643
|
-
cwd and strands the batch in a sink that dies at teardown. Both now carry the resolved
|
|
644
|
-
`$(dirname "$(git rev-parse --git-common-dir)")` form inline.
|
|
645
|
-
|
|
646
|
-
- **Fixed — the dashboard's command allowlist had drifted from its own error message.** The
|
|
647
|
-
server accepted the bare `/audit`/`/init-pipeline`/`/update-pipeline` while the UI sent (and the
|
|
648
|
-
error text advertised) the prefixed names, so the run button would have 400'd on the only
|
|
649
|
-
commands that exist. The test suite checked *rejection* only, which is why it passed; it now pins
|
|
650
|
-
both directions.
|
|
651
|
-
|
|
652
|
-
## 1.6.0 — 2026-08-01
|
|
653
|
-
|
|
654
|
-
> **Re-run `npx cohorte@latest update --global` (or `update`)** to pick up the readiness gate, the
|
|
655
|
-
> deferred-findings route, the resumable driver and the decision journal — the update *deletes* the
|
|
656
|
-
> shadowed `/loop` command and the long-dead `/cycle` from your install, it does not just stop
|
|
657
|
-
> shipping them. Existing specs keep working: the new front-matter fields are written on demand, and a
|
|
658
|
-
> spec without them simply isn't resumable yet. **`/loop <id>` is now `/drive <id>`.**
|
|
659
|
-
|
|
660
|
-
- **New — the readiness gate between `/spec` and `/build`.** `/build` §1.6 now scores the frozen spec
|
|
661
|
-
on **implementability** before authoring the contract and before dispatching anything: contract
|
|
662
|
-
shapes complete · every area owned by a surface · named dependencies actually exist · no ambiguity a
|
|
663
|
-
surface would have to guess at · design links present. The verdict goes to
|
|
664
|
-
`specs/reports/<id>.readiness.json` (`READY` · `RESERVATIONS` · `NOT-READY` + `gaps[]`).
|
|
665
|
-
**`NOT-READY` stops the build with zero agents spawned** — a spec that can't be built doesn't get
|
|
666
|
-
cheaper by being built on N surfaces in parallel — and sends you to `/spec`. `RESERVATIONS` never
|
|
667
|
-
blocks: each gap is inlined into the affected surface's dispatch as an assumption the implementer
|
|
668
|
-
applies *and* flags in its handoff. It costs **no extra agent**: the lead already holds the spec,
|
|
669
|
-
the profile and the reconciled surface list.
|
|
670
|
-
- **New — deferred findings: `/review` stops throwing away what isn't blocking.** The review agent
|
|
671
|
-
now returns a separate `## Deferred` section (max 10) for what is real but **out of this feature's
|
|
672
|
-
scope** — pre-existing code the diff never touched, adjacent debt the spec never claims to fix —
|
|
673
|
-
each line carrying its own out-of-scope reason. Deferred items count in no severity row, move no
|
|
674
|
-
verdict, are never cross-checked, and on **every** verdict get routed into
|
|
675
|
-
`specs/refactor-backlog.md` under the owning surface's `## <domain>` heading, tagged
|
|
676
|
-
`deferred:<id>`. So `/review` feeds `/refactor` for free instead of dropping everything
|
|
677
|
-
non-blocking on the floor. Never into `## Remediation`, which is what `/fix` re-dispatches. Not
|
|
678
|
-
deferrable, ever: anything the diff touched, any spec violation, any security issue on a path this
|
|
679
|
-
feature adds or calls. `/audit` now **carries open `deferred:` items over** when it rewrites the
|
|
680
|
-
backlog. The verdict JSON gains `deferred: <n>` (informational, outside `blocking`).
|
|
681
|
-
- **BREAKING — `/loop` is renamed `/drive`, because Claude Code shadowed it.** Claude Code ships its
|
|
682
|
-
own built-in `/loop` (run a prompt on a recurring interval), which won the name: typing
|
|
683
|
-
`/loop <id>` started the *interval runner* with the feature id as its prompt, so cohorte's driver
|
|
684
|
-
never ran — and the session, having never seen `loop.md`, reported a loop that did not exist. Same
|
|
685
|
-
command, same flags, same script (`pipeline/scripts/loop.sh` keeps its name — nothing about your
|
|
686
|
-
install paths changes): type **`/drive <id>`**. The update scrubs the old `commands/loop.md`, so a
|
|
687
|
-
stale shadowed copy can't linger.
|
|
688
|
-
- **`/drive` is resumable — the spec's status is the state machine.** The lifecycle is now
|
|
689
|
-
`draft → frozen → in-progress → in-review → shipped` plus `blocked`. Before every phase the driver
|
|
690
|
-
stamps `status: in-progress` + `loop_pass` + `loop_phase` into the spec's front-matter — plain
|
|
691
|
-
`awk`, a temp file and `mv`, **zero tokens** — and on exit a terminal `in-review` (clean) or
|
|
692
|
-
`blocked`. **`/drive <id> --resume`** then continues at the pass it reached instead of re-paying the
|
|
693
|
-
ones already made, whether the session died, the ceiling hit, or the fix stopped converging.
|
|
694
|
-
`--max` stays a ceiling on the *total* passes. New **exit 4** (`not implementable`) relays the
|
|
695
|
-
readiness gate's `NOT-READY`: the one loop outcome more passes cannot fix. The dashboard's specs
|
|
696
|
-
board gains In-progress and Blocked columns and shows `↻ pass 3 · /review` on the card; `/doctor`
|
|
697
|
-
names any spec left mid-loop.
|
|
698
|
-
- **Fixed — a dead subagent no longer reads as a clean one on the conversational path.** The
|
|
699
|
-
"a dead agent is never a clean result" doctrine existed since 1.3.4 — but only inside the
|
|
700
|
-
**workflows**. `/build`, `/review` and `/fix` had nothing: a subagent that dies (rate limit,
|
|
701
|
-
transport error, exhausted context) returns *nothing*, and nothing was indistinguishable from
|
|
702
|
-
"finished, nothing to report". Concretely, a dead **reviewer** produced zero findings ⇒
|
|
703
|
-
`blocking: 0` ⇒ verdict `SHIP` ⇒ `/drive` exit 0 ⇒ the human sent to `/ship` — a clean bill of
|
|
704
|
-
health on code no agent ever read. Now every fan-out phase does a **roll call** before integrating:
|
|
705
|
-
a silent surface is retried **once** alone (byte-identical prompt, so recovery costs one agent, not
|
|
706
|
-
a rebuild), then `/build` marks it `dead` and verifies the tree with that surface's own quiet
|
|
707
|
-
commands instead of speaking for the agent, `/review` lists it in the verdict's new `unreviewed[]`
|
|
708
|
-
and **refuses to score `SHIP`**, and `/fix` leaves every one of its items `- [ ]` (a dead agent
|
|
709
|
-
never ticks a box). `/build` also writes `specs/reports/<id>.build.json` with `dead[]`, and
|
|
710
|
-
`loop.sh` aborts on either signal with **exit 2** *before* reading `blocking` — because a dead
|
|
711
|
-
reviewer makes `blocking == 0` a statement about unread code. `unreviewed` is deliberately kept
|
|
712
|
-
out of `blocking`: faking a count there would corrupt the one field the driver contract rests on.
|
|
713
|
-
The metrics line is now written even when a surface died (`"<key>":"dead"`) — an incomplete batch
|
|
714
|
-
is exactly the batch worth recording.
|
|
715
|
-
- **Fixed — `/cycle` and its workflow were removed in 1.4.0 but no installer ever scrubbed them.**
|
|
716
|
-
Every install since has kept `commands/cycle.md` + `workflows/cycle.js` on disk, so a dead command
|
|
717
|
-
stayed listed and invokable — dispatching a workflow whose phases 1.5.0 then deleted. All three
|
|
718
|
-
installers now remove them (as they already did for `/smoke`), and CI **plants the orphans before
|
|
719
|
-
re-installing** instead of asserting their absence on a fresh scratch home, which is exactly the
|
|
720
|
-
blind spot that let this survive four releases.
|
|
721
|
-
- **Reconcile now tops up `specs/_template.md`.** It was seeded once at install and never refreshed,
|
|
722
|
-
so every repo kept the front-matter its core shipped with. `/update-pipeline` adds the missing
|
|
723
|
-
front-matter fields (never the body — the section list is yours).
|
|
724
|
-
- **New — `specs/_decisions.md`, the transverse decision journal.** `PIPELINE.md` is a *stack* profile;
|
|
725
|
-
it says nothing about what the project has **decided**, so every `/spec` re-discovered or
|
|
726
|
-
contradicted the same choices. The journal is deliberately tiny: **append-only, one line per
|
|
727
|
-
decision** (`- <date> · <area> · <decision> — because <reason> · <feature_id>`), reversal by a
|
|
728
|
-
superseding line rather than an edit. Written by `/spec` at freeze (typically 0–3 lines; zero is
|
|
729
|
-
normal) and by `/build` when it adds or splits a surface. Read by the **deciding** stages only —
|
|
730
|
-
`/brainstorm`, `/spec`, `/audit`. **Implementers and reviewers never load it:** they have the frozen
|
|
731
|
-
contract, and shipping them the rationale would cost `surfaces × dispatches` tokens per feature for
|
|
732
|
-
a fact they can't act on. That exclusion is what keeps it cheap enough to be worth having. The `_`
|
|
733
|
-
prefix means `/doctor`, the dashboard scanner and the kanban backfill already skip it.
|
|
734
|
-
|
|
735
|
-
## 1.5.0 — 2026-08-01
|
|
736
|
-
|
|
737
|
-
> **Re-run `npx cohorte@latest update --global` (or `update`)** to pick up the collector and the
|
|
738
|
-
> `/smoke` removal — the update *deletes* the command and its agent from your install, it does not
|
|
739
|
-
> just stop shipping them. The new dashboard panel comes with `npx cohorte dashboard`.
|
|
740
|
-
|
|
741
|
-
- **New — `/loop <id>`: the review ⇄ fix cycle, run for you.** _(renamed `/drive` in 1.6.0 — see
|
|
742
|
-
there.)_ `/build` → `/review` → `/fix` →
|
|
743
|
-
`/review` … until a review reports **zero blocking findings** (a CRITICAL or a security issue —
|
|
744
|
-
a LOW nit never costs a pass), or the pass ceiling (`--max=N`, default 5), or two consecutive
|
|
745
|
-
reviews returning the *same* blocking findings, which means the fix is treading water and more
|
|
746
|
-
passes won't help. `--no-build` re-runs the loop on an already-built feature; `--rebuild` forces
|
|
747
|
-
a build. Every fix pass is committed (`loop(<id>): fix pass <i>`) — your way back after N
|
|
748
|
-
autonomous passes — and **no fix runs on the last pass**, since fixing without a review behind
|
|
749
|
-
it leaves unaudited code. Exit codes distinguish clean · ceiling · no verdict · non-convergent ·
|
|
750
|
-
usage, so a wrapper can tell "needs more passes" from "needs a human".
|
|
751
|
-
- **The loop does not run in your session — that's the whole design.** Each phase is a separate
|
|
752
|
-
`claude -p` child with its own fresh context, driven by the new shipped `loop.sh`; all child
|
|
753
|
-
output goes to `specs/reports/<id>.loop.log`, which the command is forbidden to read back. Your
|
|
754
|
-
session sees one line per phase and a three-line summary. A slash command cannot `/clear` itself,
|
|
755
|
-
so a conversational loop would pile the diff plus N review reports plus N contracts into a
|
|
756
|
-
history re-sent at input price every turn — it would cost more than the loop saves.
|
|
757
|
-
`disable-model-invocation: true`: an autonomous loop only ever starts because you asked.
|
|
758
|
-
- **`/review` now writes a machine-readable verdict** to `specs/reports/<id>.verdict.json` on every
|
|
759
|
-
run — verdict, finding counts by severity, per-surface breakdown, the normalized blocking items
|
|
760
|
-
and a stable `fingerprint` over them. It is the only contract between the pipeline and any
|
|
761
|
-
driver; no prose is parsed. `blocking` restates the reviewer's existing rule as a number
|
|
762
|
-
(CRITICAL + security, deduplicated), so `blocking == 0` ⟺ `SHIP`. The fingerprint hashes
|
|
763
|
-
*surface + file + problem* with the line number deliberately dropped — a fix that inserts lines
|
|
764
|
-
would otherwise change it every pass and the drift detection would never fire. A red preflight
|
|
765
|
-
writes a degraded `{"aborted":"preflight"}` verdict rather than nothing, so an abort is a
|
|
766
|
-
diagnosis instead of a silence.
|
|
767
|
-
- **BREAKING — `/smoke` and the `smoke` agent are removed.** The end-to-end run phase is gone:
|
|
768
|
-
the command, the agent, its preflight wiring, its telemetry phase and its documentation. The
|
|
769
|
-
loop is now `/brainstorm` → `/spec` → `/build` → `/review` → (`/fix` → `/review`)* → `/ship`,
|
|
770
|
-
with `/clear` safe between each. Nothing else depended on it; a `/smoke` in an old habit will
|
|
771
|
-
report an unknown command.
|
|
772
|
-
- **Nothing in the pipeline runs your app any more — that part is yours.** `/build` now closes by
|
|
773
|
-
telling you to exercise the feature by hand if it's worth it, and `/fix` says the same for
|
|
774
|
-
runtime failures. `/review` follows suit at the SHIP verdict: it ticks only what a stage
|
|
775
|
-
actually verified, and **leaves any DoD criterion that needs the app up open** (runtime flows,
|
|
776
|
-
a visual check against the design) unless you say you exercised it yourself and it held.
|
|
777
|
-
- **The preflight phase gate now gates `review` alone** (`gate.preflight.agents` defaults to
|
|
778
|
-
`[review]`). Existing profiles that list `smoke` keep working — the hook just never sees that
|
|
779
|
-
dispatch. `/doctor` compares against the new default, so re-run it after the update if it
|
|
780
|
-
flags gate drift.
|
|
781
|
-
- **Retired-phase data still renders.** Metrics files and dashboards carrying `phase: "smoke"`
|
|
782
|
-
keep their column, the transcript collector keeps attributing past `/smoke` runs to `/smoke`
|
|
783
|
-
instead of silently reclassifying them, and `telemetry-send.sh` still accepts the phase from a
|
|
784
|
-
stale install. Same treatment `/cycle` got in 1.4.0.
|
|
785
|
-
- **The cockpit now shows what a feature actually cost.** The dashboard's only metrics source
|
|
786
|
-
was `pipeline-metrics.jsonl`, written by the model itself — so it misses any run that ended
|
|
787
|
-
early and can never report tokens. On a real project it had captured 18 phase batches where
|
|
788
|
-
the transcripts hold 53 runs. The new **Cost & runtime** panel reads
|
|
789
|
-
`cohorte metrics` instead: per command, the number of runs, $ per run, $ total, tokens, wall
|
|
790
|
-
and active time, and the median number of subagents dispatched. That last column is the one
|
|
791
|
-
that makes a broken run obvious — a `/build` reporting 0 agents did no fan-out at all.
|
|
792
|
-
- **Both metrics sources are kept, because they answer different questions.** `pipeline-metrics.jsonl`
|
|
793
|
-
carries per-surface verdicts (`ok`, `REVISE:2`, `error`) that only the model knows and the
|
|
794
|
-
transcripts never contain; the collector carries money and time, which the model cannot report
|
|
795
|
-
and the transcripts record exactly. The two panels sit side by side and each says what it is
|
|
796
|
-
for. Neither replaces the other.
|
|
797
|
-
- **Fixed: discussing a command counted as running it.** An inline command mention was treated
|
|
798
|
-
as an invocation regardless of context, so a long message *about* `/review` billed that whole
|
|
799
|
-
conversation to `/review` — in cohorte's own repo it invented five `/cycle` runs out of a
|
|
800
|
-
design discussion. Inline mentions are now length-gated (an instruction is short; a discussion
|
|
801
|
-
is not); an explicit slash-command invocation is always counted.
|
|
802
|
-
|
|
803
|
-
## 1.4.0 — 2026-08-01
|
|
804
|
-
|
|
805
|
-
> **Re-run `npx cohorte@latest update --global` (or `update`)** — the workflow fixes only apply
|
|
806
|
-
> once the installed core is refreshed. Both the workflow scripts and the `profile-reader` agent
|
|
807
|
-
> are replaced by the update.
|
|
808
|
-
|
|
809
|
-
- **BREAKING — `/cycle` and `cycle.js` are removed.** The full-cycle workflow is gone: the command
|
|
810
|
-
file, the script, its tests and its documentation. The conversational path it wrapped is
|
|
811
|
-
unchanged and remains the way to run a feature — `/build` → `/smoke` → `/review` → `/fix` →
|
|
812
|
-
`/ship`, with `/clear` safe between each. `review.js`, `audit.js` and `refactor.js` are
|
|
813
|
-
untouched. Nothing else in the pipeline depended on it; a `/cycle` in an old habit will simply
|
|
814
|
-
report an unknown command. Metrics files and dashboards that already carry `phase: "cycle"`
|
|
815
|
-
lines keep rendering them.
|
|
816
|
-
- **A workflow could dispatch zero agents and still report a verdict.** Phase 0's `profile-reader`
|
|
817
|
-
(haiku) intermittently returned the profile as a JSON *string* nested under a wrapper field
|
|
818
|
-
(`{"output": "{\"surfaces\": …}"}`) instead of at the top level. The schema was
|
|
819
|
-
`{type: 'object', additionalProperties: true}` — no declared properties, no required keys — so
|
|
820
|
-
the wrapper validated cleanly and every field then read as `undefined`: `surfaces` fell back to
|
|
821
|
-
`[]`, `parallel([])` dispatched **nothing**, and because every later guard compares against
|
|
822
|
-
`surfaces`, an empty list made them all vacuously pass. The run finished with a verdict, no code
|
|
823
|
-
written, and no complaint — indistinguishable from a clean run with an empty diff. Fixed in three
|
|
824
|
-
places: `profile-reader.md` now states that the profile's keys go at the top level of the
|
|
825
|
-
structured-output tool (with the wrong shapes shown), the schema declares what it expects, and a
|
|
826
|
-
profile with no surfaces **aborts loudly** instead of proceeding. All three workflows.
|
|
827
|
-
- **`args` given as a JSON string became the feature id.** A caller that JSON-encoded its arguments
|
|
828
|
-
got that whole blob used as the id — which is how a report was written to
|
|
829
|
-
`specs/reports/{"feature": "x"}.md` — and the other options (`maxRounds`, `smoke`) silently read
|
|
830
|
-
as `undefined` on the same run, so a run could skip smoke without saying so. `args` is now parsed
|
|
831
|
-
back into an object (a bare slug is still valid shorthand), and a feature id that is not a slug
|
|
832
|
-
throws with an actionable message **before** anything touches the filesystem — so no junk file
|
|
833
|
-
can be written, and a path-shaped id is rejected.
|
|
834
|
-
- **`/doctor` warned about a file cohorte itself had written.** `/audit` writes
|
|
835
|
-
`specs/refactor-backlog.md` by design; the spec scanner globbed `specs/*.md` and flagged it for
|
|
836
|
-
having no valid front-matter `status`. It fired in every project that had ever run `/audit`. Both
|
|
837
|
-
the conversational `/doctor` and the dashboard port now exclude it.
|
|
838
|
-
- **New: `cohorte metrics` — real cost and runtime per command.** Reconstructs tokens, USD,
|
|
839
|
-
wall/active time and subagent counts from Claude Code's own transcripts, so it needs nothing
|
|
840
|
-
enabled and works retroactively on runs that already happened. It is worktree-aware (a feature
|
|
841
|
-
built across worktrees adds up instead of being dropped), attributes subagent spend back to the
|
|
842
|
-
command that spawned it, and de-duplicates the repeated `usage` blocks a single API response
|
|
843
|
-
writes across several transcript lines — summing those naively inflates tokens ~1.8×.
|
|
844
|
-
`--json`, `--runs`, `--days=N`, `--since=ISO`. Prices live in `scripts/metrics/prices.json`.
|
|
845
|
-
|
|
846
|
-
## 1.3.4 — 2026-07-31
|
|
847
|
-
|
|
848
|
-
> **Re-run `npx cohorte@latest update --global` (or `update`)** — the workflow and script
|
|
849
|
-
> fixes only apply once the installed core is refreshed.
|
|
850
|
-
|
|
851
|
-
- **The dashboard server now has tests.** `dashboard/server/*.js` is shipped runtime code — a
|
|
852
|
-
hand-rolled YAML parser every `/doctor` check derives from, the metrics aggregator, the JS port
|
|
853
|
-
of `/doctor`, the board parser, the fleet registry, and the HTTP guards — with no coverage at
|
|
854
|
-
all. `scripts/test-dashboard.mjs` (83 assertions, in CI) pins each module, including every
|
|
855
|
-
`/doctor` check both green and deliberately broken.
|
|
856
|
-
- **The gate hook now has tests.** `hooks/gate.py` is the one component that can block a command,
|
|
857
|
-
and CI only ever checked that it *parsed* — every one of its shipped regressions reached users
|
|
858
|
-
first. `scripts/test-gate.mjs` drives its real stdin→stdout contract (42 assertions: deny/ask
|
|
859
|
-
tiers, chained-command splitting, branch-conditional gating at the payload's cwd, the
|
|
860
|
-
`bypassPermissions` ask⇒deny escalation, config robustness, the preflight phase gate, worktree
|
|
861
|
-
HEAD matching) and runs in CI. No new defect was found in the gate itself — the behaviour is
|
|
862
|
-
now pinned.
|
|
863
|
-
- **A crashed reviewer scored as a clean surface.** `agent()` returns `null` when a subagent dies,
|
|
864
|
-
and a dead reviewer returns zero findings — byte-identical to a surface with nothing wrong. Both
|
|
865
|
-
`review.js` and `cycle.js` read that as `SHIP`: the review workflow answered "`/ship`" when
|
|
866
|
-
*every* reviewer had crashed, and the cycle workflow exited **SHIP-READY**, ticked the DoD and
|
|
867
|
-
stamped the freshness gate over code nobody had read. Unreviewed surfaces are now named in
|
|
868
|
-
`unreviewedSurfaces` + `questions`, can never score `SHIP`, and the cycle re-reviews instead of
|
|
869
|
-
dispatching an empty fix round. `scripts/test-workflows.mjs` (new, run in CI) pins this.
|
|
870
|
-
- **Swept the whole "dead agent read as success" family across all four workflows** — the same
|
|
871
|
-
root cause as the two above, found at eight more call sites by auditing every `agent()` result
|
|
872
|
-
in `cycle.js` · `review.js` · `audit.js` · `refactor.js`. The worst: a dead **diff-staging**
|
|
873
|
-
agent in `review.js` returned `verdict: SHIP` ("no diff — nothing to review") for a feature
|
|
874
|
-
nobody had looked at; and a dead **close/staging** agent let both `/cycle` and the review
|
|
875
|
-
workflow report `SHIP-READY` + a report path + "ship is a straight shot" when the report, the
|
|
876
|
-
DoD ticks, the freshness stamp and the metrics had never been written (and `/ship`'s freshness
|
|
877
|
-
gate skips silently when those fields are absent, so the human would have shipped on it). Also:
|
|
878
|
-
a dead auditor made a domain look **clean** instead of unaudited; a dead backlog writer/reader
|
|
879
|
-
and a dead item-ticker were each reported as success. Every one of these now distinguishes
|
|
880
|
-
"died" from "succeeded with nothing to say", and `scripts/test-workflows.mjs` pins all of them.
|
|
881
|
-
- **A dead contract agent was reported as a successful re-authoring.** Same failure shape as the
|
|
882
|
-
crashed reviewer: when the lead-equivalent agent that re-authors spec §5 + the contract file
|
|
883
|
-
died, `/cycle` still pushed a `contractChanges` entry and handed **every** consuming surface a
|
|
884
|
-
CRITICAL "the contract was RE-AUTHORED — re-read it and realign" item, pointing at a file
|
|
885
|
-
nobody had touched. It now reports the contract as UNCHANGED and ripples nothing.
|
|
886
|
-
- **A red preflight nobody owns burned every remaining round.** When no surface path appeared in
|
|
887
|
-
the failure tail and no implementer had survived the build, the fix round dispatched *zero*
|
|
888
|
-
agents, the next round found the same red gates, and the loop spun to the cap doing literally
|
|
889
|
-
nothing before reporting a stale verdict. It now stops immediately with the failure tail.
|
|
890
|
-
- **Findings belonging to no surface were dropped silently.** A finding whose file sits outside
|
|
891
|
-
every surface tree — reachable when the diff-staging agent names a key the profile lacks —
|
|
892
|
-
stayed in the open set (so the loop could never exit clean) while nobody was ever dispatched to
|
|
893
|
-
fix it. They are now named, with their `file:line`, in `questions`.
|
|
894
|
-
- **`/cycle` build telemetry hid dead implementers**: results were mapped over the *survivors*, so
|
|
895
|
-
two of three surfaces reported `ok,ok` and the dead one vanished from the funnel entirely.
|
|
896
|
-
- **The review workflow sent HIGH findings straight to `/ship`.** A `SHIP` verdict can legitimately
|
|
897
|
-
carry HIGH/MEDIUM findings (only CRITICAL and security force a fix), but the conversational
|
|
898
|
-
`/review` routes any surviving HIGH to `/fix` — the workflow said `/ship`. It now only recommends
|
|
899
|
-
shipping when nothing above LOW survived, and stamps the freshness gate on that same condition.
|
|
900
|
-
- **Smoke is now opt-in in the cycle workflow** — `/cycle <id> smoke` (or `args.smoke: true`).
|
|
901
|
-
Booting the app every round is expensive and a library project has nothing to smoke. Without it
|
|
902
|
-
the run reports `smoke: "SKIPPED"`, leaves the runtime-flow DoD boxes unticked, and says so.
|
|
903
|
-
- **The dashboard reset could move the shared global core.** Nothing stopped a project path of
|
|
904
|
-
`~` — reset would then rename `~/.claude` into a backup dir and break every repo on the machine,
|
|
905
|
-
while the UI promised the global core is never touched. It now refuses that path outright.
|
|
906
|
-
- **The cycle workflow polluted the metrics with phantom surfaces.** It wrote `rounds` / `verdict` /
|
|
907
|
-
`smoke` inside the metrics line's `surfaces` map, so the dashboard rendered them as three surface
|
|
908
|
-
rows and scored `rounds: "1"` as a failing surface. Run-level facts now sit outside `surfaces`,
|
|
909
|
-
and the dashboard knows the `cycle` phase.
|
|
910
|
-
- **Telemetry from bundled installs reported no core version.** `telemetry-send.sh` read `VERSION`
|
|
911
|
-
only from the *global* core; it now resolves the core that ships it. Payloads are also hardened —
|
|
912
|
-
a quote or newline in the results string used to produce JSON the collector dropped.
|
|
913
|
-
- **Every kanban card move added a blank line.** Ten moves of one card padded a board with fifteen
|
|
914
|
-
of them, and every phase command moves cards. Runs of blank lines are now collapsed; a board is
|
|
915
|
-
byte-stable across moves. Sub-notes of a duplicate card are no longer duplicated either.
|
|
916
|
-
- **Python bytecode could reach the published package and users' `.claude`.** `.npmignore` is inert
|
|
917
|
-
under an explicit `files` allowlist, so its `__pycache__/` rule never fired, and all three
|
|
918
|
-
installers copied the directory verbatim. Excluded at both ends, asserted in CI.
|
|
919
|
-
- **Every non-design surface agent rendered with a blank first TDD step.** `<SURFACE_TDD_STEP1>`
|
|
920
|
-
sat as numbered item 1 of the TDD list but is filled only for `uses_design` surfaces, so every
|
|
921
|
-
other agent got an empty "1." above its real first step. It is now a lead-in paragraph.
|
|
922
|
-
- Doc/template corrections found by reading the whole core against the code: the spec template's
|
|
923
|
-
`## 6+. Surface tasks` could collide with the `§8`/`§9` sections the pipeline references by
|
|
924
|
-
number; `/init-pipeline` step 04 forgot `smoke.md` in its "leave the fixed agents as-is" list;
|
|
925
|
-
the getting-started page placed `implementer.template.md` in `agents/` (it ships in `pipeline/`);
|
|
926
|
-
the dashboard docs never documented the CSRF/DNS-rebinding guard; `dashboard/README.md` was
|
|
927
|
-
missing `metrics.js`, `/api/metrics` and `/audit`; the two reference-only templates
|
|
928
|
-
(`agent-handoff.md`, `review-feedback.md`) are unreferenced copies of shapes that live in the
|
|
929
|
-
agents — `review-feedback.md` had drifted and is re-synced, and both now say so.
|
|
930
|
-
- Smaller: the dashboard no longer stalls for 13 s per project when npm is unreachable (failed
|
|
931
|
-
lookups are cached and de-duplicated); `--port=` rejects a non-numeric value instead of listening
|
|
932
|
-
on a random port; a missing hashed asset 404s instead of being served `index.html`; a project
|
|
933
|
-
card is now keyboard-activatable; long headless logs are trimmed instead of growing unbounded;
|
|
934
|
-
`install.sh --help` exists; the preflight stamp is written once per distinct directory.
|
|
935
|
-
|
|
936
|
-
## 1.3.3 — 2026-07-30
|
|
937
|
-
|
|
938
|
-
> **Re-run `npx cohorte@latest update --global` (or `update`)** — the gate fixes only apply once
|
|
939
|
-
> the installed `hooks/gate.py` is refreshed.
|
|
940
|
-
|
|
941
|
-
- **The cycle workflow could exit SHIP-READY with open findings.** A round with only HIGH/MEDIUM
|
|
942
|
-
findings scored `SHIP`, broke the loop, ticked the DoD and stamped the freshness gate — making
|
|
943
|
-
`/ship` a straight shot over unfixed findings, against the workflow's own "zero open findings"
|
|
944
|
-
contract. The exit condition is now literally zero open findings + a smoke PASS.
|
|
945
|
-
- **Dead implementers went undetected in the cycle workflow.** `agent()` returns `null` when a
|
|
946
|
-
subagent dies, but the build fan-out wrapped every result in a truthy object before the check —
|
|
947
|
-
so the "implementer(s) died" question never fired and build telemetry always said `ok`.
|
|
948
|
-
- **`gate.py` gated worktree commands as if they ran on the default branch.** Branch and HEAD were
|
|
949
|
-
resolved in `CLAUDE_PROJECT_DIR` (the main checkout, usually on `main`) instead of where the
|
|
950
|
-
command actually runs — so in a feature worktree, every `ask_on_default_branch` pattern
|
|
951
|
-
prompted, and the preflight HEAD-moved check compared against the wrong checkout. Git state now
|
|
952
|
-
resolves at the hook payload's `cwd`.
|
|
953
|
-
- **The preflight phase gate hung headless runs.** The bypassPermissions "nobody can answer an
|
|
954
|
-
ask ⇒ deny" escalation only covered Bash patterns; a review/smoke Task dispatch with a stale
|
|
955
|
-
stamp still emitted an unanswerable `ask`. The phase gate now escalates the same way.
|
|
956
|
-
- **`/init-pipeline` bundled installs registered the gate with the dead `Bash`-only matcher** —
|
|
957
|
-
the exact bug 1.3.2 fixed in the installers lived on in the template — and never dropped an
|
|
958
|
-
existing registration, so a bundled repo later switched to global ran the gate twice per
|
|
959
|
-
command. The template now mandates `Bash|Task` and a reconcile.
|
|
960
|
-
- Smaller cycle-workflow fixes: smoke telemetry reports the real failure count (was always 0 —
|
|
961
|
-
it filtered on a `kind` value that doesn't exist); a run whose last round ends on a red
|
|
962
|
-
preflight now flags that the reported findings are from the previous round; a malformed
|
|
963
|
-
preflight stamp says "unreadable" instead of "not found".
|
|
964
|
-
|
|
965
|
-
## 1.3.2 — 2026-07-30
|
|
966
|
-
|
|
967
|
-
> **Re-run `npx cohorte@latest update --global` (or `update`).** This release repairs the gate
|
|
968
|
-
> hook registration in place — updating is what applies it.
|
|
969
|
-
|
|
970
|
-
- **1.3.0's preflight phase gate never fired on any install.** `gate.py` gates review/smoke
|
|
971
|
-
dispatches on `tool_name == "Task"`, but all three installers registered the hook with
|
|
972
|
-
`matcher: "Bash"` — a Task call never reached it. The `preflight` block in `gate-config.json`
|
|
973
|
-
and `gate.preflight` in `PIPELINE.md` were both dead config. The matcher is now `Bash|Task`.
|
|
974
|
-
- **Re-installing duplicated the hook, every time.** The "already registered?" test was
|
|
975
|
-
`command.endswith("gate.py")`, which is false for the Windows form `py "C:\…\gate.py"` because
|
|
976
|
-
of the trailing quote — so `install.sh` and `bin/cli.js` appended another copy on each run, and
|
|
977
|
-
`gate.py` ran once per copy on every Bash call (four copies seen in the wild). Registration is
|
|
978
|
-
now a **reconcile**: it drops every existing `gate.py` entry and writes exactly one. Idempotent,
|
|
979
|
-
it collapses the duplicates you already have, and it upgrades the stale matcher — an
|
|
980
|
-
append-if-absent would have found the stale entry and skipped, pinning the bug forever.
|
|
981
|
-
Unrelated hooks and every other settings key are untouched.
|
|
982
|
-
- **`npx cohorte update` never touched the hook at all**, so neither fix above could have reached
|
|
983
|
-
you through the command you actually run to get fixes — only a full re-install rewrote it.
|
|
984
|
-
`install.sh` and `install.ps1` always registered on update; this port had drifted (the same
|
|
985
|
-
class of drift as 1.2.4 and 1.2.6). It now registers on both paths.
|
|
986
|
-
- CI installs **twice** before asserting the hook, via a new `scripts/assert-gate-hook.mjs`:
|
|
987
|
-
exactly one registration, matcher covering both Bash and Task. A single install could never
|
|
988
|
-
surface the duplication — which is precisely why CI stayed green while it shipped.
|
|
989
|
-
|
|
990
|
-
## 1.3.1 — 2026-07-30
|
|
991
|
-
|
|
992
|
-
- **`/cycle <feature_id> [max_rounds]`** — a launcher command for the full dev-cycle workflow,
|
|
993
|
-
so you don't have to phrase the request in prose. It resolves `workflows/cycle.js`
|
|
994
|
-
(bundled or global), checks the runtime is available (missing ⇒ it hands you the
|
|
995
|
-
conversational `/build` → `/smoke` → `/review` path instead), sanity-checks the spec is
|
|
996
|
-
frozen, launches the workflow in the background, then relays the verdict: outcome,
|
|
997
|
-
contract re-authorings to eyeball, the `questions` array verbatim, and the next step
|
|
998
|
-
(`/ship` on SHIP-READY, rerun `/cycle` or `/fix` otherwise). Kanban card moves included.
|
|
999
|
-
|
|
1000
|
-
## 1.3.0 — 2026-07-30
|
|
1001
|
-
|
|
1002
|
-
**Token economy — immediate wins, no workflow needed:**
|
|
1003
|
-
|
|
1004
|
-
- **Deterministic pre-flight before `/review` and `/smoke`.** A shipped script
|
|
1005
|
-
(`pipeline/scripts/preflight.sh`) runs typecheck + lint + tests first; red ⇒ the command
|
|
1006
|
-
aborts with the raw last-40 lines and **spawns zero agents** — a reviewer no longer burns
|
|
1007
|
-
its whole run rediscovering what `tsc` printed for free. Green runs stamp
|
|
1008
|
-
`.claude/preflight.ok`, and `gate.py` enforces it as a **phase gate**: a review/smoke
|
|
1009
|
-
dispatch with a missing/stale stamp gets a confirm (`gate.preflight` in the profile).
|
|
1010
|
-
- **Quiet commands.** New profile fields (`test_quiet_cmd`/`lint_quiet_cmd` per surface,
|
|
1011
|
-
`commands.test_quiet`/`lint_quiet` repo-wide) hold the bridled forms agents actually run
|
|
1012
|
-
(`--reporter=dot`, `--quiet`, failures-only); absent ⇒ `<cmd> 2>&1 | tail -40`.
|
|
1013
|
-
`/init-pipeline` now asks for them instead of storing a bare `pnpm test`;
|
|
1014
|
-
`/update-pipeline` tops up older profiles.
|
|
1015
|
-
- **`/review` computes the diff once.** One `git diff --stat`, then full patches staged to
|
|
1016
|
-
disk only for the touched surfaces — reviewers read the artifact instead of each
|
|
1017
|
-
re-running git.
|
|
1018
|
-
- **Conventions baked into rendered agents.** The implementer template gets a
|
|
1019
|
-
`<SURFACE_CONVENTIONS>` slice rendered at init; at runtime agents read only the profile's
|
|
1020
|
-
machine block. Edit conventions in `PIPELINE.md`, then `/update-pipeline` re-renders.
|
|
1021
|
-
- **Capped reports.** Review reports: max 20 findings, one line each, zero code excerpts;
|
|
1022
|
-
smoke returns: max 10 ❌ lines. Dispatch prompts now keep every volatile slot (feature id,
|
|
1023
|
-
paths, file lists) at the END so repeats hit the prompt-cache prefix.
|
|
1024
|
-
- `gate.py` also escalates every `ask` to a hard deny in unattended runs
|
|
1025
|
-
(`bypassPermissions`) — nobody is there to answer a prompt.
|
|
1026
|
-
|
|
1027
|
-
**Workflows (opt-in — conversational commands stay the default and the fallback):**
|
|
1028
|
-
|
|
1029
|
-
- Four deterministic multi-agent scripts for the Claude Code Workflow runtime
|
|
1030
|
-
(≥ 2.1.154, workflows enabled): **`workflows/cycle.js` — the full dev cycle on a frozen
|
|
1031
|
-
spec** (contract → parallel build → smoke ∥ review(+cross-check) → fix, looping until
|
|
1032
|
-
zero findings + PASS; contract changes handled in-loop by a lead-equivalent agent, human
|
|
1033
|
-
decisions returned in a `questions` array at the end; a clean exit ticks the DoD and
|
|
1034
|
-
stamps the freshness gate so `/ship` follows directly), `workflows/review.js` (preflight
|
|
1035
|
-
gate → one reviewer per touched surface → adversarial cross-check of CRITICAL/security
|
|
1036
|
-
findings → verdict only), `workflows/audit.js` (one auditor per domain, concurrent,
|
|
1037
|
-
prioritized backlog), `workflows/refactor.js` (big domains only: shared first, parallel
|
|
1038
|
-
implementers, per-domain verify + one retry). Mechanical phases route to haiku.
|
|
1039
|
-
- New `profile-reader` agent (haiku) — phase 0 of every workflow: returns the
|
|
1040
|
-
`PIPELINE.md` machine block as JSON, since workflow scripts have no filesystem access.
|
|
1041
|
-
- `/doctor` check 8 reports the workflow prerequisites and which path a session will take;
|
|
1042
|
-
the generated `settings.json` allow-list now covers what workflow agents need (quiet
|
|
1043
|
-
commands, shipped scripts, `git rev-parse`, retrieval MCP tools) so runs don't stall on
|
|
1044
|
-
prompts nobody is watching.
|
|
1045
|
-
- Installers (npx CLI, install.sh, install.ps1) ship `core/workflows/` + `preflight.sh` +
|
|
1046
|
-
the `profile-reader` agent in both global and bundled modes; CI dry-runs assert it.
|
|
1047
|
-
- Dashboard: new headless **Audit** action (`claude -p "/audit"` — starts without a prompt,
|
|
1048
|
-
no resume if the session dies) and the workflows state in the project drill-down.
|
|
1049
|
-
|
|
1050
|
-
## 1.2.6 — 2026-07-30
|
|
1051
|
-
|
|
1052
|
-
- **`npx cohorte install` never installed the `smoke` agent.** It copied only `review.md` and
|
|
1053
|
-
`release.md`, so `/smoke` was there but the agent it dispatches was not — the run failed
|
|
1054
|
-
saying `/smoke` is not installed. The shell installers always copied it; only the npm port
|
|
1055
|
-
drifted. It now copies every non-template agent in `core/agents/`, so nothing to keep in sync.
|
|
1056
|
-
Fix an affected install by re-running `npx cohorte install --global` (or `install --repo`).
|
|
1057
|
-
|
|
1058
|
-
## 1.2.5 — 2026-07-29
|
|
1059
|
-
|
|
1060
|
-
- **`.claude/pipeline.json`'s `core_version` never updated on global installs.** The installer
|
|
1061
|
-
bumps it in bundled mode, but a global core is shared — it cannot know which repos point at
|
|
1062
|
-
it, so nothing bumped the field and it drifted forever. Repos running a current core were
|
|
1063
|
-
still claiming `1.0.0`. `/update-pipeline` now syncs the pointer in both modes.
|
|
1064
|
-
- `/doctor` no longer reports that drift as a broken install: a global-mode pointer lagging the
|
|
1065
|
-
VERSION file is ⚠️ with the one-command fix, not ❌. The core was never the problem.
|
|
1066
|
-
|
|
1067
|
-
## 1.2.4 — 2026-07-29
|
|
1068
|
-
|
|
1069
|
-
> **If you installed with `npx cohorte`, this is the release that makes 1.2.3 actually
|
|
1070
|
-
> reach you.** Re-run `npx cohorte@latest update --global` (or `update` for a bundled core).
|
|
1071
|
-
|
|
1072
|
-
- **`npx cohorte install/update` shipped a core missing two scripts.** `bin/cli.js` — the
|
|
1073
|
-
port of `install.sh` that `npx` actually runs — copied only `scripts/*.template`, never
|
|
1074
|
-
`kanban-move.sh` or `telemetry-send.sh`. Since every caller chains them with `|| true`,
|
|
1075
|
-
the result was silent on every npx-installed machine: no kanban card moves, no telemetry
|
|
1076
|
-
pings, no error anywhere. The shell installers named both files explicitly and this port
|
|
1077
|
-
drifted from them. It now copies by a rule that needs no list to keep in sync.
|
|
1078
|
-
- The same port never copied `CHANGELOG.md` into the core either, so `/doctor` and
|
|
1079
|
-
`/update-pipeline`'s "What's new" had nothing to read on npx installs. Fixed.
|
|
1080
|
-
- CI now dry-runs `bin/cli.js` into a scratch dir and asserts the same postconditions as
|
|
1081
|
-
the `install.sh` dry-run. 1.2.3's guard only grepped the two shell installers — it would
|
|
1082
|
-
have passed this bug, because the port copies by rule rather than by name.
|
|
1083
|
-
|
|
1084
|
-
## 1.2.3 — 2026-07-29
|
|
1085
|
-
|
|
1086
|
-
- **Telemetry now covers the whole funnel.** Only `/build` was actually pinging; `/smoke`,
|
|
1087
|
-
`/review` and `/fix` wrote their metrics line but never sent one, so consenting installs
|
|
1088
|
-
reported a quarter of their pipeline. Those three are fixed, and `/brainstorm`, `/spec`
|
|
1089
|
-
(on a landed freeze) and `/ship` join them — the seven stages of `idea → PR` now report,
|
|
1090
|
-
so it's finally possible to see *where* features stall. Setup and maintenance commands
|
|
1091
|
-
(`/doctor`, `/init-pipeline`, `/update-pipeline`, `/audit`, `/refactor`, `/align-ds`)
|
|
1092
|
-
deliberately never ping: the collected set stays inside what the consent text describes.
|
|
1093
|
-
Same data categories as before, same purpose — nothing new about you is sent, so your
|
|
1094
|
-
existing consent stands and nothing re-asks. The full table is in SCHEMA.md §Telemetry.
|
|
1095
|
-
- `telemetry-send.sh` now allowlists the phase name client-side — a typo in a command file
|
|
1096
|
-
used to sail through and land a phantom phase in the dataset.
|
|
1097
|
-
- `/fix` never defined a wall-clock start, so the `seconds` in its metrics line was
|
|
1098
|
-
undefined. It now notes the epoch like `/build` and `/review` do.
|
|
1099
|
-
- **`/doctor` catches a half-copied core.** New check: `pipeline/scripts/` must hold every
|
|
1100
|
-
shipped script, and `VERSION` must not be newer than its siblings. Callers chain these
|
|
1101
|
-
scripts with `|| true`, so a missing one was invisible — no kanban move, no telemetry
|
|
1102
|
-
ping, no error. If you saw either go quiet, this is why: re-run the installer.
|
|
1103
|
-
- CI now fails if an installer forgets to copy a `scripts/*.sh`, and the dry-run install
|
|
1104
|
-
asserts the scripts land executable — the root cause above, caught before release
|
|
1105
|
-
rather than on someone's machine.
|
|
1106
|
-
- The npm tarball no longer ships `scripts/new-feature.sh` + `scripts/remove-feature.sh`
|
|
1107
|
-
— cohorte's *own* rendered isolation scripts, with this repo's ports and paths baked
|
|
1108
|
-
in. They claimed in their header to be excluded but never were (an explicit `files`
|
|
1109
|
-
whitelist wins over `.npmignore`). Only the `*.sh.template` files ship, as intended.
|
|
1110
|
-
- Fixed `validate-core.mjs` crashing on Windows (`C:\C:\…` path), so the guard above
|
|
1111
|
-
actually runs locally too.
|
|
1112
|
-
|
|
1113
|
-
## 1.2.2 — 2026-07-29
|
|
1114
|
-
|
|
1115
|
-
- The reference collector moved to its own (private) deployment repo; the public repo keeps
|
|
1116
|
-
the collector API contract in SCHEMA.md §Telemetry. No behavior change for users.
|
|
1117
|
-
|
|
1118
|
-
## 1.2.1 — 2026-07-29
|
|
1119
|
-
|
|
1120
|
-
- Telemetry collector URL shipped as the config-template default
|
|
1121
|
-
(`https://telemetry.cohorte.thebidouille.fr/v1/events`) — consenting installs start
|
|
1122
|
-
reporting once the collector is live. Still strictly opt-in; nothing changes for anyone
|
|
1123
|
-
who declined (or never answered) the consent question.
|
|
1124
|
-
|
|
1125
|
-
## 1.2.0 — 2026-07-29
|
|
1126
|
-
|
|
1127
|
-
> **Opt-in anonymous telemetry, GDPR-first.** Nothing is sent unless you explicitly say yes.
|
|
1128
|
-
|
|
1129
|
-
- `/init-pipeline` (and `/update-pipeline` on existing installs) ask ONE consent question, once per
|
|
1130
|
-
machine, default **No** — both answers are recorded in `~/.claude/cohorte.config.yaml` §`telemetry`
|
|
1131
|
-
so you're never re-asked.
|
|
1132
|
-
- When enabled, each pipeline phase fires a ~200-byte ping (fire-and-forget, 2s timeout, never
|
|
1133
|
-
blocks): core version, OS, phase, duration, per-surface result counts, and a **hash** of the
|
|
1134
|
-
feature id. Never sent: repo names, paths, code, spec content, IPs.
|
|
1135
|
-
- Withdraw anytime (`telemetry.enabled: false`); erase your history anytime (`/doctor` prints your
|
|
1136
|
-
`install_id`; `DELETE /v1/install/<id>` on the collector drops it). Full spec: SCHEMA.md
|
|
1137
|
-
§Telemetry; privacy summary in the README.
|
|
1138
|
-
- Ships a zero-dependency reference collector (`telemetry/collector.mjs` — NDJSON storage, strict
|
|
1139
|
-
field allowlist, erasure endpoint, stores no IPs) to self-host.
|
|
1140
|
-
- `/doctor` reports telemetry consent state and flags incoherent configs (enabled without a
|
|
1141
|
-
recorded consent).
|
|
1142
|
-
- Note: the shipped default `endpoint` is empty — telemetry stays dormant even for consenting
|
|
1143
|
-
installs until a collector URL ships in the config template.
|
|
1144
|
-
|
|
1145
|
-
## 1.1.1 — 2026-07-29
|
|
1146
|
-
|
|
1147
|
-
- **Fix: pipeline metrics survive worktree teardown.** With `isolation.enabled` the lead session
|
|
1148
|
-
runs inside the feature worktree, so metrics lines landed in the worktree's `.claude/` and were
|
|
1149
|
-
deleted with it — defeating their purpose (cross-feature evidence for surface splits, dashboard
|
|
1150
|
-
history). All phases now append to the **main checkout's** `.claude/pipeline-metrics.jsonl`,
|
|
1151
|
-
resolved from anywhere via `git rev-parse --git-common-dir`; `/doctor` flags a stray metrics file
|
|
1152
|
-
inside a worktree as a stale-core sign.
|
|
1153
|
-
|
|
1154
|
-
## 1.1.0 — 2026-07-29
|
|
1155
|
-
|
|
1156
|
-
> **The token-economy release.** A full audit of the core (40 verified fixes) cuts the pipeline's
|
|
1157
|
-
> consumption by an estimated 40–60% per feature, and the pipeline no longer inherits your session's
|
|
1158
|
-
> model for orchestration. Plus: pipeline metrics in the dashboard, CI on the core, and a documented
|
|
1159
|
-
> parallel-features workflow.
|
|
1160
|
-
|
|
1161
|
-
- **Byte-stable dispatches.** One dispatch template for builds AND fix loops; variable parts
|
|
1162
|
-
(design links, open Remediation items inlined verbatim) sit at the end so repeats hit the prompt
|
|
1163
|
-
cache. The lead never pastes a diff — agents compute their own, scoped to their tree. On fix
|
|
1164
|
-
loops, implementers no longer re-read the spec at all.
|
|
1165
|
-
- **Reviewers read hunks, not whole files.** `/review` stages each surface's diff to
|
|
1166
|
-
`specs/reports/<id>.<key>.diff`; tiny re-reviews skip the dispatch entirely (fast path); the
|
|
1167
|
-
merged report is staged to disk with only a verdict summary printed; LOW-only findings defer to
|
|
1168
|
-
the refactor backlog instead of forcing a fix cycle.
|
|
1169
|
-
- **`/smoke` is now an agent.** A new pinned `smoke` agent runs infra/curl/UI checks so logs,
|
|
1170
|
-
response bodies, and screenshots never enter (and re-bill in) your session's history.
|
|
1171
|
-
- **Model pins everywhere.** The `review` agent and the 10 mechanical commands
|
|
1172
|
-
(build/review/fix/smoke/ship/audit/refactor/doctor/align-ds/update-pipeline) are pinned
|
|
1173
|
-
`model: sonnet` — orchestration runs on Sonnet even if your session runs Opus/Fable. `/doctor`
|
|
1174
|
-
checks agent AND command pins; the profile template's frontend example no longer suggests
|
|
1175
|
-
`inherit`.
|
|
1176
|
-
- **Leaner outputs.** Handoff + review-report formats are inlined in the agent bodies (no template
|
|
1177
|
-
probe), templates de-boilerplated, the design brief is authored once to `specs/design/<id>.md`,
|
|
1178
|
-
metrics collapsed to one JSONL line per phase, and every command's closing now *recommends*
|
|
1179
|
-
`/clear` (all state is on disk by design).
|
|
1180
|
-
- **Pipeline metrics in the dashboard.** New per-project panel: wall-clock per phase, fix rounds,
|
|
1181
|
-
and per-surface results from `.claude/pipeline-metrics.jsonl` — see which phase/surface dominates
|
|
1182
|
-
before tuning anything.
|
|
1183
|
-
- **`kanban-move.sh`.** Card moves (move/create/dedupe/`--pr`) now run as a script outside the
|
|
1184
|
-
agent's context; installed to `<core>/pipeline/scripts/`, with the manual grep-based op as
|
|
1185
|
-
fallback.
|
|
1186
|
-
- **Spec size budget.** `/spec` targets ≤~300 lines and proposes a feature split beyond that —
|
|
1187
|
-
every spec line is paid `surfaces × dispatches` times.
|
|
1188
|
-
- **Parallel features documented.** README: one session per feature, worktree isolation as the
|
|
1189
|
-
safety mechanism, ship-then-rebase rule; `/doctor` prints the live slot table when ≥2 features
|
|
1190
|
-
run in parallel.
|
|
1191
|
-
- **CI on the core.** `scripts/validate-core.mjs` + GitHub Actions: frontmatter/pin invariants,
|
|
1192
|
-
render placeholders, cross-references, installer coverage (would have caught the smoke-agent
|
|
1193
|
-
install gap this release also fixes), plus an end-to-end install dry-run.
|
|
1194
|
-
|
|
1195
|
-
## 1.0.0 — 2026-07-28
|
|
1196
|
-
|
|
1197
|
-
> **Renamed `thebidouille-agents` → `cohorte`** and cut the first stable release. The npm package,
|
|
1198
|
-
> the CLI (`npx cohorte …`), the repo, and the user config file are all renamed. The pre-rename
|
|
1199
|
-
> `~/.claude/thebidouille.config.yaml` and `~/.claude/thebidouille-dashboard.json` are still read as a
|
|
1200
|
-
> fallback, so existing installs keep working — `/update-pipeline` migrates them forward on next run.
|
|
1201
|
-
|
|
1202
|
-
- **Repo moved to the `TheBidouilleAgency` org** (`github.com/TheBidouilleAgency/cohorte`), with a
|
|
1203
|
-
proper logo/brand kit under `assets/` and a dashboard favicon set.
|
|
1204
|
-
|
|
1205
|
-
- **The research + questionnaire capability was removed from the core.** `/research`,
|
|
1206
|
-
`/questionnaire`, their agents, templates and step files are extracted to a separate private repo
|
|
1207
|
-
and will return later as an installable Cohorte **plugin**. `update` scrubs the now-orphaned files
|
|
1208
|
-
from existing installs. The global config keeps only the shared Obsidian vault + the kanban mirror;
|
|
1209
|
-
the `research:`/`questionnaire:` config keys are gone.
|
|
1210
|
-
|
|
1211
|
-
- **`/ship` now reliably moves the kanban card to Shipped and writes the PR number.** The
|
|
1212
|
-
move-to-Shipped was a parenthetical in the command header, easy to skip — so shipped features could
|
|
1213
|
-
leave their card stuck in an earlier column. It is now an explicit, verify-after step (§4): move
|
|
1214
|
-
card `#<id>` → `shipped` **and append `PR #<num>`** (from the PR URL), then re-read the board to
|
|
1215
|
-
confirm. The bare `#<num>` is what the dashboard renders as a clickable PR link. SCHEMA.md §Kanban
|
|
1216
|
-
documents the shipped-card format. (`/ship` also moves the card → `ship` on confirm, in §1.)
|
|
1217
|
-
|
|
1218
|
-
- **Branch-aware gate — git + docker run freely on feature branches, gated only on the default
|
|
1219
|
-
branch.** The `gate` block gains two keys: `ask_on_default_branch` (patterns confirmed *only* when
|
|
1220
|
-
the checked-out branch is `default_branch`) and `default_branch` (default `main`). `gate.py`
|
|
1221
|
-
resolves the current branch at run time (`git rev-parse`); an unknown branch (no repo / detached)
|
|
1222
|
-
is treated conservatively as gated. The default profile moves git (commit/push/merge/rebase/reset)
|
|
1223
|
-
and `docker compose` into this tier, so agents move fast on feature branches while `main` stays
|
|
1224
|
-
protected; DB commands (`migration:run`, `db:`, `psql`) remain always-`ask`, destructive migrations
|
|
1225
|
-
always-`deny`. Existing gate-configs without the new keys keep working unchanged. Re-run
|
|
1226
|
-
`/update-pipeline` to regenerate `gate-config.json` with the new tier.
|
|
1227
|
-
|
|
1228
|
-
- **New `dashboard` subcommand — a local web cockpit for the pipeline.** Run
|
|
1229
|
-
`npx cohorte dashboard` to open a browser view of pipeline state: a **Fleet**
|
|
1230
|
-
overview (global core version vs npm latest + every tracked project's freshness and health
|
|
1231
|
-
at a glance), a per-project drill-down that renders `/doctor` as a live checklist, the
|
|
1232
|
-
**Surfaces ↔ agents** map from `PIPELINE.md`, and a **Specs board** (kanban by
|
|
1233
|
-
`draft·frozen·in-review·shipped`). Install/update actions run the CLI and stream their output
|
|
1234
|
-
live. Add projects by path — the set is remembered in `~/.claude/cohorte-dashboard.json`.
|
|
1235
|
-
The runtime is dependency-free (node's built-in `http` serves a prebuilt React app); the
|
|
1236
|
-
`/doctor` checks are reimplemented in JS so they run without a Claude session. Point it at any
|
|
1237
|
-
pipeline-ised repo, or at nothing (it seeds the launch directory). A **folder picker** browses
|
|
1238
|
-
the filesystem to add projects (dirs with a `PIPELINE.md` are flagged), and a **Reset pipeline**
|
|
1239
|
-
action wipes a project's entire pipeline footprint (`.claude/`, `PIPELINE.md`, optionally
|
|
1240
|
-
`specs/`) — backed up first to `.claude.bak-<ts>/`, the shared `~/.claude` core untouched — so a
|
|
1241
|
-
project riddled with old-version relics can be brought back to a clean, pipeline-managed state
|
|
1242
|
-
(then `/init-pipeline` regenerates the profile). **Init-pipeline / Update-pipeline** buttons run
|
|
1243
|
-
those Claude Code commands headless (`claude -p … --dangerously-skip-permissions`) in the project
|
|
1244
|
-
and stream the output. The server **binds `127.0.0.1` by default** (its actions execute code);
|
|
1245
|
-
`--host=ADDR` exposes it with a printed security warning, `--open` launches the browser.
|
|
1246
|
-
Projects with a linked **Obsidian Kanban board** (config `kanban.boards`) get it rendered inline —
|
|
1247
|
-
columns + cards read straight from the vault markdown (local, no token; Notion is not a kanban
|
|
1248
|
-
source in this pipeline, only /research archival). PR references become clickable links, enriched
|
|
1249
|
-
with **live PR status** (open/merged/closed/draft) + date via the user's `gh` CLI (cached 60s), and
|
|
1250
|
-
the **Shipped** column is sorted by ship date. Cards missing an explicit `#<num>` have their PR
|
|
1251
|
-
**inferred from the branch** (`…/<feature_id>`), so historical boards light up too.
|
|
1252
|
-
|
|
1253
|
-
## 0.1.27 — 2026-07-28
|
|
1254
|
-
|
|
1255
|
-
- **README gains a Prerequisites section.** Spells out what a new machine actually needs: Node ≥ 18 + npm
|
|
1256
|
-
(the only hard requirement, for the `npx` installer) versus `uv` + the Serena CLI (optional, the default
|
|
1257
|
-
retrieval provider — installed separately, independent of the `npx` core install, order irrelevant, and
|
|
1258
|
-
the pipeline still runs without it by falling back to Grep/Read). Also documents the cloned-repo case
|
|
1259
|
-
(Serena registration travels in the committed `.mcp.json`; just install the CLI + restart + `/doctor`).
|
|
1260
|
-
The mechanics were already in `SCHEMA.md` §Code retrieval, but not in the human-facing onboarding doc.
|
|
1261
|
-
|
|
1262
|
-
## 0.1.26 — 2026-07-28
|
|
1263
|
-
|
|
1264
|
-
- **The design step now references designs by full link, not a stored project id + bare filename.** A
|
|
1265
|
-
`design_files` entry is a self-contained `https://claude.ai/design/p/<projectId>?file=<file>` link that
|
|
1266
|
-
carries its own project (`/p/<projectId>`) and page (`?file=`); agents extract both and read it via
|
|
1267
|
-
`DesignSync get_file(<projectId>, <file>)`. No stored `design_project` id means a design-system rebuild
|
|
1268
|
-
(which mints a new project id) no longer breaks every spec — you just paste the new links. `design_project`
|
|
1269
|
-
becomes an optional legacy fallback (default `none`) for old bare-filename specs. Updated across `/build`
|
|
1270
|
-
(design gate + dispatch), `/smoke`, `/spec` + the spec template, `PIPELINE.md` (§design + conventions),
|
|
1271
|
-
`SCHEMA.md`, and `/doctor`. Crucially, the surface-agent render step now specifies the link-based
|
|
1272
|
-
`<SURFACE_DESIGN_INPUT>`/`<SURFACE_TDD_STEP1>` — so `/update-pipeline` re-renders design agents to resolve
|
|
1273
|
-
from the link instead of the stale `get_file(design_project, <file>)`. Existing specs keep their bare
|
|
1274
|
-
filenames until you replace them with links.
|
|
1275
|
-
|
|
1276
|
-
## 0.1.25 — 2026-07-27
|
|
1277
|
-
|
|
1278
|
-
- **`research-agent` defaults to `sonnet`** instead of silently inheriting the session model (Opus). Its
|
|
1279
|
-
work — MAP / ANALYSE / SYNTHESISE of pre-extracted text — is extraction-and-summary that Sonnet handles
|
|
1280
|
-
well at a fraction of the cost, and `/cost` showed it was one of the two heaviest subagents. The fixed
|
|
1281
|
-
agents were never tiered like the surfaces; this closes the biggest gap. If cross-cutting synthesis ever
|
|
1282
|
-
needs more, the `/research` SYNTHESISE dispatch can override the model for just that pass.
|
|
1283
|
-
- **README documents the `/clear`-safe loop** as the top token lever — since all pipeline state lives on
|
|
1284
|
-
disk, `/clear`-ing between stages sheds the accumulated main-thread context (long >150k sessions are
|
|
1285
|
-
expensive even cached), with the safe-to-clear boundary shown for the whole `/spec → … → /ship` loop.
|
|
1286
|
-
|
|
1287
|
-
## 0.1.24 — 2026-07-27
|
|
1288
|
-
|
|
1289
|
-
- **The dev loop is now `/clear`-safe between every stage.** All pipeline state already lives on disk
|
|
1290
|
-
(spec, contract, diff, Remediation checkboxes, freshness stamp), so you can `/clear` between commands
|
|
1291
|
-
to shed the accumulated main-thread context and cut token cost — each command reloads everything from
|
|
1292
|
-
disk. Every command now marks its handoff as safe to `/clear` before the next step.
|
|
1293
|
-
- **`/review` and `/smoke` stage their report to `specs/reports/<id>.md`** (a gitignored buffer in its own
|
|
1294
|
-
subfolder, like `specs/design/`) — the one context-coupling that a `/clear` used to break. `/fix` and
|
|
1295
|
-
`/spec` Mode B read the report back from disk when the context was cleared. `/init-pipeline` gitignores
|
|
1296
|
-
the buffer; `/doctor` reports it. The non-recursive `specs/*.md` glob skips the subfolder, so it never
|
|
1297
|
-
shows up as a phantom kanban card or spec.
|
|
1298
|
-
|
|
1299
|
-
## 0.1.23 — 2026-07-26
|
|
1300
|
-
|
|
1301
|
-
- **Cheaper dev loop by default — implementers now default to `sonnet`, not the Opus lead.** A surface
|
|
1302
|
-
agent mostly applies a frozen contract, which Sonnet handles well at a fraction of the cost;
|
|
1303
|
-
`/init-pipeline` and reconcile now default `surfaces[].model` to `sonnet`, keeping `haiku` for purely
|
|
1304
|
-
mechanical scaffolding and `inherit` only for surfaces with real design decisions. The fixed `release`
|
|
1305
|
-
and `questionnaire-validator` agents drop to `haiku`, `questionnaire-writer` to `sonnet`. Existing
|
|
1306
|
-
projects pick this up on the next `/update-pipeline` (agents re-render; a `model` you set by hand is kept).
|
|
1307
|
-
- **Stateless agents read a *slice* of `PIPELINE.md`, not the whole file.** The implementer and reviewer
|
|
1308
|
-
now load the machine block + only the `### Shared` and their own `### Surface:` convention stanza
|
|
1309
|
-
(+ §Testing), never the other surfaces' prose — less context re-read on every parallel dispatch.
|
|
1310
|
-
- **Leaner fix loops.** On a `/fix` re-dispatch, a surface agent works from the self-contained open
|
|
1311
|
-
Remediation items + the diff and reads only the files those findings name — no longer re-reading the
|
|
1312
|
-
whole (growing) spec or re-exploring its tree.
|
|
1313
|
-
- **Freshness gate at `/ship`.** `/review` now fingerprints the reviewed source (`reviewed_base` +
|
|
1314
|
-
`reviewed_digest` in the spec front-matter) at a SHIP verdict, and `/ship` re-checks it — refusing to
|
|
1315
|
-
ship if any source or contract file changed after the review, so a verdict can't go stale unnoticed.
|
|
1316
|
-
Specs are excluded (DoD ticks + the ship status flip don't trip it); a spec predating the gate skips it.
|
|
1317
|
-
- **Big commands lazy-load their steps (progressive disclosure).** `/init-pipeline`, `/research` and
|
|
1318
|
-
`/questionnaire` are now thin routers (a bootstrap block + a steps table) that read each step from
|
|
1319
|
-
`templates/steps/<command>/NN-*.md` as they reach it, instead of one monolithic body — the branchy
|
|
1320
|
-
commands (esp. `/research`) no longer pull an unused branch into context. Pure re-partition, verified
|
|
1321
|
-
token-for-token identical to the old bodies. No installer change (steps ride the existing `templates/` copy).
|
|
1322
|
-
- **Machine-checkable postconditions on the two silent-failure gates** — `/spec` freeze asserts
|
|
1323
|
-
`status: frozen` actually landed; `/build` asserts the contract file exists before dispatching agents.
|
|
1324
|
-
- **`/review` lets git group the diff by surface** (`git diff --name-only -- <path>` + an `:(exclude)`
|
|
1325
|
-
remainder) instead of the lead reasoning it out file by file — deterministic and cheaper.
|
|
1326
|
-
- **`/fix` collapses fully-resolved Remediation rounds** to a one-line summary, so the spec every agent
|
|
1327
|
-
re-reads stops growing unbounded across fix loops (rounds with any open item stay expanded).
|
|
1328
|
-
- **New SCHEMA § "Measuring cost"** — documents `/cost` (built-in per-subagent + per-command usage share)
|
|
1329
|
-
and the OTEL `settings.json` env block (`claude_code.token.usage` / `cost.usage`) for exact numbers.
|
|
1330
|
-
|
|
1331
|
-
## 0.1.22 — 2026-07-26
|
|
1332
|
-
|
|
1333
|
-
- **`/spec` exports a standalone design brief** — for a UI feature, freezing the spec now also writes
|
|
1334
|
-
§8 (the "spec return") to its own `specs/design/<id>.md`, in addition to printing the copy-paste
|
|
1335
|
-
block. One `.md` you can open, share, or drop straight into the design tool instead of scrolling back
|
|
1336
|
-
through the chat — regenerated on every freeze so it never drifts from the spec. Lives in the
|
|
1337
|
-
`specs/design/` subfolder on purpose, so the non-recursive `specs/*.md` glob (kanban backfill,
|
|
1338
|
-
`/doctor`) never mistakes it for a spec. Backend-only features are unaffected.
|
|
1339
|
-
|
|
1340
|
-
## 0.1.21 — 2026-07-24
|
|
1341
|
-
|
|
1342
|
-
- **Reliable local-PDF reading for `/research`** — subagent nodes often lack a PDF renderer (no
|
|
1343
|
-
poppler), which made research-agents silently fall back to a web copy of the document — fine for a
|
|
1344
|
-
public PDF, a silent fabrication risk for a private one. `/research` now **extracts the PDF to
|
|
1345
|
-
per-page text ONCE up front** (pure-Python `pypdf` in a throwaway venv — no system deps) and agents
|
|
1346
|
-
read that text, never the binary PDF. A local read that fails now returns a loud `===READ-FAILED===`
|
|
1347
|
-
instead of reconstructing from the web; the orchestrator re-extracts or surfaces it. Adds a
|
|
1348
|
-
scanned-PDF guard (no text layer ⇒ stop, needs OCR).
|
|
1349
|
-
|
|
1350
|
-
## 0.1.20 — 2026-07-24
|
|
1351
|
-
|
|
1352
|
-
- **`/fix` now checks off resolved Remediation items** — the lead flips `- [ ]` → `- [x]` (with a
|
|
1353
|
-
short "fixed" note) for every item the surface agents report addressed in their handoff, and skips
|
|
1354
|
-
already-`[x]` items when scoping the re-dispatch. Fixes two long-standing quirks: a spec whose
|
|
1355
|
-
Remediation looked permanently open even after fixes landed, and a later `/fix` re-sending
|
|
1356
|
-
already-fixed items from earlier rounds to the agents.
|
|
1357
|
-
- **`/review` now ticks the §9 DoD at a SHIP verdict** — a SHIP verdict is the pipeline's statement
|
|
1358
|
-
that the feature is done, so the lead checks off each Acceptance-criteria item its verifying stage
|
|
1359
|
-
actually covered (conformance/copy = review, tests/lint/types = build, mobile-first/runtime = smoke),
|
|
1360
|
-
leaving open any whose stage didn't run. `/ship` gains a matching gate: it lists any still-open DoD
|
|
1361
|
-
item and asks before shipping (it never ticks — that's `/review`'s job).
|
|
1362
|
-
|
|
1363
|
-
## 0.1.19 — 2026-07-24
|
|
1364
|
-
|
|
1365
|
-
- **Research decoupled from the questionnaire** — `/research` now dispatches a dedicated, standalone
|
|
1366
|
-
**`research-agent`** (an autonomous research assistant that extracts everything important in the
|
|
1367
|
-
source) instead of the old bi-mode `questionnaire-researcher`. The report no longer carries any
|
|
1368
|
-
"future questionnaire" framing: the domain-brief `goal` is a research objective, and the brief
|
|
1369
|
-
template is renamed `research-brief.md`. The blueprint step moves to its own **`questionnaire-architect`**
|
|
1370
|
-
agent, dispatched by `/questionnaire`. New Notion archive databases are titled « Recherche ». Update
|
|
1371
|
-
scrubs the retired `questionnaire-researcher` agent and old template automatically.
|
|
1372
|
-
- **Multi-pass research for large sources** — `/research` now maps a big PDF into a reading plan, runs
|
|
1373
|
-
one deep `research-agent` pass **per segment in parallel**, synthesises the cross-cutting sections,
|
|
1374
|
-
and assembles a single report. Report length scales with the source (no fixed word-count cap), so a
|
|
1375
|
-
dense thesis or state-of-the-art gets exhaustive coverage instead of being compressed into one pass.
|
|
1376
|
-
Small sources and URLs still take the single-pass path.
|
|
1377
|
-
|
|
1378
|
-
## 0.1.18 — 2026-07-22
|
|
1379
|
-
|
|
1380
|
-
- **Consolidated global config** — the research/questionnaire settings move from
|
|
1381
|
-
`~/.claude/questionnaire.config.yaml` into one `~/.claude/cohorte.config.yaml` with
|
|
1382
|
-
`obsidian` / `research` / `questionnaire` / `kanban` sections and a shared `obsidian.vault_path`.
|
|
1383
|
-
The old file is still read as a fallback; `/update-pipeline` migrates it for you. The `npx`
|
|
1384
|
-
installer now offers a quick interactive setup on a TTY.
|
|
1385
|
-
- **Obsidian kanban mirror** — an optional per-project board mirrors the pipeline
|
|
1386
|
-
(`/brainstorm`…`/ship`): each stage moves the feature's card across columns
|
|
1387
|
-
(Ideas → Brainstorm → Spec → Ready to build → Building → Review → Fix → Ship → Shipped).
|
|
1388
|
-
`/brainstorm` can pick an idea straight from the *Ideas* column; `/init-pipeline` creates + links
|
|
1389
|
-
a board (keyed by the project's `PIPELINE.md` name); `/update-pipeline` links/repairs it and
|
|
1390
|
-
**backfills existing `specs/` onto the board**, syncing each card to its spec's status. Enable it
|
|
1391
|
-
via `/init-pipeline` (new project) or `/update-pipeline` (existing) — no hand-editing.
|
|
1392
|
-
|
|
1393
|
-
## 0.1.17 — 2026-07-22
|
|
1394
|
-
|
|
1395
|
-
- **Serena dashboard no longer auto-opens** — the per-repo Serena launcher `/init-pipeline` wires now
|
|
1396
|
-
passes `--open-web-dashboard False`. The dashboard stays available (`http://localhost:24282/dashboard/`)
|
|
1397
|
-
but no longer pops a browser tab on every server start. The flag overrides each machine's
|
|
1398
|
-
`serena_config.yml`, so behaviour is uniform across the team; `/update-pipeline`'s health check appends
|
|
1399
|
-
the flag to launcher entries that predate it.
|
|
1400
|
-
|
|
1401
|
-
## 0.1.16 — 2026-07-22
|
|
1402
|
-
|
|
1403
|
-
- **Obsidian store: research and questionnaires split** — research notes land in
|
|
1404
|
-
`obsidian_research_folder` (default `Recherches/`, with `_sources/`), and a derived questionnaire
|
|
1405
|
-
is now a **separate note** in `obsidian_questionnaire_folder` (default `Questionnaires/`),
|
|
1406
|
-
wikilinked both ways with the research note. Statut lifecycle: the research note stays
|
|
1407
|
-
`Recherche`; the questionnaire note carries `À relire` / `Bloqué` / `Approuvé`. (Replaces
|
|
1408
|
-
0.1.15's single `obsidian_folder` key.) Notion store unchanged — one page per run.
|
|
1409
|
-
|
|
1410
|
-
## 0.1.15 — 2026-07-22
|
|
1411
|
-
|
|
1412
|
-
- **Obsidian store for research runs** — the research/questionnaire capability gains a `store:`
|
|
1413
|
-
switch in `~/.claude/questionnaire.config.yaml`: `notion` (default, unchanged) or `obsidian` —
|
|
1414
|
-
each run becomes a markdown note in `<vault>/<obsidian_folder>/` with frontmatter properties
|
|
1415
|
-
(`run_id`, `sujet`, `cadre`, `statut`, `date`), source PDFs copied to `_sources/` for provenance.
|
|
1416
|
-
No MCP needed; the vault path is asked once on first `/research`, then saved. Old Notion runs stay
|
|
1417
|
-
readable — pass their URL to `/questionnaire`.
|
|
1418
|
-
|
|
1419
|
-
## 0.1.14 — 2026-07-22
|
|
1420
|
-
|
|
1421
|
-
- **`/fix`** — scoped fix loop: appends a REVIEW REPORT (or `/smoke` failures) to the spec's
|
|
1422
|
-
`## Remediation` and re-dispatches ONLY the surfaces with findings, instead of the full
|
|
1423
|
-
paste-into-`/spec` + full `/build` round-trip.
|
|
1424
|
-
- **`/smoke`** — end-to-end verification between `/build` and `/review`: infra up in the feature
|
|
1425
|
-
worktree, migrations, real contract endpoints via curl (incl. RBAC denials), spec §8 UI flows
|
|
1426
|
-
mobile-first, optional screenshot diff against the Claude Design pages.
|
|
1427
|
-
- **`/doctor`** — installation diagnostic: core/pointer versions, agents↔surfaces orphans, hooks &
|
|
1428
|
-
gate config, retrieval health, design wiring, stale worktree slots — each failure with its exact fix.
|
|
1429
|
-
- **Dispatch metrics** — `/build`, `/review`, `/fix`, `/smoke` append per-agent JSONL evidence to
|
|
1430
|
-
`.claude/pipeline-metrics.jsonl` (gitignored); SCHEMA §Specialization now points at it.
|
|
1431
|
-
- **`/ship`** — watches the PR's CI checks (`gh pr checks --watch`) and, after the merge is
|
|
1432
|
-
confirmed, proposes `scripts/remove-feature.sh` (worktree + slot teardown, db kept by default).
|
|
1433
|
-
- **`/init-pipeline`** — generates `.github/workflows/pipeline-ci.yml` from the profile's commands
|
|
1434
|
-
(with go-ahead) and gitignores the metrics sink.
|
|
1435
|
-
- **CHANGELOG** — this file; shipped with the core, shown by `/update-pipeline` after an update.
|
|
1436
|
-
|
|
1437
|
-
## 0.1.13 — 2026-07-22
|
|
1438
|
-
|
|
1439
|
-
- **`/review` is parallel** — one review agent per touched surface in a single dispatch (wall-clock =
|
|
1440
|
-
slowest surface, not the sum); the lead merges the reports, worst verdict wins.
|
|
1441
|
-
- **Review agent reads less** — `mcp__serena` in its toolset (harmlessly absent when a project has no
|
|
1442
|
-
retrieval provider) and a diff-hunks-first reading rule instead of whole-file reads.
|
|
1443
|
-
|
|
1444
|
-
## 0.1.12 — 2026-07-22
|
|
1445
|
-
|
|
1446
|
-
- **Per-feature design projects** — spec `design_files` now accepts full Claude Design links, each
|
|
1447
|
-
carrying its own project id (extracted at `/build`'s design gate); the profile's `design_project`
|
|
1448
|
-
becomes an optional fallback. Design each feature in a fresh project and just paste the link.
|
|
1449
|
-
|
|
1450
|
-
## 0.1.11 and earlier
|
|
1451
|
-
|
|
1452
|
-
Pre-changelog releases: serena wiring made PATH-proof and health-checked (0.1.9–0.1.11), OIDC npm
|
|
1453
|
-
trusted publishing (since 0.1.4). See `git log` for details.
|