@cohortapp/agent-sdk 2.17.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 (526) 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.mjs +8 -6
  23. package/lib/collective/global-config.mjs +63 -1
  24. package/lib/collective/presence.mjs +142 -5
  25. package/lib/comms/send-gate.mjs +559 -1
  26. package/lib/diagnostics/alerts.mjs +49 -0
  27. package/lib/diagnostics/cadence-output-freshness.mjs +288 -0
  28. package/lib/engine/agents/definitions.mjs +343 -0
  29. package/lib/engine/agents/persist.mjs +275 -0
  30. package/lib/engine/agents/runtime.mjs +748 -0
  31. package/lib/engine/agents/usage.mjs +95 -0
  32. package/lib/engine/auth-status.mjs +139 -0
  33. package/lib/engine/budget.mjs +194 -0
  34. package/lib/engine/cli.mjs +1204 -0
  35. package/lib/engine/commands/index.mjs +269 -0
  36. package/lib/engine/context/budget.mjs +219 -0
  37. package/lib/engine/context/cache.mjs +125 -0
  38. package/lib/engine/context/child-env.mjs +215 -0
  39. package/lib/engine/context/compaction.mjs +342 -0
  40. package/lib/engine/context/images.mjs +90 -0
  41. package/lib/engine/context/instructions.mjs +327 -0
  42. package/lib/engine/context/lazy-instructions.mjs +169 -0
  43. package/lib/engine/context/manager.mjs +182 -0
  44. package/lib/engine/context/real-path.mjs +91 -0
  45. package/lib/engine/context/secret-values.mjs +163 -0
  46. package/lib/engine/context/settings.mjs +274 -0
  47. package/lib/engine/context/stream-input.mjs +159 -0
  48. package/lib/engine/guard.mjs +152 -0
  49. package/lib/engine/hooks.mjs +713 -0
  50. package/lib/engine/loop.mjs +560 -0
  51. package/lib/engine/mcp/client.mjs +254 -0
  52. package/lib/engine/mcp/config.mjs +301 -0
  53. package/lib/engine/mcp/http.mjs +201 -0
  54. package/lib/engine/mcp/index.mjs +146 -0
  55. package/lib/engine/mcp/jsonrpc.mjs +147 -0
  56. package/lib/engine/mcp/naming.mjs +66 -0
  57. package/lib/engine/mcp/resources.mjs +89 -0
  58. package/lib/engine/mcp/results.mjs +133 -0
  59. package/lib/engine/mcp/stdio.mjs +137 -0
  60. package/lib/engine/mcp/supervisor.mjs +116 -0
  61. package/lib/engine/messages.mjs +104 -0
  62. package/lib/engine/output/json.mjs +164 -0
  63. package/lib/engine/output/stream-json.mjs +266 -0
  64. package/lib/engine/permissions.mjs +845 -0
  65. package/lib/engine/process-identity.mjs +164 -0
  66. package/lib/engine/process-tree.mjs +551 -0
  67. package/lib/engine/prompt.mjs +60 -0
  68. package/lib/engine/session/store.mjs +299 -0
  69. package/lib/engine/session-runtime/args.mjs +97 -0
  70. package/lib/engine/session-runtime/host.mjs +143 -0
  71. package/lib/engine/session-runtime/inbox.mjs +122 -0
  72. package/lib/engine/session-runtime/notifications.mjs +129 -0
  73. package/lib/engine/session-runtime/registry.mjs +328 -0
  74. package/lib/engine/session-runtime/runner.mjs +344 -0
  75. package/lib/engine/session-runtime/socket.mjs +212 -0
  76. package/lib/engine/session-runtime/wakeup.mjs +115 -0
  77. package/lib/engine/skills/index.mjs +321 -0
  78. package/lib/engine/tools/bash-background.mjs +533 -0
  79. package/lib/engine/tools/bash.mjs +216 -0
  80. package/lib/engine/tools/edit.mjs +97 -0
  81. package/lib/engine/tools/glob.mjs +81 -0
  82. package/lib/engine/tools/grep.mjs +224 -0
  83. package/lib/engine/tools/index.mjs +84 -0
  84. package/lib/engine/tools/list-agents.mjs +32 -0
  85. package/lib/engine/tools/ls.mjs +127 -0
  86. package/lib/engine/tools/monitor.mjs +82 -0
  87. package/lib/engine/tools/notebook-edit.mjs +218 -0
  88. package/lib/engine/tools/read.mjs +103 -0
  89. package/lib/engine/tools/schedule-wakeup.mjs +45 -0
  90. package/lib/engine/tools/schema.mjs +144 -0
  91. package/lib/engine/tools/send-message.mjs +77 -0
  92. package/lib/engine/tools/session.mjs +70 -0
  93. package/lib/engine/tools/todo.mjs +144 -0
  94. package/lib/engine/tools/toolsearch.mjs +217 -0
  95. package/lib/engine/tools/walk.mjs +193 -0
  96. package/lib/engine/tools/web-switch.mjs +31 -0
  97. package/lib/engine/tools/webfetch-html.mjs +387 -0
  98. package/lib/engine/tools/webfetch-net.mjs +340 -0
  99. package/lib/engine/tools/webfetch.mjs +198 -0
  100. package/lib/engine/tools/websearch.mjs +91 -0
  101. package/lib/engine/tools/workflow.mjs +95 -0
  102. package/lib/engine/tools/write.mjs +76 -0
  103. package/lib/engine/tui/line-editor.mjs +137 -0
  104. package/lib/engine/tui/render.mjs +86 -0
  105. package/lib/engine/tui/tui.mjs +274 -0
  106. package/lib/engine/wire/anthropic-messages.mjs +263 -0
  107. package/lib/engine/wire/effort.mjs +36 -0
  108. package/lib/engine/wire/errors.mjs +496 -0
  109. package/lib/engine/wire/http.mjs +441 -0
  110. package/lib/engine/wire/index.mjs +76 -0
  111. package/lib/engine/wire/openai-chat.mjs +332 -0
  112. package/lib/engine/wire/prompt-cache.mjs +79 -0
  113. package/lib/engine/wire/search.mjs +140 -0
  114. package/lib/engine/wire/sse.mjs +114 -0
  115. package/lib/engine/wire/stall.mjs +349 -0
  116. package/lib/engine/wire/token-provider.mjs +175 -0
  117. package/lib/engine/wire/usage.mjs +192 -0
  118. package/lib/engine/workflow/host.mjs +524 -0
  119. package/lib/engine/workflow/journal.mjs +188 -0
  120. package/lib/engine/workflow/json-schema.mjs +171 -0
  121. package/lib/engine/workflow/meta.mjs +329 -0
  122. package/lib/engine/workflow/notifications.mjs +52 -0
  123. package/lib/engine/workflow/runtime.mjs +447 -0
  124. package/lib/engine/workflow/sandbox.mjs +534 -0
  125. package/lib/engine/workflow/worker.mjs +141 -0
  126. package/lib/engine/workflow/worktree.mjs +74 -0
  127. package/lib/execution/disposition.mjs +1 -1
  128. package/lib/execution/intake.mjs +10 -0
  129. package/lib/execution/surface-policy.mjs +15 -0
  130. package/lib/learning/curator.mjs +8 -6
  131. package/lib/learning/reflect.mjs +8 -6
  132. package/lib/model-router/catalog/cohort.yaml +137 -0
  133. package/lib/model-router/catalog.mjs +118 -1
  134. package/lib/model-router/failover.mjs +67 -16
  135. package/lib/model-router/llm-task.mjs +39 -3
  136. package/lib/model-router/resolve.mjs +89 -3
  137. package/lib/model-router/spawn.mjs +46 -47
  138. package/lib/model-router/taxonomy.mjs +126 -4
  139. package/lib/org/cost-sync.mjs +141 -11
  140. package/lib/org/inbound/broadcast.mjs +289 -0
  141. package/lib/org/inbound/collective.mjs +375 -0
  142. package/lib/org/inbound/directedness.mjs +96 -8
  143. package/lib/org/inbound/facts.mjs +78 -2
  144. package/lib/org/inbound/project.mjs +22 -0
  145. package/lib/org/inbound/surfaces.mjs +14 -0
  146. package/lib/org/llm-token.mjs +879 -0
  147. package/lib/org/mesh.mjs +61 -0
  148. package/lib/org/messaging.mjs +3 -1
  149. package/lib/org/protocol.checksum +1 -1
  150. package/lib/org/protocol.mjs +15 -0
  151. package/lib/org/quota.mjs +520 -0
  152. package/lib/org/tool-surface.mjs +104 -16
  153. package/lib/org/ui-parity.mjs +16 -1
  154. package/lib/org/work-ledger.mjs +37 -6
  155. package/lib/rate-guard.mjs +114 -1
  156. package/lib/resource-governor.mjs +41 -6
  157. package/lib/runtime/adapter.mjs +823 -0
  158. package/lib/runtime/child-env.mjs +191 -0
  159. package/lib/runtime/legacy-shell-guard.mjs +97 -0
  160. package/lib/runtime/seat-engine.mjs +162 -0
  161. package/lib/session/ask-ledger.mjs +271 -0
  162. package/lib/session/current-work.mjs +676 -0
  163. package/lib/session/feed-core.mjs +40 -3
  164. package/lib/session/launch-args.mjs +56 -4
  165. package/lib/session/status-summary.mjs +26 -9
  166. package/lib/session/upgrade-notice.mjs +42 -0
  167. package/lib/setup/claude-probe.mjs +117 -13
  168. package/lib/setup/enrich.mjs +13 -10
  169. package/lib/setup/sections/model.mjs +39 -13
  170. package/lib/telemetry/collect.mjs +208 -9
  171. package/lib/upgrade/ignored-drift.mjs +105 -0
  172. package/lib/voice/post-call-brief.mjs +30 -17
  173. package/package.json +13 -3
  174. package/plugins/maestro-skills/skills/board-work.md +5 -0
  175. package/plugins/maestro-skills/skills/inbound-triage.md +56 -15
  176. package/plugins/maestro-skills/skills/main-session.md +18 -7
  177. package/scripts/ci/check-tarball-fidelity.mjs +126 -2
  178. package/scripts/ci/run-tests.mjs +47 -19
  179. package/scripts/cohort-llm/api-key-helper.mjs +92 -0
  180. package/scripts/collective/hook-runner.mjs +29 -2
  181. package/scripts/continuous-monitor.sh +13 -0
  182. package/scripts/cost/track-claude-usage.mjs +15 -0
  183. package/scripts/daemon/agent-daemon.mjs +408 -20
  184. package/scripts/daemon/assurance.mjs +48 -12
  185. package/scripts/daemon/cadence-consumer.mjs +218 -68
  186. package/scripts/daemon/cadence-handlers.mjs +73 -4
  187. package/scripts/daemon/classifier.mjs +75 -26
  188. package/scripts/daemon/context-compiler.mjs +51 -37
  189. package/scripts/daemon/deliver.mjs +30 -1
  190. package/scripts/daemon/dispatcher.mjs +595 -149
  191. package/scripts/daemon/health.mjs +14 -1
  192. package/scripts/daemon/maestro-daemon.mjs +11 -0
  193. package/scripts/daemon/prompt-builder.mjs +24 -0
  194. package/scripts/daemon/responder.mjs +246 -79
  195. package/scripts/daemon/sdk-version.mjs +98 -16
  196. package/scripts/eval/probe-gateway.mjs +635 -0
  197. package/scripts/eval/replay/extract.mjs +270 -0
  198. package/scripts/eval/replay/grade.mjs +260 -0
  199. package/scripts/eval/replay/lib/config.mjs +50 -0
  200. package/scripts/eval/replay/lib/effects.mjs +65 -0
  201. package/scripts/eval/replay/lib/fixture.mjs +188 -0
  202. package/scripts/eval/replay/lib/judge.mjs +72 -0
  203. package/scripts/eval/replay/lib/redact.mjs +136 -0
  204. package/scripts/eval/replay/lib/sandbox.mjs +170 -0
  205. package/scripts/eval/replay/lib/schema-check.mjs +63 -0
  206. package/scripts/eval/replay/lib/transcript.mjs +76 -0
  207. package/scripts/eval/replay/mcp-replay-stub.mjs +101 -0
  208. package/scripts/eval/replay/report.mjs +185 -0
  209. package/scripts/eval/replay/run.mjs +404 -0
  210. package/scripts/fleet/rollout.mjs +1094 -0
  211. package/scripts/hooks/pre-send-audit.sh +36 -245
  212. package/scripts/hooks/pre-write-yaml-validate.mjs +275 -0
  213. package/scripts/hooks/validate-state-yaml.sh +190 -0
  214. package/scripts/huddle/huddle-llm.mjs +361 -0
  215. package/scripts/huddle/huddle-server.mjs +46 -121
  216. package/scripts/local-triggers/autoupdate.sh +448 -78
  217. package/scripts/local-triggers/run-trigger.sh +13 -0
  218. package/scripts/maintenance/pin-integrity.mjs +364 -0
  219. package/scripts/poll-slack-events.sh +41 -9
  220. package/scripts/poller/slack-socket-mode.mjs +28 -3
  221. package/scripts/session/supervisor.mjs +80 -13
  222. package/scripts/spawn-session.sh +13 -0
  223. package/bin/maestro.test.mjs +0 -1574
  224. package/lib/action-executor.test.mjs +0 -871
  225. package/lib/archetype.test.mjs +0 -132
  226. package/lib/assurance/plan-note.test.mjs +0 -234
  227. package/lib/assurance/room-budget.test.mjs +0 -486
  228. package/lib/assurance/tier.test.mjs +0 -174
  229. package/lib/autonomy.test.mjs +0 -66
  230. package/lib/backlog.test.mjs +0 -302
  231. package/lib/backup/policy.test.mjs +0 -305
  232. package/lib/budget-escalate.test.mjs +0 -232
  233. package/lib/budget-guard.envelope.test.mjs +0 -476
  234. package/lib/budget-guard.test.mjs +0 -427
  235. package/lib/cadence-bus-requeue.test.mjs +0 -83
  236. package/lib/cadence-bus-schedule.test.mjs +0 -194
  237. package/lib/cadence-bus.test.mjs +0 -720
  238. package/lib/cadences.test.mjs +0 -230
  239. package/lib/capability/inventory.test.mjs +0 -232
  240. package/lib/capability.test.mjs +0 -78
  241. package/lib/channels/base-adapter.test.mjs +0 -590
  242. package/lib/channels/channels.test.mjs +0 -371
  243. package/lib/channels/contract.test.mjs +0 -162
  244. package/lib/channels/inbox-item.test.mjs +0 -368
  245. package/lib/channels/orgmail/adapter.test.mjs +0 -448
  246. package/lib/channels/pairing.test.mjs +0 -270
  247. package/lib/channels/repeat-suppressor.test.mjs +0 -134
  248. package/lib/channels/slack-adapter.test.mjs +0 -212
  249. package/lib/channels/telegram-adapter.test.mjs +0 -306
  250. package/lib/channels/voice/adapter.test.mjs +0 -278
  251. package/lib/channels/whatsapp/adapter-baileys.test.mjs +0 -359
  252. package/lib/channels/whatsapp/baileys-typing.test.mjs +0 -154
  253. package/lib/charter.test.mjs +0 -89
  254. package/lib/claude-bin.test.mjs +0 -131
  255. package/lib/cli/board.test.mjs +0 -227
  256. package/lib/cli/design.test.mjs +0 -270
  257. package/lib/cli/doctor-checks.test.mjs +0 -336
  258. package/lib/cli/global-setup-extras.test.mjs +0 -462
  259. package/lib/cli/inbox.test.mjs +0 -230
  260. package/lib/cli/session-ack.test.mjs +0 -63
  261. package/lib/cli/session.test.mjs +0 -613
  262. package/lib/collective/capture.test.mjs +0 -121
  263. package/lib/collective/cards.test.mjs +0 -114
  264. package/lib/collective/config.test.mjs +0 -123
  265. package/lib/collective/global-config.test.mjs +0 -220
  266. package/lib/collective/global-skills.test.mjs +0 -126
  267. package/lib/collective/presence.test.mjs +0 -95
  268. package/lib/collective/recall.test.mjs +0 -116
  269. package/lib/collective/vendor-skills.test.mjs +0 -306
  270. package/lib/comms/send-gate.test.mjs +0 -770
  271. package/lib/comms.test.mjs +0 -41
  272. package/lib/context/budget.test.mjs +0 -252
  273. package/lib/context/history-scope.test.mjs +0 -79
  274. package/lib/cost/ledger-row.test.mjs +0 -183
  275. package/lib/design/design-md.test.mjs +0 -318
  276. package/lib/design/fixtures/DESIGN.golden.md +0 -238
  277. package/lib/design/fixtures/PRODUCT.golden.md +0 -67
  278. package/lib/design/fixtures/foundation.json +0 -133
  279. package/lib/design/refresh-gate.test.mjs +0 -144
  280. package/lib/design/write.test.mjs +0 -241
  281. package/lib/diagnostics/alerts.test.mjs +0 -318
  282. package/lib/diagnostics/backup-freshness.test.mjs +0 -185
  283. package/lib/diagnostics/counters.test.mjs +0 -206
  284. package/lib/diagnostics/events.test.mjs +0 -290
  285. package/lib/diagnostics/otel.test.mjs +0 -196
  286. package/lib/diagnostics/trace.test.mjs +0 -251
  287. package/lib/env-compat.test.mjs +0 -104
  288. package/lib/execution/disposition.test.mjs +0 -553
  289. package/lib/execution/drive.test.mjs +0 -270
  290. package/lib/execution/effects.test.mjs +0 -344
  291. package/lib/execution/intake.test.mjs +0 -389
  292. package/lib/execution/journal.test.mjs +0 -261
  293. package/lib/execution/match.test.mjs +0 -235
  294. package/lib/execution/pipeline.test.mjs +0 -392
  295. package/lib/execution/route.test.mjs +0 -186
  296. package/lib/execution/surface-policy.test.mjs +0 -162
  297. package/lib/fs-atomic.test.mjs +0 -72
  298. package/lib/fs-ownership.test.mjs +0 -158
  299. package/lib/goals/admission.test.mjs +0 -164
  300. package/lib/goals/classify.test.mjs +0 -167
  301. package/lib/goals/collaborate.test.mjs +0 -336
  302. package/lib/goals/gaps.test.mjs +0 -284
  303. package/lib/goals/loop.test.mjs +0 -845
  304. package/lib/hooks/bus.test.mjs +0 -387
  305. package/lib/identity/persona.test.mjs +0 -142
  306. package/lib/kpi-sensors.test.mjs +0 -278
  307. package/lib/kpi.test.mjs +0 -244
  308. package/lib/learning/config.test.mjs +0 -75
  309. package/lib/learning/counters.test.mjs +0 -69
  310. package/lib/learning/curator-consolidate.test.mjs +0 -238
  311. package/lib/learning/curator.test.mjs +0 -106
  312. package/lib/learning/reflect.test.mjs +0 -0
  313. package/lib/learning/session-index.test.mjs +0 -125
  314. package/lib/learning/skill-writer.test.mjs +0 -210
  315. package/lib/mandate/audit.test.mjs +0 -195
  316. package/lib/mandate/contract.test.mjs +0 -185
  317. package/lib/mandate/derive.test.mjs +0 -274
  318. package/lib/mandate/model.test.mjs +0 -164
  319. package/lib/mandate/refresh.test.mjs +0 -389
  320. package/lib/mcp/server.test.mjs +0 -426
  321. package/lib/model-router/auth-profiles.test.mjs +0 -580
  322. package/lib/model-router/catalog.test.mjs +0 -385
  323. package/lib/model-router/economics.test.mjs +0 -438
  324. package/lib/model-router/failover.test.mjs +0 -439
  325. package/lib/model-router/health.test.mjs +0 -338
  326. package/lib/model-router/integration-coverage.test.mjs +0 -831
  327. package/lib/model-router/integration.test.mjs +0 -564
  328. package/lib/model-router/ledger.test.mjs +0 -415
  329. package/lib/model-router/llm-task.test.mjs +0 -392
  330. package/lib/model-router/org-credentials.test.mjs +0 -265
  331. package/lib/model-router/pricing-refresh.test.mjs +0 -286
  332. package/lib/model-router/reconcile.test.mjs +0 -316
  333. package/lib/model-router/repair.test.mjs +0 -180
  334. package/lib/model-router/spawn.test.mjs +0 -446
  335. package/lib/model-router/taxonomy.test.mjs +0 -410
  336. package/lib/model-router.test.mjs +0 -1207
  337. package/lib/org/activity.test.mjs +0 -134
  338. package/lib/org/approvals.test.mjs +0 -216
  339. package/lib/org/awareness.test.mjs +0 -159
  340. package/lib/org/board-mine-cache.test.mjs +0 -53
  341. package/lib/org/board.test.mjs +0 -187
  342. package/lib/org/bootstrap-context.test.mjs +0 -153
  343. package/lib/org/client.test.mjs +0 -1206
  344. package/lib/org/cohort-client.test.mjs +0 -126
  345. package/lib/org/cost-sync.test.mjs +0 -153
  346. package/lib/org/doctor.test.mjs +0 -346
  347. package/lib/org/engagement-ledger.test.mjs +0 -112
  348. package/lib/org/engagement.test.mjs +0 -739
  349. package/lib/org/handoff.test.mjs +0 -269
  350. package/lib/org/inbound/directedness.test.mjs +0 -668
  351. package/lib/org/inbound/facts.test.mjs +0 -471
  352. package/lib/org/inbound/hydrate.test.mjs +0 -908
  353. package/lib/org/inbound/index.test.mjs +0 -429
  354. package/lib/org/inbound/project.test.mjs +0 -287
  355. package/lib/org/integration-tools.test.mjs +0 -160
  356. package/lib/org/keys.test.mjs +0 -92
  357. package/lib/org/knowledge.test.mjs +0 -326
  358. package/lib/org/leases.test.mjs +0 -235
  359. package/lib/org/mesh-directives.test.mjs +0 -110
  360. package/lib/org/mesh-integration.test.mjs +0 -127
  361. package/lib/org/mesh.test.mjs +0 -400
  362. package/lib/org/messaging.test.mjs +0 -471
  363. package/lib/org/param-contract.test.mjs +0 -477
  364. package/lib/org/policy.test.mjs +0 -237
  365. package/lib/org/protocol.checksum.test.mjs +0 -90
  366. package/lib/org/protocol.test.mjs +0 -323
  367. package/lib/org/push.test.mjs +0 -792
  368. package/lib/org/registry.test.mjs +0 -100
  369. package/lib/org/resource-tools.test.mjs +0 -361
  370. package/lib/org/tool-access.test.mjs +0 -144
  371. package/lib/org/tool-surface-integration.test.mjs +0 -120
  372. package/lib/org/tool-surface.test.mjs +0 -1268
  373. package/lib/org/typing.test.mjs +0 -291
  374. package/lib/org/ui-parity.test.mjs +0 -560
  375. package/lib/org/verify.test.mjs +0 -194
  376. package/lib/org/work-ledger.test.mjs +0 -273
  377. package/lib/plan/adoption-e2e.test.mjs +0 -366
  378. package/lib/plan/budget-enforcement.test.mjs +0 -400
  379. package/lib/plan/compile.test.mjs +0 -382
  380. package/lib/plan/emit.test.mjs +0 -269
  381. package/lib/plan/explain.test.mjs +0 -188
  382. package/lib/prompts/parallelism.test.mjs +0 -177
  383. package/lib/rag/rag.test.mjs +0 -505
  384. package/lib/rate-guard.test.mjs +0 -272
  385. package/lib/reactive-gate.test.mjs +0 -57
  386. package/lib/render.test.mjs +0 -68
  387. package/lib/resource-governor.test.mjs +0 -488
  388. package/lib/scheduling/dynamic-jobs.test.mjs +0 -344
  389. package/lib/scheduling/jitter.test.mjs +0 -140
  390. package/lib/secrets/broker.test.mjs +0 -280
  391. package/lib/secrets/providers.test.mjs +0 -274
  392. package/lib/security/audit-engine.test.mjs +0 -424
  393. package/lib/security/coerce-args.test.mjs +0 -281
  394. package/lib/security/dangerous-tools.test.mjs +0 -68
  395. package/lib/security/external-content.test.mjs +0 -84
  396. package/lib/security/redact.test.mjs +0 -441
  397. package/lib/security/secret-equal.test.mjs +0 -55
  398. package/lib/session/config.test.mjs +0 -92
  399. package/lib/session/feed-core.test.mjs +0 -198
  400. package/lib/session/first-run.test.mjs +0 -121
  401. package/lib/session/frontdoor.test.mjs +0 -205
  402. package/lib/session/handoffs.test.mjs +0 -183
  403. package/lib/session/identity.test.mjs +0 -180
  404. package/lib/session/inbox-claims.test.mjs +0 -286
  405. package/lib/session/launch-args.test.mjs +0 -157
  406. package/lib/session/liveness.test.mjs +0 -100
  407. package/lib/session/status-summary.test.mjs +0 -118
  408. package/lib/session-permissions.test.mjs +0 -120
  409. package/lib/setup/claude-probe.test.mjs +0 -187
  410. package/lib/setup/completeness.test.mjs +0 -110
  411. package/lib/setup/context-pack.test.mjs +0 -89
  412. package/lib/setup/enrich.test.mjs +0 -115
  413. package/lib/setup/enroll-from-cohort.test.mjs +0 -300
  414. package/lib/setup/integration.test.mjs +0 -162
  415. package/lib/setup/io.test.mjs +0 -77
  416. package/lib/setup/runner.test.mjs +0 -132
  417. package/lib/setup/sections/identity.test.mjs +0 -234
  418. package/lib/setup/sections/inventory.test.mjs +0 -198
  419. package/lib/setup/sections/learning.test.mjs +0 -81
  420. package/lib/setup/sections/mandate.test.mjs +0 -388
  421. package/lib/setup/sections/messaging.test.mjs +0 -127
  422. package/lib/setup/sections/model.test.mjs +0 -240
  423. package/lib/setup/sections/org.test.mjs +0 -346
  424. package/lib/setup/sections/orgmail.test.mjs +0 -118
  425. package/lib/setup/sections/recovery.test.mjs +0 -98
  426. package/lib/setup/sections/subagents.test.mjs +0 -429
  427. package/lib/setup/sections/verify.test.mjs +0 -175
  428. package/lib/setup/sot.test.mjs +0 -81
  429. package/lib/setup/state.test.mjs +0 -115
  430. package/lib/singleton.test.mjs +0 -151
  431. package/lib/subagents/cli.test.mjs +0 -389
  432. package/lib/subagents/client.test.mjs +0 -309
  433. package/lib/subagents/gap.test.mjs +0 -234
  434. package/lib/subagents/lock.test.mjs +0 -248
  435. package/lib/subagents/manifest.test.mjs +0 -175
  436. package/lib/subagents/refs.test.mjs +0 -204
  437. package/lib/subagents/resolve.test.mjs +0 -422
  438. package/lib/subagents/schema.test.mjs +0 -328
  439. package/lib/telemetry/alerts.test.mjs +0 -109
  440. package/lib/telemetry/collect.test.mjs +0 -1274
  441. package/lib/tool-definitions-integration.test.mjs +0 -83
  442. package/lib/tool-definitions.test.mjs +0 -437
  443. package/lib/upgrade/global-refresh.test.mjs +0 -65
  444. package/lib/upgrade/launchd-reconcile.test.mjs +0 -272
  445. package/lib/upgrade/post-steps.test.mjs +0 -200
  446. package/lib/upgrade/verify.test.mjs +0 -164
  447. package/lib/util/fetch-timeout.test.mjs +0 -202
  448. package/lib/util/reconnect.test.mjs +0 -369
  449. package/lib/util/unhandled.test.mjs +0 -216
  450. package/lib/voice/outbound.test.mjs +0 -69
  451. package/lib/voice/session-rotation.test.mjs +0 -114
  452. package/lib/voice/stt.test.mjs +0 -226
  453. package/lib/voice/voice.test.mjs +0 -990
  454. package/scripts/cadence/enqueue-cadence-tick.test.mjs +0 -187
  455. package/scripts/ci/check-docs-accuracy.test.mjs +0 -409
  456. package/scripts/ci/check-durable-write-seam.test.mjs +0 -90
  457. package/scripts/ci/check-no-build-artifacts.test.mjs +0 -71
  458. package/scripts/ci/check-no-residual-identity.test.mjs +0 -202
  459. package/scripts/ci/check-skill-packs.test.mjs +0 -495
  460. package/scripts/ci/check-subagent-frontmatter.test.mjs +0 -124
  461. package/scripts/ci/check.test.mjs +0 -194
  462. package/scripts/ci/conformance-org-api.test.mjs +0 -425
  463. package/scripts/cloud-relay/voice/relay-identity.test.mjs +0 -96
  464. package/scripts/collective/hook-runner.test.mjs +0 -173
  465. package/scripts/cost/fleet-digest.test.mjs +0 -207
  466. package/scripts/cost/track-claude-usage-pricing.test.mjs +0 -183
  467. package/scripts/cost/track-claude-usage.test.mjs +0 -148
  468. package/scripts/daemon/agent-daemon-board-mine.test.mjs +0 -96
  469. package/scripts/daemon/agent-daemon-design.test.mjs +0 -238
  470. package/scripts/daemon/agent-daemon-frontdoor.test.mjs +0 -60
  471. package/scripts/daemon/agent-daemon.test.mjs +0 -995
  472. package/scripts/daemon/assurance-e2e.test.mjs +0 -613
  473. package/scripts/daemon/assurance.test.mjs +0 -1791
  474. package/scripts/daemon/board-mirror.test.mjs +0 -165
  475. package/scripts/daemon/cadence-consumer-frontdoor.test.mjs +0 -393
  476. package/scripts/daemon/cadence-consumer-governance.test.mjs +0 -276
  477. package/scripts/daemon/cadence-consumer.test.mjs +0 -776
  478. package/scripts/daemon/cadence-handlers.test.mjs +0 -837
  479. package/scripts/daemon/classifier-identity.test.mjs +0 -137
  480. package/scripts/daemon/classifier.test.mjs +0 -266
  481. package/scripts/daemon/classify-kind.test.mjs +0 -40
  482. package/scripts/daemon/context-compiler.test.mjs +0 -406
  483. package/scripts/daemon/deliver.test.mjs +0 -564
  484. package/scripts/daemon/dispatcher-cooldown.test.mjs +0 -122
  485. package/scripts/daemon/dispatcher-governance.test.mjs +0 -1013
  486. package/scripts/daemon/dispatcher-resume.test.mjs +0 -166
  487. package/scripts/daemon/dispatcher-session-continuity.test.mjs +0 -365
  488. package/scripts/daemon/execution-ladder.test.mjs +0 -470
  489. package/scripts/daemon/goal-steward-cadence.test.mjs +0 -312
  490. package/scripts/daemon/inbox-deferral-session.test.mjs +0 -49
  491. package/scripts/daemon/inbox-deferral.test.mjs +0 -336
  492. package/scripts/daemon/inbox-wake.test.mjs +0 -199
  493. package/scripts/daemon/integration.test.mjs +0 -149
  494. package/scripts/daemon/lib/self-echo.test.mjs +0 -153
  495. package/scripts/daemon/lib/session-router.test.mjs +0 -554
  496. package/scripts/daemon/prompt-builder-preamble.test.mjs +0 -210
  497. package/scripts/daemon/prompt-builder.test.mjs +0 -556
  498. package/scripts/daemon/responder-cost.test.mjs +0 -68
  499. package/scripts/daemon/responder-history.test.mjs +0 -221
  500. package/scripts/daemon/sdk-version.test.mjs +0 -31
  501. package/scripts/daemon/session-lock.test.mjs +0 -252
  502. package/scripts/daemon/session-outcomes.test.mjs +0 -533
  503. package/scripts/daemon/typing-registry.test.mjs +0 -102
  504. package/scripts/hooks/pre-send-audit.test.mjs +0 -354
  505. package/scripts/huddle/huddle-prompt.test.mjs +0 -176
  506. package/scripts/local-triggers/autoupdate.test.mjs +0 -518
  507. package/scripts/local-triggers/generate-plists.test.mjs +0 -456
  508. package/scripts/media-generation/brand-clause.test.mjs +0 -135
  509. package/scripts/org/send-orgmail.first-contact.test.mjs +0 -102
  510. package/scripts/poller/inbox-privilege-injection.test.mjs +0 -167
  511. package/scripts/poller/inbox-scan-poller.test.mjs +0 -295
  512. package/scripts/poller/lib/cloud-relay-dedup.test.mjs +0 -133
  513. package/scripts/poller/slack-socket-mode.test.mjs +0 -805
  514. package/scripts/poller-launchd/install.test.mjs +0 -243
  515. package/scripts/restore-from-backup.test.mjs +0 -181
  516. package/scripts/session/feed.test.mjs +0 -196
  517. package/scripts/session/supervisor-sh.test.mjs +0 -218
  518. package/scripts/session/supervisor.test.mjs +0 -482
  519. package/scripts/setup/configure-macos.test.mjs +0 -306
  520. package/scripts/setup/gen-subagent-manifest.test.mjs +0 -124
  521. package/scripts/setup/generate-agent-package-json.test.mjs +0 -143
  522. package/scripts/setup/generate-capability.test.mjs +0 -134
  523. package/scripts/setup/init-agent.test.mjs +0 -370
  524. package/scripts/setup/init-skill-marketplace.test.mjs +0 -193
  525. package/scripts/vendor/sync-skill-packs.test.mjs +0 -103
  526. 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