@cohortapp/agent-sdk 2.16.0 → 2.18.4

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 (529) hide show
  1. package/.claude/settings.json +18 -0
  2. package/.env.example +23 -7
  3. package/README.md +1 -0
  4. package/bin/maestro.mjs +62 -0
  5. package/docs/guides/billing-console-keys.md +60 -0
  6. package/docs/guides/front-door-session.md +54 -9
  7. package/docs/guides/mac-mini.md +20 -25
  8. package/docs/guides/poller-daemon-setup.md +4 -1
  9. package/docs/guides/setup-wizard.md +1 -1
  10. package/docs/runbooks/fleet-rollout.md +156 -0
  11. package/docs/runbooks/mac-mini-bootstrap.md +12 -14
  12. package/lib/action-executor.js +19 -3
  13. package/lib/budget-guard.mjs +279 -3
  14. package/lib/channels/base-adapter.mjs +3 -1
  15. package/lib/channels/contract.mjs +2 -1
  16. package/lib/channels/inbox-item.mjs +8 -0
  17. package/lib/claude-bin.mjs +5 -6
  18. package/lib/cli/doctor-checks.mjs +141 -10
  19. package/lib/cli/global-setup-extras.mjs +5 -1
  20. package/lib/cli/inbox.mjs +100 -15
  21. package/lib/cli/seat-auth.mjs +463 -0
  22. package/lib/cli/session.mjs +80 -12
  23. package/lib/collective/capture.mjs +8 -6
  24. package/lib/collective/global-config.mjs +63 -1
  25. package/lib/collective/presence.mjs +142 -5
  26. package/lib/comms/send-gate.mjs +559 -1
  27. package/lib/context/budget.mjs +327 -0
  28. package/lib/context/history-scope.mjs +138 -0
  29. package/lib/diagnostics/alerts.mjs +49 -0
  30. package/lib/diagnostics/cadence-output-freshness.mjs +288 -0
  31. package/lib/engine/agents/definitions.mjs +343 -0
  32. package/lib/engine/agents/persist.mjs +275 -0
  33. package/lib/engine/agents/runtime.mjs +748 -0
  34. package/lib/engine/agents/usage.mjs +95 -0
  35. package/lib/engine/auth-status.mjs +139 -0
  36. package/lib/engine/budget.mjs +194 -0
  37. package/lib/engine/cli.mjs +1204 -0
  38. package/lib/engine/commands/index.mjs +269 -0
  39. package/lib/engine/context/budget.mjs +219 -0
  40. package/lib/engine/context/cache.mjs +125 -0
  41. package/lib/engine/context/child-env.mjs +215 -0
  42. package/lib/engine/context/compaction.mjs +342 -0
  43. package/lib/engine/context/images.mjs +90 -0
  44. package/lib/engine/context/instructions.mjs +327 -0
  45. package/lib/engine/context/lazy-instructions.mjs +169 -0
  46. package/lib/engine/context/manager.mjs +182 -0
  47. package/lib/engine/context/real-path.mjs +91 -0
  48. package/lib/engine/context/secret-values.mjs +163 -0
  49. package/lib/engine/context/settings.mjs +274 -0
  50. package/lib/engine/context/stream-input.mjs +159 -0
  51. package/lib/engine/guard.mjs +152 -0
  52. package/lib/engine/hooks.mjs +713 -0
  53. package/lib/engine/loop.mjs +560 -0
  54. package/lib/engine/mcp/client.mjs +254 -0
  55. package/lib/engine/mcp/config.mjs +301 -0
  56. package/lib/engine/mcp/http.mjs +201 -0
  57. package/lib/engine/mcp/index.mjs +146 -0
  58. package/lib/engine/mcp/jsonrpc.mjs +147 -0
  59. package/lib/engine/mcp/naming.mjs +66 -0
  60. package/lib/engine/mcp/resources.mjs +89 -0
  61. package/lib/engine/mcp/results.mjs +133 -0
  62. package/lib/engine/mcp/stdio.mjs +137 -0
  63. package/lib/engine/mcp/supervisor.mjs +116 -0
  64. package/lib/engine/messages.mjs +104 -0
  65. package/lib/engine/output/json.mjs +164 -0
  66. package/lib/engine/output/stream-json.mjs +266 -0
  67. package/lib/engine/permissions.mjs +845 -0
  68. package/lib/engine/process-identity.mjs +164 -0
  69. package/lib/engine/process-tree.mjs +551 -0
  70. package/lib/engine/prompt.mjs +60 -0
  71. package/lib/engine/session/store.mjs +299 -0
  72. package/lib/engine/session-runtime/args.mjs +97 -0
  73. package/lib/engine/session-runtime/host.mjs +143 -0
  74. package/lib/engine/session-runtime/inbox.mjs +122 -0
  75. package/lib/engine/session-runtime/notifications.mjs +129 -0
  76. package/lib/engine/session-runtime/registry.mjs +328 -0
  77. package/lib/engine/session-runtime/runner.mjs +344 -0
  78. package/lib/engine/session-runtime/socket.mjs +212 -0
  79. package/lib/engine/session-runtime/wakeup.mjs +115 -0
  80. package/lib/engine/skills/index.mjs +321 -0
  81. package/lib/engine/tools/bash-background.mjs +533 -0
  82. package/lib/engine/tools/bash.mjs +216 -0
  83. package/lib/engine/tools/edit.mjs +97 -0
  84. package/lib/engine/tools/glob.mjs +81 -0
  85. package/lib/engine/tools/grep.mjs +224 -0
  86. package/lib/engine/tools/index.mjs +84 -0
  87. package/lib/engine/tools/list-agents.mjs +32 -0
  88. package/lib/engine/tools/ls.mjs +127 -0
  89. package/lib/engine/tools/monitor.mjs +82 -0
  90. package/lib/engine/tools/notebook-edit.mjs +218 -0
  91. package/lib/engine/tools/read.mjs +103 -0
  92. package/lib/engine/tools/schedule-wakeup.mjs +45 -0
  93. package/lib/engine/tools/schema.mjs +144 -0
  94. package/lib/engine/tools/send-message.mjs +77 -0
  95. package/lib/engine/tools/session.mjs +70 -0
  96. package/lib/engine/tools/todo.mjs +144 -0
  97. package/lib/engine/tools/toolsearch.mjs +217 -0
  98. package/lib/engine/tools/walk.mjs +193 -0
  99. package/lib/engine/tools/web-switch.mjs +31 -0
  100. package/lib/engine/tools/webfetch-html.mjs +387 -0
  101. package/lib/engine/tools/webfetch-net.mjs +340 -0
  102. package/lib/engine/tools/webfetch.mjs +198 -0
  103. package/lib/engine/tools/websearch.mjs +91 -0
  104. package/lib/engine/tools/workflow.mjs +95 -0
  105. package/lib/engine/tools/write.mjs +76 -0
  106. package/lib/engine/tui/line-editor.mjs +137 -0
  107. package/lib/engine/tui/render.mjs +86 -0
  108. package/lib/engine/tui/tui.mjs +274 -0
  109. package/lib/engine/wire/anthropic-messages.mjs +263 -0
  110. package/lib/engine/wire/effort.mjs +36 -0
  111. package/lib/engine/wire/errors.mjs +496 -0
  112. package/lib/engine/wire/http.mjs +441 -0
  113. package/lib/engine/wire/index.mjs +76 -0
  114. package/lib/engine/wire/openai-chat.mjs +332 -0
  115. package/lib/engine/wire/prompt-cache.mjs +79 -0
  116. package/lib/engine/wire/search.mjs +140 -0
  117. package/lib/engine/wire/sse.mjs +114 -0
  118. package/lib/engine/wire/stall.mjs +349 -0
  119. package/lib/engine/wire/token-provider.mjs +175 -0
  120. package/lib/engine/wire/usage.mjs +192 -0
  121. package/lib/engine/workflow/host.mjs +524 -0
  122. package/lib/engine/workflow/journal.mjs +188 -0
  123. package/lib/engine/workflow/json-schema.mjs +171 -0
  124. package/lib/engine/workflow/meta.mjs +329 -0
  125. package/lib/engine/workflow/notifications.mjs +52 -0
  126. package/lib/engine/workflow/runtime.mjs +447 -0
  127. package/lib/engine/workflow/sandbox.mjs +534 -0
  128. package/lib/engine/workflow/worker.mjs +141 -0
  129. package/lib/engine/workflow/worktree.mjs +74 -0
  130. package/lib/execution/disposition.mjs +1 -1
  131. package/lib/execution/intake.mjs +10 -0
  132. package/lib/execution/surface-policy.mjs +15 -0
  133. package/lib/learning/curator.mjs +8 -6
  134. package/lib/learning/reflect.mjs +8 -6
  135. package/lib/model-router/catalog/cohort.yaml +137 -0
  136. package/lib/model-router/catalog.mjs +118 -1
  137. package/lib/model-router/economics.mjs +9 -0
  138. package/lib/model-router/failover.mjs +67 -16
  139. package/lib/model-router/llm-task.mjs +39 -3
  140. package/lib/model-router/resolve.mjs +95 -3
  141. package/lib/model-router/spawn.mjs +46 -47
  142. package/lib/model-router/taxonomy.mjs +126 -4
  143. package/lib/org/cost-sync.mjs +141 -11
  144. package/lib/org/inbound/broadcast.mjs +289 -0
  145. package/lib/org/inbound/collective.mjs +375 -0
  146. package/lib/org/inbound/directedness.mjs +96 -8
  147. package/lib/org/inbound/facts.mjs +82 -4
  148. package/lib/org/inbound/hydrate.mjs +555 -51
  149. package/lib/org/inbound/project.mjs +22 -0
  150. package/lib/org/inbound/surfaces.mjs +14 -0
  151. package/lib/org/llm-token.mjs +879 -0
  152. package/lib/org/mesh.mjs +61 -0
  153. package/lib/org/messaging.mjs +3 -1
  154. package/lib/org/protocol.checksum +1 -1
  155. package/lib/org/protocol.mjs +15 -0
  156. package/lib/org/quota.mjs +520 -0
  157. package/lib/org/tool-surface.mjs +104 -16
  158. package/lib/org/ui-parity.mjs +16 -1
  159. package/lib/org/work-ledger.mjs +37 -6
  160. package/lib/rate-guard.mjs +114 -1
  161. package/lib/resource-governor.mjs +41 -6
  162. package/lib/runtime/adapter.mjs +823 -0
  163. package/lib/runtime/child-env.mjs +191 -0
  164. package/lib/runtime/legacy-shell-guard.mjs +97 -0
  165. package/lib/runtime/seat-engine.mjs +162 -0
  166. package/lib/session/ask-ledger.mjs +271 -0
  167. package/lib/session/current-work.mjs +676 -0
  168. package/lib/session/feed-core.mjs +40 -3
  169. package/lib/session/launch-args.mjs +56 -4
  170. package/lib/session/status-summary.mjs +26 -9
  171. package/lib/session/upgrade-notice.mjs +42 -0
  172. package/lib/setup/claude-probe.mjs +117 -13
  173. package/lib/setup/enrich.mjs +13 -10
  174. package/lib/setup/sections/model.mjs +39 -13
  175. package/lib/telemetry/collect.mjs +208 -9
  176. package/lib/upgrade/ignored-drift.mjs +105 -0
  177. package/lib/voice/post-call-brief.mjs +30 -17
  178. package/package.json +15 -3
  179. package/plugins/maestro-skills/skills/board-work.md +5 -0
  180. package/plugins/maestro-skills/skills/inbound-triage.md +56 -15
  181. package/plugins/maestro-skills/skills/main-session.md +18 -7
  182. package/scripts/ci/check-tarball-fidelity.mjs +126 -2
  183. package/scripts/ci/run-tests.mjs +47 -19
  184. package/scripts/cohort-llm/api-key-helper.mjs +92 -0
  185. package/scripts/collective/hook-runner.mjs +29 -2
  186. package/scripts/continuous-monitor.sh +13 -0
  187. package/scripts/cost/track-claude-usage.mjs +15 -0
  188. package/scripts/daemon/agent-daemon.mjs +408 -20
  189. package/scripts/daemon/assurance.mjs +48 -12
  190. package/scripts/daemon/cadence-consumer.mjs +218 -68
  191. package/scripts/daemon/cadence-handlers.mjs +73 -4
  192. package/scripts/daemon/classifier.mjs +75 -26
  193. package/scripts/daemon/context-compiler.mjs +104 -59
  194. package/scripts/daemon/deliver.mjs +30 -1
  195. package/scripts/daemon/dispatcher.mjs +804 -157
  196. package/scripts/daemon/health.mjs +14 -1
  197. package/scripts/daemon/lib/session-router.mjs +310 -42
  198. package/scripts/daemon/maestro-daemon.mjs +11 -0
  199. package/scripts/daemon/prompt-builder.mjs +121 -12
  200. package/scripts/daemon/responder.mjs +315 -146
  201. package/scripts/daemon/sdk-version.mjs +98 -16
  202. package/scripts/eval/probe-gateway.mjs +635 -0
  203. package/scripts/eval/replay/extract.mjs +270 -0
  204. package/scripts/eval/replay/grade.mjs +260 -0
  205. package/scripts/eval/replay/lib/config.mjs +50 -0
  206. package/scripts/eval/replay/lib/effects.mjs +65 -0
  207. package/scripts/eval/replay/lib/fixture.mjs +188 -0
  208. package/scripts/eval/replay/lib/judge.mjs +72 -0
  209. package/scripts/eval/replay/lib/redact.mjs +136 -0
  210. package/scripts/eval/replay/lib/sandbox.mjs +170 -0
  211. package/scripts/eval/replay/lib/schema-check.mjs +63 -0
  212. package/scripts/eval/replay/lib/transcript.mjs +76 -0
  213. package/scripts/eval/replay/mcp-replay-stub.mjs +101 -0
  214. package/scripts/eval/replay/report.mjs +185 -0
  215. package/scripts/eval/replay/run.mjs +404 -0
  216. package/scripts/fleet/rollout.mjs +1094 -0
  217. package/scripts/hooks/pre-send-audit.sh +36 -245
  218. package/scripts/hooks/pre-write-yaml-validate.mjs +275 -0
  219. package/scripts/hooks/validate-state-yaml.sh +190 -0
  220. package/scripts/huddle/huddle-llm.mjs +361 -0
  221. package/scripts/huddle/huddle-server.mjs +46 -121
  222. package/scripts/local-triggers/autoupdate.sh +448 -78
  223. package/scripts/local-triggers/run-trigger.sh +13 -0
  224. package/scripts/maintenance/pin-integrity.mjs +364 -0
  225. package/scripts/poll-slack-events.sh +41 -9
  226. package/scripts/poller/slack-socket-mode.mjs +28 -3
  227. package/scripts/session/supervisor.mjs +80 -13
  228. package/scripts/spawn-session.sh +13 -0
  229. package/bin/maestro.test.mjs +0 -1574
  230. package/lib/action-executor.test.mjs +0 -871
  231. package/lib/archetype.test.mjs +0 -132
  232. package/lib/assurance/plan-note.test.mjs +0 -234
  233. package/lib/assurance/room-budget.test.mjs +0 -486
  234. package/lib/assurance/tier.test.mjs +0 -174
  235. package/lib/autonomy.test.mjs +0 -66
  236. package/lib/backlog.test.mjs +0 -302
  237. package/lib/backup/policy.test.mjs +0 -305
  238. package/lib/budget-escalate.test.mjs +0 -232
  239. package/lib/budget-guard.envelope.test.mjs +0 -476
  240. package/lib/budget-guard.test.mjs +0 -427
  241. package/lib/cadence-bus-requeue.test.mjs +0 -83
  242. package/lib/cadence-bus-schedule.test.mjs +0 -194
  243. package/lib/cadence-bus.test.mjs +0 -720
  244. package/lib/cadences.test.mjs +0 -230
  245. package/lib/capability/inventory.test.mjs +0 -232
  246. package/lib/capability.test.mjs +0 -78
  247. package/lib/channels/base-adapter.test.mjs +0 -590
  248. package/lib/channels/channels.test.mjs +0 -371
  249. package/lib/channels/contract.test.mjs +0 -162
  250. package/lib/channels/inbox-item.test.mjs +0 -368
  251. package/lib/channels/orgmail/adapter.test.mjs +0 -448
  252. package/lib/channels/pairing.test.mjs +0 -270
  253. package/lib/channels/repeat-suppressor.test.mjs +0 -134
  254. package/lib/channels/slack-adapter.test.mjs +0 -212
  255. package/lib/channels/telegram-adapter.test.mjs +0 -306
  256. package/lib/channels/voice/adapter.test.mjs +0 -278
  257. package/lib/channels/whatsapp/adapter-baileys.test.mjs +0 -359
  258. package/lib/channels/whatsapp/baileys-typing.test.mjs +0 -154
  259. package/lib/charter.test.mjs +0 -89
  260. package/lib/claude-bin.test.mjs +0 -131
  261. package/lib/cli/board.test.mjs +0 -227
  262. package/lib/cli/design.test.mjs +0 -270
  263. package/lib/cli/doctor-checks.test.mjs +0 -336
  264. package/lib/cli/global-setup-extras.test.mjs +0 -462
  265. package/lib/cli/inbox.test.mjs +0 -230
  266. package/lib/cli/session-ack.test.mjs +0 -63
  267. package/lib/cli/session.test.mjs +0 -613
  268. package/lib/collective/capture.test.mjs +0 -121
  269. package/lib/collective/cards.test.mjs +0 -114
  270. package/lib/collective/config.test.mjs +0 -123
  271. package/lib/collective/global-config.test.mjs +0 -220
  272. package/lib/collective/global-skills.test.mjs +0 -126
  273. package/lib/collective/presence.test.mjs +0 -95
  274. package/lib/collective/recall.test.mjs +0 -116
  275. package/lib/collective/vendor-skills.test.mjs +0 -306
  276. package/lib/comms/send-gate.test.mjs +0 -770
  277. package/lib/comms.test.mjs +0 -41
  278. package/lib/cost/ledger-row.test.mjs +0 -183
  279. package/lib/design/design-md.test.mjs +0 -318
  280. package/lib/design/fixtures/DESIGN.golden.md +0 -238
  281. package/lib/design/fixtures/PRODUCT.golden.md +0 -67
  282. package/lib/design/fixtures/foundation.json +0 -133
  283. package/lib/design/refresh-gate.test.mjs +0 -144
  284. package/lib/design/write.test.mjs +0 -241
  285. package/lib/diagnostics/alerts.test.mjs +0 -318
  286. package/lib/diagnostics/backup-freshness.test.mjs +0 -185
  287. package/lib/diagnostics/counters.test.mjs +0 -206
  288. package/lib/diagnostics/events.test.mjs +0 -290
  289. package/lib/diagnostics/otel.test.mjs +0 -196
  290. package/lib/diagnostics/trace.test.mjs +0 -251
  291. package/lib/env-compat.test.mjs +0 -104
  292. package/lib/execution/disposition.test.mjs +0 -553
  293. package/lib/execution/drive.test.mjs +0 -270
  294. package/lib/execution/effects.test.mjs +0 -344
  295. package/lib/execution/intake.test.mjs +0 -389
  296. package/lib/execution/journal.test.mjs +0 -261
  297. package/lib/execution/match.test.mjs +0 -235
  298. package/lib/execution/pipeline.test.mjs +0 -392
  299. package/lib/execution/route.test.mjs +0 -186
  300. package/lib/execution/surface-policy.test.mjs +0 -162
  301. package/lib/fs-atomic.test.mjs +0 -72
  302. package/lib/fs-ownership.test.mjs +0 -158
  303. package/lib/goals/admission.test.mjs +0 -164
  304. package/lib/goals/classify.test.mjs +0 -167
  305. package/lib/goals/collaborate.test.mjs +0 -336
  306. package/lib/goals/gaps.test.mjs +0 -284
  307. package/lib/goals/loop.test.mjs +0 -845
  308. package/lib/hooks/bus.test.mjs +0 -387
  309. package/lib/identity/persona.test.mjs +0 -142
  310. package/lib/kpi-sensors.test.mjs +0 -278
  311. package/lib/kpi.test.mjs +0 -244
  312. package/lib/learning/config.test.mjs +0 -75
  313. package/lib/learning/counters.test.mjs +0 -69
  314. package/lib/learning/curator-consolidate.test.mjs +0 -238
  315. package/lib/learning/curator.test.mjs +0 -106
  316. package/lib/learning/reflect.test.mjs +0 -0
  317. package/lib/learning/session-index.test.mjs +0 -125
  318. package/lib/learning/skill-writer.test.mjs +0 -210
  319. package/lib/mandate/audit.test.mjs +0 -195
  320. package/lib/mandate/contract.test.mjs +0 -185
  321. package/lib/mandate/derive.test.mjs +0 -274
  322. package/lib/mandate/model.test.mjs +0 -164
  323. package/lib/mandate/refresh.test.mjs +0 -389
  324. package/lib/mcp/server.test.mjs +0 -426
  325. package/lib/model-router/auth-profiles.test.mjs +0 -580
  326. package/lib/model-router/catalog.test.mjs +0 -385
  327. package/lib/model-router/economics.test.mjs +0 -438
  328. package/lib/model-router/failover.test.mjs +0 -439
  329. package/lib/model-router/health.test.mjs +0 -338
  330. package/lib/model-router/integration-coverage.test.mjs +0 -831
  331. package/lib/model-router/integration.test.mjs +0 -564
  332. package/lib/model-router/ledger.test.mjs +0 -415
  333. package/lib/model-router/llm-task.test.mjs +0 -392
  334. package/lib/model-router/org-credentials.test.mjs +0 -265
  335. package/lib/model-router/pricing-refresh.test.mjs +0 -286
  336. package/lib/model-router/reconcile.test.mjs +0 -316
  337. package/lib/model-router/repair.test.mjs +0 -180
  338. package/lib/model-router/spawn.test.mjs +0 -446
  339. package/lib/model-router/taxonomy.test.mjs +0 -410
  340. package/lib/model-router.test.mjs +0 -1207
  341. package/lib/org/activity.test.mjs +0 -134
  342. package/lib/org/approvals.test.mjs +0 -216
  343. package/lib/org/awareness.test.mjs +0 -159
  344. package/lib/org/board-mine-cache.test.mjs +0 -53
  345. package/lib/org/board.test.mjs +0 -187
  346. package/lib/org/bootstrap-context.test.mjs +0 -153
  347. package/lib/org/client.test.mjs +0 -1206
  348. package/lib/org/cohort-client.test.mjs +0 -126
  349. package/lib/org/cost-sync.test.mjs +0 -153
  350. package/lib/org/doctor.test.mjs +0 -346
  351. package/lib/org/engagement-ledger.test.mjs +0 -112
  352. package/lib/org/engagement.test.mjs +0 -739
  353. package/lib/org/handoff.test.mjs +0 -269
  354. package/lib/org/inbound/directedness.test.mjs +0 -668
  355. package/lib/org/inbound/facts.test.mjs +0 -471
  356. package/lib/org/inbound/hydrate.test.mjs +0 -453
  357. package/lib/org/inbound/index.test.mjs +0 -429
  358. package/lib/org/inbound/project.test.mjs +0 -287
  359. package/lib/org/integration-tools.test.mjs +0 -160
  360. package/lib/org/keys.test.mjs +0 -92
  361. package/lib/org/knowledge.test.mjs +0 -326
  362. package/lib/org/leases.test.mjs +0 -235
  363. package/lib/org/mesh-directives.test.mjs +0 -110
  364. package/lib/org/mesh-integration.test.mjs +0 -127
  365. package/lib/org/mesh.test.mjs +0 -400
  366. package/lib/org/messaging.test.mjs +0 -471
  367. package/lib/org/param-contract.test.mjs +0 -477
  368. package/lib/org/policy.test.mjs +0 -237
  369. package/lib/org/protocol.checksum.test.mjs +0 -90
  370. package/lib/org/protocol.test.mjs +0 -323
  371. package/lib/org/push.test.mjs +0 -792
  372. package/lib/org/registry.test.mjs +0 -100
  373. package/lib/org/resource-tools.test.mjs +0 -361
  374. package/lib/org/tool-access.test.mjs +0 -144
  375. package/lib/org/tool-surface-integration.test.mjs +0 -120
  376. package/lib/org/tool-surface.test.mjs +0 -1268
  377. package/lib/org/typing.test.mjs +0 -291
  378. package/lib/org/ui-parity.test.mjs +0 -560
  379. package/lib/org/verify.test.mjs +0 -194
  380. package/lib/org/work-ledger.test.mjs +0 -273
  381. package/lib/plan/adoption-e2e.test.mjs +0 -366
  382. package/lib/plan/budget-enforcement.test.mjs +0 -400
  383. package/lib/plan/compile.test.mjs +0 -382
  384. package/lib/plan/emit.test.mjs +0 -269
  385. package/lib/plan/explain.test.mjs +0 -188
  386. package/lib/prompts/parallelism.test.mjs +0 -177
  387. package/lib/rag/rag.test.mjs +0 -505
  388. package/lib/rate-guard.test.mjs +0 -272
  389. package/lib/reactive-gate.test.mjs +0 -57
  390. package/lib/render.test.mjs +0 -68
  391. package/lib/resource-governor.test.mjs +0 -488
  392. package/lib/scheduling/dynamic-jobs.test.mjs +0 -344
  393. package/lib/scheduling/jitter.test.mjs +0 -140
  394. package/lib/secrets/broker.test.mjs +0 -280
  395. package/lib/secrets/providers.test.mjs +0 -274
  396. package/lib/security/audit-engine.test.mjs +0 -424
  397. package/lib/security/coerce-args.test.mjs +0 -281
  398. package/lib/security/dangerous-tools.test.mjs +0 -68
  399. package/lib/security/external-content.test.mjs +0 -84
  400. package/lib/security/redact.test.mjs +0 -441
  401. package/lib/security/secret-equal.test.mjs +0 -55
  402. package/lib/session/config.test.mjs +0 -92
  403. package/lib/session/feed-core.test.mjs +0 -198
  404. package/lib/session/first-run.test.mjs +0 -121
  405. package/lib/session/frontdoor.test.mjs +0 -205
  406. package/lib/session/handoffs.test.mjs +0 -183
  407. package/lib/session/identity.test.mjs +0 -180
  408. package/lib/session/inbox-claims.test.mjs +0 -286
  409. package/lib/session/launch-args.test.mjs +0 -157
  410. package/lib/session/liveness.test.mjs +0 -100
  411. package/lib/session/status-summary.test.mjs +0 -118
  412. package/lib/session-permissions.test.mjs +0 -120
  413. package/lib/setup/claude-probe.test.mjs +0 -187
  414. package/lib/setup/completeness.test.mjs +0 -110
  415. package/lib/setup/context-pack.test.mjs +0 -89
  416. package/lib/setup/enrich.test.mjs +0 -115
  417. package/lib/setup/enroll-from-cohort.test.mjs +0 -300
  418. package/lib/setup/integration.test.mjs +0 -162
  419. package/lib/setup/io.test.mjs +0 -77
  420. package/lib/setup/runner.test.mjs +0 -132
  421. package/lib/setup/sections/identity.test.mjs +0 -234
  422. package/lib/setup/sections/inventory.test.mjs +0 -198
  423. package/lib/setup/sections/learning.test.mjs +0 -81
  424. package/lib/setup/sections/mandate.test.mjs +0 -388
  425. package/lib/setup/sections/messaging.test.mjs +0 -127
  426. package/lib/setup/sections/model.test.mjs +0 -240
  427. package/lib/setup/sections/org.test.mjs +0 -346
  428. package/lib/setup/sections/orgmail.test.mjs +0 -118
  429. package/lib/setup/sections/recovery.test.mjs +0 -98
  430. package/lib/setup/sections/subagents.test.mjs +0 -429
  431. package/lib/setup/sections/verify.test.mjs +0 -175
  432. package/lib/setup/sot.test.mjs +0 -81
  433. package/lib/setup/state.test.mjs +0 -115
  434. package/lib/singleton.test.mjs +0 -151
  435. package/lib/subagents/cli.test.mjs +0 -389
  436. package/lib/subagents/client.test.mjs +0 -309
  437. package/lib/subagents/gap.test.mjs +0 -234
  438. package/lib/subagents/lock.test.mjs +0 -248
  439. package/lib/subagents/manifest.test.mjs +0 -175
  440. package/lib/subagents/refs.test.mjs +0 -204
  441. package/lib/subagents/resolve.test.mjs +0 -422
  442. package/lib/subagents/schema.test.mjs +0 -328
  443. package/lib/telemetry/alerts.test.mjs +0 -109
  444. package/lib/telemetry/collect.test.mjs +0 -1274
  445. package/lib/tool-definitions-integration.test.mjs +0 -83
  446. package/lib/tool-definitions.test.mjs +0 -437
  447. package/lib/upgrade/global-refresh.test.mjs +0 -65
  448. package/lib/upgrade/launchd-reconcile.test.mjs +0 -272
  449. package/lib/upgrade/post-steps.test.mjs +0 -200
  450. package/lib/upgrade/verify.test.mjs +0 -164
  451. package/lib/util/fetch-timeout.test.mjs +0 -202
  452. package/lib/util/reconnect.test.mjs +0 -369
  453. package/lib/util/unhandled.test.mjs +0 -216
  454. package/lib/voice/outbound.test.mjs +0 -69
  455. package/lib/voice/session-rotation.test.mjs +0 -114
  456. package/lib/voice/stt.test.mjs +0 -226
  457. package/lib/voice/voice.test.mjs +0 -990
  458. package/scripts/cadence/enqueue-cadence-tick.test.mjs +0 -187
  459. package/scripts/ci/check-docs-accuracy.test.mjs +0 -409
  460. package/scripts/ci/check-durable-write-seam.test.mjs +0 -90
  461. package/scripts/ci/check-no-build-artifacts.test.mjs +0 -71
  462. package/scripts/ci/check-no-residual-identity.test.mjs +0 -202
  463. package/scripts/ci/check-skill-packs.test.mjs +0 -495
  464. package/scripts/ci/check-subagent-frontmatter.test.mjs +0 -124
  465. package/scripts/ci/check.test.mjs +0 -194
  466. package/scripts/ci/conformance-org-api.test.mjs +0 -425
  467. package/scripts/cloud-relay/voice/relay-identity.test.mjs +0 -96
  468. package/scripts/collective/hook-runner.test.mjs +0 -173
  469. package/scripts/cost/fleet-digest.test.mjs +0 -207
  470. package/scripts/cost/track-claude-usage-pricing.test.mjs +0 -183
  471. package/scripts/cost/track-claude-usage.test.mjs +0 -148
  472. package/scripts/daemon/agent-daemon-board-mine.test.mjs +0 -96
  473. package/scripts/daemon/agent-daemon-design.test.mjs +0 -238
  474. package/scripts/daemon/agent-daemon-frontdoor.test.mjs +0 -60
  475. package/scripts/daemon/agent-daemon.test.mjs +0 -995
  476. package/scripts/daemon/assurance-e2e.test.mjs +0 -613
  477. package/scripts/daemon/assurance.test.mjs +0 -1791
  478. package/scripts/daemon/board-mirror.test.mjs +0 -165
  479. package/scripts/daemon/cadence-consumer-frontdoor.test.mjs +0 -393
  480. package/scripts/daemon/cadence-consumer-governance.test.mjs +0 -276
  481. package/scripts/daemon/cadence-consumer.test.mjs +0 -776
  482. package/scripts/daemon/cadence-handlers.test.mjs +0 -837
  483. package/scripts/daemon/classifier-identity.test.mjs +0 -137
  484. package/scripts/daemon/classifier.test.mjs +0 -266
  485. package/scripts/daemon/classify-kind.test.mjs +0 -40
  486. package/scripts/daemon/context-compiler.test.mjs +0 -300
  487. package/scripts/daemon/deliver.test.mjs +0 -564
  488. package/scripts/daemon/dispatcher-cooldown.test.mjs +0 -122
  489. package/scripts/daemon/dispatcher-governance.test.mjs +0 -1013
  490. package/scripts/daemon/dispatcher-resume.test.mjs +0 -166
  491. package/scripts/daemon/execution-ladder.test.mjs +0 -470
  492. package/scripts/daemon/goal-steward-cadence.test.mjs +0 -312
  493. package/scripts/daemon/inbox-deferral-session.test.mjs +0 -49
  494. package/scripts/daemon/inbox-deferral.test.mjs +0 -336
  495. package/scripts/daemon/inbox-wake.test.mjs +0 -199
  496. package/scripts/daemon/integration.test.mjs +0 -149
  497. package/scripts/daemon/lib/self-echo.test.mjs +0 -153
  498. package/scripts/daemon/lib/session-router.test.mjs +0 -295
  499. package/scripts/daemon/prompt-builder-preamble.test.mjs +0 -210
  500. package/scripts/daemon/prompt-builder.test.mjs +0 -344
  501. package/scripts/daemon/responder-cost.test.mjs +0 -68
  502. package/scripts/daemon/responder-history.test.mjs +0 -185
  503. package/scripts/daemon/sdk-version.test.mjs +0 -31
  504. package/scripts/daemon/session-lock.test.mjs +0 -252
  505. package/scripts/daemon/session-outcomes.test.mjs +0 -533
  506. package/scripts/daemon/typing-registry.test.mjs +0 -102
  507. package/scripts/hooks/pre-send-audit.test.mjs +0 -354
  508. package/scripts/huddle/huddle-prompt.test.mjs +0 -176
  509. package/scripts/local-triggers/autoupdate.test.mjs +0 -518
  510. package/scripts/local-triggers/generate-plists.test.mjs +0 -456
  511. package/scripts/media-generation/brand-clause.test.mjs +0 -135
  512. package/scripts/org/send-orgmail.first-contact.test.mjs +0 -102
  513. package/scripts/poller/inbox-privilege-injection.test.mjs +0 -167
  514. package/scripts/poller/inbox-scan-poller.test.mjs +0 -295
  515. package/scripts/poller/lib/cloud-relay-dedup.test.mjs +0 -133
  516. package/scripts/poller/slack-socket-mode.test.mjs +0 -805
  517. package/scripts/poller-launchd/install.test.mjs +0 -243
  518. package/scripts/restore-from-backup.test.mjs +0 -181
  519. package/scripts/session/feed.test.mjs +0 -196
  520. package/scripts/session/supervisor-sh.test.mjs +0 -218
  521. package/scripts/session/supervisor.test.mjs +0 -482
  522. package/scripts/setup/configure-macos.test.mjs +0 -306
  523. package/scripts/setup/gen-subagent-manifest.test.mjs +0 -124
  524. package/scripts/setup/generate-agent-package-json.test.mjs +0 -143
  525. package/scripts/setup/generate-capability.test.mjs +0 -134
  526. package/scripts/setup/init-agent.test.mjs +0 -370
  527. package/scripts/setup/init-skill-marketplace.test.mjs +0 -193
  528. package/scripts/vendor/sync-skill-packs.test.mjs +0 -103
  529. package/scripts/watchdog/memory-watchdog.test.mjs +0 -64
