catherd-cli 1.4.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 (320) hide show
  1. package/README.md +188 -169
  2. package/THIRD_PARTY_NOTICES.md +217 -35
  3. package/catalog/jev.json +27 -1
  4. package/catalog/models.json +56 -239
  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 -356
  11. package/plugin/skills/catherd-setup/SKILL.md +21 -20
  12. package/src/adapters/all.ts +0 -4
  13. package/src/adapters/backend.ts +19 -4
  14. package/src/adapters/claude-code/index.ts +126 -14
  15. package/src/adapters/codex/events.ts +10 -0
  16. package/src/adapters/codex/index.ts +17 -5
  17. package/src/adapters/cursor/home.ts +1 -1
  18. package/src/adapters/cursor/index.ts +10 -4
  19. package/src/adapters/opencode/index.ts +38 -1
  20. package/src/cli.ts +27 -27
  21. package/src/domain/agents.ts +3 -1
  22. package/src/domain/bars.ts +33 -107
  23. package/src/domain/blocked.ts +72 -0
  24. package/src/domain/branch.ts +51 -0
  25. package/src/domain/brief.ts +106 -0
  26. package/src/domain/catalog.ts +69 -313
  27. package/src/domain/changes.ts +23 -1
  28. package/src/domain/cost.ts +19 -29
  29. package/src/domain/errors.ts +6 -2
  30. package/src/domain/fail-lines.ts +26 -0
  31. package/src/domain/failover.ts +37 -75
  32. package/src/domain/findings.ts +47 -0
  33. package/src/domain/gate-brief.ts +53 -0
  34. package/src/domain/hints.ts +13 -2
  35. package/src/domain/ids.ts +13 -2
  36. package/src/domain/jev.ts +47 -2
  37. package/src/domain/judge.ts +124 -0
  38. package/src/domain/lane.ts +118 -3
  39. package/src/domain/milestone-memory.ts +53 -0
  40. package/src/domain/notice.ts +32 -8
  41. package/src/domain/notify.ts +32 -0
  42. package/src/domain/plan-doc.ts +198 -0
  43. package/src/domain/plan-lint.ts +141 -0
  44. package/src/domain/profile-rules.ts +175 -138
  45. package/src/domain/profile.ts +140 -63
  46. package/src/domain/record.ts +68 -3
  47. package/src/domain/reply.ts +29 -0
  48. package/src/domain/role-prompts.ts +182 -56
  49. package/src/domain/role-scope.ts +76 -0
  50. package/src/domain/role-tools.ts +34 -0
  51. package/src/domain/roles.ts +2 -0
  52. package/src/domain/route.ts +90 -0
  53. package/src/domain/rules.ts +33 -0
  54. package/src/domain/run-events.ts +298 -0
  55. package/src/domain/run-machine.ts +668 -0
  56. package/src/domain/run-state.ts +1310 -0
  57. package/src/domain/scorecard.ts +197 -0
  58. package/src/domain/select.ts +229 -72
  59. package/src/domain/slopalytics.ts +72 -0
  60. package/src/domain/state.ts +5 -0
  61. package/src/domain/util.ts +22 -0
  62. package/src/domain/workspace.ts +130 -0
  63. package/src/entry/answer-command.ts +39 -0
  64. package/src/entry/catalog-command.ts +24 -165
  65. package/src/entry/check-bin.ts +17 -0
  66. package/src/entry/cli-kit.ts +18 -2
  67. package/src/entry/daemon-bin.ts +22 -0
  68. package/src/entry/deps.ts +2 -0
  69. package/src/entry/doctor-command.ts +20 -2
  70. package/src/entry/glyphs.ts +15 -2
  71. package/src/entry/host-arg.ts +28 -0
  72. package/src/entry/init-command.ts +20 -69
  73. package/src/entry/knowledge-command.ts +121 -5
  74. package/src/entry/lock-command.ts +103 -8
  75. package/src/entry/mcp/handshake.ts +6 -2
  76. package/src/entry/mcp/role-bin.ts +20 -0
  77. package/src/entry/mcp/role-server.ts +134 -0
  78. package/src/entry/mcp/server.ts +85 -21
  79. package/src/entry/mcp/session-tools.ts +149 -0
  80. package/src/entry/panel/openapi.ts +189 -0
  81. package/src/entry/panel/server.ts +410 -0
  82. package/src/entry/panel-command.ts +68 -0
  83. package/src/entry/pause-command.ts +67 -0
  84. package/src/entry/profile-command.ts +33 -18
  85. package/src/entry/role-cli-command.ts +159 -0
  86. package/src/entry/runs-command.ts +81 -27
  87. package/src/entry/scorecard-command.ts +187 -0
  88. package/src/entry/supervise-bin.ts +1 -1
  89. package/src/entry/supervise-command.ts +30 -3
  90. package/src/entry/workspace-command.ts +44 -0
  91. package/src/infra/boot-lock.ts +25 -0
  92. package/src/infra/delivery.ts +3 -0
  93. package/src/infra/dispatch-dir.ts +2 -0
  94. package/src/infra/env.ts +11 -3
  95. package/src/infra/git.ts +70 -0
  96. package/src/infra/heavy-lock.ts +133 -6
  97. package/src/infra/host-probe.ts +16 -0
  98. package/src/infra/launch.ts +63 -7
  99. package/src/infra/lock-activity.ts +88 -0
  100. package/src/infra/login-env.ts +48 -0
  101. package/src/infra/memory.ts +45 -0
  102. package/src/infra/ntfy.ts +40 -0
  103. package/src/infra/open-url.ts +42 -0
  104. package/src/infra/paths.ts +37 -2
  105. package/src/infra/role-mcp.ts +69 -0
  106. package/src/infra/slopalytics.ts +30 -0
  107. package/src/infra/store.ts +6 -1
  108. package/src/infra/supervisor.ts +107 -16
  109. package/src/services/admission.ts +133 -31
  110. package/src/services/backends.ts +4 -6
  111. package/src/services/budget.ts +26 -6
  112. package/src/services/capture.ts +1 -22
  113. package/src/services/catalog-service.ts +155 -254
  114. package/src/services/credentials.ts +15 -26
  115. package/src/services/daemon.ts +181 -0
  116. package/src/services/dispatch-service.ts +209 -17
  117. package/src/services/dispatches.ts +30 -2
  118. package/src/services/doctor-access.ts +8 -3
  119. package/src/services/doctor-backends.ts +1 -1
  120. package/src/services/doctor-checks.ts +47 -0
  121. package/src/services/doctor-docker.ts +221 -0
  122. package/src/services/doctor-role-mcp.ts +65 -0
  123. package/src/services/doctor.ts +72 -15
  124. package/src/services/end-push.ts +157 -0
  125. package/src/services/failover-rungs.ts +109 -0
  126. package/src/services/finalize.ts +24 -2
  127. package/src/services/gate-env.ts +217 -0
  128. package/src/services/gate-service.ts +231 -45
  129. package/src/services/global-install.ts +46 -13
  130. package/src/services/jev-service.ts +2 -4
  131. package/src/services/lane-edit.ts +154 -0
  132. package/src/services/lane-service.ts +291 -55
  133. package/src/services/milestone-check.ts +433 -0
  134. package/src/services/milestone-tree.ts +170 -0
  135. package/src/services/milestones.ts +167 -29
  136. package/src/services/notifier.ts +124 -4
  137. package/src/services/notify-service.ts +26 -0
  138. package/src/services/orchestrator-wait.ts +82 -0
  139. package/src/services/panel-setup.ts +116 -0
  140. package/src/services/pause.ts +161 -0
  141. package/src/services/peek.ts +79 -17
  142. package/src/services/plan-input.ts +151 -0
  143. package/src/services/ports.ts +60 -5
  144. package/src/services/preflight.ts +232 -24
  145. package/src/services/profile-service.ts +31 -3
  146. package/src/services/profile-store.ts +18 -6
  147. package/src/services/protocol.ts +123 -25
  148. package/src/services/provenance.ts +34 -89
  149. package/src/services/questions.ts +24 -0
  150. package/src/services/reconcile.ts +33 -1
  151. package/src/services/reentry.ts +7 -6
  152. package/src/services/role-access.ts +27 -0
  153. package/src/services/routing-service.ts +161 -42
  154. package/src/services/run-briefs.ts +477 -0
  155. package/src/services/run-client.ts +217 -0
  156. package/src/services/run-effects.ts +837 -0
  157. package/src/services/run-events-store.ts +174 -0
  158. package/src/services/run-evidence.ts +1 -1
  159. package/src/services/run-pin.ts +125 -0
  160. package/src/services/run-read.ts +221 -0
  161. package/src/services/run-report.ts +176 -0
  162. package/src/services/run-service.ts +204 -23
  163. package/src/services/run-store.ts +159 -18
  164. package/src/services/scorecard-metrics.ts +86 -0
  165. package/src/services/scorecard.ts +382 -0
  166. package/src/services/scratch.ts +60 -0
  167. package/src/services/sessions.ts +3 -1
  168. package/src/services/state.ts +21 -0
  169. package/src/services/summary.ts +76 -12
  170. package/src/services/tree-path.ts +27 -0
  171. package/src/services/verifier-brief.ts +23 -0
  172. package/src/services/verifier-step.ts +48 -0
  173. package/src/services/workspace-admission.ts +259 -0
  174. package/src/services/workspace-service.ts +259 -0
  175. package/src/services/workspace-store.ts +95 -0
  176. package/web/dist/assets/Brand-PKlUX5TE.js +1 -0
  177. package/web/dist/assets/Brand-PKlUX5TE.js.br +0 -0
  178. package/web/dist/assets/Brand-PKlUX5TE.js.gz +0 -0
  179. package/web/dist/assets/Modal-Dxc5so53.js +1 -0
  180. package/web/dist/assets/Modal-Dxc5so53.js.br +0 -0
  181. package/web/dist/assets/Modal-Dxc5so53.js.gz +0 -0
  182. package/web/dist/assets/Pressable-C8-T6Ed_.js +1 -0
  183. package/web/dist/assets/StatusChip-B5xfI_Mn.js +153 -0
  184. package/web/dist/assets/StatusChip-B5xfI_Mn.js.br +0 -0
  185. package/web/dist/assets/StatusChip-B5xfI_Mn.js.gz +0 -0
  186. package/web/dist/assets/_app-Ea5cpyKe.js +1 -0
  187. package/web/dist/assets/_app-Ea5cpyKe.js.br +0 -0
  188. package/web/dist/assets/_app-Ea5cpyKe.js.gz +0 -0
  189. package/web/dist/assets/_runId-pTG0fXVo.js +1 -0
  190. package/web/dist/assets/_runId-pTG0fXVo.js.br +0 -0
  191. package/web/dist/assets/_runId-pTG0fXVo.js.gz +0 -0
  192. package/web/dist/assets/drawer-Du3cdlok.js +1 -0
  193. package/web/dist/assets/drawer-Du3cdlok.js.br +0 -0
  194. package/web/dist/assets/drawer-Du3cdlok.js.gz +0 -0
  195. package/web/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  196. package/web/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  197. package/web/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  198. package/web/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  199. package/web/dist/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  200. package/web/dist/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  201. package/web/dist/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  202. package/web/dist/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  203. package/web/dist/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  204. package/web/dist/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  205. package/web/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  206. package/web/dist/assets/index-B6GiwDkh.js +11 -0
  207. package/web/dist/assets/index-B6GiwDkh.js.br +0 -0
  208. package/web/dist/assets/index-B6GiwDkh.js.gz +0 -0
  209. package/web/dist/assets/index-C5IbylvM.css +2 -0
  210. package/web/dist/assets/index-C5IbylvM.css.br +0 -0
  211. package/web/dist/assets/index-C5IbylvM.css.gz +0 -0
  212. package/web/dist/assets/label-DFSYBc62.js +1 -0
  213. package/web/dist/assets/label-DFSYBc62.js.br +0 -0
  214. package/web/dist/assets/label-DFSYBc62.js.gz +0 -0
  215. package/web/dist/assets/link-D8EcKZUt.js +1 -0
  216. package/web/dist/assets/link-D8EcKZUt.js.br +0 -0
  217. package/web/dist/assets/link-D8EcKZUt.js.gz +0 -0
  218. package/web/dist/assets/login-DaN5HPPW.js +1 -0
  219. package/web/dist/assets/login-DaN5HPPW.js.br +0 -0
  220. package/web/dist/assets/login-DaN5HPPW.js.gz +0 -0
  221. package/web/dist/assets/query-Cu--ccT3.js +1 -0
  222. package/web/dist/assets/questions-shoO9OVj.js +1 -0
  223. package/web/dist/assets/questions-shoO9OVj.js.br +0 -0
  224. package/web/dist/assets/questions-shoO9OVj.js.gz +0 -0
  225. package/web/dist/assets/react-query.gen-Bu2yV-qJ.js +12 -0
  226. package/web/dist/assets/react-query.gen-Bu2yV-qJ.js.br +0 -0
  227. package/web/dist/assets/react-query.gen-Bu2yV-qJ.js.gz +0 -0
  228. package/web/dist/assets/rolldown-runtime-XKyaHtl9.js +1 -0
  229. package/web/dist/assets/run-status-C0DRuV7U.js +1 -0
  230. package/web/dist/assets/runs-C3rg2zZc.js +1 -0
  231. package/web/dist/assets/runs-C3rg2zZc.js.br +0 -0
  232. package/web/dist/assets/runs-C3rg2zZc.js.gz +0 -0
  233. package/web/dist/assets/setup-5I4Vl9fR.js +1 -0
  234. package/web/dist/assets/setup-5I4Vl9fR.js.br +0 -0
  235. package/web/dist/assets/setup-5I4Vl9fR.js.gz +0 -0
  236. package/web/dist/assets/table-BOxXhqS4.js +1 -0
  237. package/web/dist/assets/table-BOxXhqS4.js.br +0 -0
  238. package/web/dist/assets/table-BOxXhqS4.js.gz +0 -0
  239. package/web/dist/assets/textfield-BzRFkxBF.js +1 -0
  240. package/web/dist/assets/textfield-BzRFkxBF.js.br +0 -0
  241. package/web/dist/assets/textfield-BzRFkxBF.js.gz +0 -0
  242. package/web/dist/assets/time--9kSQbbp.js +1 -0
  243. package/web/dist/assets/use-css-variable-CpnN9WtA.js +5 -0
  244. package/web/dist/assets/use-css-variable-CpnN9WtA.js.br +0 -0
  245. package/web/dist/assets/use-css-variable-CpnN9WtA.js.gz +0 -0
  246. package/web/dist/assets/useMutation-CVPKlR34.js +1 -0
  247. package/web/dist/assets/useMutation-CVPKlR34.js.br +0 -0
  248. package/web/dist/assets/useMutation-CVPKlR34.js.gz +0 -0
  249. package/web/dist/index.html +15 -0
  250. package/catalog/ATTRIBUTION.md +0 -36
  251. package/catalog/scores.json +0 -3202
  252. package/catalog/sources.json +0 -97
  253. package/src/adapters/antigravity/events.ts +0 -131
  254. package/src/adapters/antigravity/home.ts +0 -46
  255. package/src/adapters/antigravity/index.ts +0 -320
  256. package/src/adapters/antigravity/models.ts +0 -37
  257. package/src/adapters/grok/events.ts +0 -112
  258. package/src/adapters/grok/home.ts +0 -132
  259. package/src/adapters/grok/index.ts +0 -339
  260. package/src/adapters/grok/models.ts +0 -48
  261. package/src/domain/calibration.ts +0 -125
  262. package/src/domain/sources.ts +0 -144
  263. package/src/entry/mcp/dispatch-tools.ts +0 -52
  264. package/src/entry/mcp/lane-tools.ts +0 -84
  265. package/src/entry/mcp/protocol-tools.ts +0 -57
  266. package/src/entry/mcp/run-tools.ts +0 -148
  267. package/src/entry/mcp/setup-tools.ts +0 -108
  268. package/src/entry/tui/commands.ts +0 -563
  269. package/src/entry/tui/effects.ts +0 -381
  270. package/src/entry/tui/fixtures.ts +0 -637
  271. package/src/entry/tui/profile-edits.ts +0 -146
  272. package/src/entry/tui/profile-tree.ts +0 -429
  273. package/src/entry/tui/providers/app.tsx +0 -162
  274. package/src/entry/tui/providers/boundary.tsx +0 -57
  275. package/src/entry/tui/providers/data.tsx +0 -160
  276. package/src/entry/tui/providers/keymap.tsx +0 -166
  277. package/src/entry/tui/providers/root.tsx +0 -45
  278. package/src/entry/tui/providers/theme.tsx +0 -17
  279. package/src/entry/tui/providers/toast.tsx +0 -77
  280. package/src/entry/tui/run.tsx +0 -114
  281. package/src/entry/tui/state.ts +0 -373
  282. package/src/entry/tui/stories.ts +0 -114
  283. package/src/entry/tui/text.ts +0 -130
  284. package/src/entry/tui/theme.ts +0 -140
  285. package/src/entry/tui/views/app.tsx +0 -208
  286. package/src/entry/tui/views/dialogs.tsx +0 -41
  287. package/src/entry/tui/views/profile-actions.ts +0 -331
  288. package/src/entry/tui/views/profiles.tsx +0 -520
  289. package/src/entry/tui/views/runs.tsx +0 -573
  290. package/src/entry/tui/views/save-dialog.tsx +0 -340
  291. package/src/entry/tui/views/status.tsx +0 -209
  292. package/src/entry/tui/widgets/chrome.tsx +0 -114
  293. package/src/entry/tui/widgets/dialog-confirm.tsx +0 -58
  294. package/src/entry/tui/widgets/dialog-prompt.tsx +0 -52
  295. package/src/entry/tui/widgets/dialog-select.tsx +0 -212
  296. package/src/entry/tui/widgets/dialog.tsx +0 -68
  297. package/src/entry/tui/widgets/line.tsx +0 -92
  298. package/src/entry/tui/widgets/list.tsx +0 -197
  299. package/src/entry/tui/widgets/spinner.tsx +0 -49
  300. package/src/entry/tui/widgets/toast.tsx +0 -62
  301. package/src/infra/sources/arena.ts +0 -87
  302. package/src/infra/sources/artificial-analysis.ts +0 -112
  303. package/src/infra/sources/cache.ts +0 -124
  304. package/src/infra/sources/csv.ts +0 -38
  305. package/src/infra/sources/epoch.ts +0 -82
  306. package/src/infra/sources/http.ts +0 -75
  307. package/src/infra/sources/litellm.ts +0 -58
  308. package/src/infra/sources/models-dev.ts +0 -59
  309. package/src/infra/sources/openrouter-endpoints.ts +0 -52
  310. package/src/infra/sources/openrouter-models.ts +0 -60
  311. package/src/infra/sources/rows.ts +0 -38
  312. package/src/infra/sources/vectara.ts +0 -69
  313. package/src/infra/sources/zip.ts +0 -48
  314. package/src/services/catalog-refresh.ts +0 -201
  315. package/src/services/doctor-sources.ts +0 -76
  316. package/src/services/runs-page.ts +0 -255
  317. package/src/services/source-derive.ts +0 -374
  318. package/src/services/source-sync.ts +0 -305
  319. package/src/services/standins.ts +0 -204
  320. package/src/services/treat-likes.ts +0 -97
