@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
@@ -122,6 +122,15 @@
122
122
  "command": "./scripts/hooks/block-mcp-cohort-send.sh"
123
123
  }
124
124
  ]
125
+ },
126
+ {
127
+ "matcher": "Write|Edit",
128
+ "hooks": [
129
+ {
130
+ "type": "command",
131
+ "command": "node ./scripts/hooks/pre-write-yaml-validate.mjs"
132
+ }
133
+ ]
125
134
  }
126
135
  ],
127
136
  "PostToolUse": [
@@ -133,6 +142,15 @@
133
142
  "command": "./scripts/hooks/post-action-log.sh"
134
143
  }
135
144
  ]
145
+ },
146
+ {
147
+ "matcher": "Bash|Write|Edit",
148
+ "hooks": [
149
+ {
150
+ "type": "command",
151
+ "command": "./scripts/hooks/validate-state-yaml.sh"
152
+ }
153
+ ]
136
154
  }
137
155
  ],
138
156
  "Stop": [
package/.env.example CHANGED
@@ -63,7 +63,7 @@ COHORT_AGENT_EMAIL=
63
63
  # is in effect and what `claude auth status` reports (presence of a credential,
64
64
  # not its validity — a bad token surfaces on the first real spawn).
65
65
  #
66
- # Option A — subscription OAuth token ← THE FLEET DEFAULT (seat machines)
66
+ # Option A — subscription OAuth token (NOT the fleet posture — see Option C)
67
67
  # On ANY machine where you are logged in to Claude Code, run
68
68
  # claude setup-token
69
69
  # and paste the long-lived token below, together with
@@ -72,25 +72,38 @@ COHORT_AGENT_EMAIL=
72
72
  # keychain login is NOT relied on because it expires headlessly. The token is
73
73
  # per seat; mint a fresh one with the same command when it is rejected.
74
74
  # Headless setup reads it from the environment: CLAUDE_CODE_OAUTH_TOKEN=… maestro setup --headless
75
+ # It still RUNS, but it has no per-agent ceiling and no central spend
76
+ # visibility: do NOT provision a new agent seat on it (gate G4).
75
77
  CLAUDE_CODE_OAUTH_TOKEN=
76
78
 
77
79
  # Option B — keychain login on this machine (interactive / dev boxes only)
78
80
  # `claude login` here, leave CLAUDE_CODE_OAUTH_TOKEN and ANTHROPIC_API_KEY
79
81
  # empty, set MAESTRO_PREFER_SUBSCRIPTION_AUTH=1. Doctor warns: the login
80
- # expires headlessly and a seat machine should hold the token instead.
82
+ # expires headlessly and an agent seat belongs on Option C.
81
83
  #
82
84
  # Set to 1 for Option A and Option B: every claude spawn strips
83
85
  # ANTHROPIC_API_KEY from its env so claude rides the subscription (token or
84
86
  # keychain) — routine cadence ticks then cost zero API credits.
85
87
  MAESTRO_PREFER_SUBSCRIPTION_AUTH=
86
88
 
87
- # Option C — API key (pay-per-token)
88
- # Set ANTHROPIC_API_KEY to a valid sk-ant-api03-... key and leave the two
89
- # above empty. Get one: https://console.anthropic.com/settings/keys
89
+ # Option C — API key (pay-per-token) ← THE FLEET POSTURE (agent seats)
90
+ # Set ANTHROPIC_API_KEY to a valid sk-ant-api03-... key created INSIDE a
91
+ # Console workspace with a monthly spend cap, one workspace per agent, and
92
+ # leave the two above empty. Get one:
93
+ # https://console.anthropic.com/settings/keys
90
94
  # Doctor validates it against api.anthropic.com on every run; an invalid
91
95
  # key cascades 401s through every sub-session spawn.
96
+ # Runbook: docs/guides/billing-console-keys.md
92
97
  ANTHROPIC_API_KEY=
93
98
 
99
+ # OPTIONAL — Arm the G4 guard. `maestro doctor` and `maestro seat-auth` WARN on
100
+ # a seat still using subscription OAuth (and on a seat carrying both rails,
101
+ # which is ambiguous about where its spend lands). Set this to 1 and those
102
+ # warnings become failures — do that once the fleet has migrated, so a seat that
103
+ # regresses to a subscription token announces itself. Never fails an
104
+ # engine=cohort seat that holds no Anthropic credential: that is its posture.
105
+ MAESTRO_REQUIRE_CONSOLE_KEY=
106
+
94
107
  # OPTIONAL — Supplemental model access (GPT-4, embeddings)
95
108
  # Get your key: https://platform.openai.com/api-keys
96
109
  # Subscription: OpenAI API plan (pay-per-token)
@@ -226,6 +239,9 @@ GREPTILE_API_KEY=
226
239
  # Flags that control system behaviour. These are not secrets.
227
240
  #
228
241
 
229
- # Enable session context compiler for optimised daemon prompts
230
- # Set to 1 to pre-compile context before each Claude Code session (recommended)
242
+ # The session context compiler: pre-compile context before each Claude Code
243
+ # session. ON BY DEFAULT in code as well as here — the two used to disagree
244
+ # (code read `=== "1"`, this file shipped `=1`), so which of two materially
245
+ # different context paths ran depended on whether the operator had copied this
246
+ # file. Set to 0 only to fall back to the legacy path in a hurry.
231
247
  DAEMON_CONTEXT_COMPILER=1
package/README.md CHANGED
@@ -161,6 +161,7 @@ Verifies the agent installation end-to-end. Checks include:
161
161
  - **Config:** `config/environment.yaml`, `config/contacts.yaml`, `config/priorities.yaml`, `config/sla-defaults.yaml`.
162
162
  - **State:** `state/dashboards/executive-summary.yaml`, `state/queues/action-stack.yaml`, `knowledge/decisions/decision-schema.yaml`.
163
163
  - **Environment:** `.env` file with `ANTHROPIC_API_KEY` (required), `SLACK_USER_TOKEN`, `GMAIL_APP_PASSWORD` (optional).
164
+ - **Billing rail (G4):** which Claude rail this seat is on — `api-key` (the fleet posture: a per-agent Console key in a capped workspace), `subscription`, `both` (ambiguous, flagged loudly) or `neither`. Variable **names** only; no credential value is ever printed. A warning today; `MAESTRO_REQUIRE_CONSOLE_KEY=1` turns it into a failure once the fleet has migrated. `maestro seat-auth --row` prints the paste-able inventory row and `maestro seat-auth --fleet` the template it pastes into — see [billing: Console API keys](docs/guides/billing-console-keys.md).
164
165
  - **Dependencies:** `node_modules` installed, Claude CLI available, jq available, emergency-stop script present.
165
166
 
166
167
  Doctor exits non-zero when issues are found and prints actionable remediation (most commonly: `npx @cohortapp/agent-sdk upgrade`). Doctor also verifies the collective-memory wiring (see below).
package/bin/maestro.mjs CHANGED
@@ -37,6 +37,7 @@ import { runAudit, applyFixes, buildAttestation } from "../lib/security/audit-en
37
37
  import { selectProvider } from "../lib/secrets/providers.mjs";
38
38
  import { syncSecrets, rotateSecret, makeBroker, auditLogPath } from "../lib/secrets/broker.mjs";
39
39
  import { applyBrandEnvCompat } from "../lib/env-compat.mjs";
40
+ import { buildIgnoredDriftReport, formatIgnoredLine, IGNORED_DRIFT_REL } from "../lib/upgrade/ignored-drift.mjs";
40
41
 
41
42
  // Fleet back-compat FIRST: bridge NEOLITH_* ⇄ COHORT_* env names before any
42
43
  // env-first resolution below — installed hosts still export the legacy names.
@@ -1249,6 +1250,8 @@ Per-file behaviour:
1249
1250
  const counts = { added: 0, updated: 0, same: 0, ignored: 0, preserved: 0, mergeKept: 0, forced: 0, pruned: 0, pruneKept: 0 };
1250
1251
  const preservedFiles = [];
1251
1252
  const ignoredFiles = [];
1253
+ // repoRel → the upstream file the protection kept out (null when upstream ships nothing there): the drift report's input.
1254
+ const ignoredSources = new Map();
1252
1255
  const prunedFiles = [];
1253
1256
  const pruneKeptFiles = [];
1254
1257
  // What upstream ships right now — becomes this machine's provenance record.
@@ -1276,6 +1279,7 @@ Per-file behaviour:
1276
1279
  if (isIgnored) {
1277
1280
  counts.ignored++;
1278
1281
  ignoredFiles.push(repoRel);
1282
+ ignoredSources.set(repoRel, srcFile);
1279
1283
  if (flags.verbose) console.log(` · ${repoRel} (ignored via .maestroignore)`);
1280
1284
  continue;
1281
1285
  }
@@ -1414,6 +1418,7 @@ Per-file behaviour:
1414
1418
  if (matchesIgnore(repoRel, ignorePatterns)) {
1415
1419
  counts.ignored++;
1416
1420
  ignoredFiles.push(repoRel);
1421
+ ignoredSources.set(repoRel, null);
1417
1422
  if (flags.verbose) console.log(` · ${repoRel} (orphan, ignored via .maestroignore)`);
1418
1423
  continue;
1419
1424
  }
@@ -1504,6 +1509,7 @@ Per-file behaviour:
1504
1509
  if (matchesIgnore(repoRel, ignorePatterns)) {
1505
1510
  counts.ignored++;
1506
1511
  ignoredFiles.push(repoRel);
1512
+ ignoredSources.set(repoRel, src);
1507
1513
  if (flags.verbose) console.log(` · ${repoRel} (ignored via .maestroignore)`);
1508
1514
  continue;
1509
1515
  }
@@ -1596,6 +1602,26 @@ Per-file behaviour:
1596
1602
  if (counts.updated) ok(`${counts.updated} updated (vendored, no local edits)`);
1597
1603
  if (counts.same) console.log(` = ${counts.same} already up-to-date`);
1598
1604
  if (counts.ignored) console.log(` · ${counts.ignored} ignored (.maestroignore protected)`);
1605
+ // A protected file is a fork the operator owns; "N ignored" hid how far
1606
+ // upstream had moved under each one. Say it per file, and keep the answer
1607
+ // in .maestro/ignored-drift.json for doctor and the next reader.
1608
+ let ignoredDrift = null;
1609
+ if (ignoredFiles.length) {
1610
+ const readOrNull = (p) => { try { return p && existsSync(p) ? readFileSync(p, "utf8") : null; } catch { return null; } };
1611
+ ignoredDrift = buildIgnoredDriftReport(
1612
+ [...new Set(ignoredFiles)].sort().map((repoRel) => ({ path: repoRel, local: readOrNull(join(cwd, repoRel)), upstream: readOrNull(ignoredSources.get(repoRel)) })),
1613
+ { sdkVersion: readFrameworkVersion(), at: new Date().toISOString() },
1614
+ );
1615
+ for (const f of ignoredDrift.files) console.log(formatIgnoredLine(f));
1616
+ if (ignoredDrift.counts.drifts) warn(`${ignoredDrift.counts.drifts} protected file(s) drift from upstream — every upstream fix to those paths stops here until you port it (diff each against node_modules/@cohortapp/agent-sdk/<path>)`);
1617
+ if (!flags.dryRun) {
1618
+ try {
1619
+ const out = join(cwd, IGNORED_DRIFT_REL);
1620
+ mkdirSync(dirname(out), { recursive: true });
1621
+ writeFileSync(out, JSON.stringify(ignoredDrift, null, 2) + "\n");
1622
+ } catch (e) { warn(`could not write ${IGNORED_DRIFT_REL}: ${e && e.message ? e.message : e}`); }
1623
+ }
1624
+ }
1599
1625
  if (counts.mergeKept) console.log(` ~ ${counts.mergeKept} merge-mode kept (agents/ custom files preserved)`);
1600
1626
  if (counts.preserved) warn(`${counts.preserved} preserved (local edits — kept your version)`);
1601
1627
  if (counts.forced) warn(`${counts.forced} force-overwritten (backups in .maestro/backup/)`);
@@ -3341,6 +3367,38 @@ async function globalSetup(args = []) {
3341
3367
  ok("global hooks already present (no change)");
3342
3368
  }
3343
3369
 
3370
+ // 1b) Per-seat .claude/settings.json: the state-YAML gate hooks (PreToolUse on
3371
+ // Write|Edit, PostToolUse on Bash|Write|Edit). These belong in the SEAT file,
3372
+ // not ~/.claude — their commands are seat-relative and only mean anything
3373
+ // inside an agent repo. A hand edit there does not survive a fresh checkout
3374
+ // or an upgrade, which is why the scaffold copy carries them for new seats
3375
+ // and this merge carries them onto existing ones (upgrade runs global-setup
3376
+ // as a post-step). Deep-merged, idempotent, backed up before write.
3377
+ {
3378
+ const seatSettingsPath = join(cwd, ".claude", "settings.json");
3379
+ let seat = {};
3380
+ if (existsSync(seatSettingsPath)) {
3381
+ try { seat = JSON.parse(readFileSync(seatSettingsPath, "utf-8")); } catch { seat = null; }
3382
+ }
3383
+ if (seat === null) {
3384
+ warn(`${seatSettingsPath} is not valid JSON — state-YAML gate hooks not merged (repair it, then re-run global-setup)`);
3385
+ } else {
3386
+ const merged = gc.mergeStateYamlGateHooks(seat);
3387
+ if (merged.added.length > 0) {
3388
+ if (!dryRun) {
3389
+ mkdirSync(dirname(seatSettingsPath), { recursive: true });
3390
+ if (existsSync(seatSettingsPath)) {
3391
+ try { copyFileSync(seatSettingsPath, `${seatSettingsPath}.backup.${tsStamp()}`); } catch { /* */ }
3392
+ }
3393
+ writeFileSync(seatSettingsPath, JSON.stringify(merged.settings, null, 2) + "\n");
3394
+ }
3395
+ ok(`${dryRun ? "[dry-run] " : ""}seat hooks added to .claude/settings.json: ${merged.added.join(", ")}`);
3396
+ } else {
3397
+ ok("seat state-YAML gate hooks already present (no change)");
3398
+ }
3399
+ }
3400
+ }
3401
+
3344
3402
  // 2) global CLAUDE.md directive (only our delimited block is touched).
3345
3403
  let mdContent = "";
3346
3404
  if (existsSync(claudeMdPath)) { try { mdContent = readFileSync(claudeMdPath, "utf-8"); } catch { /* */ } }
@@ -3806,9 +3864,11 @@ switch (command) {
3806
3864
  case "who-owns": case "who": await whoOwnsCmd(args); break;
3807
3865
  case "inbox": process.exitCode = await (await import("../lib/cli/inbox.mjs")).runInbox(args); break;
3808
3866
  case "session-ack": process.exitCode = await (await import("../lib/cli/session-ack.mjs")).runSessionAck(args); break;
3867
+ case "seat-auth": process.exitCode = await (await import("../lib/cli/seat-auth.mjs")).runSeatAuth(args); break;
3809
3868
  case "session": { const r = await (await import("../lib/cli/session.mjs")).run(args); process.exitCode = r.code; break; }
3810
3869
  case "board": await (await import("../lib/cli/board.mjs")).boardCmd(args); break;
3811
3870
  case "design": await (await import("../lib/cli/design.mjs")).designCmd(args); break;
3871
+ case "run": process.exitCode = await (await import("../lib/engine/cli.mjs")).runFromProcess(args); break;
3812
3872
  case "init":
3813
3873
  case "update-init":
3814
3874
  case "init-update":
@@ -3836,9 +3896,11 @@ Usage:
3836
3896
  npx @cohortapp/agent-sdk who-owns <scope> Who owns a scope / escalate-to / reports (org context, zero-LLM)
3837
3897
  npx @cohortapp/agent-sdk inbox list|show|claim|reply|done|defer The main session's inbox (JSON; shares the daemon's markers)
3838
3898
  npx @cohortapp/agent-sdk session-ack <tickId> Ack a cadence tick handed to the main session
3899
+ npx @cohortapp/agent-sdk seat-auth [--row|--fleet] Which Claude billing rail this seat is on (G4) — variable NAMES only, never a value
3839
3900
  npx @cohortapp/agent-sdk session <cmd> Front-door session: status|attach|start|stop|restart|spawn|peers|handoffs|ack
3840
3901
  npx @cohortapp/agent-sdk board mine|track|claim|complete Your work across every board (maestro board --help)
3841
3902
  npx @cohortapp/agent-sdk design sync [--out <dir>] Pull the brand foundation → DESIGN.md + PRODUCT.md
3903
+ npx @cohortapp/agent-sdk run -p "<prompt>" [flags] Cohort Engine, headless (cohort run --help)
3842
3904
 
3843
3905
  Upgrade flags:
3844
3906
  --dry-run, -n Preview changes without writing
@@ -65,6 +65,7 @@ make per-agent spend attribution and revocation possible).
65
65
 
