catherd-cli 1.5.0 → 2.0.0-beta.20261022113309

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 (275) hide show
  1. package/README.md +164 -208
  2. package/THIRD_PARTY_NOTICES.md +217 -35
  3. package/catalog/jev.json +27 -1
  4. package/catalog/models.json +56 -247
  5. package/package.json +6 -8
  6. package/plugin/.claude-plugin/plugin.json +1 -1
  7. package/plugin/.codex-plugin/plugin.json +1 -1
  8. package/plugin/bin/catherd-mcp +1 -1
  9. package/plugin/commands/catherd.md +2 -2
  10. package/plugin/skills/catherd/SKILL.md +97 -421
  11. package/plugin/skills/catherd-setup/SKILL.md +20 -19
  12. package/src/adapters/all.ts +0 -4
  13. package/src/adapters/backend.ts +1 -2
  14. package/src/adapters/cursor/home.ts +1 -1
  15. package/src/adapters/cursor/index.ts +4 -4
  16. package/src/cli.ts +22 -27
  17. package/src/domain/bars.ts +33 -107
  18. package/src/domain/blocked.ts +72 -0
  19. package/src/domain/branch.ts +51 -0
  20. package/src/domain/brief.ts +21 -6
  21. package/src/domain/catalog.ts +69 -324
  22. package/src/domain/cost.ts +15 -30
  23. package/src/domain/errors.ts +2 -2
  24. package/src/domain/fail-lines.ts +26 -0
  25. package/src/domain/failover.ts +37 -87
  26. package/src/domain/findings.ts +47 -0
  27. package/src/domain/gate-brief.ts +1 -0
  28. package/src/domain/ids.ts +13 -2
  29. package/src/domain/jev.ts +47 -2
  30. package/src/domain/judge.ts +124 -0
  31. package/src/domain/lane.ts +22 -3
  32. package/src/domain/milestone-memory.ts +53 -0
  33. package/src/domain/notice.ts +25 -8
  34. package/src/domain/notify.ts +32 -0
  35. package/src/domain/plan-doc.ts +198 -0
  36. package/src/domain/plan-lint.ts +141 -0
  37. package/src/domain/profile-rules.ts +101 -160
  38. package/src/domain/profile.ts +116 -63
  39. package/src/domain/record.ts +53 -2
  40. package/src/domain/role-prompts.ts +131 -45
  41. package/src/domain/role-scope.ts +4 -34
  42. package/src/domain/role-tools.ts +2 -2
  43. package/src/domain/roles.ts +2 -0
  44. package/src/domain/route.ts +17 -0
  45. package/src/domain/rules.ts +33 -0
  46. package/src/domain/run-events.ts +298 -0
  47. package/src/domain/run-machine.ts +668 -0
  48. package/src/domain/run-state.ts +1310 -0
  49. package/src/domain/scorecard.ts +197 -0
  50. package/src/domain/select.ts +151 -146
  51. package/src/domain/slopalytics.ts +72 -0
  52. package/src/entry/answer-command.ts +39 -0
  53. package/src/entry/catalog-command.ts +25 -174
  54. package/src/entry/check-bin.ts +17 -0
  55. package/src/entry/cli-kit.ts +1 -1
  56. package/src/entry/daemon-bin.ts +22 -0
  57. package/src/entry/glyphs.ts +15 -2
  58. package/src/entry/init-command.ts +18 -68
  59. package/src/entry/knowledge-command.ts +45 -4
  60. package/src/entry/lock-command.ts +6 -7
  61. package/src/entry/mcp/role-server.ts +18 -0
  62. package/src/entry/mcp/server.ts +13 -40
  63. package/src/entry/mcp/session-tools.ts +149 -0
  64. package/src/entry/panel/openapi.ts +189 -0
  65. package/src/entry/panel/server.ts +410 -0
  66. package/src/entry/panel-command.ts +68 -0
  67. package/src/entry/profile-command.ts +10 -14
  68. package/src/entry/role-cli-command.ts +47 -3
  69. package/src/entry/runs-command.ts +3 -19
  70. package/src/entry/scorecard-command.ts +187 -0
  71. package/src/entry/supervise-bin.ts +1 -1
  72. package/src/infra/env.ts +0 -2
  73. package/src/infra/git.ts +64 -0
  74. package/src/infra/heavy-lock.ts +45 -7
  75. package/src/infra/launch.ts +63 -7
  76. package/src/infra/memory.ts +45 -0
  77. package/src/infra/ntfy.ts +40 -0
  78. package/src/infra/open-url.ts +42 -0
  79. package/src/infra/paths.ts +2 -2
  80. package/src/infra/slopalytics.ts +30 -0
  81. package/src/infra/store.ts +6 -1
  82. package/src/services/admission.ts +24 -9
  83. package/src/services/backends.ts +4 -6
  84. package/src/services/capture.ts +1 -22
  85. package/src/services/catalog-service.ts +155 -262
  86. package/src/services/credentials.ts +4 -20
  87. package/src/services/daemon.ts +181 -0
  88. package/src/services/dispatch-service.ts +5 -1
  89. package/src/services/doctor-backends.ts +1 -1
  90. package/src/services/doctor-checks.ts +47 -0
  91. package/src/services/doctor.ts +4 -9
  92. package/src/services/failover-rungs.ts +109 -0
  93. package/src/services/finalize.ts +12 -0
  94. package/src/services/gate-env.ts +1 -2
  95. package/src/services/gate-service.ts +21 -6
  96. package/src/services/jev-service.ts +2 -4
  97. package/src/services/lane-service.ts +34 -3
  98. package/src/services/milestone-check.ts +433 -0
  99. package/src/services/milestone-tree.ts +170 -0
  100. package/src/services/milestones.ts +35 -8
  101. package/src/services/notifier.ts +69 -2
  102. package/src/services/notify-service.ts +26 -0
  103. package/src/services/panel-setup.ts +116 -0
  104. package/src/services/plan-input.ts +151 -0
  105. package/src/services/ports.ts +30 -4
  106. package/src/services/preflight.ts +82 -8
  107. package/src/services/profile-service.ts +30 -3
  108. package/src/services/profile-store.ts +8 -3
  109. package/src/services/protocol.ts +4 -0
  110. package/src/services/provenance.ts +31 -90
  111. package/src/services/questions.ts +9 -0
  112. package/src/services/reconcile.ts +11 -0
  113. package/src/services/routing-service.ts +26 -15
  114. package/src/services/run-briefs.ts +477 -0
  115. package/src/services/run-client.ts +217 -0
  116. package/src/services/run-effects.ts +837 -0
  117. package/src/services/run-events-store.ts +174 -0
  118. package/src/services/run-evidence.ts +1 -1
  119. package/src/services/run-read.ts +221 -0
  120. package/src/services/run-report.ts +176 -0
  121. package/src/services/run-service.ts +55 -6
  122. package/src/services/run-store.ts +54 -7
  123. package/src/services/scorecard-metrics.ts +86 -0
  124. package/src/services/scorecard.ts +382 -0
  125. package/src/services/summary.ts +27 -3
  126. package/src/services/tree-path.ts +27 -0
  127. package/src/services/workspace-admission.ts +5 -13
  128. package/src/services/workspace-service.ts +5 -0
  129. package/web/dist/assets/Brand-PKlUX5TE.js +1 -0
  130. package/web/dist/assets/Brand-PKlUX5TE.js.br +0 -0
  131. package/web/dist/assets/Brand-PKlUX5TE.js.gz +0 -0
  132. package/web/dist/assets/Modal-Dxc5so53.js +1 -0
  133. package/web/dist/assets/Modal-Dxc5so53.js.br +0 -0
  134. package/web/dist/assets/Modal-Dxc5so53.js.gz +0 -0
  135. package/web/dist/assets/Pressable-C8-T6Ed_.js +1 -0
  136. package/web/dist/assets/StatusChip-B5xfI_Mn.js +153 -0
  137. package/web/dist/assets/StatusChip-B5xfI_Mn.js.br +0 -0
  138. package/web/dist/assets/StatusChip-B5xfI_Mn.js.gz +0 -0
  139. package/web/dist/assets/_app-Ea5cpyKe.js +1 -0
  140. package/web/dist/assets/_app-Ea5cpyKe.js.br +0 -0
  141. package/web/dist/assets/_app-Ea5cpyKe.js.gz +0 -0
  142. package/web/dist/assets/_runId-pTG0fXVo.js +1 -0
  143. package/web/dist/assets/_runId-pTG0fXVo.js.br +0 -0
  144. package/web/dist/assets/_runId-pTG0fXVo.js.gz +0 -0
  145. package/web/dist/assets/drawer-Du3cdlok.js +1 -0
  146. package/web/dist/assets/drawer-Du3cdlok.js.br +0 -0
  147. package/web/dist/assets/drawer-Du3cdlok.js.gz +0 -0
  148. package/web/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  149. package/web/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  150. package/web/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  151. package/web/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  152. package/web/dist/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  153. package/web/dist/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  154. package/web/dist/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  155. package/web/dist/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  156. package/web/dist/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  157. package/web/dist/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  158. package/web/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  159. package/web/dist/assets/index-B6GiwDkh.js +11 -0
  160. package/web/dist/assets/index-B6GiwDkh.js.br +0 -0
  161. package/web/dist/assets/index-B6GiwDkh.js.gz +0 -0
  162. package/web/dist/assets/index-C5IbylvM.css +2 -0
  163. package/web/dist/assets/index-C5IbylvM.css.br +0 -0
  164. package/web/dist/assets/index-C5IbylvM.css.gz +0 -0
  165. package/web/dist/assets/label-DFSYBc62.js +1 -0
  166. package/web/dist/assets/label-DFSYBc62.js.br +0 -0
  167. package/web/dist/assets/label-DFSYBc62.js.gz +0 -0
  168. package/web/dist/assets/link-D8EcKZUt.js +1 -0
  169. package/web/dist/assets/link-D8EcKZUt.js.br +0 -0
  170. package/web/dist/assets/link-D8EcKZUt.js.gz +0 -0
  171. package/web/dist/assets/login-DaN5HPPW.js +1 -0
  172. package/web/dist/assets/login-DaN5HPPW.js.br +0 -0
  173. package/web/dist/assets/login-DaN5HPPW.js.gz +0 -0
  174. package/web/dist/assets/query-Cu--ccT3.js +1 -0
  175. package/web/dist/assets/questions-shoO9OVj.js +1 -0
  176. package/web/dist/assets/questions-shoO9OVj.js.br +0 -0
  177. package/web/dist/assets/questions-shoO9OVj.js.gz +0 -0
  178. package/web/dist/assets/react-query.gen-Bu2yV-qJ.js +12 -0
  179. package/web/dist/assets/react-query.gen-Bu2yV-qJ.js.br +0 -0
  180. package/web/dist/assets/react-query.gen-Bu2yV-qJ.js.gz +0 -0
  181. package/web/dist/assets/rolldown-runtime-XKyaHtl9.js +1 -0
  182. package/web/dist/assets/run-status-C0DRuV7U.js +1 -0
  183. package/web/dist/assets/runs-C3rg2zZc.js +1 -0
  184. package/web/dist/assets/runs-C3rg2zZc.js.br +0 -0
  185. package/web/dist/assets/runs-C3rg2zZc.js.gz +0 -0
  186. package/web/dist/assets/setup-5I4Vl9fR.js +1 -0
  187. package/web/dist/assets/setup-5I4Vl9fR.js.br +0 -0
  188. package/web/dist/assets/setup-5I4Vl9fR.js.gz +0 -0
  189. package/web/dist/assets/table-BOxXhqS4.js +1 -0
  190. package/web/dist/assets/table-BOxXhqS4.js.br +0 -0
  191. package/web/dist/assets/table-BOxXhqS4.js.gz +0 -0
  192. package/web/dist/assets/textfield-BzRFkxBF.js +1 -0
  193. package/web/dist/assets/textfield-BzRFkxBF.js.br +0 -0
  194. package/web/dist/assets/textfield-BzRFkxBF.js.gz +0 -0
  195. package/web/dist/assets/time--9kSQbbp.js +1 -0
  196. package/web/dist/assets/use-css-variable-CpnN9WtA.js +5 -0
  197. package/web/dist/assets/use-css-variable-CpnN9WtA.js.br +0 -0
  198. package/web/dist/assets/use-css-variable-CpnN9WtA.js.gz +0 -0
  199. package/web/dist/assets/useMutation-CVPKlR34.js +1 -0
  200. package/web/dist/assets/useMutation-CVPKlR34.js.br +0 -0
  201. package/web/dist/assets/useMutation-CVPKlR34.js.gz +0 -0
  202. package/web/dist/index.html +15 -0
  203. package/catalog/ATTRIBUTION.md +0 -44
  204. package/catalog/scores.json +0 -3202
  205. package/catalog/sources.json +0 -97
  206. package/src/adapters/antigravity/events.ts +0 -131
  207. package/src/adapters/antigravity/home.ts +0 -46
  208. package/src/adapters/antigravity/index.ts +0 -335
  209. package/src/adapters/antigravity/models.ts +0 -37
  210. package/src/adapters/grok/events.ts +0 -112
  211. package/src/adapters/grok/home.ts +0 -187
  212. package/src/adapters/grok/index.ts +0 -358
  213. package/src/adapters/grok/models.ts +0 -48
  214. package/src/domain/calibration.ts +0 -132
  215. package/src/domain/sources.ts +0 -144
  216. package/src/entry/mcp/dispatch-tools.ts +0 -52
  217. package/src/entry/mcp/lane-tools.ts +0 -131
  218. package/src/entry/mcp/protocol-tools.ts +0 -63
  219. package/src/entry/mcp/push-tools.ts +0 -16
  220. package/src/entry/mcp/run-tools.ts +0 -164
  221. package/src/entry/mcp/setup-tools.ts +0 -109
  222. package/src/entry/mcp/workspace-tools.ts +0 -142
  223. package/src/entry/tui/commands.ts +0 -563
  224. package/src/entry/tui/effects.ts +0 -385
  225. package/src/entry/tui/fixtures.ts +0 -637
  226. package/src/entry/tui/profile-edits.ts +0 -146
  227. package/src/entry/tui/profile-tree.ts +0 -429
  228. package/src/entry/tui/providers/app.tsx +0 -162
  229. package/src/entry/tui/providers/boundary.tsx +0 -57
  230. package/src/entry/tui/providers/data.tsx +0 -160
  231. package/src/entry/tui/providers/keymap.tsx +0 -166
  232. package/src/entry/tui/providers/root.tsx +0 -45
  233. package/src/entry/tui/providers/theme.tsx +0 -17
  234. package/src/entry/tui/providers/toast.tsx +0 -77
  235. package/src/entry/tui/run.tsx +0 -114
  236. package/src/entry/tui/state.ts +0 -400
  237. package/src/entry/tui/stories.ts +0 -114
  238. package/src/entry/tui/text.ts +0 -130
  239. package/src/entry/tui/theme.ts +0 -140
  240. package/src/entry/tui/views/app.tsx +0 -208
  241. package/src/entry/tui/views/dialogs.tsx +0 -41
  242. package/src/entry/tui/views/profile-actions.ts +0 -331
  243. package/src/entry/tui/views/profiles.tsx +0 -520
  244. package/src/entry/tui/views/runs.tsx +0 -619
  245. package/src/entry/tui/views/save-dialog.tsx +0 -344
  246. package/src/entry/tui/views/status.tsx +0 -213
  247. package/src/entry/tui/widgets/chrome.tsx +0 -114
  248. package/src/entry/tui/widgets/dialog-confirm.tsx +0 -58
  249. package/src/entry/tui/widgets/dialog-prompt.tsx +0 -52
  250. package/src/entry/tui/widgets/dialog-select.tsx +0 -212
  251. package/src/entry/tui/widgets/dialog.tsx +0 -68
  252. package/src/entry/tui/widgets/line.tsx +0 -92
  253. package/src/entry/tui/widgets/list.tsx +0 -197
  254. package/src/entry/tui/widgets/spinner.tsx +0 -49
  255. package/src/entry/tui/widgets/toast.tsx +0 -62
  256. package/src/infra/sources/arena.ts +0 -95
  257. package/src/infra/sources/artificial-analysis.ts +0 -119
  258. package/src/infra/sources/cache.ts +0 -126
  259. package/src/infra/sources/csv.ts +0 -38
  260. package/src/infra/sources/epoch.ts +0 -82
  261. package/src/infra/sources/http.ts +0 -75
  262. package/src/infra/sources/litellm.ts +0 -58
  263. package/src/infra/sources/models-dev.ts +0 -59
  264. package/src/infra/sources/openrouter-endpoints.ts +0 -52
  265. package/src/infra/sources/openrouter-models.ts +0 -60
  266. package/src/infra/sources/rows.ts +0 -38
  267. package/src/infra/sources/vectara.ts +0 -69
  268. package/src/infra/sources/zip.ts +0 -48
  269. package/src/services/catalog-refresh.ts +0 -201
  270. package/src/services/doctor-sources.ts +0 -76
  271. package/src/services/runs-page.ts +0 -290
  272. package/src/services/source-derive.ts +0 -397
  273. package/src/services/source-sync.ts +0 -312
  274. package/src/services/standins.ts +0 -238
  275. package/src/services/treat-likes.ts +0 -113
