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.
Files changed (211) hide show
  1. package/README.md +7 -0
  2. package/assets/manifest.json +193 -0
  3. package/assets/migrations/config/README.md +12 -0
  4. package/assets/migrations/state/0001_init.sql +154 -0
  5. package/assets/prompts/README.md +11 -0
  6. package/assets/prompts/agents/fixer.md +7 -0
  7. package/assets/prompts/agents/implementer.md +12 -0
  8. package/assets/prompts/agents/reviewer.md +8 -0
  9. package/assets/prompts/agents/security-reviewer.md +7 -0
  10. package/assets/prompts/phases/build.md +5 -0
  11. package/assets/prompts/phases/review.md +5 -0
  12. package/assets/prompts/phases/test.md +5 -0
  13. package/assets/prompts/system.md +11 -0
  14. package/assets/schemas/agent-output.schema.json +225 -0
  15. package/assets/schemas/auth-status.schema.json +87 -0
  16. package/assets/schemas/command-result.schema.json +192 -0
  17. package/assets/schemas/commands.schema.json +952 -0
  18. package/assets/schemas/config.schema.json +2259 -0
  19. package/assets/schemas/doctor-report.schema.json +104 -0
  20. package/assets/schemas/events.schema.json +8514 -0
  21. package/assets/schemas/fake-script.schema.json +549 -0
  22. package/assets/schemas/inspect.schema.json +3133 -0
  23. package/assets/schemas/manifest.schema.json +79 -0
  24. package/assets/schemas/ownership.schema.json +52 -0
  25. package/assets/schemas/policy-verdict.schema.json +282 -0
  26. package/assets/schemas/project-model.schema.json +783 -0
  27. package/assets/schemas/project-status.schema.json +217 -0
  28. package/assets/schemas/reconcile-plan.schema.json +155 -0
  29. package/assets/schemas/run-diff.schema.json +177 -0
  30. package/assets/schemas/run-snapshot-manifest.schema.json +2104 -0
  31. package/assets/schemas/run-state.schema.json +1755 -0
  32. package/assets/schemas/runtime-capabilities.schema.json +1545 -0
  33. package/assets/schemas/sandbox-capabilities.schema.json +116 -0
  34. package/assets/schemas/skill.schema.json +87 -0
  35. package/assets/schemas/spec.schema.json +202 -0
  36. package/assets/schemas/tool-catalogue.schema.json +655 -0
  37. package/assets/schemas/trust-record.schema.json +38 -0
  38. package/assets/skills/README.md +9 -0
  39. package/assets/skills/inspect-surface.md +4 -0
  40. package/dist/agent-host.mjs +50 -0
  41. package/dist/agent-host.mjs.map +1 -0
  42. package/dist/bundle-manifest.json +102 -0
  43. package/dist/chunks/__host-DgGPyco9.mjs +18 -0
  44. package/dist/chunks/__host-DgGPyco9.mjs.map +1 -0
  45. package/dist/chunks/approve-Cv135UqI.mjs +19 -0
  46. package/dist/chunks/approve-Cv135UqI.mjs.map +1 -0
  47. package/dist/chunks/auth-BT5oVp76.mjs +132 -0
  48. package/dist/chunks/auth-BT5oVp76.mjs.map +1 -0
  49. package/dist/chunks/auth-D8rCVY33.mjs +84 -0
  50. package/dist/chunks/auth-D8rCVY33.mjs.map +1 -0
  51. package/dist/chunks/brainstorm-CU10T1tm.mjs +7 -0
  52. package/dist/chunks/brainstorm-CU10T1tm.mjs.map +1 -0
  53. package/dist/chunks/cancel-KV_cpsqS.mjs +15 -0
  54. package/dist/chunks/cancel-KV_cpsqS.mjs.map +1 -0
  55. package/dist/chunks/canonical-C8UxeEmB.mjs +57 -0
  56. package/dist/chunks/canonical-C8UxeEmB.mjs.map +1 -0
  57. package/dist/chunks/catalogue-BvwSrM_j.mjs +1549 -0
  58. package/dist/chunks/catalogue-BvwSrM_j.mjs.map +1 -0
  59. package/dist/chunks/compose-Cr0hP0qm.mjs +7303 -0
  60. package/dist/chunks/compose-Cr0hP0qm.mjs.map +1 -0
  61. package/dist/chunks/config-DefHA2Lw.mjs +96 -0
  62. package/dist/chunks/config-DefHA2Lw.mjs.map +1 -0
  63. package/dist/chunks/contract-B0ra2-bm.mjs +295 -0
  64. package/dist/chunks/contract-B0ra2-bm.mjs.map +1 -0
  65. package/dist/chunks/contract-vYbwYr0Y.mjs +123 -0
  66. package/dist/chunks/contract-vYbwYr0Y.mjs.map +1 -0
  67. package/dist/chunks/deny-ClTxSvHJ.mjs +15 -0
  68. package/dist/chunks/deny-ClTxSvHJ.mjs.map +1 -0
  69. package/dist/chunks/diff-Qw0II0sj.mjs +101 -0
  70. package/dist/chunks/diff-Qw0II0sj.mjs.map +1 -0
  71. package/dist/chunks/discover-30Ciya_0.mjs +20 -0
  72. package/dist/chunks/discover-30Ciya_0.mjs.map +1 -0
  73. package/dist/chunks/doctor-DfCrKpfT.mjs +222 -0
  74. package/dist/chunks/doctor-DfCrKpfT.mjs.map +1 -0
  75. package/dist/chunks/fix-D4Tj8RVA.mjs +18 -0
  76. package/dist/chunks/fix-D4Tj8RVA.mjs.map +1 -0
  77. package/dist/chunks/gc-BBXlBF5w.mjs +161 -0
  78. package/dist/chunks/gc-BBXlBF5w.mjs.map +1 -0
  79. package/dist/chunks/init-Okz4mlhW.mjs +30 -0
  80. package/dist/chunks/init-Okz4mlhW.mjs.map +1 -0
  81. package/dist/chunks/inspect-Buby4cQD.mjs +22 -0
  82. package/dist/chunks/inspect-Buby4cQD.mjs.map +1 -0
  83. package/dist/chunks/logs-Giq5sUau.mjs +25 -0
  84. package/dist/chunks/logs-Giq5sUau.mjs.map +1 -0
  85. package/dist/chunks/migrate-DRoFUg53.mjs +19 -0
  86. package/dist/chunks/migrate-DRoFUg53.mjs.map +1 -0
  87. package/dist/chunks/models-Btp6X2YZ.mjs +24 -0
  88. package/dist/chunks/models-Btp6X2YZ.mjs.map +1 -0
  89. package/dist/chunks/pause-BASBfKLO.mjs +16 -0
  90. package/dist/chunks/pause-BASBfKLO.mjs.map +1 -0
  91. package/dist/chunks/policy-DUIgzF3W.mjs +139 -0
  92. package/dist/chunks/policy-DUIgzF3W.mjs.map +1 -0
  93. package/dist/chunks/providers-Dx78imKj.mjs +19 -0
  94. package/dist/chunks/providers-Dx78imKj.mjs.map +1 -0
  95. package/dist/chunks/reconcile-BfD785gd.mjs +26 -0
  96. package/dist/chunks/reconcile-BfD785gd.mjs.map +1 -0
  97. package/dist/chunks/render-DyZr5Lgi.mjs +53 -0
  98. package/dist/chunks/render-DyZr5Lgi.mjs.map +1 -0
  99. package/dist/chunks/resume-GJQRb2Eb.mjs +15 -0
  100. package/dist/chunks/resume-GJQRb2Eb.mjs.map +1 -0
  101. package/dist/chunks/retry-CLrUem1H.mjs +15 -0
  102. package/dist/chunks/retry-CLrUem1H.mjs.map +1 -0
  103. package/dist/chunks/review-BDdjb6kB.mjs +17 -0
  104. package/dist/chunks/review-BDdjb6kB.mjs.map +1 -0
  105. package/dist/chunks/run-CgTWYlcd.mjs +82 -0
  106. package/dist/chunks/run-CgTWYlcd.mjs.map +1 -0
  107. package/dist/chunks/run-tool-C3rAv4XF.mjs +26 -0
  108. package/dist/chunks/run-tool-C3rAv4XF.mjs.map +1 -0
  109. package/dist/chunks/schema-C9QbUW4H.mjs +578 -0
  110. package/dist/chunks/schema-C9QbUW4H.mjs.map +1 -0
  111. package/dist/chunks/send-BdnJ85Nz.mjs +19 -0
  112. package/dist/chunks/send-BdnJ85Nz.mjs.map +1 -0
  113. package/dist/chunks/ship-DTuLGoaJ.mjs +19 -0
  114. package/dist/chunks/ship-DTuLGoaJ.mjs.map +1 -0
  115. package/dist/chunks/shutdown-BM92Iyv2.mjs +15 -0
  116. package/dist/chunks/shutdown-BM92Iyv2.mjs.map +1 -0
  117. package/dist/chunks/skip-DZG5kpcH.mjs +18 -0
  118. package/dist/chunks/skip-DZG5kpcH.mjs.map +1 -0
  119. package/dist/chunks/spec-Bq0P3jVh.mjs +20 -0
  120. package/dist/chunks/spec-Bq0P3jVh.mjs.map +1 -0
  121. package/dist/chunks/src-CId6kMsY.mjs +1689 -0
  122. package/dist/chunks/src-CId6kMsY.mjs.map +1 -0
  123. package/dist/chunks/src-CfAOde7C.mjs +5403 -0
  124. package/dist/chunks/src-CfAOde7C.mjs.map +1 -0
  125. package/dist/chunks/src-Cu3TxNob.mjs +783 -0
  126. package/dist/chunks/src-Cu3TxNob.mjs.map +1 -0
  127. package/dist/chunks/src-DcU4IXMe.mjs +117 -0
  128. package/dist/chunks/src-DcU4IXMe.mjs.map +1 -0
  129. package/dist/chunks/src-JxawBQBn.mjs +446 -0
  130. package/dist/chunks/src-JxawBQBn.mjs.map +1 -0
  131. package/dist/chunks/src-s7YRvk0t.mjs +2116 -0
  132. package/dist/chunks/src-s7YRvk0t.mjs.map +1 -0
  133. package/dist/chunks/status-SMjiOMYy.mjs +29 -0
  134. package/dist/chunks/status-SMjiOMYy.mjs.map +1 -0
  135. package/dist/chunks/tail-BuhT-2PH.mjs +25 -0
  136. package/dist/chunks/tail-BuhT-2PH.mjs.map +1 -0
  137. package/dist/chunks/update-BXIppsbi.mjs +16 -0
  138. package/dist/chunks/update-BXIppsbi.mjs.map +1 -0
  139. package/dist/cli.mjs +175 -0
  140. package/dist/cli.mjs.map +1 -0
  141. package/package.json +17 -32
  142. package/CHANGELOG.md +0 -1453
  143. package/bin/cli.js +0 -812
  144. package/bin/report.js +0 -141
  145. package/core/adapter/render.js +0 -389
  146. package/core/agents/implementer.template.md +0 -142
  147. package/core/agents/profile-reader.md +0 -50
  148. package/core/agents/release.md +0 -58
  149. package/core/agents/review.md +0 -179
  150. package/core/commands/cohorte-align-ds.md +0 -33
  151. package/core/commands/cohorte-audit.md +0 -58
  152. package/core/commands/cohorte-brainstorm.md +0 -70
  153. package/core/commands/cohorte-build.md +0 -219
  154. package/core/commands/cohorte-doctor.md +0 -170
  155. package/core/commands/cohorte-fix.md +0 -80
  156. package/core/commands/cohorte-fleet.md +0 -103
  157. package/core/commands/cohorte-init-pipeline.md +0 -31
  158. package/core/commands/cohorte-intake.md +0 -92
  159. package/core/commands/cohorte-patch.md +0 -118
  160. package/core/commands/cohorte-refactor.md +0 -59
  161. package/core/commands/cohorte-retro.md +0 -85
  162. package/core/commands/cohorte-review.md +0 -270
  163. package/core/commands/cohorte-ship.md +0 -122
  164. package/core/commands/cohorte-spec.md +0 -101
  165. package/core/commands/cohorte-update-pipeline.md +0 -134
  166. package/core/hooks/gate.py +0 -580
  167. package/core/runtimes/claude.json +0 -74
  168. package/core/runtimes/codex.json +0 -83
  169. package/core/runtimes/cursor.json +0 -76
  170. package/core/runtimes/gemini.json +0 -76
  171. package/core/runtimes/opencode.json +0 -73
  172. package/core/templates/agent-handoff.md +0 -34
  173. package/core/templates/brainstorm-return.md +0 -36
  174. package/core/templates/decisions.template.md +0 -42
  175. package/core/templates/design-brief.md +0 -44
  176. package/core/templates/patch.template.md +0 -86
  177. package/core/templates/pr-body.md +0 -25
  178. package/core/templates/review-feedback.md +0 -38
  179. package/core/templates/spec.template.md +0 -87
  180. package/core/templates/steps/init-pipeline/01-detect-stack.md +0 -44
  181. package/core/templates/steps/init-pipeline/02-interview-gaps.md +0 -55
  182. package/core/templates/steps/init-pipeline/03-draft-profile.md +0 -10
  183. package/core/templates/steps/init-pipeline/04-write-render.md +0 -115
  184. package/core/templates/steps/init-pipeline/05-report.md +0 -12
  185. package/core/workflows/audit.js +0 -240
  186. package/core/workflows/loop.js +0 -641
  187. package/core/workflows/refactor.js +0 -276
  188. package/core/workflows/review.js +0 -456
  189. package/install.ps1 +0 -103
  190. package/install.sh +0 -114
  191. package/lib/doctor.js +0 -504
  192. package/lib/runtime.js +0 -134
  193. package/lib/versions.js +0 -149
  194. package/lib/yaml.js +0 -129
  195. package/profile/PIPELINE.template.md +0 -251
  196. package/profile/SCHEMA.md +0 -698
  197. package/profile/cohorte.config.template.yaml +0 -43
  198. package/scripts/assert-gate-hook.mjs +0 -75
  199. package/scripts/kanban-move.sh +0 -313
  200. package/scripts/metrics/collect.mjs +0 -531
  201. package/scripts/metrics/prices.json +0 -42
  202. package/scripts/new-feature.sh.template +0 -98
  203. package/scripts/preflight.sh +0 -124
  204. package/scripts/remove-feature.sh.template +0 -56
  205. package/scripts/test-adapter.mjs +0 -368
  206. package/scripts/test-gate.mjs +0 -428
  207. package/scripts/test-kanban.mjs +0 -304
  208. package/scripts/test-lib.mjs +0 -310
  209. package/scripts/test-metrics.mjs +0 -156
  210. package/scripts/test-workflows.mjs +0 -758
  211. package/scripts/validate-core.mjs +0 -320