66
66
  ```sh
67
67
  maestro doctor # validates ANTHROPIC_API_KEY against api.anthropic.com
68
+ maestro seat-auth # which rail this seat is on, by variable NAME (see below)
68
69
  ```
69
70
 
70
71
  After the cost-telemetry work (roadmap item 0.3) lands, `maestro doctor` also
@@ -72,6 +73,65 @@ turns RED when sessions have run but recorded spend is $0, and a nightly digest
72
73
  reconciles the local ledger against the Admin Cost API. Until then, confirm spend
73
74
  is accruing in the Console workspace view for a canary agent.
74
75
 
76
+ ## The tooling: `maestro seat-auth` (G4)
77
+
78
+ A seat can state, about itself, which rail it is on — and the answer is a
79
+ **verdict over variable names**, never a value. Nothing here prints, logs or
80
+ stores a credential, not even truncated.
81
+
82
+ | Verdict | Meaning | Doctor level |
83
+ | -------------- | ---------------------------------------------------------------------- | -------------------------------- |
84
+ | `api-key` | `ANTHROPIC_API_KEY` only — the fleet posture | ok |
85
+ | `subscription` | `MAESTRO_PREFER_SUBSCRIPTION_AUTH` and/or `CLAUDE_CODE_OAUTH_TOKEN` | warn (fail when armed, below) |
86
+ | `both` | a Console key **and** a subscription credential on the same seat | warn (fail when armed) — loud |
87
+ | `neither` | no Claude credential at all | fail — except on an engine-cohort seat, where it is expected |
88
+
89
+ **`both` is its own verdict and is worth flagging loudly.** It is not "half
90
+ migrated": it is ambiguous. The runtime adapter blanks `ANTHROPIC_API_KEY` on a
91
+ seat that `subscriptionAuth()` calls true (`lib/runtime/adapter.mjs`), so the
92
+ subscription rail wins the lanes that go through the adapter while a lane that
93
+ passes the environment straight through may use the key. Spend then lands in
94
+ two places and neither is authoritative. Migrate, do not stack.
95
+
96
+ ```sh
97
+ maestro seat-auth # the verdict, the names present, the remediation
98
+ maestro seat-auth --json # the same, machine-readable
99
+ maestro seat-auth --row # ONE markdown row to paste into the fleet inventory
100
+ maestro seat-auth --fleet # the inventory template, one row per org member
101
+ ```
102
+
103
+ The same verdict appears as a row in `maestro doctor`, so an operator who runs
104
+ only doctor still sees it.
105
+
106
+ ### The fleet inventory
107
+
108
+ A seat's environment lives on the seat's own machine. There is no remote
109
+ inventory mechanism and this tooling does not invent one. So the fleet report is
110
+ a **template plus paste-able rows**: run `maestro seat-auth --fleet` once (it
111
+ pre-fills one row per member from the org directory), then on each machine run
112
+ `maestro seat-auth --row` and paste the line over that seat's row. The measured
113
+ columns — seat, agent id, machine, verdict, which variable names are present,
114
+ when it was checked — fill themselves; the Console-side columns (account,
115
+ workspace, cap, key id last 4, revocation date) stay blank, because only a human
116
+ with Console access knows them and a tool that guessed them would teach people
117
+ to trust a guess.
118
+
119
+ ### Arming the guard
120
+
121
+ The check **warns** by default, deliberately: seats are live, and a check that
122
+ failed on the day it shipped would break the seats it exists to move. Once every
123
+ row of the inventory reads `api-key`, set
124
+
125
+ ```sh
126
+ MAESTRO_REQUIRE_CONSOLE_KEY=1
127
+ ```
128
+
129
+ in each seat's `.env` (or the fleet's environment). `subscription` and `both`
130
+ then FAIL `maestro doctor` and exit 1 from `maestro seat-auth`, so a seat that
131
+ regresses to a subscription token announces itself instead of quietly billing a
132
+ personal plan. Record the date it was set fleet-wide — that, plus the last token
133
+ revocation, is what closes this gate.
134
+
75
135
  ## What is automated vs human