@@ -1,370 +1,111 @@
1
1
  ---
2
2
  name: catherd
3
- description: Use when the user asks for a task or a project to be orchestrated with catherd — /catherd, "orchestrate this with catherd", "run this on catherd" — or when resuming a paused catherd run. Not for a plain request that merely mentions an architect, a verifier, a review or a plan.
3
+ description: Use when the user asks for a task or a project to be orchestrated with catherd — /catherd, "orchestrate this with catherd", "run this on catherd" — or when resuming, answering or reading a catherd run. Not for a plain request that merely mentions an architect, a verifier, a review or a plan.
4
4
  ---
5
5
 
6
6
  # catherd
7
7
 
8
8
  ## Overview
9
9
 
10
- You are the orchestrator of an autopilot build. The goals, in order:
10
+ catherd runs the work in a background daemon: it plans, dispatches the roles, reviews, verifies and lands each
11
+ milestone by itself, and writes everything it does to the run's `events.jsonl`. You are the owner's front door to
12
+ it, not its driver. Your job is four things:
11
13
 
12
- 1. the work finishes without the user;
13
- 2. it finishes fast;
14
- 3. it stays cheap;
15
- 4. it holds its quality.
14
+ - write the A-lines the run must meet;
15
+ - start the run;
16
+ - carry the owner's answers to the questions the run parks;
17
+ - relay the finished report.
16
18
 