@@ -0,0 +1,74 @@
1
+ /**
2
+ * lib/engine/workflow/worktree.mjs — a git worktree for one agent() call with
3
+ * `isolation: "worktree"`.
4
+ *
5
+ * The worktree is created on a new branch from the repository's HEAD, under the
6
+ * run's directory (outside the project, so it never shows up as untracked
7
+ * files in it). The child works there. When it ends, a worktree whose HEAD has
8
+ * not moved and whose status is clean is removed with its branch; anything
9
+ * else is kept, and the agent's result names its path and branch.
10
+ *
11
+ * Only for a working directory inside a git repository with at least one
12
+ * commit; otherwise the call gets an error (`usage: true`, which agent()
13
+ * rejects with) instead of running unisolated. A kept worktree is listed in the
14
+ * run's `end` record. Before creating one, `git worktree prune` forgets
15
+ * worktrees whose directories no longer exist.
16
+ *
17
+ * @module lib/engine/workflow/worktree
18
+ */
19
+
20
+ import { execFile } from "node:child_process";
21
+ import { mkdirSync } from "node:fs";
22
+ import path from "node:path";
23
+
24
+ const GIT_TIMEOUT_MS = 30_000;
25
+
26
+ /**
27
+ * @param {string[]} args @param {string} cwd
28
+ * @returns {Promise<{ok:boolean, stdout:string, stderr:string}>}
29
+ */
30
+ function git(args, cwd) {
31
+ // GIT_DIR and friends in the engine's environment (a hook's, say) would point git elsewhere.
32
+ const env = { PATH: process.env.PATH ?? "/usr/bin:/bin", HOME: process.env.HOME ?? "", LANG: "C", GIT_TERMINAL_PROMPT: "0" };
33
+ return new Promise((resolve) => {
34
+ execFile("git", args, { cwd, env, timeout: GIT_TIMEOUT_MS, maxBuffer: 4 * 1024 * 1024 }, (err, stdout, stderr) => {
35
+ resolve({ ok: !err, stdout: String(stdout ?? "").trim(), stderr: String(stderr ?? "").trim() || (err ? err.message : "") });
36
+ });
37
+ });
38
+ }
39
+
40
+ /**
41
+ * @param {{cwd:string, dir:string, branch:string}} o
42
+ * @returns {Promise<{ok:true, path:string, branch:string, base:string, repo:string, root:string}|{ok:false, error:string, usage?:boolean}>}
43
+ */
44
+ export async function createWorktree({ cwd, dir, branch }) {
45
+ const top = await git(["rev-parse", "--show-toplevel"], cwd);
46
+ if (!top.ok || top.stdout === "") return { ok: false, usage: true, error: `isolation "worktree" needs a git repository, and ${cwd} is not in one` };
47
+ const base = await git(["rev-parse", "HEAD"], top.stdout);
48
+ if (!base.ok) return { ok: false, usage: true, error: `isolation "worktree" needs a commit to start from; the repository at ${top.stdout} has none` };
49
+ // Forget worktrees whose directories are gone (a run directory deleted, a process
50
+ // that exited before removing one), so they do not stay registered in .git/worktrees.
51
+ await git(["worktree", "prune"], top.stdout);
52
+ mkdirSync(path.dirname(dir), { recursive: true });
53
+ const add = await git(["worktree", "add", "-b", branch, dir, base.stdout], top.stdout);
54
+ if (!add.ok) return { ok: false, error: `could not create a worktree: ${add.stderr}` };
55
+ // The child works in the same place inside the worktree as cwd is inside the repository.
56
+ const rel = path.relative(top.stdout, cwd);
57
+ return { ok: true, path: rel && !rel.startsWith("..") ? path.join(dir, rel) : dir, branch, base: base.stdout, repo: top.stdout, root: dir };
58
+ }
59
+
60
+ /**
61
+ * Remove the worktree when nothing changed; keep it otherwise.
62
+ * @param {{root:string, branch:string, base:string, repo:string}} w
63
+ * @returns {Promise<{removed:boolean, reason:string}>}
64
+ */
65
+ export async function finishWorktree(w) {
66
+ const status = await git(["status", "--porcelain"], w.root);
67
+ const head = await git(["rev-parse", "HEAD"], w.root);
68
+ if (!status.ok || !head.ok) return { removed: false, reason: "its state could not be read" };
69
+ if (status.stdout !== "" || head.stdout !== w.base) return { removed: false, reason: status.stdout !== "" ? "it has uncommitted changes" : "it has new commits" };
70
+ const rm = await git(["worktree", "remove", "--force", w.root], w.repo);
71
+ if (!rm.ok) return { removed: false, reason: `removing it failed: ${rm.stderr}` };
72
+ await git(["branch", "-D", w.branch], w.repo);
73
+ return { removed: true, reason: "unchanged" };
74
+ }
@@ -47,7 +47,7 @@ import { dedupeKey, threadKey } from "./journal.mjs";
47
47
  * directedness ladder. A human pointed at this agent; the agent owes an answer.