76
136
 
77
137
  maestro cannot create Console workspaces or keys for you — that requires a human
@@ -177,15 +177,60 @@ summary and in `.maestro/upgrade-result.json` `{from, to, at, steps}`:
177
177
  | `globalInstall` | `npm i -g @cohortapp/agent-sdk@<this version>` so `maestro` / `cohort` / `cohort-mcp` on PATH match the agent dir (`MAESTRO_SKIP_GLOBAL_INSTALL=1` skips) |
178
178
  | `verify` | the `maestro upgrade --verify` report, below |
179
179
 
180
- autoupdate then kickstarts the daemon and health-gates it: the daemon
181
- process must be alive with a fresh `org-mesh connected` / `[daemon] Running`
182
- line, and — when a `-session` plist was generated — the session label must be
183
- in `launchctl list` with a live supervisor process. A missing session is
184
- logged as `reconcile-failed` and does **not** roll back (the daemon's
185
- `--print` lane is the front door meanwhile; doctor says what to do). Every
186
- launchd and `pgrep` question is scoped to *this* agent (`ai.maestro.<first>-*`
187
- and its own agent dir), so two seats on one Mac never gate on — or restart —
188
- each other.
180
+ autoupdate then kickstarts the daemon and health-gates it. **The gate means
181
+ health, not "running"** — it used to be "pid alive + a fresh `org-mesh
182
+ connected` line", and a crash-looping daemon satisfies both (launchd respawns
183
+ it, and every respawn prints the line again): one seat logged `up to date
184
+ (2.17.0)` hourly for six days, 2026-09-15..21, while its daemon died ~25 s
185
+ after every start, and the org saw no presence beat from it for ten days. The
186
+ daemon now has to answer all of:
187
+
188
+ - **pid stability** — the daemon pid set is unchanged across two samples 90 s
189
+ apart and every pid's `ps etime` is ≥ 90 s (3× the observed crash
190
+ interval, well inside the hourly cadence; `MAESTRO_AUTOUPDATE_STABLE_S`);
191
+ - **no fatal line** in its own log since the restart (`[DAEMON]
192
+ uncaughtException:`, `[daemon] Fatal:`, `[wrapper] FATAL:`,
193
+ `ERR_MODULE_NOT_FOUND`) — the log has no per-line timestamps and the
194
+ wrapper names the file for the day the process started, so "since the
195
+ restart" is a line offset taken before the kickstart;
196
+ - **an org-acknowledged beat** — `state/org/last-beat.json` `{at, ok, code?}`,
197
+ which `lib/org/mesh.mjs` overwrites on every presence beat (`ok:true` only
198
+ when the org answered 2xx), must say `ok:true`, post-date the daemon's start
199
+ and be younger than 5 min (`MAESTRO_AUTOUPDATE_BEAT_FRESH_S`, the same bar
200
+ after which hq's presence view calls a seat offline). Skipped only for a
201
+ seat `config/org.yaml` does not enrol.
202
+
203
+ When a `-session` plist was generated, the session label must also be loaded
204
+ with a live supervisor process; a missing session is logged as
205
+ `reconcile-failed` and does **not** roll back (the daemon's `--print` lane is
206
+ the front door meanwhile; doctor says what to do). Every launchd and `pgrep`
207
+ question is scoped to *this* agent (`ai.maestro.<first>-*` and its own agent
208
+ dir), so two seats on one Mac never gate on — or restart — each other.
209
+
210
+ **Being up to date is not an exemption.** When the installed version is
211
+ already `@latest` the run still runs the same gate on the current version.
212
+ An unhealthy daemon is logged loudly, recorded in `state/autoupdate/last.json`
213
+ as `{ok:false, healthy:false, reason:"unhealthy-current: …"}` (the beat
214
+ carries it as `machine.upgrade`), and announced once per episode through
215
+ `state/session/upgrade-notice.json` `{from:CUR, to:CUR, healthy:false,
216
+ reason}` so the front-door session's feed surfaces it as a `daemon-unhealthy`
217
+ directive — a distinct action from `upgrade-available`, so no session restarts
218
+ on a health report. Nothing is rolled back (there is no upgrade to undo), an
219
+ `unhealthy-current` entry never holds a later release, and a recovery restores
220
+ `last.json`.
221
+
222
+ **A stale daemon is reconciled on the same path.** A hand-run `maestro
223
+ upgrade` installs the package and reconciles the seat but never restarts the
224
+ daemon (its verify row says the new version "takes effect when autoupdate
225
+ kickstarts it"). When `state/dashboards/daemon-health.yaml` shows the live
226
+ daemon started on a different `sdk_version` than the installed one, the hourly
227
+ run kickstarts it, waits, and runs the gate exactly as after an automatic
228
+ install — a healthy outcome writes the same `{from:<old>, to:<new>}` notice, so
229
+ the session restarts itself onto the new code when idle. The fatal scan starts
230
+ at the running daemon's own boot marker (`[DAEMON] boot pid=<pid>`, the first
231
+ line `maestro-daemon.mjs` prints), never at the top of the shared start-day
232
+ log, so a one-off crash earlier the same day that launchd already recovered
233
+ from is history, not health.
189
234
 
190
235
  An unhealthy daemon **rolls back**: the previous SDK is reinstalled into the
191
236
  agent dir and *that* package's `upgrade` runs, the global install is put back
@@ -32,20 +32,17 @@ npm i -g @cohortapp/agent-sdk # GLOBAL on purpose: every Claude Code sess
32
32
  # this seat needs `maestro` + `cohort-mcp` on PATH
33
33
  ```