17
- Your job:
19
+ **Your first call is `status()`.** Its `version` must be the one this plugin pins, `catherd-cli@2.0.0-beta.20261022113309`. If it
20
+ differs, stop and tell the user to restart their host session so the plugin and its server match.
18
21
 
19
- - plan the milestones;
20
- - dispatch the roles;
21
- - read their one-line results;
22
- - report.
23
-
24
- The catherd server keeps `state.md` true: it rewrites it on every dispatch, climb and landing.
25
-
26
- **Your first call is `status()`.** Its `version` must be the one this plugin pins, `catherd-cli@1.4.0`. If it differs, stop and tell the user to restart their host session so the plugin and its server match. Read its host and capability diagnostics; unknown or conflicting identity never authorizes ownership or push.
27
-
28
- **You never edit product files.** Every line of code, tests or docs comes from a role, including a one-line fix.
29
-
30
- **You run in the user's own session, on purpose.** The main thread is the user's own model in Claude Code or native Codex, with their plugins, hooks and memory beside it: the environment they decide in every day. Never propose a stripped launcher or a headless relay to save tokens.
31
-
32
- **Each role runs in its vendor's own harness with the user's customizations — never isolate it.** Codex roles keep the user's config, hooks, MCP servers, skills and `AGENTS.md`. The one exception is the user's own choice, the profile's `harness.<name>.isolated`, and `dispatch` applies it for you.
22
+ **You never edit product files and you never dispatch a role.** Every line of code, tests or docs comes from a
23
+ role the daemon runs. Each role runs headless in its vendor's own harness with the user's customizations; never
24
+ isolate it (the profile's `harness.<name>.isolated` is the user's own choice, and the daemon applies it).
33
25
 
34
26
  ## Tools
35
27
 