package/README.md CHANGED
@@ -6,22 +6,24 @@
6
6
  (")(")
7
7
  ```
8
8
 
9
- Autopilot builds from your own Claude Code or native Codex session. Your profile routes the architect, verifier and workers to their backends; Codex, opencode, Cursor, Grok Build,
10
- Antigravity or headless Claude Code processes write the code, and [Jev](https://typesafe.ai) picks the model and effort for each piece
9
+ Autopilot builds from your own Claude Code or native Codex session. Your profile routes the architect, verifier and workers to their backends; Codex, opencode, Cursor
10
+ or headless Claude Code processes write the code, and [Jev](https://typesafe.ai) picks the model and effort for each piece
11
11
  of work, climbing a ladder only when a cheaper rung falls short.
12
12
 
13
13
  - **Your harness, as you set it up.** Every role runs in its vendor's own CLI with your config,
14
14
  hooks, skills and `AGENTS.md`. Isolation is an opt-in toggle per profile and harness, for when
15
15
  you'd rather save the tokens your customizations cost.
16
- - **Claude roles stay native on Claude Code.** `claude:` rungs require that host and run as ordinary Claude Code subagents; Codex,
17
- opencode, Cursor, Grok Build, Antigravity and headless `claude-code:` rungs run through catherd's MCP server.
18
- - **Survives restarts.** Workers are detached processes writing straight to disk, so a dropped
19
- MCP server never loses a run.
20
- - **Results come to you.** Roles run side by side while you keep talking. Claude Code uses its peer inbox; Codex uses queued next input through its existing native server. A busy Codex conversation processes it after the active turn. Queue acceptance and result collection are separate; `peek` shows how a run stands.
21
- - **A protocol the tools enforce.** Every lane is routed, every brief ends with the reply contract, and a
22
- milestone lands only after a reviewer and a verifier passed it. Workers can run their own checks (network,
23
- loopback, Docker, the lock dir); an owner question parks one milestone, not the run.
24
- - **Guard rails for autopilot.** Quota failover to a stand-in that clears the same bars, a preflight check
16
+ - **A daemon drives the run.** `run_start` launches a detached daemon that plans, dispatches, reviews, verifies
17
+ and lands each milestone from the run's own `events.jsonl`. Every role runs headless in its vendor's CLI
18
+ (Claude Code, Codex, opencode, Cursor); the session needs none of it once the run has started, and a dropped
19
+ session or MCP server never loses a run.
20
+ - **Questions reach your phone.** A parked question and the final report are sent to your ntfy topic
21
+ (`notify.url`), and answered from the session (`answer`) or the terminal (`catherd answer`).
22
+ - **A protocol the daemon enforces.** Every lane implements its plan tasks as written, and every role, whatever vendor runs it, gets its role's text and ends with the reply contract, and a
23
+ milestone lands only after a reviewer and a verifier passed it. A judge role decides what no rule can (an
24
+ ambiguous finding, a stuck fix round, an unmet check) from the run's facts. An owner question parks one milestone,
25
+ not the run.
26
+ - **Guard rails for autopilot.** Quota failover to an indexed stand-in at least as intelligent, a preflight check
25
27
  before any worker starts, per-repo knowledge carried between runs, and a run budget.
26
28
 
27
29
  ## Requirements
@@ -35,25 +37,20 @@ of work, climbing a ladder only when a cheaper rung falls short.
35
37
  - Claude Code's `claude` CLI 2.1.282 or newer, for headless `claude-code:` rungs
36
38
  - Cursor's CLI, `cursor-agent` 2026.09.28 or newer: `curl https://cursor.com/install -fsS | bash`, then