34
34
 
35
- ## 3. The Claude token — one auth story for the whole seat
35
+ ## 3. The Claude credential — one Console API key per seat
36
36
 
37
37
  Every `claude` the seat runs (the daemon's `--print` lane, the main session,
38
- cadence sub-sessions) authenticates with a **long-lived subscription OAuth
39
- token**, never the interactive keychain login (which expires headlessly and
40
- has stranded seats before). Mint it on **any** machine where you are logged
41
- in to Claude Code with the Max subscription — your laptop is fine:
38
+ cadence sub-sessions) authenticates with an **Anthropic Console API key**
39
+ created for this agent, in a Console workspace with its own spend limit. Do
40
+ not use a Claude subscription on an agent seat: neither a `claude setup-token`
41
+ token nor the keychain login (which also expires headlessly). Creating the
42
+ workspace and the key: [billing-console-keys.md](billing-console-keys.md).
42
43
 
43
- ```bash
44
- claude setup-token # prints one token; copy it
45
- ```
46
-
47
- Keep it in your clipboard / password manager for step 5. It is per seat: mint
48
- a fresh one whenever `cohort doctor` reports the token as rejected.
44
+ Keep the key in your password manager for step 5. It is per seat: rotate it in
45
+ the Console whenever `cohort doctor` reports it as rejected.
49
46
 