36
- The catherd MCP tools ship with this plugin. Discover them through the host's available capability mechanism: tool names and deferred loading vary by host. In Claude Code they appear as `mcp__plugin_catherd_catherd__<name>`; use `ToolSearch` there when deferred, and load `PushNotification` if available. Codex uses its own exposed tools and discovery facility; never invent a Claude `ToolSearch`, `Agent` or notification tool there.
37
-
38
- Pass the actual project `repo` explicitly to profile, setup and catalog tools that accept it. The native Codex MCP server starts in the installed plugin root, so its cwd is not evidence of the project. `run_start(repo, ...)` establishes the run's repository.
39
-
40
- | Tool | Use |
41
- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
42
- | `status(run?)` | First, and whenever the user asks where it stands: `version`, then per run the open owner questions, the `state.md` tail, live roles, totals, Claude subagents, the verifier's step, budget, milestones |
43
- | `run_start(repo, title, a_lines)` | Once per project. Returns `run`, the id every other call takes, `dir`, the run folder `R`, and `protocol`: the next step of the milestone loop and its six-line checklist |
44
- | `peek(run?, name?)` | Never waits. Per run: the open owner questions first (the owner's to answer), each live role with its rung, time and last event, every finished record not yet read, the next step, the verifier's step, and `protocol` (the milestone loop's next step and the checklist). It marks nothing read: `result` does |
45
- | `route(run, lane_file?, role?)` | A lane's rung (from Jev, else the lane file's `Kind:`/`Difficulty:`, else the profile), or a role's rung. Returns `rung`, `ladder`, `backend`, `agent` |
46
- | `preflight(run, confirmed?)` | Each lane's fast check once, before any lane runs. Outcomes below |
47
- | `dispatch(run, role, name, brief, rung, thread?, lane?, next?)` | Starts one process role (Codex, claude-code or opencode) and returns at launch, in about a second, with `dispatched`. It routes a lane not routed yet, appends the role's reply contract to the brief, and its result arrives as a catherd message |
48
- | `result(run, name)` | A role's latest reply, capped, its record and its `hints`; reading a finished record marks it read |
49
- | `cancel(run, name)` | Stops a live role and returns its record, `cancelled`, and `hints` |
50
- | `record_agent_run(run, name, role, rung, total_tokens, duration_ms?, cost_usd?, status?, lane?)` | Native Claude Agent results on Claude Code only. The budget counts them; `lane` counts their time toward that lane's kind; a verifier named `verifier-<M>` records FAIL with `status: "failed"` |
51
- | `climb(run, lane, reason, evidence?, env?)` | The lane's next rung, with its `backend` and `agent`, or `top: true`. `env: true` when the environment, not the rung, caused it |
52
- | `ask(run, question, state)` | Jev's `finding` or `same-defect` answer |
53
- | `gate_check(run, item, command, paths, milestone?)`, `gate_pass(run, item, command, paths, evidence)` | The verifier's gate ledger: an item that passed on the same content is carried over, not run again; `milestone` scopes the digest's carried items |
54
- | `park(run, milestone, question)`, `answer(run, milestone, answer)` | An owner question parks its milestone while the rest of the run goes on; the owner's answer unparks it |
55
- | `land(run, milestone, what, commit, evidence, next, learned?, skip?)` | A landed milestone's ledger row, with the minutes it took, `state.md`, and `digest`, the milestone's digest. Refused until the milestone has its reviewer and its verifier. `learned` appends to this repo's `knowledge.md` |
56
- | `read_knowledge(repo)` | What past runs of this repo learned. The dossier brief reads it |
57
- | `write_run_file(run, path, content)`, `read_run_file(run, path)` | Files in `R`. Never your own Write or Read tools there: `R` is outside the repo |
58
- | `set_next(run, next)` | The next step, when you pause or the plan changes. Returns `state` and, when git fails, `hints` |
59
- | `runs_summary(run?, repo?, role?, since_days?)` | Time, tokens, refusals and climbs per role and rung, the Claude subagent runs, and the harness cost, for the report |
60
- | `profile_get(repo?)` | The profile this repo runs on: each role's access, rungs and enforcement, failover, budget, timeouts, and the moments to push |
61
-
62
- **A tool returns `hints` when it has any:** one line each, on what to do next. Read them before you move on.
63
-
64
- **Every error is `{ code, message, fix }`.** Read the code, act on the fix, and never retry the same call blindly:
65
-
66
- - `E_ADMIT_OVERLAP`: the lane shares an owned path with a running lane. Dispatch it when that one returns.
67
- - `E_ADMIT_DUPLICATE`: that role name is already running. It reports through a catherd message when it finishes; `peek(run, name)` shows it now, and `cancel` stops it.
68
- - `E_ADMIT_RUNG`: the rung is not on that role's ladder, it is a `claude:` rung, or the profile turns the role off. Use the rung `route` returned; native `claude:` requires Claude Code; skip a role that is off. On Codex, explain the exact `claude-code:` model/effort equivalent or the reviewed host-default reset instead of converting the rung yourself.
69
- - `E_RUN_BUDGET`: the run's budget is spent (a soft cap: roles already running finish). Pause, report and push.
70
- - `E_BACKEND_MISSING`, `E_BACKEND_NOT_LOGGED_IN`, `E_BACKEND_TOO_OLD`, `E_BACKEND_CANNOT_RUN`: tell the user the `fix`, word for word, then pause.
71
- - `E_LANE_INVALID`: a lane file's `Kind:` or `Difficulty:` is missing or not one the catalog knows. Fix the header (the `fix` lists the values), or have the architect fix it, then call again.
72
- - `E_LAND_GATE`: the milestone has no reviewer record or no verifier verdict since its lanes started, it is parked, or its `skip` does not hold. Run what the message names, then land again.
73
- - `E_CLIMB_DESIGN`: the evidence points at the plan, not the rung. Send it to the architect (an `ask` finding, then an architect delta), not up the ladder.
74
-
75
- ## Roles
76
-
77
- | Role | How to run it | Job |
78
- | ----------- | ----------------------------------------------------------------------- | ------------------------------------------------------- |
79
- | architect | `route(run, role: "architect")`, then the backend rule below | Decisions, milestones, lane files. No code. |
80
- | verifier | `route(run, role: "verifier")`, then the backend rule below | Independent PASS/FAIL of a milestone, by running it |
81
- | worker | `dispatch(run, "worker", "worker-<lane>", brief, rung, lane: "<lane>")` | One lane: its code and its tests |
82
- | reviewer | `dispatch(run, "reviewer", "reviewer-<m>", brief, rung)` | Review of a milestone's diff |
83
- | ui-reviewer | `dispatch(run, "ui-reviewer", "ui-<m>", brief, rung)` | Screenshots of the changed screens with `agent-browser` |
84
- | artist | `dispatch(run, "artist", "artist-<n>", brief, rung)` | Images a screen needs, with Codex's built-in image tool |
85
- | writer | `dispatch(run, "writer", "writer-<m>", brief, rung)` | README, docs, changelog, MR body |
86
- | researcher | `dispatch(run, "researcher", "researcher-<n>", brief, rung)` | The dossier, or one factual question about the code |
87
-
88
- - **Every rung comes from `route`,** never from you, for every role including architect and verifier. A rung names its backend: `backend:model#effort`, like `codex:gpt-6.1-sol#high` or `claude:claude-opus-5-5#high`. Only `backend: "claude"` on a Claude Code host uses `Agent(subagent_type: <agent>)`, with the brief and run id as its prompt. Every process backend uses `dispatch` followed by `result`, on either host. `dispatch` refuses native Claude rungs; Codex never fabricates native agents or silently changes `claude:` to `claude-code:`.
89
- - **Only omitted architect/verifier rungs follow the host:** Codex uses exactly `codex:gpt-6.1-sol#high` and `codex:gpt-6.1-sol#low`; Claude Code retains its native Claude defaults. Explicit ladders, model IDs, efforts and existing materialized profiles stay unchanged. A deliberate reset removes only those two roles' `rungs` and `defaultRung` through the reviewed CLI workflow in the setup skill.
90
- - **Verify the exact `gpt-6.1-sol` model ID against native catalog discovery and validation.** If the catalog spells it differently, report the mismatch and resolve it explicitly with the owner; never silently normalize or substitute a model. Retain architect high and verifier low effort.
91
- - **After every native Claude subagent returns on Claude Code,** call `record_agent_run(run, name, role, rung, total_tokens, duration_ms, lane)` with the numbers its Agent result reports (`lane` when it worked one). Claude runs cost the budget too, and catherd cannot see them otherwise. Process roles already have dispatch records; do not report them as native agents.
92
- - **A role the profile disables** (`profile_get`; every role but the worker can be off) is skipped, and the report says so.
93
- - **Access:** catherd sets it per role. Worker, artist and writer write in the repo, the temp dir and catherd's lock dir, and reach the network, loopback ports and a local Docker, so a worker runs its installs and tests itself; reviewer, researcher and architect read; verifier and UI reviewer get full access for Docker, a browser, gate logs and screenshots. `catherd doctor` says per backend what a worker can reach.
94
- - **A read-only role on claude-code or opencode has no shell** (no `git diff`, no `ls`), so its brief must list the files to read.
95
- - **Cheap rungs hide broken tools.** The lowest Track A rung stays silent about a broken tool about a third of the time, so every lane on it is checked by your fast check, not by its own word.
96
- - **Native Claude agents, only on Claude Code:**
97
- - catherd generates them from the profile, and Claude Code registers them at session start.
98
- - Pass no `model` to those Agent calls. Never let `Plan`, `general-purpose` or `Explore` stand in.
99
- - `Agent type … not found` means the profile changed after this session started: tell the user to open a new session.
100
- - If the model needs a newer Claude Code, stop and tell the user to upgrade Claude Code. Never pass a `model` to get past it.
101
- - **The record:** each dispatch has its own folder, `R/roles/<name>/<dispatchId>/` (brief, reply, events, stderr); `result(run, name)` reads the latest. `R/runs.jsonl` holds one record per dispatch (role, rung, status, thread, seconds, tokens, the owned files it changed and any it should not have). `R/agents.jsonl` holds the Claude subagent runs you reported. Together they are the token and time record: never keep your own.
102
-
103
- ## Effort: the ladder, decided by Jev
104
-
105
- A lane starts on the lowest rung that can do it, and climbs one rung when it shows it cannot. The ladders come from the profile and the catalog. With the default profile:
106
-
107
- | Track | Lanes | Rungs, low to high |
108
- | ----- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
109
- | A | `copy` or `build`: an existing pattern, a clear fast check | `codex:gpt-6-luna#high` → `codex:gpt-6-sol#medium` → `codex:gpt-6-sol#high` → `codex:gpt-6-sol#xhigh` |
110
- | B | `logic` or `hard`, or `terminal` work: state, concurrency, ops, unclear cause | `codex:gpt-6-sol#medium` → `codex:gpt-6-sol#high` → `codex:gpt-6-sol#xhigh` |
111
-
112
- **Jev picks the start, when the user has it.** Jev (TypeSafe) is a decision model: it answers a fixed set of questions about the lane with calibrated probabilities, usually in well under a second, for a fraction of a cent; `route` gives up on it after 25 s. It is optional. When its probabilities do not settle the track, or with no Jev key, `route` uses the lane file's `Kind:` and `Difficulty:` lines (`source: "lane"`), else the profile's default (`source: "default"`), so the run never waits on it. When Jev is sure of the kind but not the difficulty, `route` keeps Jev's kind and takes the difficulty from the lane's `Difficulty:` line, else the role's default (`source: "jev-kind"`). Every Jev call is logged to `R/jev.jsonl`, without the lane's text.
113
-
114
- | When | Call | On the answer |
115
- | --------------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------- |
116
- | Each lane, before its first dispatch | `route(run, "lanes/Mx.Ly.md")` | Dispatch it at `rung` |
117
- | A review finding that may be the plan's fault | `ask(run, "finding", { lane_file: "lanes/Mx.Ly.md", finding: "<the line>" })` | `design` → the architect. Else → the worker |
118
- | A finding back after its fix round | `ask(run, "same-defect", { before: "<old line>", after: "<new line>" })` | `yes` → climb one rung |
119
-
120
- **Climb one rung** with `climb(run, lane, reason, evidence)` (add `env: true` when a missing service, a broken tool or a usage limit caused it, not the rung), then dispatch the lane at the new rung on a fresh thread whose brief is the lane file plus the path of the failing evidence, when:
121
-
122
- - your fast check fails twice on that lane (`check-failed-twice`);
123
- - the lane gets a BLOCKER (`blocker`), or Jev calls a returning finding the same defect (`same-defect`);
124
- - the reply says `STATUS: refused` or `blocked`, or the run exits 0 while the lane's owned files are unchanged: that is a refusal, whatever the reply says (`refused`, `blocked`, `unchanged`). The record's `hints` flag each of these as `climb: <reason>`.
125
-
126
- A usage limit is not a climb. When the profile names a stand-in for that rung, catherd has already started the role on it, on a fresh thread, before it tells you: its message says `limit on <rung>; failed over to <rung>`, the limited record's first hint says `limit: … failed over to <rung>`, and the stand-in's own result arrives later. With no stand-in, the message says `paused: no stand-in` and the run is paused.
127
-
128
- A climb is for capability only. When the evidence says the lane cannot be done as planned (the plan contradicts itself, the fix needs a file the lane does not own, an interface between lanes), `climb` refuses with `E_CLIMB_DESIGN`: that goes to the architect.
129
-
130
- A failure on the top rung (`top: true`) goes to the architect when Jev calls it design, else to the report as open.
131
-
132
- - Jev decides which model does the work. It never decides that the work is done: only a check, the reviewer or the verifier does.
133
- - `R/routes.jsonl` records each lane's rung and every climb with its reason; `R/outcomes.jsonl` gets one row per lane when its milestone lands or it fails its top rung; a lane written again (landed after failing its top rung, or re-landed) keeps its rows, and the last row per lane wins.
134
- - Never put a secret or a key into an `ask` state. Keep the state short and in English.
135
-
136
- ## Threads
137
-
138
- A resumed thread replays its whole history on every tool call. In the first real run, one worker thread cost 20–25M input tokens per resume, and threads were 90% of the Codex spend.
139
-
140
- - **Resume a thread only for its own fix round:** the reviewer's findings on that piece, or the verifier's FAIL, at the same rung. That is `dispatch(…, thread: <record.thread>)`, with the fix as the brief.
141
- - **A new piece of work gets a fresh thread,** even for the same worker role: a new bug, a cleanup slice, a docs pass, a re-run, a climb to the next rung. Its brief carries what it needs, from its lane file and the ledger.
142
- - A `thread-heavy` hint means that thread is spent. Its next piece starts fresh.
143
-
144
- ## Your own context
145
-
146
- Your context is re-read on every turn, and it is the run's most expensive token. In the first real run you were 68% of the Claude spend: 269 turns at about 220k tokens each.
147
-
148
- - **One turn per transition.** Make a transition's independent calls back to back (a `land`, the next lanes' routes and dispatches), each `dispatch` returning in about a second, then end the turn with one status line.
149
- - **Read little, and read it narrowly.**
150
- - From the architect, read its short reply. The plan lives in `plan.md` and the lane files; read a section with `read_run_file` only when a decision needs it.
151
- - From a role, read its record and its capped reply.
152
- - Never read a log, a diff, a test file or source.
153
- - **Brief by path.** A brief names the files a role must read (its lane file, a prior reply, a finding). Never paste their contents into your own context to copy them over.
154
- - **Screenshots are paths.** The UI reviewer's findings are text, each with its screenshot path. Open one yourself only when you must decide on a finding the text leaves unclear.
155
-
156
- ## After dispatching
157
-
158
- Call `dispatch` from your main thread only, never from a subagent: catherd messages the session that dispatched.
159
-
160
- - **Dispatch every independent role one after another.** Each `dispatch` returns in about a second, once its role has started, so they all run side by side.
161
- - **Then write one status line and end your turn.** Claude Code receives `<cross-session-message from-name="catherd">` through its peer inbox with its existing priorities. Codex receives queued next input through the existing native server (`--remote unix://`): idle sessions can wake; a busy session processes it after the active turn, without Claude's urgent next-tool-round promise. The notice names the run, dispatch and every event ID, including every coalesced event. Call `result(run, name)` for each stored record you will act on, then dispatch what follows.
162
- - **A single role is `dispatch`, then end your turn.**
163
- - **Never `sleep`, loop, use `await_results`, or call `peek` again and again.** Call `peek(run)` when the user asks how it is going, when a decision needs the other roles' state, or once after `run_start` on a resumed run.
164
- - **Queue acceptance is not processing or collection.** An unloaded, interrupted or restarted conversation may retain input without generating. Accepted and ambiguous events are never automatically resent; durable unread records remain recoverable with `peek`/`result`. Only `result` collects a finished record. `status` and `result` do not adopt ownership; explicit `peek(run)`, `run_start` and `dispatch` do.
165
- - **Duplicate notices are idempotent reads.** Preserve every event ID, consult the actual stored record and protocol, and never redispatch work or land a milestone twice because input repeats. A message or transcript echo supplies neither delivery acknowledgement nor user approval; reviewer/verifier gates remain authoritative.
166
- - **An ambiguous retry is an explicit decision:** after validating the current owner and exact stored event, use `catherd runs retry-push <run> <name> --event '<exact event ID>' --acknowledge-possible-duplicate` from that owner's host session. It may duplicate native input. Accepted receipts suppress another enqueue for that owner/event; no supported history reconciliation API means retain ambiguity until this deliberate decision. Unknown/conflicting hosts never push.
167
-
168
- **When the user asks where it stands,** call `peek(run)` once and answer from it; `status(run)` adds the totals, budget and milestones.
169
-
170
- **Push a notification through an available host facility** only at the moments the profile's `notify` lists (`profile_get({ repo })`), one line each. Claude Code may use `PushNotification`; if the host exposes none, report in the conversation without inventing a notification or scheduled follow-up:
171
-
172
- - `milestone`: a milestone landed: its name, its commit, the time it took, and the path of its digest (`land`'s `digest`);
173
- - `finish`: the run finished: verdict and total time;
174
- - `blocked`: a milestone is parked on a decision only the user can make (`park`): push the full question.
175
-
176
- Nothing else pushes: a phone that buzzes for progress teaches the user to ignore it.
177
-
178
- ## The run folder
179
-
180
- `run_start` creates `R` under catherd's data directory, outside the repo. It outlives the session. `R` holds:
181
-
182
- - **`plan.md`:** the architect's decisions, milestones and lanes. It changes only by an architect delta.
183
- - **`lanes/Mx.Ly.md`:** one file per lane, the only plan a worker reads. Its second line, `Owns: <paths>`, is what `dispatch` uses to refuse a lane that shares a file with a running one, and to spot a refusal.
184
- - **`ledger.md`:** one row per landed piece, appended by `land`. Never rewritten.
185
- - **`state.md`:** rewritten by the server at every dispatch, climb and landing, so a fresh session resumes from it alone: HEAD, the dirty files and their owners, each running role with its brief, thread and rung, the last check, the next step, and on the last line `Protocol next:`, the step of the milestone loop the run is at.
186
- - **`runs.jsonl`, `agents.jsonl`, `jev.jsonl`, `routes.jsonl`, `outcomes.jsonl`, `harness.jsonl`, `verifier.jsonl`, `questions.jsonl`:** the record.
187
- - **`digests/<milestone>.md`:** each landed milestone's digest, written by `land`.
188
- - **`roles/<name>/<dispatchId>/`** (each dispatch's brief, reply, events and stderr) and **`shots/`** (screenshots).
189
- - **The repo's `knowledge.md`** (beside the runs, per repo, not per run): what past runs learned. `land`'s `learned` appends to it; `read_knowledge` reads it.
190
-
191
- **Pause** (on the user's word, a usage limit, or `E_RUN_BUDGET`): dispatch nothing new, `cancel(run, name)` each live role the user wants stopped, and bring down only this run's stack. Leave the tree as it is, call `set_next(run, "paused: <why>; resume with <step>")`, then stop. On a usage limit with no stand-in, catherd has already written the pause.
192
-
193
- **Cancel** a role with `cancel(run, name)` when the user asks, or when a role is plainly stuck on work you no longer need. It returns the role's record, `cancelled`, and marks it read.
194
-
195
- **Resume** (a new session, or after your context was compacted): `status()` names the run, and `status(run)` shows it. Before dispatching anything, call `peek(run)` once: it lists the open owner questions first, the roles still running, the records not read yet (read each with `result`), and `protocol`, the step of the milestone loop the run is at, with the checklist. It also makes this session the run's owner, so catherd messages you from now on. Check HEAD and the dirty files against its `state.md`, whose last line is the same step. Continue each role on its own thread with `dispatch(…, thread, brief: "<where it stopped>")` (`dispatch` refuses a name that is still running).
196
-
197
- **Owner questions:** a product question outside the A-lines never stops the run. `park(run, milestone, question)` parks that milestone (`land` refuses it until it is answered), notify through the available host facility as above, and go on with the milestones and runs that do not depend on it. When the owner answers in this session, `answer(run, milestone, answer)`, then finish the milestone.
198
-
199
- ## The sequence
200
-
201
- **Once per project:**
202
-
203
- 1. **A-lines.** Write the request as numbered, observable lines `A1…An`. Ask the user every open product question now; after this point, run without them. Then `run_start(repo, title, a_lines)`.
204
- - **Plan in hand:** when the request names a plan the user already has, keep it as an A-line, `plan: <path>[, <path>…]`. The run then skips the dossier, and the architect translates that plan instead of designing one (step 3).
205
- 2. **Dossier.** One researcher, `researcher-dossier`, maps the code the A-lines touch. Its brief asks for, with `file:line` everywhere:
206
- - what past runs of this repo learned (`read_knowledge(repo)`), so it maps only what changed since then;
207
- - the files and folders involved, one line each on what they hold;
208
- - the existing patterns the work should copy, by path;
209
- - the build, test and run commands, with how long the full suite takes;
210
- - the lint and type-check commands, and how to scope each to one package;
211
- - the symbols the change will call or alter, with their signatures;
212
- - the repo's rules (`CLAUDE.md`, `AGENTS.md`, conventions) that bind this work;
213
- - risks: shared files, generated code, slow or flaky tests.
214
-
215
- It may run to 200 lines; the 15-line cap does not apply to it. Its reply is `result(run, "researcher-dossier")`, at the record's `replyPath`. A native Claude researcher on Claude Code writes it to `R/dossier.md` with `write_run_file` instead.
216
-
217
- 3. **Architect,** once, with the A-lines, the run id and the dossier's path. It reads the dossier first, writes `plan.md` and every `lanes/Mx.Ly.md` itself with `write_run_file`, and replies with a short list of milestones and lanes. Each lane names its owned files and its **fast check**: its targeted tests plus the linter, and the type check when the repo has one, scoped to the lane's owned packages (seconds to a minute or two). Each milestone names its **full check** (the whole suite).
218
- - A full check slower than about five minutes is a problem to solve, not to live with. The architect makes speeding it up (parallel tests, a shared fixture) an early lane.
219
- - Every lane file starts with these lines: `# Mx.Ly — <title>`, `Owns: <paths>` (repo-relative, a trailing `/` for a folder, never a glob), `Fast check: <command>`, `Kind: repo_code|terminal|ui|prose|research` and `Difficulty: copy|build|logic|hard`.
220
- - **Plan in hand** (a `plan:` A-line): no dossier. Brief the architect with the A-lines, the run id and the plan's paths, to translate, not design: each plan task becomes lanes (`Owns:`, `Fast check:`, `Kind:`, `Difficulty:`), each MR or phase a milestone with its full check. It copies the plan's decisions into `plan.md` and the lane files, redesigns only what the plan leaves undecided, and stays the target for `design` findings.
221
- - **No dossier and no architect** for a polish or fix run (a list of known defects or tweaks to code that exists) or a single mechanical task. You write the lane files yourself with `write_run_file`, straight from the A-lines: one lane per cluster of defects that share files, with owned files found by `grep -n`, and the same header lines.
222
- 4. **Route and preflight.** `route(run, "lanes/Mx.Ly.md")` for every lane, one call per lane; each may wait up to 25 s on Jev (`dispatch` routes a lane you missed, and starts it at the routed rung when yours is off its ladder). `route`, `preflight` and `dispatch` refuse a lane whose `Kind:` or `Difficulty:` the catalog does not know (`E_LANE_INVALID`). Then, once every lane file exists, `preflight(run)` once, before dispatching any lane. Each lane comes back as one of:
223
- - `pass`: the check already passes on the base tree;
224
- - `fails-as-expected`: it runs and fails, because the lane has not been done yet;
225
- - `skipped`: it checks a file the lane creates;
226
- - `cannot-start`: it could not even run (a missing command, exit 126 or 127, a 120 s timeout, or no `Fast check:` line). Only this blocks: fix that lane's check, or ask the architect to, and run `preflight` again.
227
-
228
- When it returns `needsConfirmation: true`, the profile wants the user to see the commands first: show them the `commands`, and on their yes call `preflight(run, confirmed: true)`.
229
-
230
- **Per milestone:**
231
-
232
- 5. **Lanes.** Dispatch every lane of the milestone, one after another, each at its rung, then end your turn: workers, the artist, and a researcher if needed. A worker's brief points at its lane file, and `dispatch` gets its `lane`. A worker runs its own fast check until it passes.
233
- - When a worker's message arrives, read it with `result`: check its STATUS line, its `changedOwned` and its `hints`, then run its fast check yourself once. A fail goes back to the same thread with the failing output's path; a second fail climbs a rung.
234
- - A `violation: <paths>` hint means the role wrote outside its lane. Send those paths to the reviewer with the milestone; a lane that needs them gets an `Owns:` delta from the architect.
235
- 6. **writer,** when the milestone changes docs. It starts once the workers are done.
236
- 7. **reviewer,** named `reviewer-<M>`, once, over the whole milestone diff on a frozen tree.
237
- - **UI pass,** when the milestone touched a screen. List the changed files (`git diff --name-only <milestone base>`), map them to the screens that render them, and brief the UI reviewer on those screens only. You start the app first.
238
- 8. **One fix round.** Send each lane's findings, verbatim, to its own worker thread, at its rung. A BLOCKER climbs a rung instead, on a fresh thread. Dispatch every lane's fix, then end your turn. Then resume the same reviewer thread, and it re-checks only the BLOCKER and BUG lines.
239
- - Before routing a finding that questions the plan, `ask(run, "finding", …)`. `design` goes to the architect: `SendMessage` to the same native Claude agent on Claude Code, or `dispatch` with its recorded process `thread` for its own delta, followed by `result`. Its delta rewrites the lane files.
240
- - A finding that comes back: `ask(run, "same-defect", …)`. `yes` gets one climb and one re-check of that line. Anything still open goes to the report, not into another round.
241
- 9. **verifier,** named `verifier-<M>`, with the run id, the milestone's A-lines and the **full check**, on a frozen tree: it owns the independent gate. Route it first. A native Claude verifier runs in the foreground on Claude Code; a Codex or other process verifier uses `dispatch`, end the turn, then `result`. A full check that starts while a role still edits proves nothing, and it has to run again. Never give it a worker's reply.
242
- - It checks each gate item with `gate_check` first and skips an item that passed on the same content (carried over from its commit); it records each pass with `gate_pass`, runs independent items side by side within the lock's slots, and builds each commit's images once. It names git-ignored inputs (`.env`, generated files) in `paths` explicitly: `.` covers only HEAD and uncommitted not-ignored changes. It passes `gate_check` the milestone it verifies, so the digest lists only that milestone's carried items. `peek` and `status` show its current step.
243
- - For a native Claude verifier only, call `record_agent_run(run, "verifier-<M>", "verifier", rung, …)`, with `status: "failed"` when its verdict is FAIL: only a PASS is recorded `ok`. A process verifier on any backend counts through its dispatch record only when its reply opens `VERDICT: PASS`; collect it with `result` before landing.
244
- - On FAIL, the owning worker fixes it, and you ask the same verifier to re-check: native Claude `SendMessage`, or process `dispatch` with its own recorded thread followed by `result`.
245
- - A second FAIL on the same line goes to the architect.
246
- - A third one: pause, report and push.
247
- 10. **Land.** Commit the milestone path-scoped, then `land(run, milestone, what, commit, evidence, next, learned)`, passing `learned` when the milestone taught the next run something worth knowing (a slow suite, a flaky test, a pattern to copy); push if the profile's `notify` has `milestone`, with the digest's path, and move to the next milestone.
248
- - `land` refuses (`E_LAND_GATE`) a milestone with no reviewer record (a `reviewer-<M>` dispatch record, or a native Claude `record_agent_run` row with role reviewer and that name, status `ok`) or no verifier verdict since its lanes started. A skip over an empty commit range is refused too: commit first. A milestone that changed only docs lands with `skip: "docs-only"`; one that changed no source file with `skip: "no-code"` and the required local gate evidence in `evidence`. Follow the repo's CI policy; a skill never authorizes triggering checks.
249
- - Commit only while no role is writing. A pre-commit hook may stash unstaged files, and a role's edits vanish under it.
250
- - The next milestone's lanes can start in the same turn as the `land`.
251
-
252
- **Finish:** run the project's final gate if it has one.
253
-
254
- - The verifier is the gate owner, with `gate_check` and `gate_pass`. On Claude Code a native Claude verifier runs in the **foreground** (`run_in_background: false`); a background subagent dies with the session. A process verifier on either host uses `dispatch`/`result` and its durable record; finish only after its PASS.
255
- - Beside it, in the background:
256
- - any independent review (a spec or milestone review by a fresh verifier);
257
- - the writer's MR body;
258
- - one **whole-app UI pass**, for what a change broke on a screen nobody touched.
259
- - A gate FAIL goes to a fresh worker thread as one piece. The gate then re-runs from the start on the new SHA.
260
-
261
- Then report to the user, in their language, and push if `notify` has `finish`:
262
-
263
- - the verdict per milestone;
264
- - the commits;
265
- - one line per role run, with its rung;
266
- - the time and token sums per backend and per rung, and the climbs with their reasons (`runs_summary({ run })`), the Claude subagent runs you reported (say they are reported, not measured), and the Jev decisions with how many fell back (`status(run)`);
267
- - the harness line from `runs_summary`: what the user's claude-code and opencode customizations cost per run, so they can judge the isolation toggle (`/catherd-setup` offers it). Codex reports no per-request input, so it has no harness figure: say so instead of offering one;
268
- - the run's budget spend (`status(run)`), if the profile set one;
269
- - what was left open, and why.
270
-
271
- Roles never commit. You commit, following the repo's rules.
272
-
273
- ## Brief for a role
274
-
275
- The brief is the `brief` text you pass to `dispatch` (catherd writes it to the dispatch's own `brief.md` and hands it to the CLI on stdin), or the prompt of a native Claude role's Agent call on Claude Code, with the run id. It has these parts, in order:
276
-
277
- 1. The role and the goal, in one line.
278
- 2. The A-lines this run must meet.
279
- 3. The files it owns, and the files it must not touch. If the repo has a `CLAUDE.md`, add "Read CLAUDE.md first": Codex loads only `AGENTS.md`.
280
- 4. For a worker:
281
- - "Read `<R>/lanes/Mx.Ly.md`": decisions, signatures, data shapes;
282
- - its fast check (targeted tests, lint and type check), to run until it passes;
283
- - "Run the full suite only if this brief says so", and "Wrap any full build or full test suite in `bunx catherd-cli@1.4.0 lock -- <command>`": other lanes share the machine.
284
- 5. For a reviewer: the A-lines and the changed files, with new files read in full. It reports every finding as `BLOCKER|BUG|NIT file:line — problem — fix`, covering:
285
- - unmet A-lines and edge cases;
286
- - code or abstractions nobody needs;
287
- - comments that restate code;
288
- - tests that assert nothing.
289
-
290
- With no finding, the reply is `CLEAN`.
291
-
292
- 6. For a UI reviewer:
293
- - the URL and the changed screens, by route;
294
- - the viewports and themes;
295
- - `agent-browser screenshot <R>/shots/<name>.png` at viewport size, not full page; it opens each PNG with its image tool;
296
- - every finding is `BLOCKER|BUG|NIT <screen> — problem — fix — <R>/shots/<name>.png`, always with the path.
297
- 7. For an artist, per image:
298
- - the screen, where the image sits, its shape;
299
- - the mood and scene in words (subject, materials, light, colour): taste, not measurements;
300
- - the final `.webp` path in the repo's assets folder. The worker's brief names the same path, so both lanes run at once.
301
-
302
- Its rules:
303
- - use the built-in image tool, and copy its untouched output from `${CODEX_HOME:-~/.codex}/generated_images/`; the record's `images` lists those paths;
304
- - the only processing is `cwebp -q 85 in.png -o out.webp`;
305
- - never paint, patch or upscale;
306
- - never redraw a real logo, and never present a generated person as a real customer;
307
- - add one provenance line per image to a `README.md` beside it.
308
-
309
- The tool tops out around 1536×1024.
310
-
311
- 8. Not the reply shape: `dispatch` appends the role's reply contract to every brief ("Do not commit", at most 15 lines, and the last line `STATUS: complete|partial|blocked|refused — <one line why>`), and a native Claude role's agent carries it.
312
-
313
- ## Reading results
314
-
315
- - Read each record a catherd message announces, its `hints`, and the reply, with `result(run, name)`, nothing else. Read the stderr the `failed: read <path>` hint names, with `read_run_file`, only when `status` is `failed`. Never read a diff or a log yourself: that is the reviewer's and verifier's job, and your context is the run's most expensive token.
316
- - Exit 0 means the model finished, not that it is right. The STATUS line is the role's claim; `changedOwned` and your fast check are the facts.
317
- - `failed` comes only from a real turn failure or an exit with no reply; a reconnect mid-run does not count. Read the reply before you retry.
318
- - `cli-too-old`: tell the user the upgrade command its `cli-too-old:` hint names. `limit` with no stand-in: a usage limit is the user's to fix: pause, report and push that turn. `timeout`: the role went quiet for the profile's idle minutes, or ran past its wall minutes; resume its thread once with where it stopped, then climb.
319
- - `thread-heavy`: that thread is spent; its next piece starts fresh.
320
-
321
- ## Red flags
322
-
323
- | You notice | Do instead |
324
- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
325
- | A lane waits on another lane that shares none of its files | Dispatch it now, beside the others |
326
- | A role dispatched, then waited on, before the next independent one is dispatched | Dispatch every independent role first, then end your turn |
327
- | `sleep`, `await_results`, a loop, or repeated `peek` to see whether a role is done | End your turn; use the host's completion input and durable `result` recovery |
328
- | A worker or fix loop runs the full suite to check one change | Its fast check. The full check is the verifier's, once per milestone |
329
- | A reviewer or verifier runs after each lane | Once per milestone, over the whole milestone |
330
- | A third review round | One fix round, one climb for a returning defect, one re-check. The rest goes to the report |
331
- | You open a diff, a log or a source file to judge the work | Send a reviewer, or the verifier |
332
- | You open every screenshot | Read the findings. Open one path only to settle an unclear finding |
333
- | The UI pass covers the whole app mid-run | Changed screens only. The whole app once, at finish |
334
- | You write `state.md`, the ledger or a brief file with your own tools | The server writes `state.md`, `land` writes the ledger, `dispatch` writes the brief |
335
- | A new bug, cleanup, re-run or climb sent with `thread` | A fresh thread. Resume only for that piece's own findings at the same rung |
336
- | One transition spread over several turns (a land, routes, dispatches) | One turn: every independent call back to back, then one status line |
337
- | A plan, log or test file read whole into your context | `read_run_file` for the one section, or `grep -n` then those lines. Or name the path in a brief |
338
- | You copy the architect's plan into `plan.md` yourself | The architect writes `plan.md` and the lane files. With a plan in hand, it copies the user's plan into them |
339
- | A dossier, or an architect designing afresh, with a plan in hand | No dossier. Brief the architect to translate the plan, and to design only what it leaves undecided |
340
- | A dossier or an architect for a polish or fix run | Write the lane files from the A-lines yourself |
341
- | A lane file without an `Owns:` line | Add it: `dispatch` refuses the lane without one |
342
- | A native Claude subagent on Claude Code returned and you moved on | `record_agent_run` with its `total_tokens` and `duration_ms` first |
343
- | A rung written as `model#effort` | `backend:model#effort`, exactly as `route` returned it |
344
- | `dispatch` retried after an `E_*` error without doing what its `fix` says | Do the `fix`, or pause and tell the user |
345
- | A `cannot-start` preflight lane dispatched anyway | Fix its fast check first, and run `preflight` again |
346
- | You pick a rung by feel | `route`. Its default covers the case where Jev is unsure or down |
347
- | Jev's answer taken as proof a lane is done | Jev picks who works. Checks, the reviewer and the verifier decide done |
348
- | A reply from the lowest Track A rung trusted without your fast check | Run it. Cheap rungs hide broken tools |
349
- | A reviewer, or a `logic`/`hard` lane, on a rung you chose yourself | The rung `route` returned |
350
- | Exit 0 with the owned files unchanged, treated as done | A refusal: climb with reason `unchanged` |
351
- | A native Claude gate verifier dispatched in the background | Foreground on Claude Code; process verifiers use `dispatch`/`result` on either host |
352
- | A full check started while a worker still edits | Wait for a frozen tree. That run proves nothing |
353
- | Lanes dispatched before `preflight` ran | Run `preflight(run)` first; a lane whose check cannot even start wastes a dispatch |
354
- | An architect planning without reading what past runs learned | `read_knowledge(repo)` first, from the dossier brief |
355
- | A landed milestone that taught something, landed without `learned` | Pass it: the next run's architect reads `knowledge.md` |
356
- | You update catherd, this plugin or the profile while a run is in flight | After the run. A role mid-flight must see one version |
357
- | You stop to ask the user something mid-run | Decide within the A-lines and note it for the report. A product question outside them parks its milestone (`park`), with a push; the rest goes on |
358
- | A brief that spells out the reply shape and the STATUS line | `dispatch` appends the reply contract itself |
359
- | A milestone landed without its reviewer and verifier | `reviewer-<M>`, then the routed verifier's independent PASS, then `land` |
360
- | A climb for a finding that questions the plan or the lane's owned files | `ask` finding, then the architect. `climb` refuses it (`E_CLIMB_DESIGN`) |
361
- | A gate item run again on content that already passed it | The verifier's `gate_check` carries it over |
362
- | A push for progress that is not a landed milestone, the finish or a block | No push. `status(run)` answers when the user asks |
363
- | Your own decision changes behavior that already exists and no A-line asked for it (e.g. re-numbering `list` to match a new command) | Pick the option that keeps existing behavior, and fit the new code to it |
364
- | `Agent(subagent_type: "Plan", model: "opus")` for the architect | Route first: native Claude's returned `agent` with no model on Claude Code, otherwise `dispatch`/`result` |
365
- | `dispatch` called from a subagent | The main thread: catherd messages the session that dispatched |
366
- | `codex exec` or `opencode run` called by hand | Always `dispatch`: it records the run, keeps `state.md` true and guards the lanes |
367
- | You isolate a role's harness yourself, or tell a role to ignore the user's config | Never. Only the profile's `harness.<name>.isolated`, which the user sets |
368
- | The architect's plan contains function bodies | Ask for decisions and signatures. The worker writes the code |
369
- | "It's one line, I'll fix it myself" | Send it to the worker's thread |
370
- | The artist's image was resized, retouched or patched | Regenerate it from the artist's thread |
28
+ Six tools, nothing else.
29
+
30
+ | Tool | Use |
31
+ | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
32
+ | `run_start(repo, title, a_lines, plan?, base?)` | Starts a run. Returns its id and the notify url its questions go to. |
33
+ | `status(run?)` | Each run's phase, milestones, live roles, parked questions, quota holds and whether the daemon is alive (a dead one is restarted). |
34
+ | `answer(run, unit, answer)` | Answers a parked unit (the run, a milestone or a lane); it runs again with the answer. |
35
+ | `cancel(run)` | Stops the run: every live role is cancelled. |
36
+ | `result(run, name?)` | The run's report, or with `name` one role's record. |
37
+ | `profile(action, …)` | Reads, validates or changes a profile, or sets `notify_url`. Tuning is the `catherd-setup` skill's. |
38
+
39
+ ## Starting a run
40
+
41
+ 1. Write the A-lines, the acceptance lines the work must meet, one per line, each checkable. Ask the owner every
42
+ product question first, before the run starts: a daemon that must park later costs a round trip.
43
+ 2. A plan the owner already has ("implement the plan at …", a scorecard prompt) goes in `run_start`'s `plan:`
44
+ (several files, a contracts file included, as a list); an A-line `plan: <path>[, <path>…]` does the same. Write
45
+ only the acceptance lines the plan does not already state. The run then skips the dossier, and the architect
46
+ translates the plan instead of designing. With no plan, say that the architect writes one first, and the run
47
+ waits once for the owner's approval of it.
48
+ 3. Call `run_start(repo, title, a_lines, plan?)` with the repo's absolute path. If it fails, `error.code` and
49
+ `error.fix` say what to do; relay them.
50
+ A run whose milestones should each be their own branch and merge request takes a `base`, a branch on origin
51
+ (`run_start(repo, title, a_lines, base)`). Each milestone then works in its own worktree from `origin/<base>`;
52
+ independent milestones run side by side while the machine has the memory for them (the profile's
53
+ `limits.memory`); a milestone that builds on another names it on an `After:` line. Without `base`, the run
54
+ works in the repo, one milestone at a time.
55
+ 4. Tell the owner the run id and the notify url (an ntfy topic) to subscribe to on the phone: that is where a
56
+ parked question and the final report arrive.
57
+ 5. End the turn. **The run does not need this session: it continues if the session is compacted or closed.**
58
+ Never poll, `sleep` or loop on `status`.
59
+
60
+ ## When the run reports
61
+
62
+ A report reaches you as a catherd message (`<cross-session-message from-name="catherd">`) or the owner reads the
63
+ phone notice and asks. Either way:
64
+
65
+ 1. Call `status(run)`. It lists the parked units with their questions, the live roles and any quota hold (a hold
66
+ lifts by itself; say when).
67
+ 2. A parked unit is the owner's question. Put it to them in their own language, with the daemon's context and your
68
+ recommended answer, one question at a time. Pass their answer with `answer(run, unit, answer)` and nothing
69
+ else: do not rephrase it into a decision of your own. The run goes on with the work that does not depend on it.
70
+ A question may also be the plan's approval: relay `catherd run-file read <run> plan.md` for the owner to read,
71
+ then pass `answer approve` (the owner's yes) or the owner's changes as the answer; the architect revises and the
72
+ run asks again, the same way. It asks again later only when an architect change edits an approved `D<n>`
73
+ decision. A parked lane whose question quotes a DESIGN: line is a conflict between the plan and the code: the
74
+ owner answers it (the plan or the code changes). A question may also be a `push` (a landed milestone of a run with a base branch waits for the owner: relay the
75
+ question with its commands; an `answer push` has catherd push the branch and ask again with the MR command, and
76
+ any other answer, once the MR is merged, unblocks the milestones after it, which matters when the repo squash-merges)
77
+ or a `check_broken` (the milestone's check cannot run, so fix the environment, then answer).
78
+ 3. A role that failed, a gate that is red or a milestone that climbed is the daemon's to handle; report it, do not
79
+ step in. The secret scan of a milestone's check uses `gitleaks` when it is installed; it is optional. Stop the run only on the owner's word: `cancel(run)`.
80
+
81
+ ## The end
82
+
83
+ When `status(run)` shows the run ended, call `result(run)` and relay the report in the owner's language: what
84
+ landed, the known issues, and what the judge decided and why. `result(run, name)` shows one role's record when the
85
+ owner asks how a lane went.
86
+
87
+ The report may end with a rules review: a judge's proposed changes to the repo's standing rules, each with its
88
+ `catherd knowledge add` or `catherd knowledge rm` command, and the run has already ended. Give the owner each change in
89
+ one line and run a command only on their yes; a rule for some roles only is written
90
+ `catherd knowledge add "[worker, reviewer] <rule>"`.
91
+
92
+ **Push and the merge request only on the owner's word.** The run lands milestones on its own branch and pushes
93
+ it only when the owner answers `push`; catherd never opens an MR or merges. A merge request title is the run's outcome, under 72 characters, never the branch name.
94
+
95
+ ## Errors
96
+
97
+ A tool failure carries `error.code`, `error.message` and often `error.fix`: act on the fix before you retry, and
98
+ tell the owner when the fix is theirs. Codes you will meet:
99
+
100
+ - `E_RUN_BUDGET`: the run's budget is spent; the owner raises it in the profile (`catherd-setup`) or ends the run.
101
+ - `E_BACKEND_NOT_LOGGED_IN`: a backend the run needs has no login; the owner logs in, then the daemon proceeds.
102
+ - `E_ADMIT_RUNG`: no rung can fill a role; the profile needs one (`catherd-setup`).
103
+ - `E_ROLE_SCOPE`: a role session called `run_start`, `answer`, `cancel`, `result` or `profile`; only you, the owner's session, may.
104
+
105
+ ## What not to do
106
+
107
+ - Do not run the work yourself while a run is in flight: a second writer in the repo races the daemon's lanes.
108
+ - Do not promise a time: the roles take what they take, and a quota hold waits for its window.
109
+ - Do not copy secrets, tokens or notify urls into a lane, an A-line or a message to a role.
110
+ - Do not call `catherd` from a shell to drive a run; the six tools are the interface. `catherd answer` and
111
+ `catherd runs` are the owner's own terminal.