48
48
  */
49
49
  export const T0_REASONS = Object.freeze([
50
- "direct", "dm", "mention", "named", "assignee", "reviewer", "owner",
50
+ "direct", "dm", "mention", "collective", "named", "assignee", "reviewer", "owner",
51
51
  "approver", "requester", "proposer", "participant", "invited", "attendee",
52
52
  "waiting_on",
53
53
  ]);
@@ -64,6 +64,7 @@ export const INTAKE_ORIGINS = Object.freeze([
64
64
  export const SURFACE_FAMILY = Object.freeze({
65
65
  dm: "messaging",
66
66
  mention: "messaging",
67
+ broadcast: "messaging",
67
68
  thread_reply: "messaging",
68
69
  call: "calling",
69
70
  task_assigned: "board",
@@ -99,6 +100,7 @@ export const SURFACE_TOPIC = Object.freeze({
99
100
  export const KIND_SURFACE = Object.freeze({
100
101
  message: "dm",
101
102
  mention: "mention",
103
+ broadcast: "broadcast",
102
104
  thread_reply: "thread_reply",
103
105
  call: "call",
104
106
  voice_note: "dm",
@@ -129,6 +131,7 @@ export const KIND_SURFACE = Object.freeze({
129
131
  export const RECONSTRUCTED_REASON = Object.freeze({
130
132
  dm: "dm",
131
133
  mention: "mention",
134
+ broadcast: "collective",
132
135
  thread_reply: "thread",
133
136
  call: "invited",
134
137
  task_assigned: "assignee",
@@ -424,6 +427,13 @@ export function fromChannelEvent(item, o = {}) {
424
427
  surface = "mention";
425
428
  reason = "mention";
426
429
  why.push(`${service} channel item names me`);
430
+ } else if (kind === "broadcast") {
431
+ // The org projection already proved the four broadcast conditions (human
432
+ // author, my room, not threaded, collective address) before stamping the
433
+ // kind; a channel adapter that stamps it is making the same claim.
434
+ surface = "broadcast";
435
+ reason = "collective";
436
+ why.push(`${service} channel item is a human's roll-call to the whole room`);
427
437
  } else if (kind === "thread_reply" || (item.is_reply === true && s(item.thread_id))) {
428
438
  // A reply in a thread. Whether the agent is IN that thread is a fact only
429
439
  // the adapter has; without it this is a lane-tier claim at best.
@@ -140,6 +140,21 @@ export const ORG_SURFACE_POLICY = Object.freeze({
140
140
  maxChainDepth: 2,
141
141
  ambientDrop: false,
142
142
  }),
143
+ /**
144
+ * A human's roll-call to the whole room. Respondable, now, in public — and
145
+ * the chain depth is ONE: the answer is a single post about myself, and a
146
+ * roll-call must never become a conversation between thirteen agents.
147
+ */
148
+ broadcast: Object.freeze({
149
+ respondable: true,
150
+ replyMethod: "messaging.send",
151
+ latency: "now",
152
+ actionClasses: Object.freeze([]),
153
+ offlineSafe: true,
154
+ selfApprove: true,
155
+ maxChainDepth: 1,
156
+ ambientDrop: true,
157
+ }),
143
158
  /** A reply in a thread I am part of. Same room, same tightness as a mention. */
144
159
  thread_reply: Object.freeze({
145
160
  respondable: true,
@@ -339,14 +339,16 @@ export function parseConsolidationEnvelope(text, validIds) {
339
339
  export async function defaultConsolidateSpawn(prompt, opts = {}) {
340
340
  try {
341
341
  const { spawnSync } = await import("node:child_process");
342
- const { resolveClaudeBin, daemonClaudeArgs, augmentedPath } = await import("../claude-bin.mjs");
343
- const model = opts.model || "sonnet";
344
- const args = ["--print", "--model", model, ...daemonClaudeArgs()];
345
- const res = spawnSync(resolveClaudeBin(), args, {
346
- input: prompt,
342
+ const { buildSpawn } = await import("../runtime/adapter.mjs");
343
+ // argv + env from the runtime adapter (lane "curator"): --print --model <m>
344
+ // <daemon MCP args>, prompt on stdin, PATH augmented.
345
+ const spec = buildSpawn({ lane: "curator", model: opts.model || "sonnet", prompt, mcp: {}, env: process.env });
346
+ if (!spec.ok) return "";
347
+ const res = spawnSync(spec.bin, spec.argv, {
348
+ input: spec.stdin,
347
349
  encoding: "utf8",
348
350
  timeout: opts.timeoutMs || CONSOLIDATE_TIMEOUT_MS,
349
- env: { ...process.env, PATH: augmentedPath() },
351
+ env: spec.env,
350
352
  maxBuffer: 8 * 1024 * 1024,
351
353
  });
352
354
  if (res.status === 0 && res.stdout) return res.stdout;
@@ -28,7 +28,7 @@
28
28
  "use strict";
29
29
 
30
30
  import { spawnSync } from "node:child_process";
31
- import { resolveClaudeBin, daemonClaudeArgs, augmentedPath } from "../claude-bin.mjs";
31
+ import { buildSpawn } from "../runtime/adapter.mjs";
32
32
  import { captureSession, countUserTurns } from "../collective/capture.mjs";
33
33
  import { readRecentCards } from "../collective/cards.mjs";
34
34
  import { jaccard, tokenSet } from "../collective/recall.mjs";
@@ -146,13 +146,15 @@ export function buildReviewPrompt(transcriptText, extras = {}) {
146
146
  /** Default reviewer spawn: one `claude --print --model <sonnet>`. Fail-open → "". */
147
147
  export function defaultReviewSpawn(prompt, opts = {}) {
148
148
  try {
149
- const model = opts.model || "sonnet";
150
- const args = ["--print", "--model", model, ...daemonClaudeArgs()];
151
- const res = spawnSync(resolveClaudeBin(), args, {
152
- input: prompt,
149
+ // argv + env from the runtime adapter (lane "reflect"): --print --model <m>
150
+ // <daemon MCP args>, prompt on stdin, PATH augmented.
151
+ const spec = buildSpawn({ lane: "reflect", model: opts.model || "sonnet", prompt, mcp: {}, env: process.env });
152
+ if (!spec.ok) return "";
153
+ const res = spawnSync(spec.bin, spec.argv, {
154
+ input: spec.stdin,
153
155
  encoding: "utf8",
154
156
  timeout: opts.timeoutMs || REFLECT_TIMEOUT_MS,
155
- env: { ...process.env, PATH: augmentedPath() },
157
+ env: spec.env,
156
158
  maxBuffer: 8 * 1024 * 1024,
157
159
  });
158
160
  if (res.status === 0 && res.stdout) return res.stdout;
@@ -0,0 +1,137 @@
1
+ # lib/model-router/catalog/cohort.yaml
2
+ # Bundled cohort-llm catalog rows (ships with @cohortapp/agent-sdk).
3
+ #
4
+ # cohort-llm is Cohort's OWN model gateway (hq docs/cohort-llm/design.md §4).
5
+ # The rows are Cohort model TIERS, never upstream model ids: the gateway routes
6
+ # each tier to its legs (design §4.7) and failover never changes the tier a seat
7
+ # is billed for (§5.1 TierRate).
8
+ #
9
+ # first_party: true — this provider is Cohort's own infrastructure, so:
10
+ # - tool_reliability A is an explicit first-party declaration (the gateway owns
11
+ # tier→leg selection and the parity eval, design §8.4), not a probe grade;
12
+ # - data_classes allows public/internal/sensitive without a config backends
13
+ # entry (it is not a third-party supplier; the gateway's own data-class
14
+ # supplier gates, design §4.7, sit behind it).
15
+ #
16
+ # auth: seat_token — there is no static env key. The seat exchanges its
17
+ # OrgApiKey for a short-lived cst_… token at POST /cohort/v1/tokens
18
+ # (lib/org/llm-token.mjs). There is deliberately no auth_env key.
19
+ #
20
+ # endpoints are the DEFAULT gateway; the loader rewrites both to
21
+ # org.cohort.llmBaseUrl or COHORT_LLM_BASE_URL when either is set.
22
+ #
23
+ # cost: null on every row. cohort-llm prices usage from its versioned price book
24
+ # and returns the cost (x-cohort-cost-micros / the cohort SSE frame); a local
25
+ # $/MTok here would be the kind of guess design C7 removes. Budget-guard reads
26
+ # /cohort/v1/quota for cohort-metered seats instead of pricing tokens.
27
+ #
28
+ # context_window follows the tier's smallest leg in the design §4.7 starting slot
29
+ # map (R3 research, fetched 2026-09-14):
30
+ # cohort-agentic GLM-5.3 (1M) → DeepSeek-V4-Pro-0813 (1M) → 1M
31
+ # cohort-reason Kimi-K3 (1M) → GLM-5.3 (1M) → 1M
32
+ # cohort-fast gpt-oss-120b (131K) → GLM-5.3-Flash (1M) → 131K
33
+ # cohort-extract DeepSeek-V4-Flash-0731 (1M) → GLM-5.3-Flash (1M) → 1M
34
+ # max_tokens is the gateway's default per-request ceiling (32K, design §4.1).
35
+ # The slot map is PROVISIONAL until the parity eval (design §8.4, W4-C).
36
+ #
37
+ # tier_map: the Anthropic-slot aliases a claude-shaped caller passes
38
+ # (`--model opus`, ANTHROPIC_DEFAULT_*_MODEL) → Cohort tiers, used when a seat's
39
+ # routing selects this provider. fable is the premium slot (Kimi-K3 class, R3).
40
+
41
+ provider: cohort
42
+ first_party: true
43
+ auth: seat_token
44
+ endpoints:
45
+ anthropic: https://llm.cohortapp.com
46
+ openai: https://llm.cohortapp.com/v1
47
+ data_residency: us
48
+ data_classes: [public, internal, sensitive]
49
+ tier_map:
50
+ fable: cohort-reason
51
+ opus: cohort-agentic
52
+ sonnet: cohort-agentic
53
+ haiku: cohort-fast
54
+ models:
55
+ - id: cohort-agentic
56
+ status: available
57
+ replaced_by: null
58
+ context_window: 1000000
59
+ context_tokens: 950000
60
+ max_tokens: 32000
61
+ cost: { input: null, output: null, cache_read: null, cache_write: null, tiered: [] }
62
+ cost_provenance: { source: gateway, fetched: "2026-09-14", volatile: true }
63
+ compat:
64
+ cache_control: anthropic
65
+ max_tokens_field: max_tokens
66
+ thinking_format: anthropic
67
+ requires_reasoning_echo: false
68
+ rejects_duplicate_tool_names: false
69
+ omit_temperature: false
70
+ supports_prompt_cache_key: true
71
+ tool_reliability: A
72
+ harness: { session: true, direct: true, batch: false }
73
+ quality: {}
74
+ notes: "2026-09-14: first-party tier; main agent loop. Legs GLM-5.3 → DeepSeek-V4-Pro-0813 (design §4.7, provisional)."
75
+
76
+ - id: cohort-reason
77
+ status: available
78
+ replaced_by: null
79
+ context_window: 1000000
80
+ context_tokens: 950000
81
+ max_tokens: 32000
82
+ cost: { input: null, output: null, cache_read: null, cache_write: null, tiered: [] }
83
+ cost_provenance: { source: gateway, fetched: "2026-09-14", volatile: true }
84
+ compat:
85
+ cache_control: anthropic
86
+ max_tokens_field: max_tokens
87
+ thinking_format: anthropic
88
+ requires_reasoning_echo: false
89
+ rejects_duplicate_tool_names: false
90
+ omit_temperature: false
91
+ supports_prompt_cache_key: true
92
+ tool_reliability: A
93
+ harness: { session: true, direct: true, batch: false }
94
+ quality: {}
95
+ notes: "2026-09-14: first-party tier; hardest background work (TTFT). Legs Kimi-K3 → GLM-5.3 (design §4.7, provisional)."
96
+
97
+ - id: cohort-fast
98
+ status: available
99
+ replaced_by: null
100
+ context_window: 131072
101
+ context_tokens: 124000
102
+ max_tokens: 32000
103
+ cost: { input: null, output: null, cache_read: null, cache_write: null, tiered: [] }
104
+ cost_provenance: { source: gateway, fetched: "2026-09-14", volatile: true }
105
+ compat:
106
+ cache_control: anthropic
107
+ max_tokens_field: max_tokens
108
+ thinking_format: anthropic
109
+ requires_reasoning_echo: false
110
+ rejects_duplicate_tool_names: false
111
+ omit_temperature: false
112
+ supports_prompt_cache_key: true
113
+ tool_reliability: A
114
+ harness: { session: true, direct: true, batch: false }
115
+ quality: {}
116
+ notes: "2026-09-14: first-party tier; classifier/haiku lanes. Legs gpt-oss-120b (131K) → GLM-5.3-Flash (design §4.7, provisional)."
117
+
118
+ - id: cohort-extract
119
+ status: available
120
+ replaced_by: null
121
+ context_window: 1000000
122
+ context_tokens: 950000
123
+ max_tokens: 32000
124
+ cost: { input: null, output: null, cache_read: null, cache_write: null, tiered: [] }
125
+ cost_provenance: { source: gateway, fetched: "2026-09-14", volatile: true }
126
+ compat:
127
+ cache_control: anthropic
128
+ max_tokens_field: max_tokens
129
+ thinking_format: anthropic
130
+ requires_reasoning_echo: false
131
+ rejects_duplicate_tool_names: false
132
+ omit_temperature: false
133
+ supports_prompt_cache_key: true
134
+ tool_reliability: A
135
+ harness: { session: true, direct: true, batch: false }
136
+ quality: {}
137
+ notes: "2026-09-14: first-party tier; structured extraction. Legs DeepSeek-V4-Flash-0731 → GLM-5.3-Flash (design §4.7, provisional)."
@@ -43,6 +43,9 @@ import {
43
43
  import { join, resolve, dirname, basename } from "node:path";
44
44
  import { fileURLToPath } from "node:url";
45
45
 
46
+ import { resolveLlmBaseUrl, cohortEndpoints } from "../org/llm-token.mjs";
47
+ import { loadOrgConfig } from "../org/client.mjs";
48
+
46
49
  // js-yaml is a hard dependency of @cohortapp/agent-sdk (package.json), but we still
47
50
  // import it defensively so the read path can degrade rather than crash if the
48
51
  // dep tree is ever broken on a machine.
@@ -87,12 +90,17 @@ const VALID_COST_KEYS = new Set([
87
90
 
88
91
  const COST_FIELDS = ["input", "output", "cache_read", "cache_write"];
89
92
 
93
+ /** How a provider authenticates: a static env key, or a Cohort seat token. */
94
+ const VALID_AUTH = new Set(["env", "seat_token"]);
95
+ const DATA_CLASS_NAMES = new Set(["public", "internal", "sensitive"]);
96
+
90
97
  // Bundled providers we recognise. The authority-merge rule "never add providers"
91
98
  // is enforced for the overlay (tighten-only); agent config MAY introduce a new
92
99
  // provider via catalog_overrides (it is the highest authority and the agent owns
93
100
  // its own machine), but we surface a warning so a typo'd provider name is loud.
94
101
  const BUNDLED_PROVIDERS = new Set([
95
102
  "anthropic",
103
+ "cohort",
96
104
  "deepseek",
97
105
  "moonshot",
98
106
  "qwen",
@@ -294,6 +302,7 @@ function normaliseRow(provider, rawRow, errors) {
294
302
  tool_reliability: VALID_GRADES.has(tool_reliability) ? tool_reliability : null,
295
303
  harness: normaliseHarness(rawRow.harness, errors, label),
296
304
  quality: rawRow.quality && typeof rawRow.quality === "object" ? { ...rawRow.quality } : {},
305
+ notes: typeof rawRow.notes === "string" ? rawRow.notes : null,
297
306
  };
298
307
  return { ok: true, row };
299
308
  }
@@ -323,6 +332,7 @@ function parseProviderDoc(doc, label, errors) {
323
332
  errors.push({ source: label, error: "catalog document missing string `provider`" });
324
333
  return null;
325
334
  }
335
+ const meta = providerMeta(doc, label, errors);
326
336
  const rows = new Map();
327
337
  const models = Array.isArray(doc.models) ? doc.models : [];
328
338
  if (!Array.isArray(doc.models)) {
@@ -337,6 +347,7 @@ function parseProviderDoc(doc, label, errors) {
337
347
  row.endpoints = doc.endpoints && typeof doc.endpoints === "object" ? { ...doc.endpoints } : {};
338
348
  row.data_residency =
339
349
  typeof doc.data_residency === "string" ? doc.data_residency : null;
350
+ Object.assign(row, cloneMeta(meta));
340
351
  rows.set(row.id, row);
341
352
  }
342
353
  return {
@@ -344,10 +355,59 @@ function parseProviderDoc(doc, label, errors) {
344
355
  auth_env: typeof doc.auth_env === "string" ? doc.auth_env : null,
345
356
  endpoints: doc.endpoints && typeof doc.endpoints === "object" ? { ...doc.endpoints } : {},
346
357
  data_residency: typeof doc.data_residency === "string" ? doc.data_residency : null,
358
+ ...cloneMeta(meta),
347
359
  rows,
348
360
  };
349
361
  }
350
362
 
363
+ /**
364
+ * Provider-level identity the router gates on (hoisted onto every row):
365
+ * first_party Cohort's own infrastructure (the cohort-llm gateway). A
366
+ * first-party provider declares its own grade and data-class
367
+ * allowance instead of earning them from a probe/config entry.
368
+ * auth "env" (auth_env names a static key, the default) or
369
+ * "seat_token" (a short-lived Cohort seat token, lib/org/llm-token.mjs).
370
+ * data_classes classes a FIRST-PARTY provider allows without a config entry.
371
+ * tier_map Anthropic-slot alias (fable/opus/sonnet/haiku) → this provider's row id.
372
+ */
373
+ function providerMeta(doc, label, errors) {
374
+ const auth = doc.auth == null ? "env" : doc.auth;
375
+ if (!VALID_AUTH.has(auth)) errors.push({ source: label, error: `auth "${auth}" not in {env,seat_token}` });
376
+ const firstParty = doc.first_party === true;
377
+ let dataClasses = null;
378
+ if (doc.data_classes != null) {
379
+ if (!Array.isArray(doc.data_classes)) {
380
+ errors.push({ source: label, error: "data_classes must be an array" });
381
+ } else {
382
+ const bad = doc.data_classes.filter((c) => !DATA_CLASS_NAMES.has(c));
383
+ if (bad.length) errors.push({ source: label, error: `unknown data_classes ${JSON.stringify(bad)}` });
384
+ dataClasses = doc.data_classes.filter((c) => DATA_CLASS_NAMES.has(c));
385
+ if (!firstParty) errors.push({ source: label, error: "data_classes is only honoured on a first_party provider (third parties are allowed per config backends)" });
386
+ }
387
+ }
388
+ const tierMap = {};
389
+ if (doc.tier_map != null) {
390
+ if (typeof doc.tier_map !== "object" || Array.isArray(doc.tier_map)) {
391
+ errors.push({ source: label, error: "tier_map must be an object" });
392
+ } else {
393
+ for (const [k, v] of Object.entries(doc.tier_map)) {
394
+ if (typeof v === "string" && v) tierMap[String(k).toLowerCase()] = v;
395
+ else errors.push({ source: label, error: `tier_map.${k} must be a row id string` });
396
+ }
397
+ }
398
+ }
399
+ return { first_party: firstParty, auth: VALID_AUTH.has(auth) ? auth : "env", data_classes: dataClasses, tier_map: tierMap };
400
+ }
401
+
402
+ function cloneMeta(meta) {
403
+ return {
404
+ first_party: meta.first_party,
405
+ auth: meta.auth,
406
+ data_classes: meta.data_classes ? [...meta.data_classes] : null,
407
+ tier_map: { ...meta.tier_map },
408
+ };
409
+ }
410
+
351
411
  // ---------------------------------------------------------------------------
352
412
  // Source gathering (each returns provider docs + records its file mtime)
353
413
  // ---------------------------------------------------------------------------
@@ -596,6 +656,8 @@ function mergePartialRow(byRef, ref, entry, layer, errors, warnings) {
596
656
  row.auth_env = entry.auth_env ?? null;
597
657
  row.endpoints = entry.endpoints ?? {};
598
658
  row.data_residency = entry.data_residency ?? null;
659
+ // A config-created row is never first-party: that is a bundled declaration.
660
+ Object.assign(row, { first_party: false, auth: "env", data_classes: null, tier_map: {} });
599
661
  byRef.set(ref, row);
600
662
  }
601
663
  return;
@@ -689,6 +751,11 @@ export function loadCatalog(agentRoot, opts = {}) {
689
751
  for (const row of parsed.rows.values()) byRef.set(row.ref, row);
690
752
  }
691
753
 
754
+ // The cohort gateway's base URL is seat configuration, not catalog data:
755
+ // org.cohort.llmBaseUrl, then COHORT_LLM_BASE_URL, then the default. Applied
756
+ // on the bundled floor so an explicit agent catalog_override still wins.
757
+ applyCohortBaseUrl(byRef, providersByName, cohortBaseUrlFor(root, opts));
758
+
692
759
  // Layer 3: pricing cache (COST ONLY).
693
760
  const pricing = gatherPricingCache(root, opts, errors, mtimes);
694
761
  if (pricing) {
@@ -745,6 +812,10 @@ export function loadCatalog(agentRoot, opts = {}) {
745
812
  auth_env: doc.auth_env,
746
813
  endpoints: doc.endpoints,
747
814
  data_residency: doc.data_residency,
815
+ first_party: doc.first_party === true,
816
+ auth: doc.auth || "env",
817
+ data_classes: doc.data_classes || null,
818
+ tier_map: doc.tier_map || {},
748
819
  });
749
820
  }
750
821
 
@@ -761,6 +832,49 @@ export function loadCatalog(agentRoot, opts = {}) {
761
832
  };
762
833
  }
763
834
 
835
+ /** The cohort gateway base URL for this load (injectable, else config/env). */
836
+ function cohortBaseUrlFor(root, opts) {
837
+ if (opts && typeof opts.cohortLlmBaseUrl === "string" && opts.cohortLlmBaseUrl) {
838
+ return opts.cohortLlmBaseUrl.replace(/\/+$/, "");
839
+ }
840
+ let cfg = opts && opts.orgConfig !== undefined ? opts.orgConfig : null;
841
+ if (cfg === null) {
842
+ try { cfg = existsSync(join(root, "config", "org.yaml")) ? loadOrgConfig(root) : {}; } catch { cfg = {}; }
843
+ }
844
+ return resolveLlmBaseUrl({ cfg, env: (opts && opts.env) || process.env });
845
+ }
846
+
847
+ /** Point the cohort provider (and its rows) at a gateway base URL. */
848
+ function applyCohortBaseUrl(byRef, providersByName, baseUrl) {
849
+ const doc = providersByName.get("cohort");
850
+ if (!doc) return;
851
+ const endpoints = cohortEndpoints(baseUrl);
852
+ doc.endpoints = { ...doc.endpoints, ...endpoints };
853
+ for (const row of byRef.values()) {
854
+ if (row.provider === "cohort") row.endpoints = { ...row.endpoints, ...endpoints };
855
+ }
856
+ }
857
+
858
+ /**
859
+ * The Cohort tier for a claude-shaped model flag. A `cohort-*` id passes
860
+ * through; an Anthropic-slot alias or id (fable/opus/sonnet/haiku, e.g.
861
+ * "claude-sonnet-4-6") maps through the provider's tier_map; anything else is
862
+ * null (the caller decides — never a silent guess).
863
+ * @param {string} modelFlag
864
+ * @param {Record<string,string>} tierMap
865
+ * @returns {string|null}
866
+ */
867
+ export function cohortTierFor(modelFlag, tierMap) {
868
+ const m = typeof modelFlag === "string" ? modelFlag.trim().toLowerCase() : "";
869
+ if (!m) return null;
870
+ if (m.startsWith("cohort-")) return m;
871
+ const map = tierMap && typeof tierMap === "object" ? tierMap : {};
872
+ for (const slot of ["fable", "opus", "sonnet", "haiku"]) {
873
+ if ((m === slot || m.includes(slot)) && map[slot]) return map[slot];
874
+ }
875
+ return null;
876
+ }
877
+
764
878
  function maxMtime(mtimes) {
765
879
  let m = 0;
766
880
  for (const t of mtimes) if (t > m) m = t;
@@ -863,6 +977,7 @@ function mtimeSignature(root, opts) {
863
977
  }
864
978
  }
865
979
  for (const [tag, fn, injected] of [
980
+ ["org", (r) => join(r, "config", "org.yaml"), opts.orgConfig !== undefined || typeof opts.cohortLlmBaseUrl === "string"],
866
981
  ["price", pricingCachePath, opts.pricingCache !== undefined],
867
982
  ["local", localConfigPath, opts.localConfig !== undefined],
868
983
  ["agent", agentConfigPath, opts.agentConfig !== undefined],
@@ -870,6 +985,8 @@ function mtimeSignature(root, opts) {
870
985
  if (injected) parts.push(`${tag}:injected`);
871
986
  else parts.push(`${tag}:${mtimeSafe(fn(root))}`);
872
987
  }
988
+ // The gateway URL may come from the environment.
989
+ parts.push(`llm:${typeof opts.cohortLlmBaseUrl === "string" ? opts.cohortLlmBaseUrl : ((opts.env || process.env).COHORT_LLM_BASE_URL || "")}`);
873
990
  // Overlay is passed by value (already verified); fold its version in.
874
991
  if (opts.overlay) parts.push(`ovl:${opts.overlay.version || "?"}`);
875
992
  return parts.join("|");
@@ -922,4 +1039,4 @@ export const _internals = {
922
1039
  mtimeSignature,
923
1040
  };
924
1041
 
925
- export default { loadCatalog, loadCatalogCached, invalidateCatalogCache, lookupModel, listModels };
1042
+ export default { loadCatalog, loadCatalogCached, invalidateCatalogCache, lookupModel, listModels, cohortTierFor };
@@ -310,6 +310,8 @@ const DEFERRABLE_PREFIXES = Object.freeze([
310
310
  // the live conversational / inbox path.
311
311
  const REALTIME_TASK_CLASSES = Object.freeze(new Set([
312
312
  "session.responder",
313
+ "session.answer",
314
+ "session.plan",
313
315
  "classify.inbox",
314
316
  "huddle",
315
317
  "voice.brief",
@@ -556,6 +558,13 @@ const HAIKU_EXPLORE = Object.freeze({
556
558
  // cheap classes where a subagent would only add overhead.
557
559
  const SPAWN_KNOBS = Object.freeze({
558
560
  "session.responder": { maxTurns: 40, effort: null, agentsJson: HAIKU_EXPLORE },
561
+ // The reply tiers (design §5.6 / §5.1). Until now `dispatcher.mjs` hardcoded
562
+ // `session.responder` for every spawn, so `effort` was ALWAYS null and
563
+ // `maxTurns` always 40 — complexity moved the model and the timeout and
564
+ // nothing else. An answer gets low effort and a short leash; a plan gets high
565
+ // effort, a longer one, and the cheap-subagent map it will actually use.
566
+ "session.answer": { maxTurns: 6, effort: "low", agentsJson: null },
567
+ "session.plan": { maxTurns: 60, effort: "high", agentsJson: HAIKU_EXPLORE },
559
568
  "classify.inbox": { maxTurns: 1, effort: null, agentsJson: null },
560
569
  lookup: { maxTurns: 2, effort: null, agentsJson: null },
561
570
  enrich: { maxTurns: 3, effort: null, agentsJson: null },