50
47
  ## 4. Create the agent repo
51
48
 
@@ -59,7 +56,7 @@ including `.mcp.json`, which exposes the `cohort-mcp` org tool surface to
59
56
  interactive Claude sessions, and the PreToolUse hooks that keep its outbound
60
57
  writes on the CLI lane).
61
58
 
62
- ## 5. Enroll against `https://os.cohortapp.com` — and paste the token
59
+ ## 5. Enroll against `https://os.cohortapp.com` — and paste the API key
63
60
 
64
61
  Two lanes — pick one:
65
62
 
@@ -68,13 +65,13 @@ Two lanes — pick one:
68
65
 
69
66
  ```bash
70
67
  export COHORT_API_KEY=nlk_… COHORT_ORG_ID=<org-ID> COHORT_AGENT_ID=<member-slug>
71
- cohort setup # the model section (order 30) asks for the token from step 3
72
- # headless / one-paste bootstrap: the token comes from the environment instead of a prompt
73
- CLAUDE_CODE_OAUTH_TOKEN=<token> cohort setup --headless
68
+ cohort setup # the model section (order 30) asks for the API key from step 3
69
+ # headless / one-paste bootstrap: the key comes from the environment instead of a prompt
70
+ ANTHROPIC_API_KEY=<key> cohort setup --headless
74
71
  ```
