cohorte 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +264 -0
  2. package/LICENSE +661 -0
  3. package/README.md +269 -0
  4. package/bin/cli.js +339 -0
  5. package/core/agents/implementer.template.md +74 -0
  6. package/core/agents/release.md +51 -0
  7. package/core/agents/review.md +85 -0
  8. package/core/commands/align-ds.md +32 -0
  9. package/core/commands/audit.md +31 -0
  10. package/core/commands/brainstorm.md +48 -0
  11. package/core/commands/build.md +91 -0
  12. package/core/commands/doctor.md +50 -0
  13. package/core/commands/fix.md +62 -0
  14. package/core/commands/init-pipeline.md +32 -0
  15. package/core/commands/refactor.md +38 -0
  16. package/core/commands/review.md +68 -0
  17. package/core/commands/ship.md +68 -0
  18. package/core/commands/smoke.md +55 -0
  19. package/core/commands/spec.md +67 -0
  20. package/core/commands/update-pipeline.md +96 -0
  21. package/core/hooks/__pycache__/gate.cpython-312.pyc +0 -0
  22. package/core/hooks/gate.py +129 -0
  23. package/core/templates/agent-handoff.md +34 -0
  24. package/core/templates/brainstorm-return.md +36 -0
  25. package/core/templates/design-brief.md +35 -0
  26. package/core/templates/pr-body.md +29 -0
  27. package/core/templates/review-feedback.md +36 -0
  28. package/core/templates/spec.template.md +84 -0
  29. package/core/templates/steps/init-pipeline/01-detect-stack.md +40 -0
  30. package/core/templates/steps/init-pipeline/02-interview-gaps.md +41 -0
  31. package/core/templates/steps/init-pipeline/03-draft-profile.md +10 -0
  32. package/core/templates/steps/init-pipeline/04-write-render.md +88 -0
  33. package/core/templates/steps/init-pipeline/05-report.md +12 -0
  34. package/dashboard/README.md +54 -0
  35. package/dashboard/dist/apple-touch-icon-180.png +0 -0
  36. package/dashboard/dist/assets/index-CoBuEdy-.js +42 -0
  37. package/dashboard/dist/assets/index-DN5OGW9g.css +1 -0
  38. package/dashboard/dist/favicon-16.png +0 -0
  39. package/dashboard/dist/favicon-32.png +0 -0
  40. package/dashboard/dist/favicon-48.png +0 -0
  41. package/dashboard/dist/icon-192.png +0 -0
  42. package/dashboard/dist/icon-512.png +0 -0
  43. package/dashboard/dist/index.html +16 -0
  44. package/dashboard/server/doctor.js +266 -0
  45. package/dashboard/server/fleet.js +119 -0
  46. package/dashboard/server/index.js +306 -0
  47. package/dashboard/server/kanban.js +158 -0
  48. package/dashboard/server/versions.js +111 -0
  49. package/dashboard/server/yaml.js +126 -0
  50. package/install.ps1 +359 -0
  51. package/install.sh +301 -0
  52. package/package.json +40 -0
  53. package/profile/PIPELINE.template.md +208 -0
  54. package/profile/SCHEMA.md +303 -0
  55. package/profile/cohorte.config.template.yaml +43 -0
  56. package/scripts/new-feature.sh.template +89 -0
  57. package/scripts/remove-feature.sh.template +53 -0
