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
@@ -4,11 +4,12 @@ import { join } from "node:path";
4
4
  import type { BackendAdapter } from "../adapters/backend.ts";
5
5
  import { budgetStatus, formatBudget } from "../domain/budget.ts";
6
6
  import { CatherdError, errorMessage } from "../domain/errors.ts";
7
- import { assertId, formatRung, newDispatchId, parseRung } from "../domain/ids.ts";
7
+ import { assertId, formatRung, headlessRung, newDispatchId, parseRung } from "../domain/ids.ts";
8
8
  import { assertLaneHeader, overlaps } from "../domain/lane.ts";
9
9
  import { roleTimeouts } from "../domain/profile.ts";
10
10
  import type { RunRecord } from "../domain/record.ts";
11
11
  import { composeBrief } from "../domain/brief.ts";
12
+ import { rulesBlock } from "../domain/rules.ts";
12
13
  import { briefOwns, DOCS_OWNS } from "../domain/changes.ts";
13
14
  import { grantsScratch, ROLE_SERVER_BACKENDS } from "../domain/role-tools.ts";
14
15
  import type { Role } from "../domain/roles.ts";
@@ -22,6 +23,7 @@ import { log } from "../infra/log.ts";
22
23
  import { processStartTime } from "../infra/proc.ts";
23
24
  import { ensurePrivateDir, PRIVATE_FILE, writeJsonAtomic, writeTextAtomic } from "../infra/store.ts";
24
25
  import { readyAdapter, standInFor } from "./backends.ts";
26
+ import { failoverBackends } from "./failover-rungs.ts";
25
27
  import { spendOf } from "./budget.ts";
