@cohortapp/agent-sdk 2.17.0 → 2.18.5

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 (531) hide show
  1. package/.claude/settings.json +18 -0
  2. package/.env.example +18 -5
  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/setup-wizard.md +1 -1
  9. package/docs/runbooks/fleet-rollout.md +156 -0
  10. package/docs/runbooks/mac-mini-bootstrap.md +12 -14
  11. package/lib/action-executor.js +19 -3
  12. package/lib/budget-guard.mjs +279 -3
  13. package/lib/channels/base-adapter.mjs +3 -1
  14. package/lib/channels/contract.mjs +2 -1
  15. package/lib/channels/inbox-item.mjs +8 -0
  16. package/lib/claude-bin.mjs +5 -6
  17. package/lib/cli/doctor-checks.mjs +141 -10
  18. package/lib/cli/global-setup-extras.mjs +5 -1
  19. package/lib/cli/inbox.mjs +100 -15
  20. package/lib/cli/seat-auth.mjs +463 -0
  21. package/lib/cli/session.mjs +80 -12
  22. package/lib/collective/capture-slots.mjs +234 -0
  23. package/lib/collective/capture.mjs +8 -6
  24. package/lib/collective/config.mjs +2 -0
  25. package/lib/collective/global-config.mjs +63 -1
  26. package/lib/collective/loop-guard.mjs +155 -0
  27. package/lib/collective/presence.mjs +142 -5
  28. package/lib/comms/send-gate.mjs +559 -1
  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/failover.mjs +67 -16
  138. package/lib/model-router/llm-task.mjs +39 -3
  139. package/lib/model-router/resolve.mjs +89 -3
  140. package/lib/model-router/spawn.mjs +46 -47
  141. package/lib/model-router/taxonomy.mjs +126 -4
  142. package/lib/org/cost-sync.mjs +141 -11
  143. package/lib/org/inbound/broadcast.mjs +289 -0
  144. package/lib/org/inbound/collective.mjs +375 -0
  145. package/lib/org/inbound/directedness.mjs +96 -8
  146. package/lib/org/inbound/facts.mjs +78 -2
  147. package/lib/org/inbound/project.mjs +22 -0
  148. package/lib/org/inbound/surfaces.mjs +14 -0
  149. package/lib/org/llm-token.mjs +879 -0
  150. package/lib/org/mesh.mjs +61 -0
  151. package/lib/org/messaging.mjs +3 -1
  152. package/lib/org/protocol.checksum +1 -1
  153. package/lib/org/protocol.mjs +15 -0
  154. package/lib/org/quota.mjs +520 -0
  155. package/lib/org/tool-surface.mjs +104 -16
  156. package/lib/org/ui-parity.mjs +16 -1
  157. package/lib/org/work-ledger.mjs +37 -6
  158. package/lib/rate-guard.mjs +114 -1
  159. package/lib/resource-governor.mjs +41 -6
  160. package/lib/runtime/adapter.mjs +833 -0
  161. package/lib/runtime/child-env.mjs +191 -0
  162. package/lib/runtime/legacy-shell-guard.mjs +97 -0
  163. package/lib/runtime/seat-engine.mjs +162 -0
  164. package/lib/session/ask-ledger.mjs +271 -0
  165. package/lib/session/current-work.mjs +676 -0
  166. package/lib/session/feed-core.mjs +40 -3
  167. package/lib/session/launch-args.mjs +56 -4
  168. package/lib/session/status-summary.mjs +26 -9
  169. package/lib/session/upgrade-notice.mjs +42 -0
  170. package/lib/setup/claude-probe.mjs +117 -13
  171. package/lib/setup/enrich.mjs +13 -10
  172. package/lib/setup/sections/model.mjs +39 -13
  173. package/lib/telemetry/collect.mjs +229 -11
  174. package/lib/upgrade/ignored-drift.mjs +105 -0
  175. package/lib/voice/post-call-brief.mjs +30 -17
  176. package/package.json +13 -3
  177. package/plugins/maestro-skills/skills/board-work.md +5 -0
  178. package/plugins/maestro-skills/skills/inbound-triage.md +56 -15
  179. package/plugins/maestro-skills/skills/main-session.md +18 -7
  180. package/scaffold/config/collective.yaml +7 -0
  181. package/scripts/ci/check-durable-write-seam.mjs +3 -1
  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 +142 -19
  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 +51 -37
  194. package/scripts/daemon/deliver.mjs +30 -1
  195. package/scripts/daemon/dispatcher.mjs +595 -149
  196. package/scripts/daemon/health.mjs +14 -1
  197. package/scripts/daemon/maestro-daemon.mjs +11 -0
  198. package/scripts/daemon/prompt-builder.mjs +24 -0
  199. package/scripts/daemon/responder.mjs +246 -79
  200. package/scripts/daemon/sdk-version.mjs +98 -16
  201. package/scripts/eval/probe-gateway.mjs +635 -0
  202. package/scripts/eval/replay/extract.mjs +270 -0
  203. package/scripts/eval/replay/grade.mjs +260 -0
  204. package/scripts/eval/replay/lib/config.mjs +50 -0
  205. package/scripts/eval/replay/lib/effects.mjs +65 -0
  206. package/scripts/eval/replay/lib/fixture.mjs +188 -0
  207. package/scripts/eval/replay/lib/judge.mjs +72 -0
  208. package/scripts/eval/replay/lib/redact.mjs +136 -0
  209. package/scripts/eval/replay/lib/sandbox.mjs +170 -0
  210. package/scripts/eval/replay/lib/schema-check.mjs +63 -0
  211. package/scripts/eval/replay/lib/transcript.mjs +76 -0
  212. package/scripts/eval/replay/mcp-replay-stub.mjs +101 -0
  213. package/scripts/eval/replay/report.mjs +185 -0
  214. package/scripts/eval/replay/run.mjs +404 -0
  215. package/scripts/fleet/rollout.mjs +1151 -0
  216. package/scripts/hooks/pre-send-audit.sh +36 -245
  217. package/scripts/hooks/pre-write-yaml-validate.mjs +275 -0
  218. package/scripts/hooks/validate-state-yaml.sh +190 -0
  219. package/scripts/huddle/huddle-llm.mjs +361 -0
  220. package/scripts/huddle/huddle-server.mjs +46 -121
  221. package/scripts/local-triggers/autoupdate.sh +465 -81
  222. package/scripts/local-triggers/run-trigger.sh +13 -0
  223. package/scripts/maintenance/pin-integrity.mjs +364 -0
  224. package/scripts/poll-slack-events.sh +41 -9
  225. package/scripts/poller/slack-socket-mode.mjs +28 -3
  226. package/scripts/session/supervisor.mjs +80 -13
  227. package/scripts/spawn-session.sh +13 -0
  228. package/bin/maestro.test.mjs +0 -1574
  229. package/lib/action-executor.test.mjs +0 -871
  230. package/lib/archetype.test.mjs +0 -132
  231. package/lib/assurance/plan-note.test.mjs +0 -234
  232. package/lib/assurance/room-budget.test.mjs +0 -486
  233. package/lib/assurance/tier.test.mjs +0 -174
  234. package/lib/autonomy.test.mjs +0 -66
  235. package/lib/backlog.test.mjs +0 -302
  236. package/lib/backup/policy.test.mjs +0 -305
  237. package/lib/budget-escalate.test.mjs +0 -232
  238. package/lib/budget-guard.envelope.test.mjs +0 -476
  239. package/lib/budget-guard.test.mjs +0 -427
  240. package/lib/cadence-bus-requeue.test.mjs +0 -83
  241. package/lib/cadence-bus-schedule.test.mjs +0 -194
  242. package/lib/cadence-bus.test.mjs +0 -720
  243. package/lib/cadences.test.mjs +0 -230
  244. package/lib/capability/inventory.test.mjs +0 -232
  245. package/lib/capability.test.mjs +0 -78
  246. package/lib/channels/base-adapter.test.mjs +0 -590
  247. package/lib/channels/channels.test.mjs +0 -371
  248. package/lib/channels/contract.test.mjs +0 -162
  249. package/lib/channels/inbox-item.test.mjs +0 -368
  250. package/lib/channels/orgmail/adapter.test.mjs +0 -448
  251. package/lib/channels/pairing.test.mjs +0 -270
  252. package/lib/channels/repeat-suppressor.test.mjs +0 -134
  253. package/lib/channels/slack-adapter.test.mjs +0 -212
  254. package/lib/channels/telegram-adapter.test.mjs +0 -306
  255. package/lib/channels/voice/adapter.test.mjs +0 -278
  256. package/lib/channels/whatsapp/adapter-baileys.test.mjs +0 -359
  257. package/lib/channels/whatsapp/baileys-typing.test.mjs +0 -154
  258. package/lib/charter.test.mjs +0 -89
  259. package/lib/claude-bin.test.mjs +0 -131
  260. package/lib/cli/board.test.mjs +0 -227
  261. package/lib/cli/design.test.mjs +0 -270
  262. package/lib/cli/doctor-checks.test.mjs +0 -336
  263. package/lib/cli/global-setup-extras.test.mjs +0 -462
  264. package/lib/cli/inbox.test.mjs +0 -230
  265. package/lib/cli/session-ack.test.mjs +0 -63
  266. package/lib/cli/session.test.mjs +0 -613
  267. package/lib/collective/capture.test.mjs +0 -121
  268. package/lib/collective/cards.test.mjs +0 -114
  269. package/lib/collective/config.test.mjs +0 -123
  270. package/lib/collective/global-config.test.mjs +0 -220
  271. package/lib/collective/global-skills.test.mjs +0 -126
  272. package/lib/collective/presence.test.mjs +0 -95
  273. package/lib/collective/recall.test.mjs +0 -116
  274. package/lib/collective/vendor-skills.test.mjs +0 -306
  275. package/lib/comms/send-gate.test.mjs +0 -770
  276. package/lib/comms.test.mjs +0 -41
  277. package/lib/context/budget.test.mjs +0 -252
  278. package/lib/context/history-scope.test.mjs +0 -79
  279. package/lib/cost/ledger-row.test.mjs +0 -183
  280. package/lib/design/design-md.test.mjs +0 -318
  281. package/lib/design/fixtures/DESIGN.golden.md +0 -238
  282. package/lib/design/fixtures/PRODUCT.golden.md +0 -67
  283. package/lib/design/fixtures/foundation.json +0 -133
  284. package/lib/design/refresh-gate.test.mjs +0 -144
  285. package/lib/design/write.test.mjs +0 -241
  286. package/lib/diagnostics/alerts.test.mjs +0 -318
  287. package/lib/diagnostics/backup-freshness.test.mjs +0 -185
  288. package/lib/diagnostics/counters.test.mjs +0 -206
  289. package/lib/diagnostics/events.test.mjs +0 -290
  290. package/lib/diagnostics/otel.test.mjs +0 -196
  291. package/lib/diagnostics/trace.test.mjs +0 -251
  292. package/lib/env-compat.test.mjs +0 -104
  293. package/lib/execution/disposition.test.mjs +0 -553
  294. package/lib/execution/drive.test.mjs +0 -270
  295. package/lib/execution/effects.test.mjs +0 -344
  296. package/lib/execution/intake.test.mjs +0 -389
  297. package/lib/execution/journal.test.mjs +0 -261
  298. package/lib/execution/match.test.mjs +0 -235
  299. package/lib/execution/pipeline.test.mjs +0 -392
  300. package/lib/execution/route.test.mjs +0 -186
  301. package/lib/execution/surface-policy.test.mjs +0 -162
  302. package/lib/fs-atomic.test.mjs +0 -72
  303. package/lib/fs-ownership.test.mjs +0 -158
  304. package/lib/goals/admission.test.mjs +0 -164
  305. package/lib/goals/classify.test.mjs +0 -167
  306. package/lib/goals/collaborate.test.mjs +0 -336
  307. package/lib/goals/gaps.test.mjs +0 -284
  308. package/lib/goals/loop.test.mjs +0 -845
  309. package/lib/hooks/bus.test.mjs +0 -387
  310. package/lib/identity/persona.test.mjs +0 -142
  311. package/lib/kpi-sensors.test.mjs +0 -278
  312. package/lib/kpi.test.mjs +0 -244
  313. package/lib/learning/config.test.mjs +0 -75
  314. package/lib/learning/counters.test.mjs +0 -69
  315. package/lib/learning/curator-consolidate.test.mjs +0 -238
  316. package/lib/learning/curator.test.mjs +0 -106
  317. package/lib/learning/reflect.test.mjs +0 -0
  318. package/lib/learning/session-index.test.mjs +0 -125
  319. package/lib/learning/skill-writer.test.mjs +0 -210
  320. package/lib/mandate/audit.test.mjs +0 -195
  321. package/lib/mandate/contract.test.mjs +0 -185
  322. package/lib/mandate/derive.test.mjs +0 -274
  323. package/lib/mandate/model.test.mjs +0 -164
  324. package/lib/mandate/refresh.test.mjs +0 -389
  325. package/lib/mcp/server.test.mjs +0 -426
  326. package/lib/model-router/auth-profiles.test.mjs +0 -580
  327. package/lib/model-router/catalog.test.mjs +0 -385
  328. package/lib/model-router/economics.test.mjs +0 -438
  329. package/lib/model-router/failover.test.mjs +0 -439
  330. package/lib/model-router/health.test.mjs +0 -338
  331. package/lib/model-router/integration-coverage.test.mjs +0 -831
  332. package/lib/model-router/integration.test.mjs +0 -564
  333. package/lib/model-router/ledger.test.mjs +0 -415
  334. package/lib/model-router/llm-task.test.mjs +0 -392
  335. package/lib/model-router/org-credentials.test.mjs +0 -265
  336. package/lib/model-router/pricing-refresh.test.mjs +0 -286
  337. package/lib/model-router/reconcile.test.mjs +0 -316
  338. package/lib/model-router/repair.test.mjs +0 -180
  339. package/lib/model-router/spawn.test.mjs +0 -446
  340. package/lib/model-router/taxonomy.test.mjs +0 -410
  341. package/lib/model-router.test.mjs +0 -1207
  342. package/lib/org/activity.test.mjs +0 -134
  343. package/lib/org/approvals.test.mjs +0 -216
  344. package/lib/org/awareness.test.mjs +0 -159
  345. package/lib/org/board-mine-cache.test.mjs +0 -53
  346. package/lib/org/board.test.mjs +0 -187
  347. package/lib/org/bootstrap-context.test.mjs +0 -153
  348. package/lib/org/client.test.mjs +0 -1206
  349. package/lib/org/cohort-client.test.mjs +0 -126
  350. package/lib/org/cost-sync.test.mjs +0 -153
  351. package/lib/org/doctor.test.mjs +0 -346
  352. package/lib/org/engagement-ledger.test.mjs +0 -112
  353. package/lib/org/engagement.test.mjs +0 -739
  354. package/lib/org/handoff.test.mjs +0 -269
  355. package/lib/org/inbound/directedness.test.mjs +0 -668
  356. package/lib/org/inbound/facts.test.mjs +0 -471
  357. package/lib/org/inbound/hydrate.test.mjs +0 -908
  358. package/lib/org/inbound/index.test.mjs +0 -429
  359. package/lib/org/inbound/project.test.mjs +0 -287
  360. package/lib/org/integration-tools.test.mjs +0 -160
  361. package/lib/org/keys.test.mjs +0 -92
  362. package/lib/org/knowledge.test.mjs +0 -326
  363. package/lib/org/leases.test.mjs +0 -235
  364. package/lib/org/mesh-directives.test.mjs +0 -110
  365. package/lib/org/mesh-integration.test.mjs +0 -127
  366. package/lib/org/mesh.test.mjs +0 -400
  367. package/lib/org/messaging.test.mjs +0 -471
  368. package/lib/org/param-contract.test.mjs +0 -477
  369. package/lib/org/policy.test.mjs +0 -237
  370. package/lib/org/protocol.checksum.test.mjs +0 -90
  371. package/lib/org/protocol.test.mjs +0 -323
  372. package/lib/org/push.test.mjs +0 -792
  373. package/lib/org/registry.test.mjs +0 -100
  374. package/lib/org/resource-tools.test.mjs +0 -361
  375. package/lib/org/tool-access.test.mjs +0 -144
  376. package/lib/org/tool-surface-integration.test.mjs +0 -120
  377. package/lib/org/tool-surface.test.mjs +0 -1268
  378. package/lib/org/typing.test.mjs +0 -291
  379. package/lib/org/ui-parity.test.mjs +0 -560
  380. package/lib/org/verify.test.mjs +0 -194
  381. package/lib/org/work-ledger.test.mjs +0 -273
  382. package/lib/plan/adoption-e2e.test.mjs +0 -366
  383. package/lib/plan/budget-enforcement.test.mjs +0 -400
  384. package/lib/plan/compile.test.mjs +0 -382
  385. package/lib/plan/emit.test.mjs +0 -269
  386. package/lib/plan/explain.test.mjs +0 -188
  387. package/lib/prompts/parallelism.test.mjs +0 -177
  388. package/lib/rag/rag.test.mjs +0 -505
  389. package/lib/rate-guard.test.mjs +0 -272
  390. package/lib/reactive-gate.test.mjs +0 -57
  391. package/lib/render.test.mjs +0 -68
  392. package/lib/resource-governor.test.mjs +0 -488
  393. package/lib/scheduling/dynamic-jobs.test.mjs +0 -344
  394. package/lib/scheduling/jitter.test.mjs +0 -140
  395. package/lib/secrets/broker.test.mjs +0 -280
  396. package/lib/secrets/providers.test.mjs +0 -274
  397. package/lib/security/audit-engine.test.mjs +0 -424
  398. package/lib/security/coerce-args.test.mjs +0 -281
  399. package/lib/security/dangerous-tools.test.mjs +0 -68
  400. package/lib/security/external-content.test.mjs +0 -84
  401. package/lib/security/redact.test.mjs +0 -441
  402. package/lib/security/secret-equal.test.mjs +0 -55
  403. package/lib/session/config.test.mjs +0 -92
  404. package/lib/session/feed-core.test.mjs +0 -198
  405. package/lib/session/first-run.test.mjs +0 -121
  406. package/lib/session/frontdoor.test.mjs +0 -205
  407. package/lib/session/handoffs.test.mjs +0 -183
  408. package/lib/session/identity.test.mjs +0 -180
  409. package/lib/session/inbox-claims.test.mjs +0 -286
  410. package/lib/session/launch-args.test.mjs +0 -157
  411. package/lib/session/liveness.test.mjs +0 -100
  412. package/lib/session/status-summary.test.mjs +0 -118
  413. package/lib/session-permissions.test.mjs +0 -120
  414. package/lib/setup/claude-probe.test.mjs +0 -187
  415. package/lib/setup/completeness.test.mjs +0 -110
  416. package/lib/setup/context-pack.test.mjs +0 -89
  417. package/lib/setup/enrich.test.mjs +0 -115
  418. package/lib/setup/enroll-from-cohort.test.mjs +0 -300
  419. package/lib/setup/integration.test.mjs +0 -162
  420. package/lib/setup/io.test.mjs +0 -77
  421. package/lib/setup/runner.test.mjs +0 -132
  422. package/lib/setup/sections/identity.test.mjs +0 -234
  423. package/lib/setup/sections/inventory.test.mjs +0 -198
  424. package/lib/setup/sections/learning.test.mjs +0 -81
  425. package/lib/setup/sections/mandate.test.mjs +0 -388
  426. package/lib/setup/sections/messaging.test.mjs +0 -127
  427. package/lib/setup/sections/model.test.mjs +0 -240
  428. package/lib/setup/sections/org.test.mjs +0 -346
  429. package/lib/setup/sections/orgmail.test.mjs +0 -118
  430. package/lib/setup/sections/recovery.test.mjs +0 -98
  431. package/lib/setup/sections/subagents.test.mjs +0 -429
  432. package/lib/setup/sections/verify.test.mjs +0 -175
  433. package/lib/setup/sot.test.mjs +0 -81
  434. package/lib/setup/state.test.mjs +0 -115
  435. package/lib/singleton.test.mjs +0 -151
  436. package/lib/subagents/cli.test.mjs +0 -389
  437. package/lib/subagents/client.test.mjs +0 -309
  438. package/lib/subagents/gap.test.mjs +0 -234
  439. package/lib/subagents/lock.test.mjs +0 -248
  440. package/lib/subagents/manifest.test.mjs +0 -175
  441. package/lib/subagents/refs.test.mjs +0 -204
  442. package/lib/subagents/resolve.test.mjs +0 -422
  443. package/lib/subagents/schema.test.mjs +0 -328
  444. package/lib/telemetry/alerts.test.mjs +0 -109
  445. package/lib/telemetry/collect.test.mjs +0 -1274
  446. package/lib/tool-definitions-integration.test.mjs +0 -83
  447. package/lib/tool-definitions.test.mjs +0 -437
  448. package/lib/upgrade/global-refresh.test.mjs +0 -65
  449. package/lib/upgrade/launchd-reconcile.test.mjs +0 -272
  450. package/lib/upgrade/post-steps.test.mjs +0 -200
  451. package/lib/upgrade/verify.test.mjs +0 -164
  452. package/lib/util/fetch-timeout.test.mjs +0 -202
  453. package/lib/util/reconnect.test.mjs +0 -369
  454. package/lib/util/unhandled.test.mjs +0 -216
  455. package/lib/voice/outbound.test.mjs +0 -69
  456. package/lib/voice/session-rotation.test.mjs +0 -114
  457. package/lib/voice/stt.test.mjs +0 -226
  458. package/lib/voice/voice.test.mjs +0 -990
  459. package/scripts/cadence/enqueue-cadence-tick.test.mjs +0 -187
  460. package/scripts/ci/check-docs-accuracy.test.mjs +0 -409
  461. package/scripts/ci/check-durable-write-seam.test.mjs +0 -90
  462. package/scripts/ci/check-no-build-artifacts.test.mjs +0 -71
  463. package/scripts/ci/check-no-residual-identity.test.mjs +0 -202
  464. package/scripts/ci/check-skill-packs.test.mjs +0 -495
  465. package/scripts/ci/check-subagent-frontmatter.test.mjs +0 -124
  466. package/scripts/ci/check.test.mjs +0 -194
  467. package/scripts/ci/conformance-org-api.test.mjs +0 -425
  468. package/scripts/cloud-relay/voice/relay-identity.test.mjs +0 -96
  469. package/scripts/collective/hook-runner.test.mjs +0 -173
  470. package/scripts/cost/fleet-digest.test.mjs +0 -207
  471. package/scripts/cost/track-claude-usage-pricing.test.mjs +0 -183
  472. package/scripts/cost/track-claude-usage.test.mjs +0 -148
  473. package/scripts/daemon/agent-daemon-board-mine.test.mjs +0 -96
  474. package/scripts/daemon/agent-daemon-design.test.mjs +0 -238
  475. package/scripts/daemon/agent-daemon-frontdoor.test.mjs +0 -60
  476. package/scripts/daemon/agent-daemon.test.mjs +0 -995
  477. package/scripts/daemon/assurance-e2e.test.mjs +0 -613
  478. package/scripts/daemon/assurance.test.mjs +0 -1791
  479. package/scripts/daemon/board-mirror.test.mjs +0 -165
  480. package/scripts/daemon/cadence-consumer-frontdoor.test.mjs +0 -393
  481. package/scripts/daemon/cadence-consumer-governance.test.mjs +0 -276
  482. package/scripts/daemon/cadence-consumer.test.mjs +0 -776
  483. package/scripts/daemon/cadence-handlers.test.mjs +0 -837
  484. package/scripts/daemon/classifier-identity.test.mjs +0 -137
  485. package/scripts/daemon/classifier.test.mjs +0 -266
  486. package/scripts/daemon/classify-kind.test.mjs +0 -40
  487. package/scripts/daemon/context-compiler.test.mjs +0 -406
  488. package/scripts/daemon/deliver.test.mjs +0 -564
  489. package/scripts/daemon/dispatcher-cooldown.test.mjs +0 -122
  490. package/scripts/daemon/dispatcher-governance.test.mjs +0 -1013
  491. package/scripts/daemon/dispatcher-resume.test.mjs +0 -166
  492. package/scripts/daemon/dispatcher-session-continuity.test.mjs +0 -365
  493. package/scripts/daemon/execution-ladder.test.mjs +0 -470
  494. package/scripts/daemon/goal-steward-cadence.test.mjs +0 -312
  495. package/scripts/daemon/inbox-deferral-session.test.mjs +0 -49
  496. package/scripts/daemon/inbox-deferral.test.mjs +0 -336
  497. package/scripts/daemon/inbox-wake.test.mjs +0 -199
  498. package/scripts/daemon/integration.test.mjs +0 -149
  499. package/scripts/daemon/lib/self-echo.test.mjs +0 -153
  500. package/scripts/daemon/lib/session-router.test.mjs +0 -554
  501. package/scripts/daemon/prompt-builder-preamble.test.mjs +0 -210
  502. package/scripts/daemon/prompt-builder.test.mjs +0 -556
  503. package/scripts/daemon/responder-cost.test.mjs +0 -68
  504. package/scripts/daemon/responder-history.test.mjs +0 -221
  505. package/scripts/daemon/sdk-version.test.mjs +0 -31
  506. package/scripts/daemon/session-lock.test.mjs +0 -252
  507. package/scripts/daemon/session-outcomes.test.mjs +0 -533
  508. package/scripts/daemon/typing-registry.test.mjs +0 -102
  509. package/scripts/hooks/pre-send-audit.test.mjs +0 -354
  510. package/scripts/huddle/huddle-prompt.test.mjs +0 -176
  511. package/scripts/local-triggers/autoupdate.test.mjs +0 -518
  512. package/scripts/local-triggers/generate-plists.test.mjs +0 -456
  513. package/scripts/media-generation/brand-clause.test.mjs +0 -135
  514. package/scripts/org/send-orgmail.first-contact.test.mjs +0 -102
  515. package/scripts/poller/inbox-privilege-injection.test.mjs +0 -167
  516. package/scripts/poller/inbox-scan-poller.test.mjs +0 -295
  517. package/scripts/poller/lib/cloud-relay-dedup.test.mjs +0 -133
  518. package/scripts/poller/slack-socket-mode.test.mjs +0 -805
  519. package/scripts/poller-launchd/install.test.mjs +0 -243
  520. package/scripts/restore-from-backup.test.mjs +0 -181
  521. package/scripts/session/feed.test.mjs +0 -196
  522. package/scripts/session/supervisor-sh.test.mjs +0 -218
  523. package/scripts/session/supervisor.test.mjs +0 -482
  524. package/scripts/setup/configure-macos.test.mjs +0 -306
  525. package/scripts/setup/gen-subagent-manifest.test.mjs +0 -124
  526. package/scripts/setup/generate-agent-package-json.test.mjs +0 -143
  527. package/scripts/setup/generate-capability.test.mjs +0 -134
  528. package/scripts/setup/init-agent.test.mjs +0 -370
  529. package/scripts/setup/init-skill-marketplace.test.mjs +0 -193
  530. package/scripts/vendor/sync-skill-packs.test.mjs +0 -103
  531. package/scripts/watchdog/memory-watchdog.test.mjs +0 -64