37
39
  `cursor-agent login` (below)
38
- - Grok Build's `grok` 1.0.44 or newer: `curl -fsSL https://x.ai/cli/install.sh | bash`, then `grok login`
39
- (below)
40
- - Google's Antigravity CLI, `agy` 1.2.13 or newer: `brew install --cask antigravity-cli`, or
41
- `curl -fsSL https://antigravity.google/cli/install.sh | bash` (with `~/.local/bin` on PATH), then run `agy` once
42
- to sign in (below)
43
40
  - Optional: a TypeSafe API key for Jev, in `TYPESAFE_API_KEY` or saved by `catherd init`
44
- - Optional: a free [Artificial Analysis](https://artificialanalysis.ai) API key for more scores, in
45
- `ARTIFICIAL_ANALYSIS_API_KEY` or saved by `catherd init`; its numbers are read for you alone and never shipped
41
+ - Optional: [gitleaks](https://github.com/gitleaks/gitleaks) (`brew install gitleaks`): catherd's milestone check
42
+ scans the commits of a milestone with it for a leaked secret; without it the scan is skipped and the record says so
46
43
 
47
44
  `catherd doctor` checks each backend's version and login and prints the fix for anything missing. The default
48
45
  profile runs its workers on Codex; without Codex, doctor's fix also names how to move those roles to a backend
49
- you have (`/catherd-setup`, or `catherd profile set roles.<role>.rungs <rung> --host <codex|claude-code>`). Codex-only setup does not require or configure Claude; enabled selected roles and reachable failover decide optional dependencies. Doctor sends nothing by default; `--test-push` is an explicit smoke send from a validated host session (`--thread <uuid>` names the Codex thread from a shell; inside a session, the `test_push` tool does the same).
46
+ you have (`/catherd-setup`, or `catherd profile set roles.<role>.rungs <rung> --host <codex|claude-code>`). Codex-only setup does not require or configure Claude; enabled selected roles and reachable failover decide optional dependencies. Doctor sends nothing by default; `--test-push` is an explicit smoke send from a validated host session (`--thread <uuid>` names the Codex thread from a shell).
50
47
 
51
48
  ### Cursor
52
49
 
53
50
  A Cursor rung names Cursor's own model slug, with the effort as the slug's suffix: `cursor:gpt-6-sol#xhigh` runs
54
- `gpt-6-sol-xhigh`, and `#default` runs the bare slug (`cursor:composer-2.5#default`). `cursor-agent models` lists
51
+ `gpt-6-sol-xhigh`, and `#default` runs the bare slug of a model whose index entry has no effort. `cursor-agent models` lists
55
52
  what your account offers; `catherd catalog refresh` reads it. No profile uses Cursor until you put a rung on it.
56
- Its Composer and Grok models bill from Cursor's own pool, the other models at API rates after your plan's included
53
+ Its own models (Composer, Grok) bill from Cursor's own pool, the other models at API rates after your plan's included
57
54
  usage, so a Cursor rung ranks as `metered`.
58
55
 
59
56
  - **Native** (the default) runs with your login and your Cursor setup. It also loads your Claude Code hooks,
@@ -65,55 +62,14 @@ usage, so a Cursor rung ranks as `metered`.
65
62
  move to another home. catherd runs Cursor under its own HOME with its own `sandbox.json`, which gives a worker
66
63
  catherd's writable roots.
67
64
 
68
- ### Grok Build
69
-
70
- A Grok rung names grok's model and effort: `grok:grok-4.6#high` runs `grok -m grok-4.6 --effort high`, and
71
- `#default` passes no effort. `grok models` lists your models but no efforts, so catherd offers Grok Build's `low`
72
- to `xhigh`; `catherd catalog refresh` reads the list. No profile uses grok until you put a rung on it. A Grok login
73
- (SuperGrok, X Premium+) bills your subscription and `XAI_API_KEY` bills per token: `catherd doctor` says when a
74
- profile's `billing.grok` differs from your login. On a usage limit, a Grok rung fails over to the same model on
75
- Cursor, and a Cursor Grok rung to grok, unless the profile names another stand-in.
76
-
77
- - **Native** (the default) runs with your login and your grok setup. It also loads your Claude Code plugins,
78
- agents, skills, hooks and permission rules, and your Cursor rules and MCP. `workspace-write` runs in grok's
79
- sandbox under catherd's own profile, `catherd-ws`, which lets a worker write the lock dir, temp and the
80
- toolchain caches: catherd adds its marked `[profiles.catherd-*]` tables to `~/.grok/sandbox.toml` and leaves the
81
- rest of that file alone. `read-only` runs grok's kernel `read-only` profile. On a Mac whose
82
- `/var/run/docker.sock` is a link (Docker Desktop, OrbStack, Colima) grok refuses that profile, so catherd gives
83
- the role only the read tools instead (`advisory`); `catherd doctor` says which applies. On macOS no grok profile
84
- controls the network.
85
- - **Isolated** (`catherd profile set harness.grok.isolated true`) needs `XAI_API_KEY`: catherd never copies your
86
- grok login, whose refresh token rotates. catherd runs grok under its own HOME with its own `sandbox.toml`.
87
-
88
- grok keeps a session on the access it started with, so catherd refuses to resume one under another access.
89
-
90
- ### Antigravity
91
-
92
- An Antigravity rung names the model `agy models` lists, without an effort suffix; the effort is agy's `--effort`
93
- (`low`, `medium`, `high` or `max`), and `#default` passes none: `antigravity:gemini-3.8-flash#low`. No profile uses
94
- Antigravity until you put a rung on it. catherd never runs `agy -p` while agy is signed out, since agy would open a
95
- browser and wait; `catherd doctor` says so, with the fix. A sign-in check that passed is kept for 10 minutes, so
96
- after you sign agy out, restart the catherd MCP server (or wait those minutes) before the next Antigravity dispatch.
97
- A Google login draws on your plan's quota (doctor shows
98
- what is left); `GEMINI_API_KEY` bills the Gemini API project. Gemini rungs fail over between Antigravity and Cursor
99
- when either runs out, unless your profile names another stand-in.
100
-
101
- - **Native** (the default) runs with your Google login and your `~/.gemini` settings, which the Antigravity desktop
102
- app shares and catherd never edits. `workspace-write` runs shell commands in agy's sandbox, which reaches the
103
- workspace, temp and build caches but no network unless your own `read_url` rules grant it; the file tools are not
104
- confined (`advisory`). agy has no read-only mode, so a read-only role (the reviewer, the architect) cannot run on
105
- native Antigravity: `profile validate` refuses it.
106
- - **Isolated** (`catherd profile set harness.antigravity.isolated true`) needs `GEMINI_API_KEY`. catherd runs agy
107
- under its own HOME, with its own settings: the Gemini API as the provider, write and command deny rules for
108
- read-only roles, and catherd's writable roots and the network for `workspace-write`.
109
-
110
- Whether Google's plan terms allow an orchestrator to drive `agy` on a consumer plan is not settled here. The API-key
111
- route is the one meant for automation; check the terms before you rely on a plan login.
112
-
113
65
  ## Install
114
66
 
115
67
  catherd runs from Claude Code or, since 1.4, from native Codex; one global `catherd` and one plugin version serve both. To check a packaged build before you rely on it, follow the [local packaged acceptance procedure](docs/dev/live-verification.md#14-native-codex-packaging-and-completion-acceptance); a matching version alone does not prove that the feature core ran.
116
68
 
69
+ Channels: `catherd-cli@latest` is the stable release. `catherd-cli@beta` and the `plugin-beta` marketplace carry
70
+ the next one before it is stable (CONTRIBUTING.md, "Beta channel"). `catherd-cli@1` is the 1.x line, which receives
71
+ bug fixes only (CONTRIBUTING.md, "Maintenance line (1.x)").
72
+
117
73
  ### Claude Code
118
74
 
119
75
  ```sh
@@ -124,13 +80,12 @@ catherd init --host claude-code
124
80
  The npm package is `catherd-cli`; the command it installs is `catherd`. `bunx catherd-cli init --host claude-code`
125
81
  works too (a terminal with no host evidence cannot pick the architect/verifier defaults, so name the host): `init`
126
82
  installs the global command at its own version (`--no-global` skips it) and says `installing catherd…` before
127
- it does, though the first `bunx` resolve itself prints nothing for up to half a minute: bunx fetches about a
128
- hundred packages before catherd's first line, TypeScript among them (a peer dependency of OpenTUI's native
129
- layer, which Bun installs), so `bun add -g catherd-cli` first is the quicker start. `init` asks for the
130
- optional Jev key and the optional Artificial Analysis key, syncs the public model sources, writes the default
83
+ it does, though the first `bunx` resolve itself prints nothing for up to half a minute: bunx fetches the
84
+ package before catherd's first line, so `bun add -g catherd-cli` first is the quicker start. `init` asks for the
85
+ optional Jev key, fetches the Slopalytics index, writes the default
131
86
  profile and links its Claude agents, lists your backends' models, and ends with a readiness report (`--no-input`
132
87
  asks nothing and keeps what exists; `--profile <name>` sets up and activates that profile instead of `default`;
133
- piped, it reads one answer per line once stdin closes: the Jev key, the Artificial Analysis key, the profile,
88
+ piped, it reads one answer per line once stdin closes: the Jev key, the profile,
134
89
  whether to replace it, each on its own line even when a question is skipped). Then add the plugin to
135
90
  Claude Code:
136
91
 
@@ -161,11 +116,27 @@ Pass the actual project `repo` to repository-aware MCP profile/setup/catalog cal
161
116
  In either supported host, use the installed shared skills through that host's skill invocation and tool discovery:
162
117
 
163
118
  - `/catherd <task>` runs a task on autopilot; `/catherd` alone resumes the latest run. While it runs, keep
164
- talking: completion arrives through the host's transport, and "how is it going?" gets a `peek`.
119
+ talking: a report arrives through the host's transport and on your phone, and "how is it going?" gets a `status`.
165
120
  - `/catherd-setup` tunes your profile in conversation: which models and efforts each role may
166
121
  use, cost or speed, isolation, budget and failover.
167
122
 
168
- `route` chooses the backend for every role. Native `claude:` uses Claude Code's `Agent` and `record_agent_run` only on Claude Code; process backends, including Codex architect/verifier, use `dispatch` followed by `result`. Omitted Codex architect/verifier choices are exactly `codex:gpt-6.1-sol#high` / `codex:gpt-6.1-sol#low`; omitted Claude choices retain their existing native defaults. Verify that exact model ID against native catalog discovery and validation; if spelling differs, resolve the mismatch explicitly with the owner, never silently normalize or substitute, and retain high/low efforts. Explicit ladders and materialized profiles are preserved, without silently converting `claude:` to `claude-code:`. To opt into host defaults, review and save the narrow reset:
123
+ A session sees six tools:
124
+
125
+ | Tool | What it does |
126
+ | ----------------------------------------------- | -------------------------------------------------------------------------------------------- |
127
+ | `run_start(repo, title, a_lines, plan?, base?)` | Starts a run and returns its id and the notify url its questions go to |
128
+ | `status(run?)` | Phase, milestones, live roles, parked questions, quota holds and whether the daemon is alive |
129
+ | `answer(run, unit, answer)` | Answers a parked unit (the run, a milestone or a lane); it runs again with the answer |
130
+ | `cancel(run)` | Stops the run and every live role |
131
+ | `result(run, name?)` | The run's report (the merge request body), or one role's record |
132
+ | `profile(action, …)` | Reads, validates or changes a profile, or sets `notify_url` |
133
+
134
+ Set where questions go once: `notify.url` is an [ntfy](https://ntfy.sh) topic url (`catherd-setup`, or the `profile`
135
+ tool's `notify_url`). The daemon sends to it from your machine, so a question and the final report reach the phone
136
+ with no session open. If `notify.url` is unset, `run_start` makes a random, unlisted topic on the public ntfy.sh and
137
+ sends questions there; set `notify.url` to your own ntfy server for privacy. Omitted Codex architect/verifier choices are exactly `codex:gpt-6.1-sol#high` /
138
+ `codex:gpt-6.1-sol#low`; omitted Claude choices retain their existing defaults, and a `claude:` rung runs as its
139
+ headless `claude-code:` twin. To opt into host defaults, review and save the narrow reset:
169
140
 
170
141
  ```sh
171
142
  catherd profile reset-host-defaults <profile> --host codex --preview --json > /tmp/catherd-host-defaults-review.json
@@ -175,79 +146,92 @@ catherd profile reset-host-defaults <profile> --host codex --expect /tmp/catherd
175
146
 
176
147
  It removes only architect/verifier `rungs` and `defaultRung`; every other setting stays intact. Run profile CLI commands from the project directory and choose the actual profile name. Use `--host claude-code` for Claude defaults.
177
148
 
178
- Completion never uses `await_results` or model polling. Codex sends through `codex queue --remote unix://` to the validated original thread: idle wake and ordered busy follow-up are the native semantics, without Claude's urgent tool-round priority. A receipt proves queue acceptance, not observed generation or collection; unloaded/interrupted hosts may retain input. Only `result` collects the actual stored record. Explicit `peek(run)` adopts the run for the current host/session; `status` and `result` do not. Unknown/conflicting identity never owns or pushes.
179
-
180
- When a role ends, its own supervisor also queues the notice to a Codex owner's thread, under the same receipt as the server's push, so a thread whose MCP server Codex has stopped still hears, and nothing arrives twice. Run a Codex coordinator inside `tmux` (or `screen`): Codex stops a thread's MCP servers once no client is attached, and the queued input waits for the next attach. Every catherd message names the role's `thread:`; resume it with `dispatch(…, thread: "latest")` under the same name.
181
-
182
- Roles get catherd's tools too. Headless Codex and Claude Code roles get a `catherd_role` MCP server, isolated or not, without any change to your config; roles on other backends run `catherd run-file read|write <run> <path>` and `catherd gate check|pass <run> …` from their shell, bound to their own run and to their role's tools: every role may read run files, only the architect and researcher write them, and only the verifier runs `gate check|pass` (anything else is `E_ROLE_SCOPE`). The coordinator tools (`dispatch`, `result`, `land`, `climb`, `peek` of another role, `run_start`, `park`, `answer`, `cancel`, `set_next`, `profile_set`, `test_push`, `run_pin`, `lane_set`, `owns_add`, `record_agent_run` and the workspace writers) are the orchestrator's: a role's process gets `E_ROLE_SCOPE` for them, so a role can never take the run over.
183
-
184
- Recover unread work with `peek` and `result`. Accepted or ambiguous attempts are not automatically resent. When ambiguity needs a deliberate retry, run from the current owner's validated host session:
185
-
186
- ```sh
187
- catherd runs retry-push <run> <name> --event '<exact event ID from peek/status>' --acknowledge-possible-duplicate
188
- ```
189
-
190
- This acknowledges possible duplicate native input; an accepted receipt still suppresses a repeat for that owner/event. Without a supported history reconciliation API, retain ambiguity until an explicit decision. Notices preserve all event IDs, including coalesced events; repeated input means idempotent reads, never another dispatch or landing. Stored records and independent reviewer/verifier gates are authoritative. Profile notification moments use an available host facility, without inventing a Codex notification tool or scheduled wake.
149
+ A run's reports reach the session that started it (Claude Code's peer inbox, Codex's queued next input) and the phone.
150
+ `status` revives a daemon that died, so asking "how is it going?" is always safe. Roles get catherd's tools too:
151
+ headless Codex and Claude Code roles get a `catherd_role` MCP server, and other roles run
152
+ `catherd run-file read|write <run> <path>` and `catherd gate check|pass <run> …` from their shell, bound to their own
153
+ run and role (anything else is `E_ROLE_SCOPE`). `run_start`, `answer`, `cancel`, `result` and `profile` are the owner's: a role's process gets
154
+ `E_ROLE_SCOPE` for them, so a role can never take the run over.
191
155
 
192
156
  In a terminal:
193
157
 
194
- | Command | What it does |
195
- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
196
- | `catherd` | The dashboard: Status, Profiles and Runs (below) |
197
- | `catherd init [--host codex\|claude-code\|auto] [--no-input] [--no-global] [--profile <p>]` | First-run setup; installs the global `catherd` at its own version unless `--no-global` |
198
- | `catherd doctor [--host codex\|claude-code\|auto] [--test-push [--thread <uuid>]] [--docker] [--json]` | Readiness and capability report; no send unless explicit smoke; `--docker` probes a compose network and the Docker disk; exits 3 when not ready |
199
- | `catherd profile list\|show\|use [--repo]\|new [--from <p>]\|copy\|rm\|diff\|validate` | Profiles; `use --repo` binds one to the repo you are in |
200
- | `catherd profile use --repo --clear` | Unbinds the repo you are in; it runs on the active profile again |
201
- | `catherd profile set <path> <value> [--profile <p>]` | One field, e.g. `roles.verifier.access read-only`, `roles.worker.network false`, `budget.usd 20` |
202
- | `catherd status [run]`, `catherd watch [--once] [--interval <s>]` | Where runs stand, grouped by host and session; read-only ownership |
203
- | `catherd runs list [--repo <path>]\|show <id> [--debug [--name <n>]]\|cancel <id> <name>` | Past runs, by session; `--debug` adds exit.json and the stderr and event tails, `--name` one role's |
204
- | `catherd runs clean [<id>]` | Removes the roles' scratch folders (each role's `$TMPDIR`) of runs with no live role |
205
- | `catherd catalog refresh\|list [--backend <b>] [--role <r>] [--text <t>] [--scored]` | The models catherd can place, filtered |
206
- | `catherd catalog sync [--force] [--unmatched]` | Fetches the public model facts and scores now (below); `--unmatched` lists ids no model matched |
207
- | `catherd catalog treat-like <rung> <like>` | Scores an unscored rung as a scored one |
208
- | `catherd catalog treat-like --suggest <rung>\|--clear <rung>\|--reset` | The three nearest stand-ins for a rung; removes one or every mapping of yours |
209
- | `catherd knowledge show\|add "<line>"\|path [--repo <path>]` | The repo's knowledge.md, keyed by its git origin (its toplevel when it has none), which new runs read; `add` appends a fact of yours, marked "by hand" |
210
- | `catherd knowledge env set NAME=value\|NAME --from VAR`, `env rm NAME`, `env list` | The repo's gate environment, which the verifier and preflight run with; a secret by reference only |
211
- | `catherd runs supersede <id> --by <id>`, `catherd runs pin <id>` | Closes a run with a pointer to the one that took over; re-pins a run to the repo's profile now |
212
- | `catherd pause --machine\|--workspace <id> "<reason>"`, `catherd resume --machine\|--workspace <id>` | Pauses every run on the machine (or in a workspace) on one blocker; dispatch is refused until resume |
213
- | `catherd lock [--slots N] [--role verifier [--run <id>]] -- <cmd>` | Runs a heavy command behind the machine-wide semaphore, in its own session (no /dev/tty); `--role verifier` keeps two runs' verifiers apart |
214
- | `catherd run-file read\|write <run> <path>` | A run's plan, lanes and notes (`write` reads stdin); in a role, its own run only |
215
- | `catherd gate check <run> [--item <i> --command <c> --paths <p,…>] [--milestone <M>]`, `catherd gate pass <run> --item <i> --command <c> --paths <p,…> --evidence <e>` | A verifier's gate evidence, as `gate_check`/`gate_pass`; in a role, its own run only |
216
- | `catherd mcp` | The MCP server on stdio; the plugin starts it, you never need to |
217
- | `catherd capture-fixtures [--backend <b>] [--out <dir>]` | Contributors: records sanitized test fixtures from real runs (see CONTRIBUTING.md) |
158
+ | Command | What it does |
159
+ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
160
+ | `catherd`, `catherd panel [--port <n>] [--no-open]` | The panel in your browser on 127.0.0.1: Setup, Runs and Questions; a fresh token each start; `catherd --help` for the commands |
161
+ | `catherd init [--host codex\|claude-code\|auto] [--no-input] [--no-global] [--profile <p>]` | First-run setup; installs the global `catherd` at its own version unless `--no-global` |
162
+ | `catherd doctor [--host codex\|claude-code\|auto] [--test-push [--thread <uuid>]] [--docker] [--json]` | Readiness and capability report; no send unless explicit smoke; `--docker` probes a compose network and the Docker disk; exits 3 when not ready |
163
+ | `catherd profile list\|show\|use [--repo]\|new [--from <p>]\|copy\|rm\|diff\|validate` | Profiles; `use --repo` binds one to the repo you are in |
164
+ | `catherd profile use --repo --clear` | Unbinds the repo you are in; it runs on the active profile again |
165
+ | `catherd profile set <path> <value> [--profile <p>]` | One field, e.g. `roles.verifier.access read-only`, `roles.worker.network false`, `budget.usd 20` |
166
+ | `catherd status [run]`, `catherd watch [--once] [--interval <s>]` | Where runs stand, grouped by host and session; read-only ownership |
167
+ | `catherd runs list [--repo <path>]\|show <id> [--debug [--name <n>]]\|cancel <id> <name>` | Past runs, by session; `--debug` adds exit.json and the stderr and event tails, `--name` one role's |
168
+ | `catherd runs clean [<id>]` | Removes the roles' scratch folders (each role's `$TMPDIR`) of runs with no live role |
169
+ | `catherd catalog refresh\|list [--backend <b>] [--role <r>] [--text <t>]` | The models catherd can place, with their indexed pairs |
170
+ | `catherd catalog sync [--force]` | Fetches the Slopalytics index now (below); it is refreshed at most hourly otherwise |
171
+ | `catherd knowledge show [--role <role>]\|add "<line>"\|rm "<text>"\|path [--repo <path>]` | The repo's knowledge.md, keyed by its git origin (its toplevel when it has none), which new runs read; `add` appends a fact of yours, marked "by hand"; a `[role, …]` tag after the source scopes a line to those roles' briefs; `rm` removes the one line the text matches |
172
+ | `catherd knowledge env set NAME=value\|NAME --from VAR`, `env rm NAME`, `env list` | The repo's gate environment, which the verifier and preflight run with; a secret by reference only |
173
+ | `catherd runs supersede <id> --by <id>`, `catherd runs pin <id>` | Closes a run with a pointer to the one that took over; re-pins a run to the repo's profile now |
174
+ | `catherd pause --machine\|--workspace <id> "<reason>"`, `catherd resume --machine\|--workspace <id>` | Pauses every run on the machine (or in a workspace) on one blocker; dispatch is refused until resume |
175
+ | `catherd lock [--slots N] [--role verifier [--run <id>]] -- <cmd>` | Runs a heavy command behind the machine-wide semaphore, in its own session (no /dev/tty); `--role verifier` keeps two runs' verifiers apart |
176
+ | `catherd run-file read\|write <run> <path>` | A run's plan, lanes and notes (`write` reads stdin); in a role, its own run only |
177
+ | `catherd gate check <run> [--item <i> --command <c> --paths <p,…>] [--milestone <M>]`, `catherd gate pass <run> --item <i> --command <c> --paths <p,…> --evidence <e>` | A verifier's gate evidence, as `gate_check`/`gate_pass`; in a role, its own run only |
178
+ | `catherd gate run <run> --milestone <M> [--command <c>] [--at <base checkout>] [--force]` | A verifier's milestone check, run by catherd on the committed HEAD, detached: failures the base already has do not block, a new failure is rerun once, and `land` needs its record |
179
+ | `catherd answer <run> <unit> <text>` | Answers a parked unit from the terminal, as the `answer` tool does; the daemon picks it up |
180
+ | `catherd mcp` | The MCP server on stdio; the plugin starts it, you never need to |
181
+ | `catherd capture-fixtures [--backend <b>] [--out <dir>]` | Contributors: records sanitized test fixtures from real runs (see CONTRIBUTING.md) |
182
+ | `catherd scorecard prepare <task>`, `record <dir> --label <l>`, `compare <label>` | Contributors: measures a catherd version on four fixed tasks against the 1.5.0 baseline (docs/dev/scorecard.md) |
218
183
 
219
184
  A profile command without a profile name (`show`, `set`, `diff`, `validate`), like the MCP profile tools, acts
220
185
  on the profile the repo you are in runs on: the one bound to it, else the active one. Pass `repo` explicitly to MCP tools; profile CLI commands accept `--host` for effective defaults. Run them as
221
186
  `bunx catherd-cli <command>` when catherd is not installed globally. Every read command takes `--json`; a bare `catherd runs` is `catherd runs list`. Exit codes: 0 ok, 1 error, 2 usage, 3 not ready, 130 interrupted; an error prints
222
187
  `error E_CODE: message` and a `fix:` line. `--verbose` (or `CATHERD_LOG=debug`) logs more to
223
- `~/.local/share/catherd/logs/`, kept for 7 days with secrets redacted. The dashboard takes `--plain` (ASCII, no colour)
224
- and `--reduced-motion`; `doctor` and `init` take `--plain` for ASCII glyphs too. `NO_COLOR` drops colour, never glyphs.
225
-
226
- Model facts and scores also come from public sources: models.dev, OpenRouter, LiteLLM, Arena (LMArena), Vectara's
227
- hallucination leaderboard and Epoch AI, plus Artificial Analysis when you give `catherd init` a free key. The MCP
228
- server syncs them in the background when a host session starts (each source at most every 12 hours, never
229
- delaying the session), `init` syncs them, and `catherd catalog sync` (or the `catalog_sync` tool) does it on demand.
230
- Each answer is kept in `~/.local/share/catherd/sources/`; a source that fails keeps its last good answer, and with no
231
- network and no sync at all catherd routes on the scores it ships. Those are the keyless sources' values, refreshed
232
- weekly (`catalog/ATTRIBUTION.md` credits each source); Artificial Analysis values are read with your key only and
233
- never shipped.
234
-
235
- A lane's kind and difficulty pick a bar: a threshold on each dimension it spans (`repo_code`, `terminal`,
236
- `honesty`, `agentic`, `frontend`; `steer` is shown but has no default bar), and the lane starts on the cheapest
237
- rung that clears them all. A rung with no value on a dimension takes its nearest stand-in's as `inferred`, and
238
- `profile validate` and `doctor` list it as a "stand-in to confirm": confirm or replace it with `catherd catalog
239
- treat-like --suggest <rung>`, then `treat-like <rung> <like>`. A ladder holds only rungs at least as strong as its
240
- start, and rungs of equal scores on two quotas start on the one the run has used least. `route` returns the rung,
241
- its ladder and a one-line why (a lane's declared `Kind:`/`Difficulty:` wins over Jev, and the why says when Jev
242
- disagreed, when no rung clears the bar, or when a tie decided); the run's `routes.jsonl` keeps every role's
243
- decision with, for the rung it picks, each threshold, the value used, its confidence and source, and catherd's own
244
- runs on it ("12 lanes, 2 climbed, 1 partial"), which it shows but never routes on. A bar of your own goes in `~/.config/catherd/catalog.override.json`, per dimension
245
- (`"bars": { "ui": { "hard": { "frontend": 1700, "honesty": null } } }`: a number sets a threshold, `null` removes
246
- the default's).
188
+ `~/.local/share/catherd/logs/`, kept for 7 days with secrets redacted. `doctor` and `init` take `--plain` for ASCII glyphs. `NO_COLOR` drops colour, never glyphs.
189
+
190
+ The catalog reads one source: the [Slopalytics](https://slopalyticsproxy.vercel.app) index, one `intelligence`
191
+ number per model and effort. It is fetched hourly (the MCP server does it in the background when a host session
192
+ starts, `init` does it, and `catherd catalog sync [--force]` does it on demand) and
193
+ cached in `~/.local/share/catherd/slopalytics.json`; a fetch that fails keeps the last good index and `doctor`
194
+ names the error. A model and effort the index does not list is not offered: it is absent from the catalog and
195
+ `catherd catalog list`, and a profile that names one fails `profile validate`. `CATHERD_NO_SYNC=1` stops the automatic
196
+ refreshes.
197
+
198
+ A lane's difficulty picks a bar: a percentile of the intelligence of the shipped models' indexed pairs (copy the
199
+ 20th, build the 45th, logic the 60th, hard the 65th), and the lane starts on the cheapest rung that clears it
200
+ (the fastest under `objective speed`). Every kind of lane is held to the same bar. A ladder holds only rungs at
201
+ least as intelligent as its start, and rungs of equal intelligence on two quotas start on the one the run has used
202
+ least. A failover stand-in must be indexed, on another quota and at least as intelligent as the rung it replaces.
203
+ Routing gives the rung, its ladder and a one-line why (a lane's declared `Kind:`/`Difficulty:` wins over Jev, and
204
+ the why says when Jev disagreed, when no rung clears the bar, or when a tie decided); the run's `routes.jsonl`
205
+ keeps every role's decision with, for the rung it picks, its intelligence, the bar it was held to and catherd's own
206
+ runs on it ("12 lanes, 2 climbed, 1 partial"), which it shows but never routes on. A run starts only when every
207
+ enabled role has an indexed rung, and it keeps the index it started on: a later refresh never changes what it
208
+ dispatches on.
209
+
210
+ Jev's yes/no answers shape the difficulty it gives: a yes to an unexplained cause, a cross-service invariant or
211
+ shared state lifts a lane to at least logic, and a yes to purely mechanical work holds it at build. A profile can
212
+ move a bar's percentile (`catherd profile set bars.logic 55`), and so can one role (`catherd profile set
213
+ roles.worker.bars.hard 65`), one difficulty at a time. `catherd profile set maxEffort.codex:gpt-6.1-sol xhigh` caps a
214
+ model's effort for every route, climb and failover; the default profile ships Opus 5.5 and Sonnet 5.5 at high and
215
+ GPT-6.1 Sol at xhigh (`null` removes one). A coding worker never runs below medium effort, whatever the objective or
216
+ the budget. Every failover is a `failover` row in the run's `routes.jsonl`.
247
217
 
248
218
  Run data lives in `~/.local/share/catherd/`, config in `~/.config/catherd/` (both follow
249
219
  `XDG_*`).
250
220
 
221
+ ### A milestone per branch
222
+
223
+ Start a run with `base` (a branch on origin, such as `main`) and each milestone becomes its own branch and git
224
+ worktree, made from `origin/<base>` under the run's folder (`trees/<milestone>`) and set up once with the `Setup:`
225
+ line the plan carries under its `#` title. Every role of the milestone works in that tree. Milestones whose `After:`
226
+ milestones are merged run side by side, a new one starting only while the machine has the memory for it: it counts
227
+ what is free (on macOS through `kern.memorystatus_level`, since `os.freemem()` reads almost nothing there), less a
228
+ reserve, and starts one more only when a milestone's share still fits above a floor. The defaults are 2 GB of
229
+ reserve and 3 GB per milestone and floor; set them per profile with `catherd profile set limits.memory.reserveMb
230
+ <MB>` (or `perMilestoneMb`, `floorMb`). A landed milestone asks you to push its branch and merge its merge request;
231
+ answer `push` and catherd pushes the branch and prints the command that opens the MR. catherd never opens an MR and
232
+ never merges; once you answer that it is merged (or origin's base holds it), a clean worktree is removed. A run
233
+ without `base` works in the repo, one milestone at a time.
234
+
251
235
  ### Coordinating several repositories
252
236
 
253
237
  A workspace can be a plain directory containing independent Git repositories. Declare its members explicitly
@@ -260,85 +244,57 @@ in `catherd.workspace.json`; catherd does not scan neighboring folders:
260
244
  }
261
245
  ```
262
246
 
263
- Run `catherd workspace inspect /path/to/workspace --json` to check the resolved members. Through MCP,
264
- `workspace_start` takes `root`, `title`, `a_lines`, and `steps`: each step has `id`, a member `repo`, `title`,
265
- `a_lines`, optional `depends_on` step ids, and the `milestone` that releases its dependents (default `M1`).
266
- A step with `release: "merge"` and a `base` ref (`origin/main`) releases them only once its landed commit is
267
- an ancestor of that ref (`git merge-base --is-ancestor`), checked when a dependent asks; fetch first, nothing
268
- is polled.
269
- An explicit `repos` map can replace the manifest. Only members used by the steps enter the run snapshot.
270
- Steps reusing one member must be ordered by dependencies. A final verification step can reuse a member
271
- after both parallel producer steps land; unordered steps in the same repository are refused.
272
-
273
- Write the shared interface or coordination agreement with `workspace_contract(workspace, content)` before
274
- starting children; the first child freezes it, and every child receives `workspace-contract.md`.
275
- `workspace_child_start(workspace, step)` creates a single-repo run only when its prerequisites have landed.
276
- Use the existing route, dispatch, verification and land workflow with that child's run id. Each member keeps
277
- its own profile, knowledge and repository rules; workers write within their own repository.
278
-
279
- `workspace_status(workspace)` and `catherd workspace status <id> --json` show the shared view and spending.
280
- The optional workspace `budget` (`minutes`, `tokens`, `usd`; no cap unless given, minutes from the first
281
- child) stops new admissions when aggregate observed spending reaches its cap, alongside each child's budget;
282
- `workspace_budget(workspace, …)` raises it. Running workers may overshoot; native subagent usage is reported
283
- after execution. Dependency readiness requires a recorded landing and finalized dispatches, not just a
284
- finished worker. Landing a step's completion milestone and dispatch admission share the parent lock; other
285
- milestones land freely, and a landed step admits a post-land fix. `workspace_pause(workspace, reason)` stops
286
- every child's admission on one blocker until `workspace_resume`. Workspaces support at most 100 repositories
287
- and 100 steps. A run folder without a readable `meta.json` is skipped and named in `workspace_status`; with a
288
- cap set, unreadable or negative usage evidence blocks admission until repaired. Stored status remains available after a checkout disappears, while child
289
- recovery and admission require the captured Git root. catherd never automatically commits, pushes,
290
- rolls back repositories or starts the next child.
247
+ Run `catherd workspace inspect /path/to/workspace --json` to check the resolved members, and
248
+ `catherd workspace status <id> --json` for a workspace run's children, dependencies and spending. The workspace
249
+ tools (`workspace_start`, `workspace_child_start`, …) are not on the session in 2.0: the daemon runs single-repo
250
+ runs, and a coordinated program is a later plan. The read-only commands, the stored runs and the `pause --workspace`
251
+ switch stay.
291
252
 
292
253
  ### Environment variables
293
254
 
294
- | Variable | What it does |
295
- | ----------------------------- | ----------------------------------------------------------------------------------------------------------- |
296
- | `TYPESAFE_API_KEY` | The Jev key, instead of the one `catherd init` saves |
297
- | `ARTIFICIAL_ANALYSIS_API_KEY` | An Artificial Analysis key for `catalog sync`, instead of the one `catherd init` saves |
298
- | `CATHERD_NO_SYNC` | `1`: no automatic sync of the public sources (at MCP server start and in `init`); `catalog sync` still runs |
299
- | `CURSOR_API_KEY` | Cursor's API key: logs `cursor-agent` in, and is what an isolated Cursor role runs on |
300
- | `XAI_API_KEY` | xAI's API key: logs `grok` in when no Grok login is active, and is what an isolated grok role runs on |
301
- | `GEMINI_API_KEY` | The Gemini API key an isolated Antigravity role runs on (agy reads it only with its Gemini API provider) |
302
- | `CATHERD_HOME` | Puts config and data under `$CATHERD_HOME/config` and `$CATHERD_HOME/data` instead of XDG |
303
- | `CATHERD_LOG` | Log level: `off`, `error`, `warn`, `info` (default) or `debug` (what `--verbose` sets) |
304
- | `CATHERD_LOCK_SLOTS` | `catherd lock`'s slot count when `--slots` is not given (before the profile's `lock.heavy`) |
305
- | `CATHERD_REDUCED_MOTION` | Any value: the dashboard's `--reduced-motion` |
306
- | `CATHERD_NO_KITTY` | Any value: turns off the kitty keyboard protocol in the dashboard, for terminals it breaks |
307
- | `CATHERD_CLAUDE_AGENTS_DIR` | Where catherd links its Claude agents (default: `$CLAUDE_CONFIG_DIR/agents`, else `~/.claude/agents`) |
308
- | `NO_COLOR` | Drops colour (the dashboard's and `--help`'s; piped `--help` has none either) |
309
-
310
- For development only: `CATHERD_STORY=1` opens the dashboard's storybook, and `CATHERD_LIVE=1` enables the live
311
- tests (CONTRIBUTING.md has the rest).
312
-
313
- ### The dashboard
314
-
315
- `catherd` opens three tabs: **1 Status** (every check with its fix; `y` copies the fix, `r` checks again),
316
- **2 Profiles** (one tree per profile: roles with their access, default rung, models and efforts, then routing,
317
- harness, budget, failover, timeouts and notify) and **3 Runs** (the host sessions that drove your runs, newest
318
- first; a session opens on its runs, their milestones and every role with its rung, status, time and last event, live
319
- ones first; a milestone opens on its digest (what landed, lanes and climbs, reviewer and verifier, tokens); a role
320
- opens on its brief, reply and record; the open screen redraws as run files change; `esc` goes back,
321
- `p` pauses). `catherd watch` opens it on Runs.
322
-
323
- - `ctrl+p` lists every command with its key and CLI twin; `?` lists the keys that work where you are.
324
- - `ctrl+x` is the leader: `ctrl+x 1`–`3` tabs, `ctrl+x n` new profile, `ctrl+x l` profiles, `ctrl+x u` and
325
- `ctrl+x r` undo and redo, `ctrl+x q` quit.
326
- - Lists: arrows or `j`/`k`, `pgup`/`pgdn`, `home`/`g`, `end`/`G`, `/` to filter; `space` ticks, `enter`
327
- changes or opens, `→`/`←` expand and collapse.
328
- - Edits are staged: nothing is written until `ctrl+s` shows the diff and you choose Save or Save & make active.
329
- `enter` never saves.
330
- - Inside a repo bound to a profile, the dashboard opens on that profile, and making a profile active binds the
331
- repo to it (as `catherd profile use <name> --repo`).
332
- - `esc` backs out one level and never quits. `q` quits, asking first if something is unsaved; `ctrl+c` quits
333
- when nothing is, and pressed twice within 1.5 s discards and exits 130.
334
- - Deleting a profile or cancelling a live role takes `ctrl+d` twice.
335
- - `--plain` draws ASCII without colour, `NO_COLOR` drops the colour, `--reduced-motion` stops the spinner.
336
- - Rebind a key in `~/.config/catherd/config.json`: `"keybinds": { "profile.save": "ctrl+w", "app.help": "none" }`
337
- (the palette shows each command by title; the ids are listed in
338
- [`src/entry/tui/commands.ts`](src/entry/tui/commands.ts)).
255
+ | Variable | What it does |
256
+ | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
257
+ | `TYPESAFE_API_KEY` | The Jev key, instead of the one `catherd init` saves |
258
+ | `CATHERD_NO_SYNC` | `1`: no automatic fetch of the Slopalytics index (at MCP server start, in `init` and at run start); `catalog sync` still runs |
259
+ | `CURSOR_API_KEY` | Cursor's API key: logs `cursor-agent` in, and is what an isolated Cursor role runs on |
260
+ | `CATHERD_HOME` | Puts config and data under `$CATHERD_HOME/config` and `$CATHERD_HOME/data` instead of XDG |
261
+ | `CATHERD_LOG` | Log level: `off`, `error`, `warn`, `info` (default) or `debug` (what `--verbose` sets) |
262
+ | `CATHERD_LOCK_SLOTS` | `catherd lock`'s slot count when `--slots` is not given (before the profile's `lock.heavy`) |
263
+ | `CATHERD_CLAUDE_AGENTS_DIR` | Where catherd links its Claude agents (default: `$CLAUDE_CONFIG_DIR/agents`, else `~/.claude/agents`) |
264
+ | `NO_COLOR` | Drops colour (`--help`'s; piped `--help` has none either) |
265
+
266
+ For development only: `CATHERD_LIVE=1` enables the live tests (CONTRIBUTING.md has the rest). `CATHERD_PANEL_DIST`
267
+ points `catherd panel` at another build of the panel than the one the package ships.
268
+
269
+ ### The panel
270
+
271
+ `catherd` (or `catherd panel`) serves the panel on `127.0.0.1` (port 4317; `--port 0` takes any free one) and opens
272
+ your browser on it. It prints `catherd panel: http://127.0.0.1:<port>/login#token=<token>` and keeps running until
273
+ Ctrl-C; `--no-open` prints the link without opening it. The token is new each start and travels in the link's
274
+ fragment, so no request or log carries it; the login page reads it, clears it from the address bar and signs you
275
+ in. A restart signs every tab out. The panel answers only to `127.0.0.1` and `localhost`, and refuses a write or a
276
+ socket from another origin.
277
+
278
+ - **Setup**: the catalog and each backend with doctor's status and fix, the profile this repo runs on with its
279
+ errors and warnings, and each role's rungs, picked from the indexed Slopalytics pairs and saved through the
280
+ profile service (other settings stay with `catherd profile set`).
281
+ - **Runs**: every run, and for each one its milestones, live roles, parked questions, quota holds and its timeline,
282
+ newest first, live over the run's `events.jsonl`. **Cancel run** stops a live run; a run starts from your
283
+ session, never from the panel.
284
+ - **Questions**: each parked unit with its question and an answer box; the unit runs again once you send it.
285
+
286
+ `catherd watch` prints the live runs as text.
339
287
 
340
288
  ## Upgrading
341
289
 
290
+ From 1.5: `bun add -g catherd-cli@latest && catherd doctor`, then `claude plugin marketplace update catherd && claude
291
+ plugin update catherd@catherd` and a new session. A run started on 1.5 finishes on 1.5, so keep it installed until
292
+ those end; new runs go through the daemon. The session has six tools (`run_start`, `status`, `answer`, `cancel`,
293
+ `result`, `profile`), every role runs headless, and a parked question goes to `notify.url`. `catherd` opens the
294
+ browser panel in place of the TUI. The catalog reads one source, the Slopalytics index, so a profile rung it does
295
+ not list must be picked again (`catherd catalog list --role <role>`). Grok Build and Antigravity are gone.
296
+ [MIGRATION.md](MIGRATION.md), "From 1.5 to 2.0", has the rest.
297
+
342
298
  From 1.4: `bun add -g catherd-cli@latest && catherd doctor`, update the plugin and start a new session; `doctor`
343
299
  names the Claude agent links to refresh. There is still no `wait` tool (it never shipped and is gone): end the
344
300
  turn, and on Codex run the coordinator inside `tmux`. A role calling a coordinator tool now gets `E_ROLE_SCOPE`,
@@ -369,12 +325,12 @@ Code session. The details are in [MIGRATION.md](MIGRATION.md).
369
325
  | [CHANGELOG.md](CHANGELOG.md) | Releases |
370
326
  | [CONTRIBUTING.md](CONTRIBUTING.md) | Development setup, the checks, commits, changesets, live tests |
371
327
  | [SECURITY.md](SECURITY.md) | Reporting a vulnerability; what catherd stores and how |
328
+ | [`docs/specs/2026-10-12-catherd-2.0-design.md`](docs/specs/2026-10-12-catherd-2.0-design.md) | The 2.0 design (binding where it differs from the earlier ones) |
372
329
  | [`docs/specs/2026-10-02-catherd-1.5-design.md`](docs/specs/2026-10-02-catherd-1.5-design.md) | The 1.5 design (binding where it differs from the earlier ones) |
373
330
  | [`docs/specs/2026-09-28-catherd-1.1-design.md`](docs/specs/2026-09-28-catherd-1.1-design.md) | The 1.1 design (binding; builds on 1.0's) |
374
331
  | [`docs/specs/2026-09-25-catherd-1.0-design.md`](docs/specs/2026-09-25-catherd-1.0-design.md) | The 1.0 design |
375
332
  | [`docs/dev/`](docs/dev/) | Maintainer docs: live verification, manual tests, dependencies, ideas |
376
333
  | [`docs/dev/live-verification.md`](docs/dev/live-verification.md) | What CI cannot run: live tests, fixture capture, the Codex sandbox |
377
- | [`docs/tui-frames.md`](docs/tui-frames.md) | Every dashboard screen as text (generated, checked in CI) |
378
334
  | [`docs/plans/`](docs/plans/), [`docs/handoff/`](docs/handoff/), [`docs/research/`](docs/research/) | How 1.0 was designed and built: plans, reviews, research |
379
335
  | [`docs/archive/0.x/`](docs/archive/0.x/) | The 0.x design and plans, for history |
380
336