75
72
 
76
- Either way `.env` ends up with `CLAUDE_CODE_OAUTH_TOKEN` +
77
- `MAESTRO_PREFER_SUBSCRIPTION_AUTH=1`, mode 600. No `ANTHROPIC_API_KEY`.
73
+ Either way `.env` ends up with `ANTHROPIC_API_KEY`, mode 600, and no
74
+ `CLAUDE_CODE_OAUTH_TOKEN` or `MAESTRO_PREFER_SUBSCRIPTION_AUTH`.
78
75
 
79
76
  > **`COHORT_ORG_ID` is the org's ID, not its slug** — this line said
80
77
  > `<org-slug>` and that would 401 every call. The value rides as `x-org-id`
@@ -98,7 +95,7 @@ Two lanes — pick one:
98
95
 
99
96
  | Order | Section | What it does |
100
97
  | --- | --- | --- |
101
- | 30 | `model` | Claude auth — **`oauth-token` by default**: paste the `claude setup-token` output; writes `CLAUDE_CODE_OAUTH_TOKEN` + `MAESTRO_PREFER_SUBSCRIPTION_AUTH=1`, chmods `.env` 600 |
98
+ | 30 | `model` | Claude auth — **`api-key` by default**: paste the agent's Console API key; writes `ANTHROPIC_API_KEY`, chmods `.env` 600 |
102
99
  | 75 | `org` | endpoint + token (the enrollment SoT) |