26
28
  import {
27
29
  type Admit,
@@ -39,6 +41,8 @@ import { finalizeDispatch } from "./finalize.ts";
39
41
  import { gateEnvParts, readGateEnv } from "./gate-env.ts";
40
42
  import { assertNotPaused } from "./pause.ts";
41
43
  import { currentOwns } from "./lane-edit.ts";
44
+ import { planContext } from "./plan-input.ts";
45
+ import { standingRules } from "./run-service.ts";
42
46
  import { unfinishedAfter } from "./protocol.ts";
43
47
  import { runProfile } from "./run-pin.ts";
44
48
  import type { Deps } from "./ports.ts";
@@ -60,6 +64,8 @@ export interface AdmitInput {
60
64
  /** the dispatching session (spec §3.3); absent means the session this process serves */
61
65
  sessionId?: string | null;
62
66
  host?: KnownHost;
67
+ /** plan 35: where the role works (its milestone's worktree in a base run); absent means the run's repo */
68
+ cwd?: string;
63
69
  }
64
70
 
65
71
  /** Spec §3.3: SIGTERM, then SIGKILL this long after. */
@@ -181,11 +187,15 @@ export async function admit(
181
187
  throw new CatherdError("E_ADMIT_RUNG", `${i.rung} is a native Claude rung`, {
182
188
  fix: `run it as Agent(subagent_type: "${deps.profiles.agentFor(run.meta.repo, i.role, i.rung)}"), then record_agent_run`,
183
189
  });
184
- const allowed = new Set([
190
+ const ladder = [
185
191
  ...rc.rungs,
186
192
  ...rc.rungs.flatMap((r) => standInFor(profile.failover, r, run.meta.repo) ?? []),
187
- ]);
188
- if (!allowed.has(formatRung(rung)))
193
+ ];
194
+ // the daemon runs every role headless (spec 2.0 decision 12): a native rung's headless twin is on its ladder too
195
+ const allowed = new Set([...ladder, ...ladder.map(headlessRung)]);
196
+ // a rung the daemon failed a limit over to may be on any configured backend (spec 2.0 decision 6)
197
+ const failedOver = i.failoverFrom !== null && failoverBackends(profile).has(rung.backend);
198
+ if (!allowed.has(formatRung(rung)) && !failedOver)
189
199
  throw new CatherdError(
190
200
  "E_ADMIT_RUNG",
191
201
  `${i.rung} is not on the ${i.role} ladder of profile ${profile.name}`,
@@ -208,7 +218,7 @@ export async function admit(
208
218
  `${adapter.id} keeps the access a thread started with: ${i.thread} ran ${started.access}, and the ${i.role} role runs ${rc.access}`,
209
219
  { fix: "dispatch a fresh thread (omit `thread`)" },
210
220
  );
211
- // and the network grant: grok keeps a session's sandbox profile, agy's isolated homes differ by it.
221
+ // and the network grant: a CLI that keeps a session's sandbox profile keeps it.
212
222
  // A record from before 1.3 carries no grant to compare.
213
223
  if (started?.network !== undefined && adapter.resume.sameAccessOnly && started.network !== network)
214
224
  throw new CatherdError(
@@ -234,11 +244,12 @@ export async function admit(
234
244
  // spec 1.5 plan 21 (#42 findings 1, 2): the role server goes in whether the harness is isolated or not, so no
235
245
  // role is refused for isolation, and a thread an isolated run started resumes as it started
236
246
  const roleServer = ROLE_SERVER_BACKENDS.includes(rung.backend);
247
+ const cwd = i.cwd ?? run.meta.repo;
237
248
  await prepared(adapter, {
238
249
  rung,
239
250
  access: rc.access,
240
251
  isolated,
241
- repo: run.meta.repo,
252
+ repo: cwd,
242
253
  network,
243
254
  });
244
255
 
@@ -255,7 +266,7 @@ export async function admit(
255
266
  network,
256
267
  thread: i.thread,
257
268
  isolated,
258
- repo: run.meta.repo,
269
+ repo: cwd,
259
270
  briefPath: p.brief,
260
271
  replyPath: p.reply,
261
272
  dispatchDir: dir,
@@ -302,7 +313,7 @@ export async function admit(
302
313
  throw new CatherdError("E_RUN_BUDGET", `the run budget is spent: ${formatBudget(budget)}`, {
303
314
  fix: "ask the user to raise profile.budget, or finish the run with what landed",
304
315
  });
305
- const before = await statusSnapshot(run.meta.repo);
316
+ const before = await statusSnapshot(cwd);
306
317
  const session = currentSession(deps);
307
318
  const sessionId = i.sessionId !== undefined ? i.sessionId : (session?.sessionId ?? null);
308
319
  const admitted: Admit = {
@@ -325,11 +336,13 @@ export async function admit(
325
336
  network,
326
337
  cliVersion: probe.version,
327
338
  admittedAt: new Date(deps.now()).toISOString(),
328
- repo: run.meta.repo,
339
+ repo: cwd,
329
340
  before,
330
341
  ...(sessionId ? { sessionId, host: i.host ?? session?.host ?? "claude-code" } : {}),
331
342
  };
332
343
  ensurePrivateDir(dir);
344
+ // plan 34: the repo's standing rules for this role; a knowledge file that cannot be read adds nothing
345
+ const rules = await standingRules(run.meta.repo, i.role).catch(() => "");
333
346
  // plan 23: the verifier runs with the repo's gate environment (DOCKER_HOST, a proxy, …)
334
347
  const gate =
335
348
  i.role === "verifier" ? gateEnvParts(await readGateEnv(run.meta.repo)) : { values: {}, refs: {} };
@@ -345,6 +358,8 @@ export async function admit(
345
358
  lane: i.lane === null ? null : { id: i.lane, text: readFileSync(laneFile(run, i.lane), "utf8") },
346
359
  scratch,
347
360
  roleServer,
361
+ version: deps.version,
362
+ context: [planContext(run, i.role), rulesBlock(rules, i.role)].filter(Boolean).join("\n\n") || null,
348
363
  }),
349
364
  );
350
365
  // Spec §10.4: the adapter's overrides only; the supervisor adds its own inherited env at spawn
@@ -5,7 +5,6 @@ import { adapterFor } from "../adapters/registry.ts";
5
5
  import "../adapters/all.ts";
6
6
  import { CatherdError } from "../domain/errors.ts";
7
7
  import { formatRung, tryParseRung } from "../domain/ids.ts";
8
- import { PAIRED_FAILOVER } from "../domain/profile.ts";
9
8
 
10
9
  const READY_TTL_MS = 10 * 60_000;
11
10
  const ready = new Map<string, { at: number; probe: Probe }>();
@@ -17,7 +16,7 @@ export const resetReadiness = (): void => ready.clear();
17
16
  function execFormatError(e: unknown): string | null {
18
17
  if (!(e instanceof Error)) return null;
19
18
  if ((e as { code?: unknown }).code !== "ENOEXEC" && !/exec format error/i.test(e.message)) return null;
20
- // macOS names the path (posix_spawn '/…/grok'), Linux only the command (uv_spawn 'grok')
19
+ // macOS names the path (posix_spawn '/…/bin'), Linux only the command (uv_spawn 'bin')
21
20
  const bin = /spawn '([^']+)'/.exec(e.message)?.[1];
22
21
  return bin ? (Bun.which(bin, { PATH: process.env.PATH ?? "" }) ?? bin) : "exec format error";
23
22
  }
@@ -64,18 +63,17 @@ export async function readyAdapter(backend: string): Promise<{ adapter: BackendA
64
63
  const probe = await probeBackend(adapter);
65
64
  const problem = probe.problems[0];
66
65
  // spec 1.3 §3.3: a probe that finds the CLI logged out lists E_BACKEND_NOT_LOGGED_IN, so a dispatch never
67
- // reaches it (agy opens a browser and waits); logged out alone is no problem where a CLI runs without a login
66
+ // reaches it (it may open a browser and wait); logged out alone is no problem where a CLI runs without a login
68
67
  if (problem) throw new CatherdError(problem.code, problem.message, { fix: problem.fix });
69
68
  ready.set(backend, { at: now, probe });
70
69
  return { adapter, probe };
71
70
  }
72
71
 
73
72
  /**
74
- * Spec §4.5: a rung's stand-in on a usage limit: the profile's, else the same model on its paired backend
75
- * (spec 1.3 §7.3), else its backend's default (for `repo`, when given), else none.
73
+ * Spec §4.5: a rung's stand-in on a usage limit: the profile's, else its backend's default (for `repo`, when given), else none.
76
74
  */
77
75
  export function standInFor(failover: Record<string, string>, rung: string, repo?: string): string | null {
78
- const own = failover[rung] ?? PAIRED_FAILOVER[rung];
76
+ const own = failover[rung];
79
77
  if (own) return own;
80
78
  const r = tryParseRung(rung);
81
79
  if (!r) return null;
@@ -37,11 +37,6 @@ const HAIKU = "claude-code:claude-haiku-4-5-20251001#default";
37
37
  /** spec 1.3 §4.6: `auto` has no family; only the live kit and the capture run it */
38
38
  const AUTO = "cursor:auto#default";
39
39
  const BUNNY = "opencode:opencode/space-bunny-free#default";
40
- /** spec 1.3 §5.6: grok 1.0.44's default model (research §3.4) at its cheapest effort */
41
- const GROK = "grok:grok-4.6#low";
42
- /** spec 1.3 §6.6: the cheapest Gemini effort; capture runs isolated, on GEMINI_API_KEY */
43
- const FLASH_LOW = "antigravity:gemini-3.8-flash#low";
44
-
45
40
  /** Spec §11.7–8: one cheap run per backend, plus a read-only role trying to write where enforcement is advisory. */
46
41
  const CAPTURE_CASES: CaptureCase[] = [
47
42
  { backend: "codex", name: "ok", rung: "codex:gpt-6-luna#low", access: "read-only", brief: SAY_HELLO },
@@ -53,22 +48,6 @@ const CAPTURE_CASES: CaptureCase[] = [
53
48
  { backend: "cursor", name: "ok", rung: AUTO, access: "workspace-write", brief: WORK },
54
49
  { backend: "cursor", name: "resume", rung: AUTO, access: "read-only", brief: SAY_HELLO, resume: RECALL },
55
50
  { backend: "cursor", name: "read-only-write", rung: AUTO, access: "read-only", brief: TRY_WRITE },
56
- // spec 1.3 §5.6: the same three on grok; its read-only is the kernel profile, or the read tools on a Mac
57
- // with a symlinked docker socket
58
- { backend: "grok", name: "ok", rung: GROK, access: "workspace-write", brief: WORK },
59
- { backend: "grok", name: "resume", rung: GROK, access: "read-only", brief: SAY_HELLO, resume: RECALL },
60
- { backend: "grok", name: "read-only-write", rung: GROK, access: "read-only", brief: TRY_WRITE },
61
- // spec 1.3 §6.6: the same three on agy; read-only runs under catherd's deny rules (research §8 agy 2, 5, 6)
62
- { backend: "antigravity", name: "ok", rung: FLASH_LOW, access: "workspace-write", brief: WORK },
63
- {
64
- backend: "antigravity",
65
- name: "resume",
66
- rung: FLASH_LOW,
67
- access: "read-only",
68
- brief: SAY_HELLO,
69
- resume: RECALL,
70
- },
71
- { backend: "antigravity", name: "read-only-write", rung: FLASH_LOW, access: "read-only", brief: TRY_WRITE },
72
51
  ];
73
52
  export const CAPTURE_BACKENDS = [...new Set(CAPTURE_CASES.map((c) => c.backend))];
74
53
 
@@ -122,7 +101,7 @@ async function runOnce(
122
101
  const p = Bun.spawn([plan.cmd, ...plan.args], {
123
102
  cwd: plan.cwd,
124
103
  env: workerEnv(process.env, plan.env, plan.cwd),
125
- // spec 1.3 §3.3: the brief goes on stdin only to a CLI whose plan reads it there (grok reads a file)
104
+ // spec 1.3 §3.3: the brief goes on stdin only to a CLI whose plan reads it there (one reads a file)
126
105
  stdin: plan.stdinPath ? Bun.file(plan.stdinPath) : "ignore",
127
106
  stdout: "pipe",
128
107
  stderr: "pipe",