@@ -0,0 +1,68 @@
1
+ ---
2
+ description: Dispatch the read-only review agent to audit the feature against its frozen spec.
3
+ argument-hint: <feature_id>
4
+ ---
5
+
6
+ You are the **lead**. Dispatch the review for feature **$ARGUMENTS**.
7
+
8
+ > Read `PIPELINE.md` §`vcs.default_branch` (diff base) and the `surfaces`/`contract` fields.
9
+ >
10
+ > Template paths below (`.claude/templates/…`) resolve to `~/.claude/templates/…` when the core is
11
+ > installed globally — read whichever exists.
12
+ >
13
+ > **Kanban** (SCHEMA.md §Kanban): move card `#$ARGUMENTS` → **Review**. No-op silently if no board.
14
+
15
+ ## 1. Gather the inputs for stateless reviewers
16
+
17
+ - Confirm `specs/$ARGUMENTS.md` exists.
18
+ - Compute the diff, and let **git do the grouping** (deterministic — don't reason it out file by file):
19
+ per surface, `git diff <default_branch> --name-only -- <surface.path>` is exactly that surface's changed
20
+ files; the **`shared` remainder** (contract file + anything outside every surface) is
21
+ `git diff <default_branch> --name-only -- . $(for p in <each surface.path>; do printf ':(exclude)%s ' "$p"; done)`.
22
+ Attach the remainder to the most relevant surface's reviewer and say so in its dispatch. A surface whose
23
+ `git diff` comes back empty gets no reviewer.
24
+
25
+ ## 2. Dispatch review agents — one per touched surface, IN PARALLEL
26
+
27
+ Spawn ONE `review` agent per surface that has changed files, in a **single message** (one Task call
28
+ each, like `/build`) so they run concurrently — NEVER serially: review wall-clock must be the
29
+ slowest surface, not the sum. A diff touching a single surface ⇒ a single reviewer. For each:
30
+
31
+ > `subagent_type: review` — "Review feature `$ARGUMENTS` — **scope: the `<surface.key>` surface
32
+ > only**. Read `PIPELINE.md` first (its flags + §Conventions/§Testing for `<surface.key>`). Spec:
33
+ > `specs/$ARGUMENTS.md` (source of truth). Contract: `<contract.path>/$ARGUMENTS.<ext>`. Changed
34
+ > files in your scope (diff vs `<default_branch>`): <list, with the `--stat` counts>. Review the
35
+ > diff hunks + immediate context — not whole files. Check spec conformance first, then correctness,
36
+ > security, conventions, RBAC/mobile-first _if the profile enables them_, and TDD coverage. Emit
37
+ > the REVIEW REPORT per `.claude/templates/review-feedback.md` — every finding self-sufficient
38
+ > (`file:line` · severity · type · concrete fix)."
39
+
40
+ Note the epoch (`date +%s`) just before dispatching — §3's metrics lines need the wall-clock.
41
+
42
+ ## 3. Merge & relay the verdict
43
+
44
+ Merge the returned reports into **one** REVIEW REPORT (same template): findings concatenated and
45
+ re-ordered by severity, counts summed, duplicates collapsed, verdict = the worst returned
46
+ (`BLOCK` > `REVISE` > `SHIP`). Append one line per reviewer to `.claude/pipeline-metrics.jsonl`
47
+ (gitignored): `{"ts":"<ISO>","feature":"$ARGUMENTS","phase":"review","surface":"<key>","seconds":<wall-clock>,"result":"<verdict>:<finding count>"}`.
48
+ Print the report **and stage it to `specs/reports/$ARGUMENTS.md`** (overwrite) — a gitignored buffer so
49
+ a `/fix` after a `/clear` can still read the findings; the `specs/reports/` subfolder is skipped by the
50
+ non-recursive `specs/*.md` glob, so it's never mistaken for a spec (no phantom card, no bogus stage). Then:
51
+
52
+ - **SHIP** → a SHIP verdict *is* the pipeline's statement that the feature meets its Definition of
53
+ Done, so **tick the DoD**: in `specs/$ARGUMENTS.md` §`Acceptance criteria / DoD`, flip each `- [ ]`
54
+ → `- [x]` for the criteria the pipeline has actually verified — spec conformance + `ui_language`
55
+ copy (this review), tests · lint · typecheck (a green `/build`), mobile-first + runtime flows (a
56
+ prior `/smoke`). **Leave `- [ ]` (and say which) any item whose verifying stage didn't run this
57
+ cycle** — e.g. no `/smoke` ⇒ the mobile-first / runtime item stays open. Ticking is the lead's job
58
+ (the reviewer is read-only). **Then stamp the freshness gate** so `/ship` can refuse to ship code
59
+ edited after this verdict: compute `BASE=$(git merge-base <default_branch> HEAD)` and write into the
60
+ spec front-matter `reviewed_base: $BASE` plus
61
+ `reviewed_digest: $(git diff $BASE -- . ':(exclude)specs/' | sha256sum | cut -c1-16)` — the fingerprint
62
+ of exactly the source you just reviewed (specs excluded, so DoD ticks + the ship status flip don't
63
+ trip it). Then tell the human they can `/ship` — _the handoff is fully on disk, so `/clear` first is safe._
64
+ - **REVISE / BLOCK**, or any finding of any severity → tell the human to run **`/fix $ARGUMENTS`** —
65
+ it appends the report to the spec's `## Remediation` and re-dispatches ONLY the surfaces with
66
+ findings. The full path (`/spec` Mode B then `/build`) remains for findings that change the
67
+ contract in ways that ripple into clean surfaces. _The report is staged to `specs/reports/$ARGUMENTS.md`,
68
+ so you can `/clear` before `/fix` — it reads the findings back from disk._
@@ -0,0 +1,68 @@
1
+ ---
2
+ description: At a SHIP verdict, dispatch the release agent to commit, push, and open the PR (with your confirmation).
3
+ argument-hint: <feature_id>
4
+ ---
5
+
6
+ You are the **lead**. Ship feature **$ARGUMENTS**. This is the outward-facing gate.
7
+
8
+ > Read `PIPELINE.md` §`vcs` (host, remote, default_branch, feature_branch_prefix).
9
+ >
10
+ > **Kanban** (SCHEMA.md §Kanban) is mirrored in **explicit steps** below, not as an afterthought:
11
+ > §1 moves the card → **Ship**; §4 moves it → **Shipped** and writes the PR number. No-op silently if
12
+ > no board. Do not skip §4's move — a shipped feature whose card is stuck in an earlier column is the
13
+ > bug this ordering prevents.
14
+
15
+ ## 1. Pre-flight (confirm before doing anything irreversible)
16
+
17
+ - Confirm the latest `/review` returned **SHIP** (no CRITICAL, no security). If not reviewed, or the
18
+ verdict was REVISE/BLOCK, stop and say so.
19
+ - **Freshness gate** — the reviewed code must be exactly what ships. If the spec front-matter carries
20
+ `reviewed_base` + `reviewed_digest`, recompute
21
+ `git diff <reviewed_base> -- . ':(exclude)specs/' | sha256sum | cut -c1-16` and compare to
22
+ `reviewed_digest`. **Match** ⇒ source unchanged since the SHIP verdict, proceed. **Mismatch** ⇒ source
23
+ (or the contract) was edited after review — the verdict is **stale**: stop and tell the human to re-run
24
+ `/review $ARGUMENTS` before shipping. Missing fields (spec predates the gate) ⇒ skip, don't block.
25
+ - **DoD gate (verify, don't tick — `/review` owns the ticking).** Read `specs/$ARGUMENTS.md`
26
+ §`Acceptance criteria / DoD`; if any item is still `- [ ]`, list the open ones and ask the human to
27
+ confirm shipping anyway (they may be deferred on purpose — e.g. a UI item on a backend-only feature).
28
+ All `- [x]` ⇒ proceed silently.
29
+ - Show `git status` + `git diff --stat`; confirm the branch is `<feature_branch_prefix>$ARGUMENTS`.
30
+ - **Ask the human to confirm** they want to commit, push, and open the PR. Wait for yes.
31
+ - After the yes: **move card `#$ARGUMENTS` → the `ship` column** (SCHEMA.md §Kanban "Move a card"). No-op if no board.
32
+
33
+ ## 2. Mark the spec shipped (BEFORE dispatch, so it ships in the same commit)
34
+
35
+ Once the human confirms, edit `specs/$ARGUMENTS.md` front-matter `status: → shipped` — **before**
36
+ dispatching the release agent, so the status flip is part of the tree it commits (otherwise it lands
37
+ uncommitted after the PR opens). Only flip after the human's "yes"; if they decline, leave it.
38
+
39
+ ## 3. Dispatch the `release` agent
40
+
41
+ Spawn one agent (`subagent_type: release`): "Release feature `$ARGUMENTS` on branch
42
+ `<feature_branch_prefix>$ARGUMENTS`. Read `PIPELINE.md` §vcs first. Spec: `specs/$ARGUMENTS.md` (already
43
+ `status: shipped` — stage it). Write conventional commit(s), push (no force), open the PR (use `gh` if
44
+ `host: github` + available; else emit the compare URL + drafted PR body from `.claude/templates/pr-body.md`).
45
+ Stage **all** the feature's changes including `specs/$ARGUMENTS.md`. Never edit source, never force-push,
46
+ never run migrations."
47
+
48
+ ## 4. Relay + move the card to Shipped (do not skip)
49
+
50
+ Print the release agent's report: commit SHA(s), pushed branch, PR URL (or compare URL + drafted body).
51
+ Confirm `specs/$ARGUMENTS.md` was committed as `status: shipped` (part of the release commit).
52
+
53
+ **Move the card to Shipped — required, and verify it actually moved.** Move card `#$ARGUMENTS` → the
54
+ `shipped` column (SCHEMA.md §Kanban "Move a card") and **append the PR number** so the line reads
55
+ `- [ ] <title> #$ARGUMENTS — PR #<num>`. Take `<num>` from the PR URL (`…/pull/13` ⇒ `13`); **always write
56
+ it when a PR was created** (the `gh` path) — it is what the dashboard turns into a PR link. If only a
57
+ compare URL was emitted (no PR yet), move the card without a number. Then **re-read the board** and confirm
58
+ the card sits under the `shipped` heading with no stale copy left under its previous column. No board ⇒
59
+ skip silently.
60
+
61
+ ## 5. After the PR — CI gate + teardown
62
+
63
+ - If `host: github` and `gh` is available, watch the PR's checks (`gh pr checks <url> --watch`) and
64
+ report the result — the human merges only on green. A red check ⇒ back to `/fix $ARGUMENTS`.
65
+ - Once the human confirms the PR is **merged**: if `isolation.enabled`, propose the teardown —
66
+ `scripts/remove-feature.sh $ARGUMENTS` (add `--drop-db` to also drop the feature db; kept by
67
+ default). It removes the worktree, deletes the merged branch, frees the slot. Never run it before
68
+ the merge is confirmed, and only with the human's go-ahead (the gate will ask anyway).
@@ -0,0 +1,55 @@
1
+ ---
2
+ description: Exercise the built feature end-to-end in its worktree — infra up, migrations, contract endpoints, key UI flows, visual check vs design — before /review.
3
+ argument-hint: <feature_id>
4
+ ---
5
+
6
+ You are the **lead**. Smoke-test feature **$ARGUMENTS** — actually run it. `/review` audits the code
7
+ read-only; nobody has executed it yet. You verify it *works*, you never fix it here (failures go
8
+ through `/fix`). Observe honestly: report what happened, not what should have happened.
9
+
10
+ > Read `PIPELINE.md` §`pipeline-profile`: `commands` (migrate/dev), `isolation` (worktree, slot
11
+ > ports, db), `contract`, `design`, `surfaces`, and the spec `specs/$ARGUMENTS.md` (§5 contract,
12
+ > §9 acceptance).
13
+ >
14
+ > **Kanban** (SCHEMA.md §Kanban): move card `#$ARGUMENTS` → **Review**. No-op silently if no board.
15
+
16
+ ## 1. Bring the feature up
17
+
18
+ - Work in the feature's checkout: with `isolation.enabled`, the sibling worktree
19
+ (`../<slug>-$ARGUMENTS`, its slot's ports + db from `.worktrees/slots.tsv`); otherwise the main
20
+ checkout on the feature branch.
21
+ - Infra as needed: the compose stack if one is declared (the gate will ask — that's expected),
22
+ then `commands.migrate`, then `commands.dev` **in the background**. Wait for ready (poll the
23
+ ports), don't assume.
24
+
25
+ ## 2. Exercise the contract (the real server, not the tests)
26
+
27
+ - Hit a representative set of spec §5 endpoints with `curl`: every route domain, every auth level,
28
+ at least one error case per class (validation `422`, unauthenticated `401`, wrong-role `403`,
29
+ conflict `409`). Compare status + response envelope against the contract.
30
+ - If `rbac.enabled`: verify at least one denial per role boundary the spec declares.
31
+ - A mismatch is a FAIL entry with the exact command, expected, and actual — precise enough for a
32
+ stateless `/fix` agent.
33
+
34
+ ## 3. Exercise the UI (only if a touched surface has `uses_design`)
35
+
36
+ - Drive the spec §8 flows against the running app, **mobile viewport first** (375px), then desktop.
37
+ - If a browser/screenshot tool is available (a project driver, playwright, an agent browser), capture
38
+ each §8 screen and compare against the feature's design pages: each `design_files` entry is a full
39
+ `https://claude.ai/design/p/<projectId>?file=<file>` link — extract its `<projectId>` (the `/p/…`
40
+ segment) + `<file>` (the `?file=` query) and fetch read-only via `DesignSync get_file(<projectId>,
41
+ <file>)`. Compare layout, states (empty/loading/error/suppressed…), copy language. Note deviations.
42
+ - No browser tooling available ⇒ **say so and skip the visual diff** — never claim a visual check
43
+ you didn't perform.
44
+
45
+ ## 4. SMOKE REPORT
46
+
47
+ - One line per check: ✅/❌ · what was exercised · (on ❌) command → expected vs actual.
48
+ - **Stage the full report to `specs/reports/$ARGUMENTS.md`** (overwrite) — the same gitignored buffer
49
+ `/review` uses (subfolder ⇒ skipped by the non-recursive `specs/*.md` glob), so a `/fix` after a
50
+ `/clear` still has the failures.
51
+ - Verdict **PASS** (all green) → tell the human to run `/review $ARGUMENTS`.
52
+ Verdict **FAIL** → the failures are findings: feed them to `/fix $ARGUMENTS`, re-run `/smoke`
53
+ after. _Either way the handoff is on disk — `/clear` before the next command is safe._
54
+ - Append one metrics line to `.claude/pipeline-metrics.jsonl` (see `/build` §4, `phase: "smoke"`).
55
+ - Tear down what you started (kill the dev server); leave shared infra as you found it.
@@ -0,0 +1,67 @@
1
+ ---
2
+ description: Interactively capture a frozen feature spec (or apply a review return) into specs/<id>.md.
3
+ argument-hint: [paste brainstorm return OR review report]
4
+ ---
5
+
6
+ You run the **spec** step in the main thread — interactive, with the human. Pasted input below:
7
+
8
+ **$ARGUMENTS**
9
+
10
+ > Read `PIPELINE.md` first: `contract` (mechanism/path — so §5 names the right schema types),
11
+ > `design.enabled` (whether §8 matters), and §Conventions. Use `specs/_template.md` as the section list.
12
+ >
13
+ > Template paths below (`.claude/templates/…`) resolve to `~/.claude/templates/…` when the core is
14
+ > installed globally — read whichever exists.
15
+ >
16
+ > **Kanban** (SCHEMA.md §Kanban): when the spec opens, move card `#<feature_id>` → **Spec**; on freeze
17
+ > (`status: frozen`, Mode A) → **Ready to build**. No-op silently if no board is configured.
18
+
19
+ Detect the mode from the pasted content:
20
+
21
+ ## Mode A — new spec (input is a brainstorm return, or empty)
22
+
23
+ 1. If empty, ask the human to paste the brainstorm return (or describe the feature) and wait.
24
+ 2. Derive a `feature_id` (kebab-case slug). Confirm it.
25
+ 3. Walk the human through each section of `specs/_template.md`, **section by section**, with focused
26
+ questions. The critical one is **§5 API CONTRACT** — pin down every endpoint/interface (method, path,
27
+ auth/role, request fields with types/validation, success envelope + data shape, and every error case),
28
+ and name the exact schema/types that will live in the contract file (`contract.path/<id>.<ext>` in the
29
+ profile's `mechanism`). Don't move on until frontend and backend could each build from it with zero
30
+ further questions. _If `contract.enabled` is false, capture the interface precisely in prose instead._
31
+ 4. Fill **§8 Design brief** (only if `design.enabled` / the feature has UI) so it's self-contained for the
32
+ design step: screens, states, components, responsive notes.
33
+ 4b. **New-surface heads-up.** If the feature clearly introduces an area no existing `surfaces[].path`
34
+ owns (a new service/app/top-level module), note it in the spec (a line in the relevant task section:
35
+ `> needs new surface: <proposed key/path>`). Don't render agents here — `/build` §1.5 auto-reconciles
36
+ it. This is just so the human isn't surprised when `/build` proposes a new agent.
37
+ 5. When the human validates, **freeze**: write `specs/<id>.md` (`status: frozen`, front-matter filled).
38
+ Create the file — do not ask the human to. **Postcondition:** `grep -q '^status: frozen' specs/<id>.md`
39
+ — if it fails the freeze didn't land; fix it before pointing the human at `/build`.
40
+ 6. Emit the **spec return** — the §8 design brief rendered via `.claude/templates/design-brief.md`.
41
+ _Only if `design.enabled` / the feature has UI; skip entirely for a backend-only feature._
42
+ - **Write it to `specs/design/<id>.md`** (a standalone `.md`, versioned with the spec). Create the
43
+ file — do not ask the human to. Keep it in the `specs/design/` subfolder, **not** `specs/<id>....md`:
44
+ the `specs/*.md` glob that drives the kanban backfill and `/doctor` is non-recursive, so a brief in
45
+ the subfolder never gets mistaken for a spec (no phantom card, no bogus stage). This is a derived
46
+ artifact that mirrors §8 — overwrite it on every freeze so it never drifts from the spec.
47
+ - Then print the same content in a copy-paste block and tell the human: paste it into the design tool
48
+ (if any — typically a fresh design project for this feature) or just open `specs/design/<id>.md`,
49
+ then run `/build <id>` and hand its design gate the resulting page link(s) — a full
50
+ `https://claude.ai/design/p/<projectId>?file=<file>` link carries its own project + page, no profile
51
+ change needed. (They can also paste the links into the spec's `design_files`
52
+ themselves.) _The frozen spec + `specs/design/<id>.md` are the whole handoff — `/clear` before
53
+ `/build` is safe._
54
+
55
+ ## Mode B — review return (input is a REVIEW REPORT)
56
+
57
+ 1. Read the report — pasted as input, or (if the context was cleared) read from `specs/reports/<id>.md`,
58
+ where `/review` stages its last report. Identify `feature_id` from its header; open `specs/<id>.md`.
59
+ 2. Append each finding to the spec's **`## Remediation`**, one per line:
60
+ `- [ ] <severity> · <file:line> · <spec-violation|quality|security> · <concrete fix>`
61
+ (Keep prior items; add the new round under a dated/numbered subheading.)
62
+ 3. If a finding implies the **contract** must change, update §5 and flag it so the lead re-authors the
63
+ contract file.
64
+ 4. Set `status: in-review`. Tell the human to run `/build <id>` to re-dispatch fresh agents.
65
+ _The spec is the whole handoff — `/clear` before `/build` is safe._
66
+
67
+ In both modes the spec is the single source of truth; agents are stateless and read only it + the diff.
@@ -0,0 +1,96 @@
1
+ ---
2
+ description: Refresh the pipeline core (global ~/.claude, or a repo's bundled .claude) to the latest published cohorte version, then reconcile this repo's generated files to it — /init-pipeline stays one-time.
3
+ argument-hint: [path-to-local-checkout]
4
+ ---
5
+
6
+ You are the **pipeline updater**. Refresh the installed pipeline core to the latest version of the pipeline
7
+ repo. The installer's `--update` mode never touches generated files: `PIPELINE.md`, rendered surface agents,
8
+ `gate-config.json`, `settings.json`, and the filled `~/.claude/cohorte.config.yaml` are all preserved.
9
+ YOU then bring those generated files up to the new core yourself (§3.5) — additively, never clobbering
10
+ the human's choices — so `/init-pipeline` never needs re-running for an upgrade.
11
+
12
+ ## 1. Detect the install scope + current version
13
+
14
+ - **Global** install ⇒ `~/.claude/pipeline/VERSION` exists. **Bundled** ⇒ this repo's
15
+ `.claude/pipeline/VERSION` exists. (Both can exist; prefer the bundled one when running inside such a
16
+ repo, and update both if the human wants.)
17
+ - **Never migrate a repo between bundled and global mode on your own.** Updating means refreshing the
18
+ core *in its current mode*. Only migrate (e.g. delete a bundled core in favor of the global one) if
19
+ the human explicitly asks — and confirm before deleting anything, since it rewrites the repo's
20
+ committed `.claude/` and the `pipeline.json` pointer teammates rely on.
21
+ - Read the VERSION file(s) — a semver like `0.1.0`, possibly suffixed `(abc1234)` for from-main
22
+ installs, or a bare commit hash on old cores. If missing, note "unknown (pre-versioning)".
23
+
24
+ ## 2. Run the update
25
+
26
+ - If `$ARGUMENTS` is a path to a local checkout of the pipeline repo (contains `core/` + `install.sh`),
27
+ run from there — useful when iterating on the pipeline itself:
28
+
29
+ ```sh
30
+ sh <path>/install.sh --update --global # global core
31
+ sh <path>/install.sh --update # bundled core of the current repo
32
+ ```
33
+
34
+ - Otherwise use the published npm package (preferred — installs the latest tagged release):
35
+
36
+ ```sh
37
+ npx cohorte@latest update --global # global core
38
+ npx cohorte@latest update # bundled core of the current repo
39
+ ```
40
+
41
+ - If npm/npx is unavailable, fall back to piping the installer from the repo's latest `main`:
42
+
43
+ ```sh
44
+ curl -fsSL https://raw.githubusercontent.com/TheBidouilleAgency/cohorte/main/install.sh | sh -s -- --update --global
45
+ # bundled: … | sh -s -- --update
46
+ ```
47
+
48
+ (The piped installer clones the repo itself; `-s --` forwards the flags.)
49
+
50
+ ## 3. Report old → new
51
+
52
+ Re-read the VERSION file(s) and print `old → new`. If unchanged, say the core was already up to date.
53
+ For a bundled repo, note that `.claude/pipeline.json`'s `core_version` was bumped and should be committed.
54
+
55
+ Then print **What's new**: read the installed `<core>/pipeline/CHANGELOG.md` and show the entries
56
+ between the old and new versions (most recent first). File absent ⇒ the old core predates 0.1.14 —
57
+ skip silently.
58
+
59
+ ## 3.5 Reconcile this repo's generated files
60
+
61
+ Only when the current repo has a `PIPELINE.md`: run the **Reconcile procedure** from the installed
62
+ `pipeline/SCHEMA.md` §Reconcile — top up the profile's machine block with new fields at their defaults
63
+ (one batched question set for any genuinely new human decision, e.g. choosing a `retrieval` provider),
64
+ re-render the surface agents from the current `implementer.template.md`, additively patch
65
+ `settings.json`/`gate-config.json`, and run any newly-added capability's wiring (e.g. Serena's
66
+ project-scope `claude mcp add`). Even when no capability is new, **re-run the retrieval provider's
67
+ health check** (SCHEMA.md §Code retrieval: CLI resolvable from PATH, `.mcp.json` entry present —
68
+ upgrading a bare `serena` entry to the PATH-proof launcher form, `.serena/` gitignored, server
69
+ actually connected) and repair whatever fails — wiring that worked at
70
+ init can rot (PATH changes, uninstalls, hand-edits). Report what was reconciled; if nothing was
71
+ missing, say so. This is why `/init-pipeline` never needs re-running for a core upgrade.
72
+
73
+ Two of the §Reconcile steps matter specifically here:
74
+
75
+ - **Global config seed** (§Reconcile step 5): if `~/.claude/cohorte.config.yaml` is absent, seed it
76
+ from the template so the kanban + shared-vault config has a home. Never clobber an existing filled
77
+ file. Report what was seeded.
78
+ - **Kanban sync** (§Reconcile step 6): resolve this project's board from `kanban.boards[<PIPELINE
79
+ name>]`. **Not linked** → offer to link/create a board (confirm the vault + `<folder>/Tasks.md`,
80
+ write the `boards` entry, create the board file per §Kanban). **Linked** → verify the board file
81
+ exists (recreate if the human confirms) and its columns match `kanban.columns` (repair drift). Either
82
+ way, run the §Kanban **full sync/backfill** from `specs/*.md` — this is what adds every
83
+ already-developed feature to the board and repositions cards to match each spec's `status`. Report
84
+ cards added / moved / already-correct. Skip silently if `kanban.enabled` is false and the human
85
+ doesn't want to turn it on.
86
+
87
+ ## 4. Tell the human the follow-ups
88
+
89
+ - **Restart / reload the Claude Code session** so it picks up updated commands, agents, and any
90
+ newly-registered MCP server.
91
+ - **Other repos using the global core:** their core is already fresh, but reconcile is per-repo — run
92
+ `/update-pipeline` inside each (it will skip the already-done core update and just reconcile).
93
+ - **Commit** the reconciled files (`PIPELINE.md`, `.claude/`, `.mcp.json` if added) so teammates get them.
94
+ - The kanban config is global and user-scoped
95
+ (`~/.claude/cohorte.config.yaml`) — never committed. The core update never touches it; only the
96
+ reconcile above seeds the file and writes kanban board links (into that global file, not the repo).
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env python3
2
+ """PreToolUse gate — generic, profile-driven.
3
+
4
+ Forces a confirmation prompt (or hard-denies) on dangerous Bash commands,
5
+ inspecting the FULL command string so chained forms like
6
+ `cd apps/api && node ace migration:run` are caught — something prefix-based
7
+ permission rules in settings.json miss.
8
+
9
+ Patterns come from `.claude/gate-config.json` (generated by /init-pipeline from
10
+ the PIPELINE.md `gate` block):
11
+
12
+ { "deny": ["node ace migration:fresh", ...],
13
+ "ask": ["git commit", "git push", "node ace migration:run", ...] }
14
+
15
+ A pattern matches a command segment when the segment *contains* the pattern
16
+ (after normalizing whitespace). `deny` wins over `ask`. If the config is missing
17
+ or unreadable, the hook stays silent (exit 0) and lets settings.json decide.
18
+
19
+ Protocol: reads the PreToolUse payload on stdin; emits a JSON permissionDecision
20
+ of "deny" or "ask" on a match; otherwise exits 0 silently.
21
+ """
22
+
23
+ import json
24
+ import os
25
+ import re
26
+ import subprocess
27
+ import sys
28
+
29
+ SPLIT = re.compile(r"&&|\|\||[;|\n]")
30
+ WS = re.compile(r"\s+")
31
+
32
+
33
+ def load_config() -> dict:
34
+ root = os.environ.get("CLAUDE_PROJECT_DIR", ".")
35
+ path = os.path.join(root, ".claude", "gate-config.json")
36
+ empty = {"deny": [], "ask": [], "ask_on_default_branch": [], "default_branch": "main"}
37
+ try:
38
+ with open(path, "r", encoding="utf-8") as fh:
39
+ cfg = json.load(fh)
40
+ except Exception:
41
+ return empty
42
+ return {
43
+ "deny": list(cfg.get("deny", [])),
44
+ "ask": list(cfg.get("ask", [])),
45
+ # Patterns gated ONLY on the default branch — allowed freely on feature branches.
46
+ "ask_on_default_branch": list(cfg.get("ask_on_default_branch", [])),
47
+ "default_branch": cfg.get("default_branch", "main") or "main",
48
+ }
49
+
50
+
51
+ def norm(s: str) -> str:
52
+ return WS.sub(" ", s.strip())
53
+
54
+
55
+ def current_branch():
56
+ """The checked-out branch of CLAUDE_PROJECT_DIR, or None (not a repo / detached / git absent)."""
57
+ root = os.environ.get("CLAUDE_PROJECT_DIR", ".")
58
+ try:
59
+ out = subprocess.run(
60
+ ["git", "rev-parse", "--abbrev-ref", "HEAD"],
61
+ cwd=root, capture_output=True, text=True, timeout=3,
62
+ )
63
+ if out.returncode == 0:
64
+ return out.stdout.strip() or None
65
+ except Exception:
66
+ pass
67
+ return None
68
+
69
+
70
+ def main() -> int:
71
+ try:
72
+ payload = json.load(sys.stdin)
73
+ except Exception:
74
+ return 0 # malformed input → don't block
75
+
76
+ if payload.get("tool_name") != "Bash":
77
+ return 0
78
+
79
+ command = (payload.get("tool_input") or {}).get("command", "") or ""
80
+ cfg = load_config()
81
+ deny, ask, branch_gated = cfg["deny"], cfg["ask"], cfg["ask_on_default_branch"]
82
+ default = cfg["default_branch"]
83
+ if not deny and not ask and not branch_gated:
84
+ return 0
85
+
86
+ # Branch-conditional patterns (e.g. git/docker) are gated only on the default branch;
87
+ # on a feature branch they run freely. Unknown branch (no repo / detached / no git) ⇒
88
+ # be conservative and gate. Resolve the branch once, lazily.
89
+ on_default = False
90
+ if branch_gated:
91
+ branch = current_branch()
92
+ on_default = branch is None or branch == default
93
+
94
+ for raw in SPLIT.split(command):
95
+ seg = norm(raw)
96
+ if not seg:
97
+ continue
98
+ for pat in deny:
99
+ if norm(pat) in seg:
100
+ return decide("deny", f"`{pat}` is forbidden by the project's PIPELINE.md gate.")
101
+ for pat in ask:
102
+ if norm(pat) in seg:
103
+ return decide("ask", f"`{pat}` is a gated command — confirm first (PIPELINE.md gate).")
104
+ if on_default:
105
+ for pat in branch_gated:
106
+ if norm(pat) in seg:
107
+ return decide("ask", f"`{pat}` is gated on the default branch `{default}` — confirm "
108
+ f"(PIPELINE.md gate). It runs freely on feature branches.")
109
+
110
+ return 0
111
+
112
+
113
+ def decide(decision: str, reason: str) -> int:
114
+ print(
115
+ json.dumps(
116
+ {
117
+ "hookSpecificOutput": {
118
+ "hookEventName": "PreToolUse",
119
+ "permissionDecision": decision,
120
+ "permissionDecisionReason": reason,
121
+ }
122
+ }
123
+ )
124
+ )
125
+ return 0
126
+
127
+
128
+ if __name__ == "__main__":
129
+ sys.exit(main())
@@ -0,0 +1,34 @@
1
+ # HANDOFF — <surface> · `<feature_id>`
2
+
3
+ Branch: <feature_branch_prefix><feature_id>
4
+ Commit/diff base: <default_branch...HEAD or "uncommitted working tree">
5
+
6
+ ## Summary
7
+
8
+ <2–4 lines: what you built and the approach>
9
+
10
+ ## Files touched
11
+
12
+ - `path/to/file` — <what & why>
13
+
14
+ ## Migrations / schema (if any)
15
+
16
+ - `<name>` — <additive change> · run with <PIPELINE.md commands.migrate>
17
+
18
+ ## Tests
19
+
20
+ - Added: <test files>
21
+ - Run: <this surface's test_cmd> · result: <pass/fail + counts>
22
+
23
+ ## Contract adherence
24
+
25
+ - [ ] Implemented exactly to the frozen contract (`<contract.path>/<feature_id>.<ext>`)
26
+ - Mismatches / assumptions: <none, or describe — DO NOT edit the contract; report instead>
27
+
28
+ ## Remediation addressed (fix loops only)
29
+
30
+ - <which `## Remediation` items you fixed, by file:line>
31
+
32
+ ## TODO / not done
33
+
34
+ - <anything deferred, blocked, or out of scope>
@@ -0,0 +1,36 @@
1
+ # BRAINSTORM RETURN — <feature title>
2
+
3
+ > Paste this into `/spec`.
4
+
5
+ **One-liner:** <what we're building, in one sentence>
6
+
7
+ ## Problem & value
8
+
9
+ <the problem, who has it, why it matters>
10
+
11
+ ## Scope
12
+
13
+ - **In:** <…>
14
+ - **Out (non-goals):** <…>
15
+
16
+ ## Roles affected
17
+
18
+ > Only if the profile has `rbac.enabled` — list the roles from `PIPELINE.md` §rbac and what each does;
19
+ > explicitly note the lowest-privilege experience. Omit this section if there is no RBAC.
20
+
21
+ <which roles do what>
22
+
23
+ ## Rough shape
24
+
25
+ - **Data:** <entities / fields touched>
26
+ - **Screens:** <key screens/flows — mobile-first if the project has UI>
27
+ - **Interface (rough):** <endpoints / methods we'll need — refined into the contract in /spec>
28
+
29
+ ## Risks & open questions
30
+
31
+ - <risk / unknown>
32
+ - <open question for /spec to resolve>
33
+
34
+ ## Panel dissent (what was contested)
35
+
36
+ <the strongest disagreement the panel surfaced — so /spec doesn't paper over it>
@@ -0,0 +1,35 @@
1
+ # DESIGN BRIEF — <feature title> (`<feature_id>`)
2
+
3
+ > The "spec return". Paste into the design tool (see `PIPELINE.md` §design). This is §8 of the frozen
4
+ > spec, standalone — `/spec` writes it to `specs/design/<feature_id>.md` on freeze. Omit entirely if
5
+ > the project has no UI.
6
+
7
+ **Goal:** <one line — what the user accomplishes>
8
+
9
+ **Design system:** use the existing UI kit (`PIPELINE.md` §design → `ui_kit_path`). Mobile-first.
10
+
11
+ ## Screens / views
12
+
13
+ For each: purpose, who sees it (role, if RBAC), and the key elements.
14
+
15
+ - **<screen name>** — <purpose> · roles: <…>
16
+ - Elements: <…>
17
+ - States: empty · loading · error · success
18
+
19
+ ## Flows
20
+
21
+ <step-by-step of the main user journey, and any role-specific variation>
22
+
23
+ ## Responsive
24
+
25
+ - Mobile (base): <layout>
26
+ - Tablet (`md:`): <changes>
27
+ - Desktop (`lg:`): <changes>
28
+
29
+ ## Data shown
30
+
31
+ <what fields/values appear on screen — must match the contract in spec §5>
32
+
33
+ ## Notes / constraints
34
+
35
+ <accessibility · copy in the profile's `ui_language` · edge cases · theming constraints>
@@ -0,0 +1,29 @@
1
+ ## <type>(<scope>): <feature title>
2
+
3
+ **feature_id:** `<feature_id>` · closes/relates: <issue if any>
4
+
5
+ ### What & why
6
+
7
+ <2–4 lines: what this ships and the value, from the spec goal>
8
+
9
+ ### Contract
10
+
11
+ <the interface + contract types added/changed — from spec §5 (omit if contract.enabled is false)>
12
+
13
+ ### Changes
14
+
15
+ > One bullet per surface (from `PIPELINE.md` §surfaces), plus the shared contract.
16
+
17
+ - **<surface.key>:** <what changed>
18
+ - **Shared:** `<contract.path>/<feature_id>.<ext>`
19
+
20
+ ### Tests
21
+
22
+ - <per surface: test runner · coverage>
23
+ - <PIPELINE.md commands.lint · typecheck · test> — green
24
+
25
+ ### Review
26
+
27
+ Verdict: **SHIP** · remediation rounds: <n>
28
+
29
+ 🤖 Generated with [Claude Code](https://claude.com/claude-code)