@@ -1,87 +0,0 @@
1
- ---
2
- feature_id: <slug>
3
- title: <Feature title>
4
- status: draft # draft → frozen → in-progress → in-review → shipped · blocked (see SCHEMA.md §Spec status)
5
- branch: <feature_branch_prefix><slug>
6
- created: <YYYY-MM-DD>
7
- reviewed_base: # merge-base sha at the last SHIP verdict — freshness-gate anchor (written by /cohorte-review)
8
- reviewed_digest: # sha256 (16 hex) of the reviewed source diff vs reviewed_base, specs excluded — /cohorte-ship re-checks
9
- design_files: [] # design page links — full URLs of the form https://claude.ai/design/p/<projectId>?file=<file> (each carries its own project + page); blank until designed; omit if no UI
10
- ---
11
-
12
- # <Feature title>
13
-
14
- ## 1. Goal & user story
15
-
16
- <one paragraph: what · who · why>
17
-
18
- ## 2. Scope
19
-
20
- **In:** …
21
- **Out (non-goals):** …
22
-
23
- ## 3. Roles & permissions
24
-
25
- > Only if `PIPELINE.md` §rbac is enabled — which roles can do what; note the lowest-privilege experience.
26
-
27
- ## 4. Data model & migrations
28
-
29
- > Additive only (never gate.deny commands). Omit if the feature has no persistence.
30
-
31
- | table | column | type | null? | default | notes |
32
- | ----- | ------ | ---- | ----- | ------- | ----- |
33
- | | | | | | |
34
-
35
- ## 5. CONTRACT (frozen)
36
-
37
- > The only sync channel. Complete enough to build every surface independently. Uses the profile's
38
- > `contract.mechanism`. If `contract.enabled` is false, capture the interface precisely in prose here.
39
-
40
- ### `<METHOD> /<path>` · auth: `<middleware/role>`
41
-
42
- - **Request** — params / query / body: `field` · type · required? · nullable? · validation
43
- - **Success** — `<status>` · response shape
44
- - **Errors** — `<status>` · when (422 validation · 401 · 403 · 404 · 409 …)
45
-
46
- <repeat per endpoint/interface>
47
-
48
- ### Contract types — lead authors `<contract.path>/<slug>.<ext>` before /cohorte-build
49
-
50
- - `<slug>...Request` / `<slug>...Response` / `<slug>Base` … (sketch the schemas here)
51
-
52
- ## 6. Surface tasks
53
-
54
- > One `###` subsection per surface in `PIPELINE.md` §surfaces (e.g. backend, frontend), each TDD.
55
- > Surfaces are subsections of §6, never top-level sections — §8 and §9 are referenced by number
56
- > across the whole pipeline (`/cohorte-build` implements "§8 flows", `/cohorte-review` checks "§9 acceptance"), so a
57
- > third surface must not become a §8 of its own.
58
-
59
- ### <surface.key>
60
-
61
- - …
62
-
63
- ## 8. Design brief (the "spec return")
64
-
65
- > Only if the project has UI. Standalone; mirrors `<core>/templates/design-brief.md`.
66
-
67
- - **Screens / views:** …
68
- - **Flows:** …
69
- - **Responsive:** mobile (base) → `md:` → `lg:`
70
- - **States:** empty · loading · error · success
71
-
72
- ## 9. Acceptance criteria / DoD
73
-
74
- - [ ] Every contract endpoint/interface implemented exactly
75
- - [ ] Each surface's tests (TDD) green
76
- - [ ] `PIPELINE.md` commands.lint · typecheck · test green
77
- - [ ] Mobile-first / responsive verified (if UI)
78
- - [ ] User-facing copy in `ui_language`
79
-
80
- ## 10. Assumptions & open questions
81
-
82
- - …
83
-
84
- ## Remediation
85
-
86
- > Filled by `/cohorte-spec` in review-return mode; empty otherwise. Each item:
87
- > `[ ] <SEVERITY> · <file:line> · <spec-violation|quality|security> · <concrete fix>`
@@ -1,44 +0,0 @@
1
- # /cohorte-init-pipeline · 01 Detect the stack
2
-
3
- ### Phase 1 — Detect the stack (read-only, no questions yet)
4
-
5
- Gather evidence, then summarize what you found. Look for:
6
-
7
- - **Package manager & workspaces:** root `package.json` (`packageManager`, `workspaces`),
8
- `pnpm-workspace.yaml`, `turbo.json`, `nx.json`, `lerna.json`; lockfiles (`pnpm-lock.yaml`,
9
- `package-lock.json`, `yarn.lock`, `bun.lockb`); or non-JS: `pyproject.toml`/`requirements.txt`,
10
- `go.mod`, `Cargo.toml`, `Gemfile`, `composer.json`.
11
- - **Surfaces (independently-built areas):** `apps/*`, `packages/*`, `services/*`, `cmd/*`, or a single
12
- root app. For each, detect its framework from its own `package.json`/config:
13
- backend markers (`adonisrc.ts`, `@adonisjs/*`, `nestjs`, `express`, `fastify`, `django`, `fastapi`,
14
- `rails`, `.go`), frontend markers (`vite.config.*`, `next.config.*`, `@tanstack/react-router`,
15
- `angular.json`, `nuxt`, `svelte`), and its test runner (`@japa/*`, `vitest`, `jest`, `playwright`,
16
- `pytest`, `go test`), linter/formatter (`eslint`, `prettier`, `biome`, `ruff`).
17
- - **Split candidates (sub-surface boundaries):** inside each surface, look for a clean internal partition
18
- — feature modules (`src/features/*`, `src/modules/*`, `app/(group)/*`), or independent services
19
- (`services/*`, domain folders). Note the surface's rough size (module/file count) so a *large* surface
20
- with a *clean* boundary can be proposed as several specialized surfaces in Phase 2. See SCHEMA.md
21
- §"Specialization — when to split one surface into more agents" for the heuristic. Don't split yet — just
22
- flag candidates + their would-be shared-code tree.
23
- - **Per-surface commands:** derive `test`/`lint`/`format`/`typecheck`/`build` from each surface's
24
- `package.json` scripts + the workspace filter syntax (e.g. `pnpm --filter <pkg> test`).
25
- - **Contract mechanism:** a shared types/schema package (`packages/shared-types`, Zod/`z.`),
26
- an `openapi.*`/`swagger.*` file, `.proto` files, or none.
27
- - **Release notes / versioning:** a `.changeset/` directory (+ `config.json`, and whether it declares a
28
- `fixed`/lockstep group — that names the anchor package), `changesets` in devDependencies, or a CI job
29
- that fails a PR lacking a note (grep `.github/workflows/*` for `changeset`). Also note the root
30
- `version`: a `0.y.z` product usually forbids `major`. None of these ⇒ `release_notes.enabled: false`.
31
- - **DB / migrations:** migration tooling (`node ace make:migration`, `knex`, `prisma`, `alembic`,
32
- `golang-migrate`), a `docker-compose.yml`, DB service.
33
- - **Design system:** an existing `design-reference/` snapshot, `components/ui`, a DesignSync MCP
34
- connection, Figma links, or none.
35
- - **Code retrieval:** is the `serena` CLI resolvable (`command -v serena`)? If not, does
36
- `~/.local/bin/serena` exist anyway — installed but PATH-broken (see SCHEMA.md §Code retrieval)?
37
- `graphify`? Is either already registered in this repo's `.mcp.json` or `claude mcp list`? (Feeds
38
- the retrieval question + Phase 4 wiring — default provider is `serena`.)
39
- - **VCS:** `git remote -v` → host + `owner/repo`; the default branch (`git symbolic-ref refs/remotes/origin/HEAD` or `git branch`).
40
- - **Existing `<memory>`** — read it; it may already state stack/conventions to fold in. **Existing
41
- `PIPELINE.md`** — if present, this is a re-run: load it as the starting draft and only reconcile deltas.
42
-
43
- Print a compact **Detection Report**: layout, surfaces (with framework + commands), contract, release
44
- notes, DB, design, vcs. Mark each field `detected` / `guessed` / `unknown`.
@@ -1,55 +0,0 @@
1
- # /cohorte-init-pipeline · 02 Interview the gaps
2
-
3
- ### Phase 2 — Interview the gaps (AskUserQuestion)
4
-
5
- Ask ONLY what you couldn't confidently detect. Batch related questions. Cover:
6
-
7
- - **Surfaces & ownership** — confirm the surface list and each one's path + owning agent name. (If a
8
- single-app repo, one surface.) Confirm the `tools` each agent needs (add `DesignSync` only to a
9
- surface with `uses_design: true`), and each surface's `model` tier: `sonnet` (Recommended default —
10
- implementers mostly apply a frozen contract, which Sonnet handles at a fraction of the Opus-lead
11
- cost), `haiku` for purely mechanical surfaces (scaffolding), `inherit` only for surfaces with real
12
- design decisions worth running on the lead's model.
13
- - **Specialization (only if Phase 1 flagged a large + cleanly-separable surface)** — offer to split it
14
- into specialized sub-surfaces (e.g. `web-checkout`, `web-billing`) so `/cohorte-build` runs them in parallel,
15
- per SCHEMA.md §Specialization. If the human accepts, apply the rules: **shared code (routing, global
16
- state, DS kit/tokens) becomes its own single-owner surface**, and cross-slice shapes go through the
17
- contract. Default to NOT splitting when boundaries are tangled or slices are tiny — coarse is fine.
18
- - **Quiet commands** (never store a bare `pnpm test` as what agents execute) — for each noisy command
19
- (tests, lint; per surface AND repo-wide), propose the detected **bridled variant** as the
20
- Recommended option: dot/failures-only reporter (`--reporter=dot` vitest/playwright, `--silent`
21
- jest, `-q` pytest, `--quiet` eslint/ruff — whatever the detected runner supports). These land in
22
- `test_quiet_cmd`/`lint_quiet_cmd` + `commands.test_quiet`/`lint_quiet` and are what agents and the
23
- `/cohorte-review` pre-flight actually run (SCHEMA.md §Output discipline). If the human declines or
24
- the runner has no such flag, leave `""` — consumers then fall back to `<cmd> 2>&1 | tail -40`.
25
- - **Contract** — mechanism (`shared-types-zod` / `openapi` / `protobuf` / `json-schema` / `none`) and
26
- where feature contracts are authored. If `none`, surfaces sync by the spec prose alone.
27
- - **Release notes (only if Phase 1 found a versioning tool or a note-enforcing CI job)** — confirm the
28
- anchor package (a `fixed`/lockstep group means ONE key propagates to all), the note's language, and the
29
- **bump policy** the lead will apply at `/cohorte-ship`: what counts as major/minor/patch here, and
30
- whether any level is forbidden (a `0.y.z` product normally forbids `major` — Changesets would jump it
31
- to `1.0.0` with no human deciding). Policy prose lands in `release_notes.guidance`. Nothing detected ⇒
32
- don't ask; leave `release_notes.enabled: false`.
33
- - **UI language** — language of all user-facing copy.
34
- - **RBAC** — is there a role hierarchy? If yes, list it highest→lowest.
35
- - **Design system** — enabled? provider (Claude Design / Figma / none) + project ids + kit/token paths.
36
- - **Code retrieval** — confirm the provider (see SCHEMA.md §Code retrieval): `serena` (Recommended
37
- default — live LSP symbol navigation, no index to maintain), `graphify` (persistent knowledge graph
38
- over code + docs — better on very large or mixed code+docs repos, but needs an index step + rescans),
39
- or `none`. Only demote from `serena` if the human objects or the provider CLI can't be installed.
40
- - **Isolation** — build features in parallel git worktrees with per-feature DB + ports, or just in the
41
- main checkout? If worktrees: DB-per-worktree? port bases? compose file?
42
- - **Gate** — confirm the destructive commands to hard-deny and the ones to confirm-first (seed from the
43
- detected DB/migration tooling + always git commit/push/merge/rebase/reset).
44
- - **Personas** — keep the default `/cohorte-brainstorm` panel, or customize members for this domain?
45
-
46
- Prefer sensible defaults from Phase 1 as the first (Recommended) option in each question.
47
-
48
- - **Kanban** (optional) — mirror this project's pipeline (`/cohorte-brainstorm`…`/cohorte-ship`) onto an Obsidian
49
- Kanban board? If the human says yes: confirm the shared vault path (`obsidian.vault_path` in
50
- `<config>`; ask if empty) and the board's location inside it (default
51
- `<ProjectName>/Tasks.md`). Phase 4 creates the board and records the link. Default: no.
52
-
53
- > The **kanban** link is user-scoped (it points at a personal vault, so it never goes in the committed
54
- > `PIPELINE.md`), but IS wired here because it is per-project — see Phase 4.
55
-
@@ -1,10 +0,0 @@
1
- # /cohorte-init-pipeline · 03 Draft the profile
2
-
3
- ### Phase 3 — Draft the profile (show, don't write yet)
4
-
5
- Assemble the full `PIPELINE.md` from the installer's `pipeline/PIPELINE.template.md` (resolve
6
- bundled-vs-global per the note above), filling the `yaml pipeline-profile`
7
- block and every prose section from Phases 1–2. **Keep it lean**: every stateless agent re-reads this
8
- file on every dispatch, so its length is a per-dispatch token+latency tax — terse rule-shaped
9
- conventions, no narration, no facts derivable from the code. **Show the human the drafted
10
- `PIPELINE.md` in a fenced block and get a go-ahead** before writing.
@@ -1,115 +0,0 @@
1
- # /cohorte-init-pipeline · 04 Write & render
2
-
3
- ### Phase 4 — Write & render (after go-ahead)
4
-
5
- 1. **Write `PIPELINE.md`** at the repo root (source: the installer's `pipeline/PIPELINE.template.md`).
6
- 2. **Wire it into `<memory>`:** if `<memory>` exists, ensure it references the profile (add a line
7
- near the top: `> Project profile & pipeline facts: **@PIPELINE.md**`). If not, create a minimal
8
- `<memory>` with that reference + a one-paragraph project intro.
9
- 3. **Render one agent per surface** — for each surface, follow SCHEMA.md §"Rendering / reconciling a
10
- surface agent" (steps 2–3): render `<agents>/<agent>.md` from the installer's
11
- `pipeline/implementer.template.md`, substituting `<SURFACE_AGENT>`, `<SURFACE_LABEL>`, `<SURFACE_PATH>`,
12
- `<SURFACE_TOOLS>`, `<SURFACE_MODEL>`, `<PROJECT_NAME>`, `<SURFACE_CONVENTIONS>` (the surface's
13
- baked convention slice — §Shared + its `### Surface:` stanza + its §Testing lines from the
14
- PIPELINE.md you just wrote), and the surface-specific blocks
15
- (`<SURFACE_EXTRA_NEVER>`, `<SURFACE_DESIGN_INPUT>`, `<SURFACE_TDD_STEP1>` — fill design-related ones
16
- only when `uses_design`).
17
- Leave the fixed agents as-is (generic, shipped by the installer): `review.md`, `release.md`,
18
- `profile-reader.md`.
19
- 4. **Generate `<state>/gate-config.json`** from the `gate` block — copy all five keys verbatim:
20
- `{"deny": [...], "ask": [...], "ask_on_default_branch": [...], "default_branch": "<vcs.default_branch>",
21
- "preflight": {"enabled": <gate.preflight.enabled>, "agents": [...], "max_age_minutes": <n>}}`
22
- (profile has no `preflight` block ⇒ omit the key — the hook then skips the phase gate).
23
- <!-- cohorte:if hooks -->
24
- 5. **Write `.claude/settings.json`** permissions (`ask`/`deny` lists mirroring the gate, **plus an
25
- `allow` list of the project's read-only / verification commands** so agents don't stall on
26
- permission prompts — including mid-workflow, where nobody is watching a prompt: the detected
27
- per-surface `test_cmd`/`lint_cmd`/`typecheck_cmd`/`build_cmd` **and their `*_quiet_cmd`
28
- variants** and repo-wide `commands.*` equivalents as `Bash(<cmd>:*)` rules, plus read-only git —
29
- `Bash(git status:*)`, `Bash(git diff:*)`, `Bash(git log:*)`, `Bash(git rev-parse:*)` — plus the
30
- shipped pipeline scripts (`Bash(<core>/pipeline/scripts/:*)` — preflight, kanban-move;
31
- a prefix rule matches a command *starting* with that path, so a `bash <path>`
32
- invocation would need its own entry), and the
33
- retrieval provider's MCP tools when wired (e.g. `mcp__serena`). Never allowlist anything matching
34
- a `gate.ask`/`gate.deny` pattern. Mention the human can widen it later with
35
- `/fewer-permission-prompts`) + the hooks, **conditioned on the install mode:**
36
- - **bundled:** register the PreToolUse hook `<core>/hooks/gate.py` with matcher `Bash|Task`
37
- (Task is required — the preflight phase gate keys off Task dispatches; a `Bash`-only matcher
38
- leaves it dead) and the PostToolUse formatter (detected formatter). Before adding, drop any
39
- existing PreToolUse entry whose command ends in `gate.py` (here AND in `~/.claude/settings.json`
40
- if one points at this repo's copy) — exactly one registration must survive, or every gated
41
- command prompts twice.
42
- - **global:** the PreToolUse gate hook is
43
- already in `~/.claude/settings.json` and reads this repo's `gate-config.json` — do **not** re-register
44
- it here (double-registration double-prompts). It no-ops where its config is absent, so one
45
- registration serves every repo; you only supply this repo's `gate-config.json`. Still write the
46
- PostToolUse formatter hook + the permissions.
47
- Preserve any existing custom keys.
48
- <!-- cohorte:else -->
49
- 5. **No permissions or hook file to write.** This runtime has neither a PreToolUse hook nor a
50
- settings.json permission model the pipeline can generate, so the gate is enforced by the
51
- commands calling `<core>/hooks/gate.py --check` at the points the profile marks gated. That
52
- means `<state>/gate-config.json` (step 4) is not decoration here — it is the ONLY place the
53
- deny/ask patterns live, so fill it from the profile exactly and do not skip it. If this repo is
54
- also driven from Claude Code, that install's hook reads the same file; nothing to duplicate.
55
- <!-- cohorte:endif -->
56
- 6. **Wire the retrieval provider** (skip if `retrieval.provider: none`):
57
- - **serena:** if the `serena` CLI is missing, have the human install it (`uv tool install -p 3.13
58
- serena-agent`) — or set the provider to `none` if they decline, and say `/cohorte-update-pipeline` can wire
59
- it later. If the binary exists (e.g. `~/.local/bin/serena`) but `command -v serena` fails,
60
- recommend the PATH fix (`uv tool update-shell`, or add `~/.local/bin` to the shell profile) for
61
- CLI use. Then register at **project scope** (committed `.mcp.json`, portable —
62
- `--project-from-cwd` resolves the project at server start) using the **PATH-proof launcher**
63
- from SCHEMA.md §Code retrieval (`sh -c 'exec "$(command -v serena || echo
64
- "$HOME/.local/bin/serena")" start-mcp-server …'` — a bare `serena` entry dies with ENOENT when
65
- Claude Code was launched from an environment without `~/.local/bin` on PATH; Windows-native
66
- teams use the bare form + PATH instead). If `.mcp.json` already has a bare `serena` entry,
67
- upgrade it to the launcher form rather than skipping. Add `.serena/` to the repo's `.gitignore`
68
- (per-machine cache/config Serena creates on first launch). On a large repo, offer the one-off
69
- `serena project index`. Finish with the **health check** from SCHEMA.md §Code retrieval and
70
- report each result — if the static checks pass but the server isn't connected in this session,
71
- say a session restart is needed; never report Serena wired on registration alone.
72
- - **graphify:** have the human install it (`uv tool install graphify` then `graphify install`),
73
- build the initial graph (`/graphify .`), and note it needs incremental rescans (`--update`) after
74
- big changes.
75
- - Either way the rendered agents already carry the provider's MCP tools in their `tools:` list
76
- (step 3 / SCHEMA §Rendering); remind the human the new MCP server appears after a session restart.
77
- 7. **Render the isolation scripts** (if `isolation.enabled`) from the installer's
78
- `pipeline/scripts/*.template` to this repo's `scripts/new-feature.sh` and `scripts/remove-feature.sh`,
79
- substituting the `__TOKENS__` (project
80
- slug, DB pattern, port bases, compose file, branch prefix, install/dev/migrate commands, per-surface
81
- env stanzas). `chmod +x` them. If isolation is disabled, skip and note features build in the main checkout.
82
- 8. **Ensure `specs/_template.md`** exists (copy from the installer's `templates/spec.template.md` if missing).
83
- 9. **Write the pointer** `<state>/pipeline.json` (committed — this is how a teammate who clones the repo
84
- knows which core to install):
85
- `{ "pipeline": "cohorte", "mode": "<bundled|global>", "core_version": "<contents of the
86
- installer's pipeline/VERSION>", "install": "<per mode: bundled ⇒ \"npm i -g cohorte && cohorte install\"
87
- note that the core is committed under .claude/; global ⇒ \"npm i -g cohorte && cohorte install --global\"
88
- (or, without npm: curl -fsSL https://raw.githubusercontent.com/TheBidouilleAgency/cohorte/main/install.sh | sh -s -- --global;
89
- Windows: install.ps1 -Global from the same repo)> " }`.
90
- In **global** mode also add, near the top of `<memory>`, a one-liner:
91
- `> Pipeline: global core — run the installer above if /cohorte-brainstorm etc. are missing.`
92
- 10. **CI workflow** (if `vcs.host: github` and no existing workflow already runs the profile's
93
- checks): with the human's go-ahead, generate `.github/workflows/pipeline-ci.yml` — on
94
- `pull_request` to `<default_branch>`: checkout, set up the `package_manager` toolchain,
95
- `commands.install`, then `commands.lint` · `commands.typecheck` · `commands.test` (+ per-surface
96
- `build_cmd`s that are non-empty). Derive the setup steps from the detected stack — mirror what a
97
- sibling workflow does if one exists. `/cohorte-ship` watches these checks before the merge.
98
- 11. **Metrics sink, report buffer & preflight stamp:** add `<state>/pipeline-metrics.jsonl` to
99
- `.gitignore` — `/cohorte-build`, `/cohorte-review` and `/cohorte-fix` append per-dispatch evidence
100
- there (SCHEMA §Specialization reads it).
101
- Also add `specs/reports/` — `/cohorte-review` stages its last report there so a `/cohorte-fix` (or
102
- `/cohorte-spec` Mode B) survives a `/clear`; it's a derived buffer, not a versioned artifact.
103
- And `<state>/preflight.ok` — a local, per-checkout freshness stamp. Versioning it breaks the phase
104
- gate for good (a committed stamp describes the tree *before* its own commit, and it rides into every
105
- new worktree as a green nobody earned). If it is already tracked: `git rm --cached <state>/preflight.ok`.
106
- 12. **Design system:** if `design.enabled` with a snapshot dir, note that `/cohorte-align-ds` is active; else the
107
- `/cohorte-align-ds` command will no-op with a clear message.
108
- 13. **Kanban** (only if the human opted in at Phase 2): wire it per SCHEMA.md §Kanban, writing into the
109
- **global** `<config>` (never into this repo — the board points at a
110
- personal vault). Create the file from `pipeline/cohorte.config.template.yaml` if absent; set
111
- `kanban.enabled: true` and `obsidian.vault_path` if it was empty. Add a `kanban.boards[<PIPELINE
112
- name>]` entry with `board: <folder>/Tasks.md`. Then **create the board file**
113
- `<vault>/<folder>/Tasks.md` (per §Kanban) if it doesn't exist — one column per `kanban.columns`
114
- stage, in pipeline order. Finally run the §Kanban backfill so any spec already in `specs/` lands on
115
- the board. Report the board path + the `obsidian://` URI. Skip silently if the human declined.
@@ -1,12 +0,0 @@
1
- # /cohorte-init-pipeline · 05 Report
2
-
3
- ### Phase 5 — Report
4
-
5
- Print: the install mode (bundled core under `.claude/` vs global core in `~/.claude/` + the committed
6
- `<state>/pipeline.json` pointer), the files written/rendered, the surface→agent mapping, and the
7
- tailored workflow line, e.g.
8
- `/cohorte-brainstorm → /cohorte-spec → (design) → /cohorte-build <id> → test → /cohorte-review → /cohorte-ship`. Tell the human to sanity-check
9
- `PIPELINE.md`, commit it, and run `/cohorte-brainstorm` to start a feature. Note that this was the one-time
10
- setup: from now on `/cohorte-update-pipeline` both refreshes the core AND reconciles the generated files
11
- (SCHEMA.md §Reconcile), and `/cohorte-build` auto-grows surfaces — re-running `/cohorte-init-pipeline` is only for deep
12
- stack changes (package manager, contract mechanism, surface overhaul).
@@ -1,240 +0,0 @@
1
- // cohorte — /cohorte-audit as a deterministic workflow (opt-in; the conversational
2
- // /cohorte-audit command remains the default path and the fallback).
3
- //
4
- // Invoke with args = {target: "<path or domain>"} (optional — default whole repo).
5
- //
6
- // Shape (SCHEMA.md §Workflows): profile via profile-reader (phase 0), the
7
- // mechanical gates staged to disk by one haiku agent, then ONE auditor per
8
- // domain (each surface + `shared`) running concurrently — the runtime caps
9
- // concurrency at 20 (CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS since 2026-08), extra
10
- // domains queue — and a merge phase that writes the
11
- // prioritized specs/refactor-backlog.md. Only the summary comes back.
12
-
13
- export const meta = {
14
- name: 'cohorte-audit',
15
- description: 'Audit the codebase against PIPELINE.md: mechanical gates, one auditor per domain in parallel, prioritized refactor backlog',
16
- whenToUse: 'Only when the human explicitly asks for the audit workflow. args = {target: "<path or domain>"} — omit for the whole repo.',
17
- phases: [
18
- { title: 'Profile', detail: 'PIPELINE.md → JSON via profile-reader', model: 'haiku' },
19
- { title: 'Gates', detail: 'format/lint/typecheck/tests → specs/reports/audit-gates.txt', model: 'haiku' },
20
- { title: 'Audit', detail: 'one review-in-audit-mode agent per domain (concurrent, runtime-capped 20)' },
21
- { title: 'Backlog', detail: 'merge + write specs/refactor-backlog.md', model: 'haiku' },
22
- ],
23
- }
24
-
25
- // The Workflow runtime hands `args` to a script verbatim, so a caller that passes a
26
- // JSON-ENCODED STRING instead of a real object gets that string back here. The old
27
- // `typeof args === 'string' ? args.trim()` then took the whole blob as the value — which
28
- // is how a report landed on disk named `specs/reports/{"feature": "x"}.md`, and how
29
- // maxRounds/smoke were silently dropped on the same run. Parse it back into the object
30
- // it was meant to be; a bare slug stays valid shorthand.
31
- const ARGS = (() => {
32
- if (typeof args === 'string') {
33
- const t = args.trim()
34
- if (t.startsWith('{')) {
35
- try { const o = JSON.parse(t); if (o && typeof o === 'object' && !Array.isArray(o)) return o } catch {}
36
- }
37
- return { feature: t, target: t }
38
- }
39
- return args && typeof args === 'object' ? args : {}
40
- })()
41
- const target = ARGS.target || ''
42
-
43
- // The profile-reader returns through a StructuredOutput tool call, and a haiku agent
44
- // intermittently nests the whole profile as a JSON *string* under a single wrapper field
45
- // ({"output": "{\"surfaces\": …}"}) instead of putting the profile's keys at the top level.
46
- // The schema here used to be {type:'object', additionalProperties:true} — no declared
47
- // properties, no required keys — so that wrapper validated cleanly and every field then read
48
- // as undefined: `surfaces` fell back to [], parallel([]) dispatched zero agents, the
49
- // dead-agent guard had no surfaces to find missing, and the run reported a verdict having
50
- // done nothing. On the surface it is indistinguishable from a clean run with an empty diff.
51
- // Declaring the shape gives the tool layer something to validate and the agent something to
52
- // aim at; unwrapProfile() salvages a wrapped return that still gets through; and the
53
- // zero-surface abort below makes the silent-success path impossible either way.
54
- // See also the structured-output section of core/agents/profile-reader.md.
55
- const PROFILE = {
56
- type: 'object', additionalProperties: true,
57
- properties: {
58
- error: { type: 'string', description: 'set ONLY when PIPELINE.md is missing or unparseable' },
59
- surfaces: {
60
- type: 'array',
61
- description: "one entry per surface, at the TOP LEVEL of this object — never a JSON string",
62
- items: {
63
- type: 'object', required: ['key'], additionalProperties: true,
64
- properties: { key: { type: 'string' }, path: { type: 'string' }, agent: { type: 'string' } },
65
- },
66
- },
67
- },
68
- }
69
-
70
- // Salvage a profile handed back as JSON text rather than as an object — either the whole
71
- // return, or nested under a single wrapper field. Anything already shaped like a profile
72
- // (has `surfaces`, or is the documented `{error}` failure shape) passes through untouched.
73
- const unwrapProfile = p => {
74
- if (typeof p === 'string') { try { return JSON.parse(p) } catch { return null } }
75
- if (!p || typeof p !== 'object') return null
76
- if (Array.isArray(p.surfaces) || p.error) return p
77
- for (const v of Object.values(p)) {
78
- if (typeof v !== 'string') continue
79
- try {
80
- const inner = JSON.parse(v)
81
- if (inner && typeof inner === 'object' && !Array.isArray(inner)) return inner
82
- } catch {}
83
- }
84
- return p
85
- }
86
-
87
- const GATES = {
88
- type: 'object', required: ['failures'], additionalProperties: false,
89
- properties: {
90
- failures: {
91
- type: 'array', maxItems: 40,
92
- items: {
93
- type: 'object', required: ['file', 'line', 'kind', 'summary'], additionalProperties: false,
94
- properties: {
95
- file: { type: 'string' }, line: { type: 'integer' },
96
- kind: { enum: ['lint', 'format', 'type', 'test'] },
97
- summary: { type: 'string', description: 'one line, no output excerpts' },
98
- },
99
- },
100
- },
101
- overflow: { type: 'integer', description: 'failures beyond the 40-item cap' },
102
- },
103
- }
104
-
105
- const BACKLOG = {
106
- type: 'object', required: ['items'], additionalProperties: false,
107
- properties: {
108
- items: {
109
- type: 'array', maxItems: 30,
110
- items: {
111
- type: 'object', required: ['severity', 'file', 'line', 'kind', 'fix'], additionalProperties: false,
112
- properties: {
113
- severity: { enum: ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] },
114
- file: { type: 'string' }, line: { type: 'integer' },
115
- kind: { enum: ['rule', 'tdd', 'lint', 'format', 'type', 'security'] },
116
- fix: { type: 'string', description: 'one concrete change, one line, no code excerpts' },
117
- },
118
- },
119
- },
120
- overflow: { type: 'integer' },
121
- },
122
- }
123
-
124
- // ── Phase 0 — profile ────────────────────────────────────────────────────────
125
- phase('Profile')
126
- const profile = unwrapProfile(await agent(
127
- 'Return this project\'s PIPELINE.md `yaml pipeline-profile` block as JSON, per your instructions.',
128
- { agentType: 'profile-reader', label: 'profile', schema: PROFILE, effort: 'low' },
129
- ))
130
- if (!profile || profile.error) {
131
- return { error: `profile unreadable: ${(profile && profile.error) || 'profile-reader returned nothing'}` }
132
- }
133
- const cmds = profile.commands || {}
134
- const surfaces = Array.isArray(profile.surfaces) ? profile.surfaces : []
135
- // A profile with no surfaces cannot do this workflow's work, and every later
136
- // guard compares against `surfaces` — an empty list makes them all vacuously
137
- // pass. Fail loudly here instead of finishing with nothing done.
138
- if (!surfaces.length) {
139
- return { error: 'profile has no surfaces — nothing would be audited. the `yaml pipeline-profile` block in PIPELINE.md is empty or unparseable, or the profile-reader mis-returned; run /cohorte-doctor' }
140
- }
141
- const quiet = (q, full) => (q && !String(q).startsWith('<') ? q : full ? `${full} 2>&1 | tail -40` : '')
142
- const scope = target || 'the whole repo'
143
-
144
- // ── Phase 1 — mechanical gates, staged to disk ───────────────────────────────
145
- phase('Gates')
146
- const gateCmds = [
147
- cmds.format ? `${cmds.format} --check` : '',
148
- quiet(cmds.lint_quiet, cmds.lint),
149
- cmds.typecheck,
150
- quiet(cmds.test_quiet, cmds.test),
151
- ].filter(c => c && !String(c).startsWith('<'))
152
- const gates = await agent(
153
- `Run the cohorte audit's mechanical gates, scoped to ${scope}. Commands (adapt the format one to the ` +
154
- `project's check mode if --check is wrong): ${gateCmds.map(c => JSON.stringify(c)).join(' · ')}.\n` +
155
- 'Redirect EVERY command\'s output into specs/reports/audit-gates.txt (append, `cmd >> file 2>&1`) — ' +
156
- 'never print it — and keep going after failures (this is an inventory, not a gate to pass). Then grep ' +
157
- 'the file and return each failure as file/line/kind/one-line summary, capped at 40 (set overflow for the rest).',
158
- { model: 'haiku', label: 'gates', schema: GATES, effort: 'low' },
159
- )
160
- // A dead gates agent is NOT "zero mechanical failures" — silence would read as the
161
- // cleanest possible inventory from a phase that never ran (SCHEMA.md §Dead agents).
162
- // The domain auditors still run (they read the staged gates file, which then simply
163
- // isn't there), but the run must say the mechanical sweep is uncovered.
164
- const gatesCovered = gates != null
165
- const mech = (gates && gates.failures) || []
166
- log(gatesCovered
167
- ? `Mechanical failures: ${mech.length}${gates.overflow ? ` (+${gates.overflow} overflow)` : ''}`
168
- : 'the gates agent died — mechanical checks NOT covered this run')
169
-
170
- // ── Phase 2 — one auditor per domain, concurrent ─────────────────────────────
171
- // Domains = every surface + `shared` (contract package + anything outside the
172
- // surface trees). The runtime caps concurrent agents at 20 by default; more domains
173
- // queue. Raising CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS raises the ceiling, it does not
174
- // change this script — the queue is the runtime's, and a queued domain is not a lost one.
175
- phase('Audit')
176
- const domains = surfaces.map(s => ({ key: s.key, path: s.path }))
177
- .concat([{ key: 'shared', path: (profile.contract && profile.contract.path) || '(everything outside the surface trees)' }])
178
- .filter(d => !target || target === d.key || String(d.path).startsWith(target) || target.startsWith(String(d.path)))
179
- if (!domains.length) return { error: `target "${target}" matches no surface/domain` }
180
-
181
- const audited = await parallel(domains.map(d => () => agent(
182
- 'Audit a target against PIPELINE.md (no spec — audit mode, per your agent instructions). Check ' +
183
- 'conventions for the domain\'s surface, TDD coverage (untested entry points / modules), and — if the ' +
184
- 'profile enables them — mobile-first + design-system usage. Mechanical findings are already staged: ' +
185
- 'read specs/reports/audit-gates.txt and fold the ones in your domain in. Return the prioritized items, ' +
186
- 'capped at 30, one line each, no code excerpts. — Variable slots: domain: ' +
187
- `${d.key} · tree: ${d.path}${target ? ` · human-requested target: ${target}` : ''}`,
188
- { agentType: 'review', label: `audit:${d.key}`, schema: BACKLOG },
189
- ).then(r => r && { key: d.key, items: r.items, overflow: r.overflow || 0 })))
190
- const perDomain = audited.filter(Boolean)
191
- // A dead auditor returns null, and a domain with no result is indistinguishable
192
- // from a domain with nothing to report — the backlog would simply omit it and the
193
- // human would read that as "clean". Name them instead.
194
- const deadDomains = domains.filter(d => !perDomain.some(p => p.key === d.key)).map(d => d.key)
195
- if (deadDomains.length) log(`Auditor died on: ${deadDomains.join(', ')} — those domains are NOT audited`)
196
-
197
- // ── Phase 3 — merge + write the backlog ──────────────────────────────────────
198
- phase('Backlog')
199
- const SEV = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3 }
200
- const body = ['# Refactor backlog', '', `> Generated by the cohorte-audit workflow (scope: ${scope}).`]
201
- if (deadDomains.length) {
202
- body.push('', `> ⚠ NOT audited (the auditor died): ${deadDomains.join(', ')} — absence of items below`,
203
- '> for those domains means "not looked at", not "clean". Re-run the audit for them.')
204
- }
205
- if (!gatesCovered) {
206
- body.push('', '> ⚠ Mechanical gates NOT run (the gates agent died) — lint/typecheck/test failures',
207
- '> are uncounted below. Re-run the audit for the mechanical sweep.')
208
- }
209
- let total = 0
210
- for (const d of perDomain) {
211
- const items = [...d.items].sort((a, b) => SEV[a.severity] - SEV[b.severity])
212
- total += items.length
213
- body.push('', `## ${d.key}`, '')
214
- for (const it of items) body.push(`- [ ] ${it.severity} · ${it.file}:${it.line} · ${it.kind} · ${it.fix}`)
215
- if (d.overflow) body.push(`- [ ] (+${d.overflow} more beyond the cap — re-audit ${d.key} after this pass)`)
216
- }
217
- const written = await agent(
218
- `Write EXACTLY this content to specs/refactor-backlog.md (overwrite), then return the single word done:\n<<<BACKLOG\n${body.join('\n')}\nBACKLOG`,
219
- { model: 'haiku', label: 'write-backlog', effort: 'low' },
220
- )
221
- // Returning `backlog: <path>` when the writer died points /cohorte-refactor at a file
222
- // that does not exist (or, worse, at the PREVIOUS run's stale backlog).
223
- const backlogOk = written != null && /done/i.test(String(written))
224
-
225
- return {
226
- backlog: backlogOk ? 'specs/refactor-backlog.md' : '(NOT written — the backlog writer died)',
227
- notAudited: deadDomains, // absence of findings here means "not looked at"
228
- mechanicalFailures: gatesCovered ? mech.length : null, // null = gates agent died, NOT zero
229
- gatesCovered,
230
- domains: Object.fromEntries(perDomain.map(d => [d.key, d.items.length + (d.overflow || 0)])),
231
- total,
232
- top: perDomain.flatMap(d => d.items.map(it => ({ ...it, domain: d.key })))
233
- .sort((a, b) => SEV[a.severity] - SEV[b.severity]).slice(0, 10)
234
- .map(it => `[${it.severity}] ${it.domain} · ${it.file}:${it.line} — ${it.fix}`),
235
- next: !backlogOk
236
- ? 'the backlog was NEVER written (writer died) — the counts above are real but nothing is on disk; re-run the audit'
237
- : deadDomains.length
238
- ? `re-audit ${deadDomains.join(', ')} (auditor died — not covered), then /cohorte-refactor <domain>`
239
- : 'refactor a domain with /cohorte-refactor <domain> (or the refactor workflow for big domains)',
240
- }