103
100
  | 76 | `messaging` | messaging.read/write + calling.write scopes, home channels |
104
101
  | 77 | `orgmail` | **workspace mailbox** — writes `config/orgmail.yaml` |
@@ -144,13 +141,11 @@ cohort doctor
144
141
 
145
142
  All green includes, in this order:
146
143
 
147
- - **Claude auth** — the mode in effect (`subscription OAuth token` is the
148
- expected line) and what `claude auth status` reports. The CLI reports that
149
- a credential is PRESENT — it answers "logged in" for any token value — so a
150
- bad token is only caught by the first real spawn (`logs/sessions`, and the
151
- beat flips to `relogin_required`); a `claude -p "ping"` after doctor is the
152
- cheap way to prove it. "keychain login"
153
- or "nothing configured" means step 3/5 was skipped.
144
+ - **Claude auth** — the mode in effect (`ANTHROPIC_API_KEY` is the expected
145
+ line for an agent seat). In API-key mode the probe makes a real call, so a
146
+ rejected key shows here. A subscription line (OAuth token or keychain login)
147
+ on an agent seat means it is still on the pre-migration setup — see step 3.
148
+ "nothing configured" means step 3/5 was skipped.
154
149
  - **Cohort sources** — for each of `base` / `orgId` / `token` / `agentId`,