@@ -183,7 +183,9 @@ function loadAgentRegistry() {
183
183
 
184
184
  const ANTHROPIC_MODEL = "claude-haiku-4-5-20251001";
185
185
  // Resolve claude against the agent's PATH (not launchd's bare env).
186
- import { resolveClaudeBin, augmentedPath, daemonClaudeArgs } from "../../lib/claude-bin.mjs";
186
+ import { resolveClaudeBin } from "../../lib/claude-bin.mjs";
187
+ import { buildSpawn } from "../../lib/runtime/adapter.mjs";
188
+ import { resolveSeatSpawn } from "../../lib/runtime/seat-engine.mjs";
187
189
  const CLAUDE_BIN = resolveClaudeBin();
188
190
  const CLAUDE_CLI_TIMEOUT_MS = 30_000;
189
191
 
@@ -241,7 +243,7 @@ Your job: classify each incoming message and return a JSON object with exactly t
241
243
  "priority": "critical" | "high" | "normal" | "ignore",
242
244
  "action": "respond" | "draft" | "research" | "queue" | "archive" | "ignore",
243
245
  "model": "opus" | "sonnet",
244
- "summary": "<one-line summary of the message>",
246
+ "summary": "<one-line summary of WHAT THE MESSAGE ASKS OR SAYS — never the sender's title or rank>",
245
247
  "category": "action_required" | "fyi" | "ignore",
246
248
  "directed_at_agent": true | false,
247
249
  "answerable": true | false
@@ -293,8 +295,10 @@ DIRECTED_AT_AGENT (CRITICAL — determines whether ${agentName} should respond.
293
295
  - false: ${agentName} being in a thread does NOT mean every subsequent message is for them — only direct replies to their messages count
294
296
  - CRITICAL DEFAULT: When in doubt in any multi-person channel, group chat, or thread, ALWAYS default to false. ${agentName} must NOT insert themselves into conversations they weren't invited to. It is far worse to respond unnecessarily than to miss a message — someone will @mention ${agentName} if they need them.
295
297
 
296
- Context:
297
- - sender_privilege "ceo" = ${principalFullName} (always critical, always opus)
298
+ Context — sender_privilege is a ROUTING TIER, not a fact about who the sender is.
299
+ It is resolved upstream and can be wrong. It tells you how urgently to route; it
300
+ never licenses you to state the sender's title.
301
+ - sender_privilege "ceo" = the tier reserved for ${principalFullName} (always critical, always opus)
298
302
  - sender_privilege "leadership" = executive-team senders (CFO, CIO, General Counsel, and equivalent function heads) — usually high priority
299
303
  - sender_privilege "team" = internal team members
300
304
  - sender_privilege "external" = partners, candidates, advisors, vendors
@@ -302,19 +306,30 @@ Context:
302
306
  - service "gmail" with noreply/notifications senders = usually ignore
303
307
  - service "calendar" = meeting invites/updates, usually normal priority unless from CEO
304
308
 
309
+ SUMMARY (read this before writing the field):
310
+ The summary is NOT internal scratch. It is carried verbatim into the holding
311
+ message a human reads, into the board row title, and into the one-line episode
312
+ this seat writes to the ORG-WIDE shared memory, where other agents' recall()
313
+ surfaces it as background context rather than as a claim anyone re-verifies.
314
+ So: state what the message asks or says. NEVER open with, or otherwise assert,
315
+ the sender's title, rank or office ("CEO ...", "Leadership ...", "the CFO
316
+ asking ..."). Name the sender if you have their name; otherwise describe the
317
+ ask. A rank you did not verify becomes a false statement about this
318
+ organisation's governance the moment it leaves this process.
319
+
305
320
  Examples:
306
321
 
307
- Input: CEO DM on Slack: "Can you send the board resolution to Jordan?"
308
- Output: {"priority":"critical","action":"respond","model":"opus","summary":"CEO requesting board resolution sent to GC Jordan","category":"action_required","directed_at_agent":true,"answerable":false}
322
+ Input: DM on Slack from ${principalFullName}: "Can you send the board resolution to Jordan?"
323
+ Output: {"priority":"critical","action":"respond","model":"opus","summary":"${principalName} requesting the board resolution be sent to GC Jordan","category":"action_required","directed_at_agent":true,"answerable":false}
309
324
 
310
- Input: CEO DM on Slack: "what kind of machine are you running on?"
311
- Output: {"priority":"critical","action":"respond","model":"opus","summary":"CEO asking what machine/infrastructure the agent runs on","category":"action_required","directed_at_agent":true,"answerable":true}
325
+ Input: DM on Slack from ${principalFullName}: "what kind of machine are you running on?"
326
+ Output: {"priority":"critical","action":"respond","model":"opus","summary":"${principalName} asking what machine/infrastructure the agent runs on","category":"action_required","directed_at_agent":true,"answerable":true}
312
327
 
313
328
  Input: GitHub notification email about a merged PR
314
329
  Output: {"priority":"ignore","action":"ignore","model":"sonnet","summary":"GitHub PR merge notification","category":"ignore","directed_at_agent":false,"answerable":false}
315
330
 
316
331
  Input: Leadership Slack: "We need the the regulator gap analysis updated by Thursday"
317
- Output: {"priority":"high","action":"draft","model":"opus","summary":"Leadership requesting the regulator gap analysis update by Thursday deadline","category":"action_required","directed_at_agent":true,"answerable":false}
332
+ Output: {"priority":"high","action":"draft","model":"opus","summary":"Request for the regulator gap analysis update by Thursday deadline","category":"action_required","directed_at_agent":true,"answerable":false}
318
333
 
319
334
  Input: Team member: "Standup notes from today's sync"
320
335
  Output: {"priority":"normal","action":"archive","model":"sonnet","summary":"Team standup notes shared","category":"fyi","directed_at_agent":false,"answerable":false}
@@ -325,8 +340,8 @@ Output: {"priority":"normal","action":"respond","model":"sonnet","summary":"Exte
325
340
  Input: Channel message from Jacob: "@${agentName} can you check the engine deployment?"
326
341
  Output: {"priority":"normal","action":"respond","model":"sonnet","summary":"Jacob asking ${agentName} to check engine deployment","category":"action_required","directed_at_agent":true,"answerable":false}
327
342
 
328
- Input: Channel message from CEO: "@AnotherAgent can you review the agentic libraries in this channel?"
329
- Output: {"priority":"normal","action":"archive","model":"sonnet","summary":"CEO asking another agent to review agentic libraries — not directed at ${agentName}","category":"fyi","directed_at_agent":false,"answerable":false}
343
+ Input: Channel message from ${principalFullName}: "@AnotherAgent can you review the agentic libraries in this channel?"
344
+ Output: {"priority":"normal","action":"archive","model":"sonnet","summary":"${principalName} asking another agent to review agentic libraries — not directed at ${agentName}","category":"fyi","directed_at_agent":false,"answerable":false}
330
345
 
331
346
  Input: Channel message from Sam to Jordan: "Jordan, did you file the compliance response yet?"
332
347
  Output: {"priority":"normal","action":"archive","model":"sonnet","summary":"Sam asking Jordan about compliance response filing","category":"fyi","directed_at_agent":false,"answerable":false}
@@ -450,22 +465,44 @@ export function parseClassification(text) {
450
465
  // • Any failure (non-zero exit, timeout, unparseable output) throws so
451
466
  // the Tier-2 llmTask fallback engages exactly as before.
452
467
 
468
+ /**
469
+ * The classifier lane's spawn from the runtime adapter (lane "classifier"):
470
+ * --print <permissions> <bare MCP> --model <m> --append-system-prompt <sys>,
471
+ * prompt on stdin; stock env posture (stale ANTHROPIC_API_KEY/AUTH_TOKEN
472
+ * stripped, PATH augmented).
473
+ *
474
+ * W4-E1 (CF-44): `seat` is the seat's engine resolved once for this spawn. A
475
+ * claude seat adds no fields (unchanged); an engine-cohort seat runs `cli.mjs run`.
476
+ * @param {{systemPrompt:string, userPrompt:string, env?:object, bin?:string, seat?:{fields:object}}} o
477
+ */
478
+ export function classifierSpawn({ systemPrompt, userPrompt, env = process.env, bin = CLAUDE_BIN, seat = { fields: {} } }) {
479
+ return buildSpawn({
480
+ lane: "classifier",
481
+ bin,
482
+ model: ANTHROPIC_MODEL,
483
+ systemPrompt,
484
+ prompt: userPrompt,
485
+ permissions: sessionPermissionArgs({ source: "classifier" }),
486
+ mcp: { source: "classifier" },
487
+ env,
488
+ ...seat.fields,
489
+ });
490
+ }
491
+
453
492
  async function runClaudeCLI(systemPrompt, userPrompt) {
493
+ // W4-E1: the seat's engine, once per spawn (a claude seat reads config/agent.json only).
494
+ const seat = await resolveSeatSpawn(agentDir());
454
495
  return new Promise((resolvePromise, rejectPromise) => {
455
- const args = [
456
- "--print",
457
- ...sessionPermissionArgs({ source: "classifier" }),
458
- ...daemonClaudeArgs(undefined, { source: "classifier" }),
459
- "--model", ANTHROPIC_MODEL,
460
- "--append-system-prompt", systemPrompt,
461
- ];
462
-
463
- const proc = spawn(CLAUDE_BIN, args, {
496
+ const spawnSpec = classifierSpawn({ systemPrompt, userPrompt, seat });
497
+ if (!spawnSpec.ok) {
498
+ // Throw-path parity: a rejection engages the Tier-2 llmTask fallback.
499
+ rejectPromise(new Error(`claude CLI unavailable: ${spawnSpec.error.message}`));
500
+ return;
501
+ }
502
+
503
+ const proc = spawn(spawnSpec.bin, spawnSpec.argv, {
464
504
  stdio: ["pipe", "pipe", "pipe"],
465
- // Force claude CLI onto keychain OAuth (Max subscription); strip any
466
- // stale ANTHROPIC_API_KEY/AUTH_TOKEN inherited from the daemon env.
467
- // Augment PATH so spawned subsessions find homebrew/nvm binaries.
468
- env: { ...process.env, PATH: augmentedPath(), ANTHROPIC_API_KEY: "", ANTHROPIC_AUTH_TOKEN: "" },
505
+ env: spawnSpec.env,
469
506
  });
470
507
 
471
508
  let stdout = "";
@@ -671,12 +708,24 @@ function classifyWithRules(item) {
671
708
  const directed = isDirectedAtAgent(item);
672
709
 
673
710
  // CEO → critical, opus (but in channels, respect directed check)
711
+ //
712
+ // The summary deliberately does NOT name the tier ("CEO message from …").
713
+ // sender_privilege is a routing tier resolved upstream and it has been wrong
714
+ // fleet-wide: the answerItem() call site (now resolveSenderPrivilege() in
715
+ // agent-daemon.mjs) once read the unparenthesised
716
+ // `a || b ? "ceo" : "unknown"`, which stamped every sender "ceo". The
717
+ // summary is carried verbatim into holding text, board rows and org-wide
718
+ // memory, so a tier name here becomes an asserted fact about the sender's
719
+ // office that nothing downstream re-verifies. Route on the tier; never
720
+ // narrate it. (The rules-path sweep covered every summary below: the
721
+ // urgent-keyword limb's "Urgent message from …" names the message's own
722
+ // content, not a rank, and is kept as is.)
674
723
  if (item.sender_privilege === "ceo") {
675
724
  return {
676
725
  priority: "critical",
677
726
  action: directed ? "respond" : "archive",
678
727
  model: "opus",
679
- summary: `CEO message from ${item.sender}`,
728
+ summary: `Message from ${item.sender}`,
680
729
  category: directed ? "action_required" : "fyi",
681
730
  directed_at_agent: directed,
682
731
  };
@@ -688,7 +737,7 @@ function classifyWithRules(item) {
688
737
  priority: "high",
689
738
  action: directed ? "respond" : "archive",
690
739
  model: "opus",
691
- summary: `Leadership message from ${item.sender}`,
740
+ summary: `Message from ${item.sender}`,
692
741
  category: directed ? "action_required" : "fyi",
693
742
  directed_at_agent: directed,
694
743
  };
@@ -5,7 +5,8 @@
5
5
  * Single export: compileContext(item, classResult, options)
6
6
  *
7
7
  * Assembles sender profile, disclosure boundaries, conversation history,
8
- * active sessions, and sent-message registry into a single context block.
8
+ * current work (this agent's sessions on the machine), and sent-message
9
+ * registry into a single context block.
9
10
  * Filters history entries by information barrier domains.
10
11
  *
11
12
  * Adaptive token budget: 12K for critical/high, 8K for normal, 4K for low.
@@ -17,6 +18,7 @@ import { isEnabled as orgEnabled, loadOrgConfig } from "../../lib/org/client.mjs
17
18
  import { recall as orgRecall } from "../../lib/org/knowledge.mjs";
18
19
  import { isPrivateConversation, historyDirNames } from "../../lib/context/history-scope.mjs";
19
20
  import { fitSections } from "../../lib/context/budget.mjs";
21
+ import { currentWorkBlock, audienceForItem } from "../../lib/session/current-work.mjs";
20
22
 
21
23
  const AGENT_REPO_DIR = process.env.__TEST_AGENT_DIR || process.env.AGENT_DIR || join(new URL(".", import.meta.url).pathname, "../..");
22
24
  const SESSION_DIR = process.env.__TEST_SESSION_DIR || join(AGENT_REPO_DIR, "state", "sessions");
@@ -168,6 +170,24 @@ function matchesForbiddenDomain(text, forbiddenDomains, domainKeywords) {
168
170
  return false;
169
171
  }
170
172
 
173
+ /**
174
+ * The information-barrier predicate for a sender: `text → true` when the text
175
+ * trips 2+ keywords of a domain that sender may not see. This is the SAME test
176
+ * `loadConversationHistory` applies to each history turn, exported so the
177
+ * current-work block gets it on BOTH reply paths (the quick path has no
178
+ * barrier machinery of its own and imports this). Fail-closed on a sender we
179
+ * cannot evaluate: `forbiddenDomains` for an unknown sender is every domain.
180
+ *
181
+ * @param {string|null} senderSlug
182
+ * @returns {(text:string)=>boolean}
183
+ */
184
+ export function forbidsTextFor(senderSlug) {
185
+ const { forbiddenDomains } = loadDisclosureBoundaries(senderSlug, ALLOC.boundaries);
186
+ if (!forbiddenDomains || forbiddenDomains.length === 0) return () => false;
187
+ const domainKeywords = buildDomainKeywords();
188
+ return (text) => matchesForbiddenDomain(String(text || ""), forbiddenDomains, domainKeywords);
189
+ }
190
+
171
191
  /**
172
192
  * Load disclosure boundaries for a sender.
173
193
  * Returns { boundariesSection, forbiddenDomains }.
@@ -337,44 +357,37 @@ function loadConversationHistory(senderSlug, channelId, budgetTokens, forbiddenD
337
357
  return fitted.text ? fitted.text : null;
338
358
  }
339
359
 
340
- // ── Active sessions ────────────────────────────────────────────────
360
+ // ── Current work (the agent's own sessions on this machine) ────────
341
361
 
342
362
  /**
343
- * Load active sessions and format as bullet list.
363
+ * The bounded "what am I doing right now" block — lib/session/current-work.
364
+ *
365
+ * This used to read `active.json` alone: the daemon's own `--print` children,
366
+ * summary + model + sender, nothing else. A human asking "what are you doing
367
+ * right now, across sessions on your machine?" was answered from a list that
368
+ * did not contain the front door, its peers, the board items in progress, or
369
+ * the fact that a person had an interactive session open. The block now
370
+ * carries all of those (and names the board item where one is linked), under
371
+ * the same token allocation, and reports a human's session as EXISTING only.
372
+ *
373
+ * SCOPED TO THE AUDIENCE. The old list put every live session's summary —
374
+ * the classifier's restatement of some other person's message — into any
375
+ * reply's context. The block is now rendered for `item`'s conversation
376
+ * (`audienceForItem`): a session from another conversation is reported as
377
+ * existing only, and what is disclosable passes the same information-barrier
378
+ * keyword filter the history above it does (`forbiddenDomains`).
344
379
  */
345
- function loadActiveSessions(budgetTokens) {
380
+ async function loadCurrentWork(budgetTokens, item, forbiddenDomains) {
346
381
  try {
347
- const filePath = join(SESSION_DIR, "active.json");
348
- const raw = readFileSync(filePath, "utf-8");
349
- const data = JSON.parse(raw);
350
-
351
- // data may be an object with session entries or an array
352
- const sessions = Array.isArray(data) ? data : Object.values(data);
353
- if (sessions.length === 0) return null;
354
-
355
- const lines = [];
382
+ const domainKeywords = forbiddenDomains && forbiddenDomains.length > 0 ? buildDomainKeywords() : null;
383
+ const audience = audienceForItem(item, {
384
+ isPrivate: isPrivateConversation(item),
385
+ forbidsText: domainKeywords ? (t) => matchesForbiddenDomain(t, forbiddenDomains, domainKeywords) : undefined,
386
+ });
387
+ const block = await currentWorkBlock(AGENT_REPO_DIR, { activePath: join(SESSION_DIR, "active.json"), audience });
388
+ if (!block) return null;
356
389
  const charBudget = budgetTokens * CHARS_PER_TOKEN;
357
- let totalChars = 0;
358
-
359
- for (const sess of sessions) {
360
- const id = sess.sessionId || sess.id || "unknown";
361
- const summary = sess.summary || sess.task || "no summary";
362
- const model = sess.model || "unknown";
363
- const sender = sess.sender || sess.owner || "unknown";
364
- const started = sess.startTime || sess.started_at || "";
365
- let age = "";
366
- if (started) {
367
- const ms = Date.now() - new Date(started).getTime();
368
- const mins = Math.round(ms / 60000);
369
- age = `${mins}m ago`;
370
- }
371
- const line = `- ${id}: ${summary} (model=${model}, sender=${sender}${age ? ", " + age : ""})`;
372
- if (totalChars + line.length > charBudget) break;
373
- lines.push(line);
374
- totalChars += line.length;
375
- }
376
-
377
- return lines.length > 0 ? lines.join("\n") : null;
390
+ return block.length > charBudget ? block.slice(0, charBudget) : block;
378
391
  } catch {
379
392
  return null;
380
393
  }
@@ -555,8 +568,9 @@ export async function compileContext(item, classResult, options = {}) {
555
568
  isPrivateConversation(item),
556
569
  );
557
570
 
558
- // Step 5 — Active sessions
559
- const sessionsText = loadActiveSessions(ALLOC.active_sessions);
571
+ // Step 5 — Current work (this agent's sessions on this machine, bounded,
572
+ // scoped to this item's conversation and the sender's barrier)
573
+ const sessionsText = await loadCurrentWork(ALLOC.active_sessions, item, forbiddenDomains);
560
574
 
561
575
  // Step 6 — Sent registry
562
576
  const sentText = loadSentRegistry(channelId, ALLOC.sent_registry);
@@ -599,7 +613,7 @@ export async function compileContext(item, classResult, options = {}) {
599
613
  sections.push("");
600
614
 
601
615
  if (sessionsText) {
602
- sections.push("## Active Sessions");
616
+ // The block carries its own "## Current Work" header.
603
617
  sections.push(sessionsText);
604
618
  sections.push("");
605
619
  }
@@ -118,7 +118,10 @@ export function resolveSlackChannel(item) {
118
118
  */
119
119
 
120
120
  /** Surfaces that genuinely live in a Cohort room — these reply with a message. */
121
- const CHANNEL_SURFACES = Object.freeze(["dm", "mention", "thread_reply", "call"]);
121
+ // `broadcast` is a room message like a mention: the roll-call answer posts
122
+ // into the space it was asked in. Without this entry the reply has no
123
+ // transport, `canDeliverTo` says no, and the surface is dark at the last step.
124
+ const CHANNEL_SURFACES = Object.freeze(["dm", "mention", "broadcast", "thread_reply", "call"]);
122
125
 
123
126
  /**
124
127
  * Error frame codes a retry cannot change.
@@ -624,6 +627,26 @@ async function sendCohortEntityComment(route, text, o = {}) {
624
627
  // The one public entry point
625
628
  // ---------------------------------------------------------------------------
626
629
 
630
+ // Refuse any outbound body carrying raw scaffold markup. A closing </thinking>,
631
+ // an <assistant> wrapper and a <user_message> marker have each reached a shared
632
+ // room, from three separate seats. The seam is the join between the daemon
633
+ // placeholder and the generated output; whatever the cause on a given seat,
634
+ // nothing carrying these markers may leave it. Permanent refusal (no retry),
635
+ // same shape as the persona-leak gate: the caller escalates, never re-sends.
636
+ const SCAFFOLD_MARKER_RE = /<\/?(thinking|assistant|user_message|user|system|antml:[a-z_]+)>/i;
637
+
638
+ /**
639
+ * The first raw scaffold marker in `text`, or null when it carries none.
640
+ * Prose that merely NAMES a marker ("the thinking tag") is not a leak — only
641
+ * the literal angle-bracketed form matches.
642
+ * @param {string} text
643
+ * @returns {string|null}
644
+ */
645
+ export function scaffoldMarkerLeak(text) {
646
+ const m = typeof text === "string" ? text.match(SCAFFOLD_MARKER_RE) : null;
647
+ return m ? m[0] : null;
648
+ }
649
+
627
650
  /**
628
651
  * Deliver `text` to the human behind `item`. No generation, no model, no
629
652
  * budget — only transport.
@@ -657,6 +680,12 @@ export async function deliver(item, text, o = {}) {
657
680
  if (!item || !text || !String(text).trim()) {
658
681
  return { sent: false, via: null, error: "nothing to deliver" };
659
682
  }
683
+ const leak = scaffoldMarkerLeak(text);
684
+ if (leak) {
685
+ const surface = (item && item.channel_id) ? "room" : "unknown";
686
+ try { console.error(`[deliver] refused: raw scaffold marker ${JSON.stringify(leak)} in outbound body (permanent, not retrying)`); } catch { /* */ }
687
+ return { sent: false, via: null, permanent: true, channel: item && item.channel_id, surface, code: "FORBIDDEN_SCOPE", error: `FORBIDDEN_SCOPE: raw scaffold marker ${leak} in outbound body — strip the marker; never send reasoning or transcript wrappers` };
688
+ }
660
689
  // `permanent` says retrying changes nothing. A caller that cannot tell the
661
690
  // difference between "hq blipped" and "there is no transport for telegram"
662
691
  // retries both at the same cadence, which is how an impossible send becomes an