155
150
  which file won (`config/org.yaml` beats the environment beats `.env`) and
156
151
  every value that lost. If you edited `.env` and nothing changed, this line
@@ -279,7 +279,10 @@ Pre-compiles session context to reduce prompt size:
279
279
 
280
280
  - Reads recent interactions, queue state, and active items
281
281
  - Compresses context to fit within token limits
282
- - Enabled via `DAEMON_CONTEXT_COMPILER=1` in `.env`
282
+ - **On by default.** Set `DAEMON_CONTEXT_COMPILER=0` in `.env` to fall back to
283
+ the legacy per-prompt history path. The code used to default this OFF while
284
+ `.env.example` shipped `=1`, so which path ran depended on whether the
285
+ operator had copied the example env; both now agree.
283
286
 
284
287
  ---
285
288
 
@@ -52,7 +52,7 @@ core runner.
52
52
  |---------|-------|-------------|
53
53
  | `identity` | 10 | Agent name and title, the **function × altitude** archetype, and the principal. Writes `config/agent.json`. |
54
54
  | `company` | 20 | Company-context interview — name, website, industry, one-line + detailed overview, stage/size, footprint, regulation, top priorities, and key people. Writes `config/company.json`. |
55
- | `model` | 30 | Claude auth. Three modes, **`oauth-token` the default**: run `claude setup-token` on any logged-in machine and paste the result (headless: `CLAUDE_CODE_OAUTH_TOKEN` in the environment) → `.env` gets `CLAUDE_CODE_OAUTH_TOKEN` + `MAESTRO_PREFER_SUBSCRIPTION_AUTH=1`; or this machine's keychain login; or a pasted Anthropic API key. Chmods `.env` 600. |
55
+ | `model` | 30 | Claude auth. Three modes, **`api-key` the default**: paste an Anthropic Console API key created for this agent in a Console workspace with a spend limit (headless: `ANTHROPIC_API_KEY` in the environment) → `.env` gets `ANTHROPIC_API_KEY`. Setup runbook: [billing-console-keys.md](billing-console-keys.md). The other two modes — a `claude setup-token` subscription token, or this machine's keychain login — are for a person's own development machine, not an agent seat. Chmods `.env` 600. |
56
56
  | `comms` | 45 | Wires each messaging channel — Slack, Gmail, SMS, WhatsApp, Telegram, voice — into `.env`/gate files and verifies inbound. |
57
57
  | `tools` | 50 | Selects which channels and MCP servers the agent should run. |
58
58
  | `operating-model` | 60 | Deterministically generates the operating charter, a seeded WBS backlog (≥5 open items), 40–60 sub-agents + skills + workflows + MCP servers + event-routing, archetype cadences, the autonomy policy, the communication profile, and the launchd plists. |