@bastani/atomic 0.9.12-alpha.1 → 0.9.13-alpha.1

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 (265) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +12 -0
  3. package/dist/builtin/intercom/README.md +5 -12
  4. package/dist/builtin/intercom/broker/client.ts +11 -2
  5. package/dist/builtin/intercom/contact-supervisor-tool.ts +13 -3
  6. package/dist/builtin/intercom/index-heavy.ts +13 -3
  7. package/dist/builtin/intercom/index.ts +43 -19
  8. package/dist/builtin/intercom/intercom-utils.ts +15 -29
  9. package/dist/builtin/intercom/package.json +1 -1
  10. package/dist/builtin/intercom/source-ownership.ts +9 -12
  11. package/dist/builtin/mcp/CHANGELOG.md +12 -0
  12. package/dist/builtin/mcp/README.md +3 -1
  13. package/dist/builtin/mcp/index.ts +10 -16
  14. package/dist/builtin/mcp/package.json +1 -1
  15. package/dist/builtin/mcp/startup-warmup.ts +20 -8
  16. package/dist/builtin/subagents/CHANGELOG.md +36 -0
  17. package/dist/builtin/subagents/README.md +22 -30
  18. package/dist/builtin/subagents/package.json +1 -1
  19. package/dist/builtin/subagents/src/extension/doctor.ts +1 -1
  20. package/dist/builtin/subagents/src/extension/fanout-child.ts +76 -56
  21. package/dist/builtin/subagents/src/extension/index.ts +23 -32
  22. package/dist/builtin/subagents/src/extension/startup-maintenance.ts +25 -44
  23. package/dist/builtin/subagents/src/intercom/result-intercom.ts +7 -7
  24. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +166 -434
  25. package/dist/builtin/subagents/src/runs/background/notify.ts +29 -8
  26. package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +2 -2
  27. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +4 -4
  28. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +2 -2
  29. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +2 -2
  30. package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +1 -281
  31. package/dist/builtin/subagents/src/runs/foreground/execution-structured-retries.ts +11 -75
  32. package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +457 -0
  33. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +119 -246
  34. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +1 -1
  35. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +18 -9
  36. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +1 -1
  37. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +4 -4
  38. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +1 -646
  39. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +2 -7
  40. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +5 -5
  41. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +7 -8
  42. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +14 -5
  43. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +158 -93
  44. package/dist/builtin/subagents/src/runs/inprocess/background-single.ts +179 -0
  45. package/dist/builtin/subagents/src/runs/inprocess/background.ts +89 -0
  46. package/dist/builtin/subagents/src/runs/inprocess/child-policy.ts +27 -0
  47. package/dist/builtin/subagents/src/runs/inprocess/control-registry.ts +55 -0
  48. package/dist/builtin/subagents/src/runs/inprocess/control-status.ts +106 -0
  49. package/dist/builtin/subagents/src/runs/inprocess/index.ts +50 -0
  50. package/dist/builtin/subagents/src/runs/inprocess/nested-routing.ts +218 -0
  51. package/dist/builtin/subagents/src/runs/{shared/subagent-prompt-runtime.ts → inprocess/prompt-behavior.ts} +37 -75
  52. package/dist/builtin/subagents/src/runs/inprocess/runner.ts +1138 -0
  53. package/dist/builtin/subagents/src/runs/{shared/nested-events.ts → inprocess/runtime-support/nested-api.ts} +13 -7
  54. package/dist/builtin/subagents/src/runs/{shared/nested-events-control.ts → inprocess/runtime-support/nested-control.ts} +18 -17
  55. package/dist/builtin/subagents/src/runs/{shared/nested-events-core.ts → inprocess/runtime-support/nested-core.ts} +14 -61
  56. package/dist/builtin/subagents/src/runs/{shared/nested-events-projection.ts → inprocess/runtime-support/nested-projection.ts} +4 -10
  57. package/dist/builtin/subagents/src/runs/{shared/nested-events-registry.ts → inprocess/runtime-support/nested-registry.ts} +19 -4
  58. package/dist/builtin/subagents/src/runs/{shared/nested-render.ts → inprocess/runtime-support/nested-rendering.ts} +3 -3
  59. package/dist/builtin/subagents/src/runs/{shared/nested-events-sanitize.ts → inprocess/runtime-support/nested-sanitize.ts} +3 -3
  60. package/dist/builtin/subagents/src/runs/inprocess.ts +1 -0
  61. package/dist/builtin/subagents/src/runs/shared/dynamic-fanout.ts +10 -4
  62. package/dist/builtin/subagents/src/runs/shared/model-candidate-filter.ts +0 -1
  63. package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +15 -492
  64. package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +13 -11
  65. package/dist/builtin/subagents/src/runs/shared/run-history.ts +3 -5
  66. package/dist/builtin/subagents/src/runs/shared/single-output.ts +4 -4
  67. package/dist/builtin/subagents/src/runs/shared/workflow-graph.ts +5 -5
  68. package/dist/builtin/subagents/src/shared/types-async.ts +0 -1
  69. package/dist/builtin/subagents/src/shared/types-config.ts +18 -0
  70. package/dist/builtin/subagents/src/shared/types-results.ts +9 -2
  71. package/dist/builtin/subagents/src/slash/prompt-template-bridge.ts +2 -3
  72. package/dist/builtin/subagents/src/slash/slash-live-state.ts +2 -2
  73. package/dist/builtin/subagents/src/tui/render-chain-graph.ts +10 -4
  74. package/dist/builtin/subagents/src/tui/render-event-formatting.ts +12 -11
  75. package/dist/builtin/subagents/src/tui/render-result-compact.ts +49 -12
  76. package/dist/builtin/subagents/src/tui/render-result.ts +46 -17
  77. package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -1
  78. package/dist/builtin/subagents/src/tui/render-status-progress.ts +8 -5
  79. package/dist/builtin/subagents/src/tui/render-widget-graph.ts +0 -8
  80. package/dist/builtin/subagents/src/tui/render-widget.ts +0 -24
  81. package/dist/builtin/web-access/CHANGELOG.md +6 -0
  82. package/dist/builtin/web-access/package.json +1 -1
  83. package/dist/builtin/workflows/CHANGELOG.md +38 -0
  84. package/dist/builtin/workflows/README.md +13 -3
  85. package/dist/builtin/workflows/package.json +1 -1
  86. package/dist/builtin/workflows/src/durable/backend.ts +7 -0
  87. package/dist/builtin/workflows/src/durable/dbos-metadata.ts +11 -1
  88. package/dist/builtin/workflows/src/durable/resume-runtime.ts +1 -0
  89. package/dist/builtin/workflows/src/durable/tool-primitive.ts +4 -28
  90. package/dist/builtin/workflows/src/durable/types.ts +5 -0
  91. package/dist/builtin/workflows/src/engine/run.ts +17 -1
  92. package/dist/builtin/workflows/src/extension/atomic-stage-session.ts +12 -39
  93. package/dist/builtin/workflows/src/extension/config-file-loader.ts +10 -1
  94. package/dist/builtin/workflows/src/extension/config-loader.ts +1 -1
  95. package/dist/builtin/workflows/src/extension/dispatcher.ts +4 -0
  96. package/dist/builtin/workflows/src/extension/index.bundle.mjs +1151 -737
  97. package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +303 -38
  98. package/dist/builtin/workflows/src/extension/render-result.ts +4 -0
  99. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -3
  100. package/dist/builtin/workflows/src/extension/runtime.ts +7 -1
  101. package/dist/builtin/workflows/src/extension/wiring.ts +53 -11
  102. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +12 -3
  103. package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +5 -2
  104. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +9 -7
  105. package/dist/builtin/workflows/src/extension/workflow-status-summary.ts +11 -0
  106. package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +18 -1
  107. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +10 -8
  108. package/dist/builtin/workflows/src/extension/workflow-tool.ts +9 -4
  109. package/dist/builtin/workflows/src/runs/background/quit.ts +28 -4
  110. package/dist/builtin/workflows/src/runs/background/resume-acknowledgements.ts +2 -1
  111. package/dist/builtin/workflows/src/runs/background/status.ts +55 -8
  112. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +4 -0
  113. package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +3 -1
  114. package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +1 -1
  115. package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +1 -1
  116. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +688 -38
  117. package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +3 -1
  118. package/dist/builtin/workflows/src/runs/shared/model-fallback-failures.ts +19 -514
  119. package/dist/builtin/workflows/src/runs/shared/retry.ts +44 -0
  120. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +5 -0
  121. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +6 -0
  122. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +5 -1
  123. package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +5 -0
  124. package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +5 -0
  125. package/dist/builtin/workflows/src/shared/persistence-restore.ts +3 -0
  126. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
  127. package/dist/builtin/workflows/src/shared/run-indicator-status.ts +75 -0
  128. package/dist/builtin/workflows/src/shared/store-public-types.ts +43 -7
  129. package/dist/builtin/workflows/src/shared/store-run-methods.ts +42 -8
  130. package/dist/builtin/workflows/src/shared/store-stage-methods.ts +31 -8
  131. package/dist/builtin/workflows/src/shared/store-types.ts +34 -0
  132. package/dist/builtin/workflows/src/shared/timing.ts +10 -0
  133. package/dist/builtin/workflows/src/tui/chat-surface-message.ts +22 -2
  134. package/dist/builtin/workflows/src/tui/session-list.ts +1 -1
  135. package/dist/builtin/workflows/src/tui/session-overlays.ts +14 -10
  136. package/dist/builtin/workflows/src/tui/session-picker.ts +20 -4
  137. package/dist/builtin/workflows/src/tui/status-list.ts +31 -47
  138. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +9 -1
  139. package/dist/builtin/workflows/src/tui/widget.ts +16 -46
  140. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  141. package/dist/core/agent-session-auto-compaction.js +54 -11
  142. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  143. package/dist/core/agent-session-events.d.ts.map +1 -1
  144. package/dist/core/agent-session-events.js +49 -14
  145. package/dist/core/agent-session-events.js.map +1 -1
  146. package/dist/core/agent-session-methods.d.ts +13 -0
  147. package/dist/core/agent-session-methods.d.ts.map +1 -1
  148. package/dist/core/agent-session-methods.js.map +1 -1
  149. package/dist/core/agent-session-models.d.ts.map +1 -1
  150. package/dist/core/agent-session-models.js +12 -1
  151. package/dist/core/agent-session-models.js.map +1 -1
  152. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  153. package/dist/core/agent-session-prompt.js +4 -0
  154. package/dist/core/agent-session-prompt.js.map +1 -1
  155. package/dist/core/agent-session-retry.d.ts +21 -4
  156. package/dist/core/agent-session-retry.d.ts.map +1 -1
  157. package/dist/core/agent-session-retry.js +232 -106
  158. package/dist/core/agent-session-retry.js.map +1 -1
  159. package/dist/core/agent-session-state.d.ts.map +1 -1
  160. package/dist/core/agent-session-state.js +2 -1
  161. package/dist/core/agent-session-state.js.map +1 -1
  162. package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
  163. package/dist/core/agent-session-tool-hooks.js +12 -0
  164. package/dist/core/agent-session-tool-hooks.js.map +1 -1
  165. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  166. package/dist/core/agent-session-tool-registry.js +1 -1
  167. package/dist/core/agent-session-tool-registry.js.map +1 -1
  168. package/dist/core/agent-session-types.d.ts +3 -1
  169. package/dist/core/agent-session-types.d.ts.map +1 -1
  170. package/dist/core/agent-session-types.js.map +1 -1
  171. package/dist/core/agent-session.d.ts +12 -1
  172. package/dist/core/agent-session.d.ts.map +1 -1
  173. package/dist/core/agent-session.js +7 -0
  174. package/dist/core/agent-session.js.map +1 -1
  175. package/dist/core/extensions/context-types.d.ts +25 -0
  176. package/dist/core/extensions/context-types.d.ts.map +1 -1
  177. package/dist/core/extensions/context-types.js.map +1 -1
  178. package/dist/core/extensions/index.d.ts +1 -1
  179. package/dist/core/extensions/index.d.ts.map +1 -1
  180. package/dist/core/extensions/index.js.map +1 -1
  181. package/dist/core/extensions/runner-context.d.ts +2 -1
  182. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  183. package/dist/core/extensions/runner-context.js +4 -0
  184. package/dist/core/extensions/runner-context.js.map +1 -1
  185. package/dist/core/extensions/runner.d.ts +3 -2
  186. package/dist/core/extensions/runner.d.ts.map +1 -1
  187. package/dist/core/extensions/runner.js +3 -1
  188. package/dist/core/extensions/runner.js.map +1 -1
  189. package/dist/core/model-fallback-failures.d.ts +30 -0
  190. package/dist/core/model-fallback-failures.d.ts.map +1 -0
  191. package/dist/core/model-fallback-failures.js +610 -0
  192. package/dist/core/model-fallback-failures.js.map +1 -0
  193. package/dist/core/retry-policy.d.ts +30 -0
  194. package/dist/core/retry-policy.d.ts.map +1 -0
  195. package/dist/core/retry-policy.js +25 -0
  196. package/dist/core/retry-policy.js.map +1 -0
  197. package/dist/core/sdk-types.d.ts +8 -2
  198. package/dist/core/sdk-types.d.ts.map +1 -1
  199. package/dist/core/sdk-types.js.map +1 -1
  200. package/dist/core/sdk.d.ts.map +1 -1
  201. package/dist/core/sdk.js +6 -1
  202. package/dist/core/sdk.js.map +1 -1
  203. package/dist/core/session-manager-core.d.ts +2 -0
  204. package/dist/core/session-manager-core.d.ts.map +1 -1
  205. package/dist/core/session-manager-core.js +7 -0
  206. package/dist/core/session-manager-core.js.map +1 -1
  207. package/dist/index-extensions.d.ts +1 -1
  208. package/dist/index-extensions.d.ts.map +1 -1
  209. package/dist/index-extensions.js.map +1 -1
  210. package/dist/index.d.ts +3 -0
  211. package/dist/index.d.ts.map +1 -1
  212. package/dist/index.js +2 -0
  213. package/dist/index.js.map +1 -1
  214. package/docs/intercom.md +5 -10
  215. package/docs/settings.md +7 -1
  216. package/docs/subagents.md +19 -19
  217. package/docs/workflows.md +21 -5
  218. package/examples/extensions/gondolin/package-lock.json +3 -3
  219. package/npm-shrinkwrap.json +29 -29
  220. package/package.json +2 -2
  221. package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +0 -112
  222. package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +0 -543
  223. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +0 -140
  224. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +0 -279
  225. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +0 -99
  226. package/dist/builtin/subagents/src/runs/background/async-execution.ts +0 -17
  227. package/dist/builtin/subagents/src/runs/background/async-resume.ts +0 -402
  228. package/dist/builtin/subagents/src/runs/background/async-status.ts +0 -411
  229. package/dist/builtin/subagents/src/runs/background/completion-claims.ts +0 -196
  230. package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +0 -102
  231. package/dist/builtin/subagents/src/runs/background/parallel-groups.ts +0 -59
  232. package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +0 -300
  233. package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +0 -166
  234. package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +0 -77
  235. package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +0 -48
  236. package/dist/builtin/subagents/src/runs/background/result-status.ts +0 -87
  237. package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +0 -72
  238. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +0 -320
  239. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +0 -105
  240. package/dist/builtin/subagents/src/runs/background/run-status.ts +0 -358
  241. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +0 -457
  242. package/dist/builtin/subagents/src/runs/background/subagent-runner-dynamic.ts +0 -376
  243. package/dist/builtin/subagents/src/runs/background/subagent-runner-finalize.ts +0 -150
  244. package/dist/builtin/subagents/src/runs/background/subagent-runner-output.ts +0 -109
  245. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel-helpers.ts +0 -128
  246. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel.ts +0 -309
  247. package/dist/builtin/subagents/src/runs/background/subagent-runner-sequential.ts +0 -173
  248. package/dist/builtin/subagents/src/runs/background/subagent-runner-state.ts +0 -578
  249. package/dist/builtin/subagents/src/runs/background/subagent-runner-step.ts +0 -330
  250. package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +0 -330
  251. package/dist/builtin/subagents/src/runs/background/subagent-runner-types.ts +0 -210
  252. package/dist/builtin/subagents/src/runs/background/subagent-runner-utils.ts +0 -69
  253. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +0 -90
  254. package/dist/builtin/subagents/src/runs/background/top-level-async.ts +0 -12
  255. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-control.ts +0 -140
  256. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +0 -108
  257. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-types.ts +0 -17
  258. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +0 -558
  259. package/dist/builtin/subagents/src/runs/shared/attempt-watchdog.ts +0 -126
  260. package/dist/builtin/subagents/src/runs/shared/final-drain.ts +0 -39
  261. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +0 -339
  262. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +0 -165
  263. package/dist/builtin/subagents/src/runs/shared/spawn-env.ts +0 -21
  264. package/dist/builtin/subagents/src/shared/post-exit-stdio-guard.ts +0 -86
  265. /package/dist/builtin/subagents/src/runs/{shared/nested-path.ts → inprocess/runtime-support/nested-paths.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,40 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.9.13-alpha.1] - 2026-08-05
6
+
7
+ ### Added
8
+
9
+ - `CreateAgentSessionOptions` and `ExtensionContext` now carry an immutable typed subagent child capability policy for in-process tool registration ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
10
+ - `CreateAgentSessionOptions` now supports construction-time system-prompt and inherited-context transforms, allowing in-process child sessions to apply typed policy without extension injection ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
11
+
12
+ ### Changed
13
+
14
+ - Typed child policy now includes MCP direct-tool selection and admission-issued Intercom identity/capability, allowing in-process extensions to consume child policy without inheritable environment state ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
15
+ - Bundled subagent launches now use in-process `AgentSession` children with typed admission, canonical identities, and live async continuation; `async: true` work is owned by the parent process and does not survive parent exit ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
16
+
17
+ ### Fixed
18
+
19
+ - Workflow runs awaiting human input now use the blue `?` indicator in the BACKGROUND panel, `/workflow connect` picker, and `/workflow status` listing, including prompts raised by hidden nested workflow children; the indicator returns to the run's current state when the prompt resolves.
20
+ - Fixed main-chat model fallback to classify provider failures consistently with workflows, advance rejected credentials and incompatible or unavailable models to the next candidate, and restore the user-selected model at the next turn without overriding an explicit `/model` choice. A failure that requesting the same model again cannot repair now takes that model out of the chain for the rest of the turn at every reasoning level, so a fallback entry differing only by its `:low`/`:high` suffix is skipped instead of retrying the same dead credential; transient rate-limit and transport failures keep those reasoning variants ([#2170](https://github.com/bastani-inc/atomic/issues/2170)).
21
+ - Fixed a context overflow that compaction cannot resolve to advance the configured `fallbackModels` chain instead of ending the turn, so a larger-context candidate can answer. Compaction still runs first, and a compactable overflow spends no fallback candidate ([#2170](https://github.com/bastani-inc/atomic/issues/2170)).
22
+ - Fixed a reasoning-level change during a model fallback stranding the session on the fallback model. Changing reasoning effort is not a model choice, so it no longer cancels the pending restore; the next turn returns to the user-selected primary and keeps the reasoning level that was chosen. Only an explicit `/model` selection or model cycle cancels the restore ([#2170](https://github.com/bastani-inc/atomic/issues/2170)).
23
+ - Fixed gRPC `ResourceExhausted` provider errors, seen from providers such as NVIDIA NIM, bypassing the same-model auto-retry budget. They are now retried like other transient provider failures, matching upstream pi-ai, and still advance a configured fallback chain when the retries are exhausted ([#2170](https://github.com/bastani-inc/atomic/issues/2170)).
24
+
25
+ ## [0.9.12] - 2026-08-04
26
+
27
+ Cumulative release of the `0.9.12-alpha.1` prerelease. The summary below covers the user-visible outcome of that work; the per-change detail remains in the prerelease section below.
28
+
29
+ ### Added
30
+
31
+ - Compaction honors `<keepContext>` / `</keepContext>` tags. Wrap any part of a prompt you never want compressed, and every line of the span — tag lines included — is protected verbatim regardless of the compression ratio. The guarantee is mechanical rather than advisory: deletion ranges are split around protected lines after the planner responds. Because the tag lines are protected too, a span is re-detected on each subsequent boundary and stays protected for the life of the session. Detection is bounded on three sides, because the transcript it scans is untrusted: a tag must be the whole line after any role header, a span is scoped to one message so an unclosed tag stops at the end of its own message rather than running to the end of the region, and tags inside tool results are inert — user and assistant messages may both protect, so prompts, steering, and an agent's own pinned information all work, but file, page, or command output an agent reads cannot mark itself unreclaimable or persist through compaction ahead of real content. Protected lines count against the keep target rather than raising it, so the compression ratio stays a real bound on output size and the unprotected remainder compresses harder. Results report force-preserved ranges as `keptRanges` ([#2172](https://github.com/bastani-inc/atomic/issues/2172)).
32
+
33
+ ### Fixed
34
+
35
+ - The compaction relevance query is no longer truncated to 1,000 characters. Truncation made prompt section order the retention policy: for a long structured prompt only the leading section reached the planner, so a constraint stated later could not influence what was kept, while the objective it qualified survived and was acted on. Long queries are safe — an oversized planner request surfaces as an explicit provider-overflow failure rather than silent truncation ([#2172](https://github.com/bastani-inc/atomic/issues/2172)).
36
+ - Cleared three advisories in the shipped dependency tree. `undici` moves 8.5.0 → 8.9.0, which covers five advisories against 8.0.0–8.8.0 — response desynchronization via the retry interceptor, two cross-user cache-directive disclosures, CRLF injection through a blob body `type`, and cookie-attribute injection — and it is the dispatcher behind `fetch_url` and every agent HTTP request. Transitively under `@modelcontextprotocol/sdk`, `ip-address` is pinned to 10.3.1 for three SSRF and trust-boundary bypasses (octal-decoded leading-zero octets, CIDR suffixes suppressing special-use classification, and misclassified IPv4-mapped/NAT64 addresses), and `hono` to 4.12.34 for a CORS-middleware ReDoS. `npm audit` is clean.
37
+ - Fixed bundled builtin extensions failing to load on Windows when shared modules were evaluated twice, so bundled workflows and tools initialize correctly.
38
+
5
39
  ## [0.9.12-alpha.1] - 2026-08-04
6
40
 
7
41
  ### Added
@@ -4,6 +4,18 @@ All notable changes to the `pi-intercom` extension will be documented in this fi
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.9.13-alpha.1] - 2026-08-05
8
+
9
+ ### Changed
10
+
11
+ - In-process child identities and supervisor capabilities now arrive through typed admission policy and are captured on each `IntercomClient` at connect time instead of being read from environment for every message. Descendants cannot inherit a parent's supervisor grant through process environment; legacy Atomic/Pi bridge metadata remains available for older hosts ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
12
+
13
+ ## [0.9.12] - 2026-08-04
14
+
15
+ ### Fixed
16
+
17
+ - Fixed bundled Intercom resources failing to load on Windows when shared modules used mixed `.ts` and `.js` import spellings.
18
+
7
19
  ## [0.9.12-alpha.1] - 2026-08-04
8
20
 
9
21
  ### Fixed
@@ -20,7 +20,7 @@ Sometimes you're running multiple Atomic/pi sessions — one researching, one ex
20
20
 
21
21
  Unlike pi-messenger (a shared chat room for multi-agent swarms), intercom is for targeted 1:1 communication where you pick the recipient.
22
22
 
23
- Intercom also integrates with delegated subagents: child agents get a child-only `contact_supervisor` tool when subagent bridge metadata is present. Atomic-prefixed bridge environment variables are supported, and legacy `PI_*` bridge metadata remains compatible. Atomic's subagent bridge also obtains a broker capability that binds the child session to the exact supervisor; client-authored channel flags are never trusted as cross-group authority. Use `reason: "need_decision"` for blocking clarification, `reason: "interview_request"` for multiple structured supervisor answers, and `reason: "progress_update"` for meaningful plan-changing updates. Normal sessions only see the regular `intercom` tool.
23
+ Intercom also integrates with delegated subagents: in-process children receive a typed admission-issued identity for `contact_supervisor`, including their canonical run/agent/index metadata and any supervisor capability. The child identity is bound to its `IntercomClient` when it connects, so each message uses the same client-owned source and a descendant cannot inherit a parent's capability through process environment. Atomic-prefixed bridge environment variables and legacy `PI_*` metadata remain compatible for older integrations only. Use `reason: "need_decision"` for blocking clarification, `reason: "interview_request"` for multiple structured supervisor answers, and `reason: "progress_update"` for meaningful plan-changing updates. Normal sessions only see the regular `intercom` tool.
24
24
 
25
25
  ## In One Minute
26
26
 
@@ -227,20 +227,13 @@ The planner typically uses `send`. If you prefer manual approval for outgoing no
227
227
 
228
228
  ## Workflow: Subagent-to-Supervisor Escalation
229
229
 
230
- This workflow requires [`pi-subagents`](https://github.com/nicobailon/pi-subagents) to be installed and to supply child bridge metadata. When `pi-subagents` spawns a delegated child with that metadata, the child session gets a subagent-only `contact_supervisor` tool in addition to the regular `intercom` tool. Normal sessions never see `contact_supervisor`.
230
+ This workflow uses Atomic's in-process subagent admission. When the runtime admits a delegated child with supervisor coordination, the child session gets a subagent-only `contact_supervisor` tool in addition to the regular `intercom` tool. Normal sessions never see `contact_supervisor`.
231
231
 
232
232
  ### When the Tool Appears
233
233
 
234
- `contact_supervisor` only registers when `pi-subagents` sets all of these environment variables:
234
+ `contact_supervisor` is registered from the typed admission record. The record binds the supervisor target, canonical child identity, child index, session name, and broker-issued capability to the child session; these values are not inherited from environment variables. If the parent does not grant supervisor coordination, the session falls back to the regular `intercom` tool.
235
235
 
236
- - `PI_SUBAGENT_ORCHESTRATOR_TARGET` the supervisor session name or ID
237
- - `PI_SUBAGENT_RUN_ID` — the run identifier
238
- - `PI_SUBAGENT_CHILD_AGENT` — the agent type
239
- - `PI_SUBAGENT_CHILD_INDEX` — the child index within the run
240
-
241
- Atomic's bundled subagent bridge additionally supplies internal `ATOMIC_SUBAGENT_SUPERVISOR_CAPABILITY` and `ATOMIC_SUBAGENT_SUPERVISOR_SESSION_ID` values issued by the broker. They are not user-configurable authentication flags: the broker accepts the capability only for the child scope and supervisor session that requested it, and the parent restores the same secret if the broker reconnects. Legacy `PI_*` aliases remain readable where applicable.
242
-
243
- If any are missing, the session falls back to the regular `intercom` tool.
236
+ The child identity remains stable across foreground continuation, `async: true`, interruption, and cold resume. Intercom detach uses the same in-process continuation as async work, so the jobs widget and terminal envelope retain one canonical path.
244
237
 
245
238
  ### Three Reasons
246
239
 
@@ -254,7 +247,7 @@ Do not use `contact_supervisor` for routine completion handoffs. Return the fina
254
247
 
255
248
  Cross-group delivery uses a dedicated broker protocol. Ordinary raw `send` frames always remain group-isolated and are rejected if they include a forged `channel: "supervisor"` marker. A child can cross groups only after its broker-issued capability has bound its registered socket to the exact supervisor. The broker adds the `supervisor` channel marker to validated inbound traffic so parent relays can distinguish it. Replies cross back only when `replyTo` matches a recorded supervisor message in the exact reverse direction; fabricated thread IDs do not bypass isolation.
256
249
 
257
- During a foreground subagent run, Atomic probes for an exact live foreground owner before delivery. The matching child reserves the request, accepts a generation-scoped detach commit, and acknowledges it before asks, sends, decisions, interviews, and progress updates enter the parent's model-visible steering queue. A busy workflow stage first reserves the message in its AgentSession generation boundary, then waits inside that admission for the same detach handshake before model-visible queue insertion. This prevents terminal stage close from overtaking the handshake while still preventing the active subagent tool from blocking the child request that would release it; unclaimed traffic and a still-current receiver whose owner disappears before commit fall back to ordinary queue insertion. One accepted commit releases foreground supervision for every active member of a parallel group while retaining each child process and eventual result. Blocking calls remain alive until the parent sends the exact threaded reply; fire-and-forget calls create no reply waiter. Background and unmatched traffic for ordinary sessions keeps queued-until-idle behavior, and generation cancellation/replacement invalidates stale handshakes.
250
+ During a foreground subagent run, Atomic probes for an exact live foreground owner before delivery. The matching child reserves the request, accepts a generation-scoped detach commit, and acknowledges it before asks, sends, decisions, interviews, and progress updates enter the parent's model-visible steering queue. A busy workflow stage first reserves the message in its AgentSession generation boundary, then waits inside that admission for the same detach handshake before model-visible queue insertion. This prevents terminal stage close from overtaking the handshake while still preventing the active subagent tool from blocking the child request that would release it; unclaimed traffic and a still-current receiver whose owner disappears before commit fall back to ordinary queue insertion. One accepted commit releases foreground supervision for every active member of a parallel group while retaining each in-process session and eventual result. Blocking calls remain alive until the parent sends the exact threaded reply; fire-and-forget calls create no reply waiter. Background and unmatched traffic for ordinary sessions keeps queued-until-idle behavior, and generation cancellation/replacement invalidates stale handshakes.
258
251
 
259
252
  ### Example: Blocked Subagent Asks for Guidance
260
253
 
@@ -38,6 +38,8 @@ export class IntercomClient extends EventEmitter {
38
38
  private socket: net.Socket | null = null;
39
39
  private _sessionId: string | null = null;
40
40
  private _supervisorSessionId: string | null = null;
41
+ /** Source identity is captured once at connect, never read from env per message. */
42
+ private _messageSource: Message["source"] | undefined;
41
43
  private pendingSends = new PendingSendRegistry();
42
44
  private pendingLists = new Map<string, { resolve: (sessions: SessionInfo[]) => void; reject: (e: Error) => void }>();
43
45
  private pendingSupervisorAuthorizations = new Map<string, {
@@ -85,10 +87,16 @@ export class IntercomClient extends EventEmitter {
85
87
  return socket;
86
88
  }
87
89
 
88
- connect(session: Omit<SessionInfo, "id">, supervisor?: SupervisorRegistration, supervisorOwnerToken?: string): Promise<void> {
90
+ connect(
91
+ session: Omit<SessionInfo, "id">,
92
+ supervisor?: SupervisorRegistration,
93
+ supervisorOwnerToken?: string,
94
+ messageSource?: Message["source"],
95
+ ): Promise<void> {
89
96
  if (this.socket) {
90
97
  return Promise.reject(new Error("Already connected"));
91
98
  }
99
+ this._messageSource = messageSource ?? readSubagentMessageSource();
92
100
 
93
101
  return new Promise((resolve, reject) => {
94
102
  const socket = net.connect(BROKER_SOCKET);
@@ -141,6 +149,7 @@ export class IntercomClient extends EventEmitter {
141
149
  }
142
150
  this._sessionId = null;
143
151
  this._supervisorSessionId = null;
152
+ this._messageSource = undefined;
144
153
  this.disconnectError = null;
145
154
  if (connectionEstablished && !wasDisconnecting) {
146
155
  this.emit("disconnected", disconnectError);
@@ -463,7 +472,7 @@ export class IntercomClient extends EventEmitter {
463
472
  replyTo: options.replyTo,
464
473
  expectsReply: options.expectsReply,
465
474
  replyError: options.replyError,
466
- source: readSubagentMessageSource(),
475
+ source: this._messageSource,
467
476
  content: { text: options.text, attachments: options.attachments },
468
477
  };
469
478
  try {
@@ -19,7 +19,7 @@ import {
19
19
  } from "./intercom-utils.js";
20
20
 
21
21
  interface ContactSupervisorDeps {
22
- childOrchestratorMetadata: ChildOrchestratorMetadata | null;
22
+ childOrchestratorMetadata: ChildOrchestratorMetadata | null | (() => ChildOrchestratorMetadata | null);
23
23
  ensureConnected(reason: "tool"): Promise<IntercomClient>;
24
24
  syncPresenceIdentity(sessionId: string): void;
25
25
  resolveSessionTarget(activeClient: IntercomClient, nameOrId: string): Promise<string | null>;
@@ -35,7 +35,10 @@ interface ContactSupervisorDeps {
35
35
 
36
36
  export function registerContactSupervisorTool(pi: ExtensionAPI, deps: ContactSupervisorDeps): void {
37
37
  const { childOrchestratorMetadata, ensureConnected, syncPresenceIdentity, resolveSessionTarget, beginReplyWait, hasReplyWaiter } = deps;
38
- if (childOrchestratorMetadata) {
38
+ const getMetadata = typeof childOrchestratorMetadata === "function"
39
+ ? childOrchestratorMetadata
40
+ : () => childOrchestratorMetadata;
41
+ if (childOrchestratorMetadata !== null) {
39
42
  pi.registerTool({
40
43
  name: "contact_supervisor",
41
44
  label: "Contact Supervisor",
@@ -116,7 +119,14 @@ export function registerContactSupervisorTool(pi: ExtensionAPI, deps: ContactSup
116
119
  };
117
120
  }
118
121
 
119
- const metadata = childOrchestratorMetadata;
122
+ const metadata = getMetadata();
123
+ if (!metadata) {
124
+ return {
125
+ content: [{ type: "text", text: "Supervisor contact is unavailable for this session" }],
126
+ isError: true,
127
+ details: { error: true },
128
+ };
129
+ }
120
130
  let sendTo: string;
121
131
  if (connectedClient.supervisorSessionId || metadata.supervisor) {
122
132
  sendTo = connectedClient.supervisorSessionId ?? metadata.supervisor!.supervisorSessionId;
@@ -15,6 +15,7 @@ import { registerSubagentRelay } from "./subagent-relay.js";
15
15
  import { ForegroundDetachHandoff, handleForegroundInboundDelivery } from "./foreground-detach-handoff.js";
16
16
  import { routeIncomingReply } from "./reply-routing.js";
17
17
  import { INBOUND_FLUSH_DELAY_MS, INBOUND_IDLE_RETRY_MS, buildPresenceIdentity, formatAttachments, readChildOrchestratorMetadata, toError } from "./intercom-utils.js";
18
+ import { readSubagentMessageSource } from "./source-ownership.js";
18
19
  import { buildIncomingCustomMessage, createIncomingMessageSender } from "./incoming-message-delivery.js";
19
20
  import { InboundIdleQueue } from "./inbound-idle-queue.js";
20
21
  import { registerTerminalOrderingBarrier } from "./terminal-ordering-barrier.js";
@@ -46,8 +47,13 @@ export default function piIntercomExtension(pi: ExtensionAPI, testOverrides: Int
46
47
  };
47
48
  let client: IntercomClient | null = null;
48
49
  const config: IntercomConfig = loadConfig();
49
- const childOrchestratorMetadata = readChildOrchestratorMetadata();
50
+ const legacyChildOrchestratorMetadata = readChildOrchestratorMetadata();
50
51
  let runtimeContext: ExtensionContext | null = null;
52
+ function currentChildOrchestratorMetadata() {
53
+ return runtimeContext?.subagentPolicy !== undefined
54
+ ? readChildOrchestratorMetadata(runtimeContext.subagentPolicy)
55
+ : legacyChildOrchestratorMetadata;
56
+ }
51
57
  let currentSessionId: string | null = null;
52
58
  let currentModel = "unknown";
53
59
  let sessionStartedAt: number | null = null;
@@ -389,8 +395,12 @@ export default function piIntercomExtension(pi: ExtensionAPI, testOverrides: Int
389
395
  attachClientHandlers(nextClient);
390
396
  try {
391
397
  await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs);
398
+ const childMetadata = currentChildOrchestratorMetadata();
392
399
  await nextClient.connect(
393
- buildRegistration(), childOrchestratorMetadata?.supervisor, supervisorAuthorizations.ownerToken,
400
+ buildRegistration(),
401
+ childMetadata?.supervisor,
402
+ supervisorAuthorizations.ownerToken,
403
+ readSubagentMessageSource(runtimeContext?.subagentPolicy),
394
404
  );
395
405
  await supervisorAuthorizations.restore(nextClient);
396
406
  if (!getLiveContext(contextAtStart, generationAtStart)) {
@@ -470,7 +480,7 @@ export default function piIntercomExtension(pi: ExtensionAPI, testOverrides: Int
470
480
  });
471
481
 
472
482
  registerContactSupervisorTool(pi, {
473
- childOrchestratorMetadata,
483
+ childOrchestratorMetadata: currentChildOrchestratorMetadata,
474
484
  ensureConnected,
475
485
  syncPresenceIdentity,
476
486
  resolveSessionTarget: resolveSessionTargetId,
@@ -92,10 +92,10 @@ function renderHeavyToolResult(loadedHeavy: CapturedHeavy | null, name: string,
92
92
  return renderIntercomToolResult(name, args);
93
93
  }
94
94
  export default function intercom(pi: ExtensionAPI, options: LightweightIntercomOptions = {}) {
95
- const delegatedSessionName = readSubagentEnv("INTERCOM_SESSION_NAME");
96
- let heavyAttempt: HeavyAttempt | null = null;
97
- let loadedHeavy: IntercomHeavyHandle | null = null;
98
- let sessionSnapshot: SessionSnapshot | null = null;
95
+ const inheritedDelegatedSessionName = readSubagentEnv("INTERCOM_SESSION_NAME");
96
+ let heavyAttempt: HeavyAttempt | null = null;
97
+ let loadedHeavy: IntercomHeavyHandle | null = null;
98
+ let sessionSnapshot: SessionSnapshot | null = null;
99
99
  let lifecycleGeneration = 0;
100
100
  let nextLeaseId = 1;
101
101
  let activeLease = createLifecycleLease<ShutdownSnapshot>(nextLeaseId++);
@@ -229,21 +229,45 @@ export default function intercom(pi: ExtensionAPI, options: LightweightIntercomO
229
229
  );
230
230
  return promise;
231
231
  }
232
- pi.on("session_start", async (event, ctx) => {
233
- if (delegatedSessionName && typeof pi.setSessionName === "function") pi.setSessionName(delegatedSessionName);
234
- if (activeLease.retired) activeLease = createLifecycleLease<ShutdownSnapshot>(nextLeaseId++, activeLease.cleanupBarrier);
235
- const lease = activeLease;
236
- await waitForPriorCleanup(lease);
237
- if (sessionSnapshot) {
238
- activeLifecycle.turnStart = null;
239
- activeLifecycle.agentStart = null;
240
- activeLifecycle.activeTools.clear();
241
- activeLifecycle.modelSelect = null;
242
- }
243
- const generation = ++lifecycleGeneration;
244
- sessionSnapshot = { event, ctx, generation, lease };
245
- if (loadedHeavy) await ensureSessionStartReplayed(loadedHeavy.heavy, lease);
246
- });
232
+ let typedContactSupervisorRegistered = hasSubagentIntercomEnv();
233
+ const registerTypedContactSupervisor = (): void => {
234
+ if (typedContactSupervisorRegistered) return;
235
+ typedContactSupervisorRegistered = true;
236
+ pi.registerTool({
237
+ name: "contact_supervisor",
238
+ label: "Contact Supervisor",
239
+ description: "Subagent-only tool for contacting the supervisor agent that delegated this task.",
240
+ promptSnippet: "Subagent-only: contact the supervisor for decisions, interviews, or meaningful updates.",
241
+ parameters: Type.Object({
242
+ reason: Type.String({ enum: ["need_decision", "progress_update", "interview_request"] }),
243
+ message: Type.Optional(Type.String()),
244
+ interview: Type.Optional(Type.Unknown()),
245
+ }),
246
+ execute: (...args) => executeHeavyTool(loadHeavy, "contact_supervisor", args),
247
+ renderResult: (...args) => renderHeavyToolResult(loadedHeavy?.heavy ?? null, "contact_supervisor", args),
248
+ });
249
+ };
250
+ pi.on("session_start", async (event, ctx) => {
251
+ const typedIdentity = ctx.subagentPolicy?.intercom;
252
+ if (typedIdentity) {
253
+ if (typedIdentity.sessionName && typeof pi.setSessionName === "function") pi.setSessionName(typedIdentity.sessionName);
254
+ registerTypedContactSupervisor();
255
+ } else if (inheritedDelegatedSessionName && typeof pi.setSessionName === "function") {
256
+ pi.setSessionName(inheritedDelegatedSessionName);
257
+ }
258
+ if (activeLease.retired) activeLease = createLifecycleLease<ShutdownSnapshot>(nextLeaseId++, activeLease.cleanupBarrier);
259
+ const lease = activeLease;
260
+ await waitForPriorCleanup(lease);
261
+ if (sessionSnapshot) {
262
+ activeLifecycle.turnStart = null;
263
+ activeLifecycle.agentStart = null;
264
+ activeLifecycle.activeTools.clear();
265
+ activeLifecycle.modelSelect = null;
266
+ }
267
+ const generation = ++lifecycleGeneration;
268
+ sessionSnapshot = { event, ctx, generation, lease };
269
+ if (loadedHeavy) await ensureSessionStartReplayed(loadedHeavy.heavy, lease);
270
+ });
247
271
  pi.on("session_shutdown", async (event, ctx) => {
248
272
  const lease = activeLease;
249
273
  const generation = ++lifecycleGeneration;
@@ -1,5 +1,4 @@
1
- import type { ExtensionAPI } from "@bastani/atomic";
2
- import { APP_NAME, getEnvValue } from "@bastani/atomic";
1
+ import { type ExtensionAPI, type SubagentChildPolicy } from "@bastani/atomic";
3
2
  import type { Attachment, Message, SessionInfo, SupervisorRegistration } from "./types.js";
4
3
  import { DEFAULT_GROUP, normalizeGroup } from "./group.js";
5
4
 
@@ -12,14 +11,6 @@ export const SUBAGENT_SUPERVISOR_AUTHORIZATION_EVENT = "subagent:supervisor-auth
12
11
  export const INBOUND_FLUSH_DELAY_MS = 200;
13
12
  export const INBOUND_IDLE_RETRY_MS = 500;
14
13
  export const DEFAULT_UNNAMED_SESSION_ALIAS_PREFIX = "subagent-chat";
15
- const ENV_PREFIX = APP_NAME.toUpperCase();
16
- const SUBAGENT_ORCHESTRATOR_TARGET_ENV = `${ENV_PREFIX}_SUBAGENT_ORCHESTRATOR_TARGET`;
17
- const SUBAGENT_RUN_ID_ENV = `${ENV_PREFIX}_SUBAGENT_RUN_ID`;
18
- const SUBAGENT_CHILD_AGENT_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD_AGENT`;
19
- const SUBAGENT_CHILD_INDEX_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD_INDEX`;
20
- const SUBAGENT_INTERCOM_SESSION_NAME_ENV = `${ENV_PREFIX}_SUBAGENT_INTERCOM_SESSION_NAME`;
21
- const SUBAGENT_SUPERVISOR_CAPABILITY_ENV = `${ENV_PREFIX}_SUBAGENT_SUPERVISOR_CAPABILITY`;
22
- const SUBAGENT_SUPERVISOR_SESSION_ID_ENV = `${ENV_PREFIX}_SUBAGENT_SUPERVISOR_SESSION_ID`;
23
14
 
24
15
  export interface ChildOrchestratorMetadata {
25
16
  orchestratorTarget: string;
@@ -76,28 +67,23 @@ export function formatAttachments(attachments: Attachment[]): string {
76
67
  }
77
68
  return text;
78
69
  }
79
- export function readChildOrchestratorMetadata(): ChildOrchestratorMetadata | null {
80
- const orchestratorTarget = getEnvValue(SUBAGENT_ORCHESTRATOR_TARGET_ENV)?.trim();
81
- const runId = getEnvValue(SUBAGENT_RUN_ID_ENV)?.trim();
82
- const agent = getEnvValue(SUBAGENT_CHILD_AGENT_ENV)?.trim();
83
- const index = getEnvValue(SUBAGENT_CHILD_INDEX_ENV)?.trim();
84
- if (!orchestratorTarget || !runId || !agent || !index) {
85
- return null;
86
- }
87
- const sessionName = getEnvValue(SUBAGENT_INTERCOM_SESSION_NAME_ENV)?.trim();
88
- const capability = getEnvValue(SUBAGENT_SUPERVISOR_CAPABILITY_ENV)?.trim();
89
- const supervisorSessionId = getEnvValue(SUBAGENT_SUPERVISOR_SESSION_ID_ENV)?.trim();
70
+ export function childOrchestratorMetadataFromPolicy(policy?: SubagentChildPolicy): ChildOrchestratorMetadata | null {
71
+ const identity = policy?.intercom;
72
+ if (!identity) return null;
90
73
  return {
91
- orchestratorTarget,
92
- runId,
93
- agent,
94
- index,
95
- ...(sessionName ? { sessionName } : {}),
96
- ...(capability && supervisorSessionId
97
- ? { supervisor: { capability, supervisorSessionId } }
98
- : {}),
74
+ orchestratorTarget: identity.orchestratorTarget,
75
+ runId: identity.runId,
76
+ agent: identity.agent,
77
+ index: String(identity.index),
78
+ ...(identity.sessionName ? { sessionName: identity.sessionName } : {}),
79
+ ...(identity.supervisor ? { supervisor: identity.supervisor } : {}),
99
80
  };
100
81
  }
82
+
83
+ /** Resolve metadata only from the admission-issued typed child identity. */
84
+ export function readChildOrchestratorMetadata(policy?: SubagentChildPolicy): ChildOrchestratorMetadata | null {
85
+ return childOrchestratorMetadataFromPolicy(policy);
86
+ }
101
87
  export function formatChildOrchestratorMessage(kind: "ask" | "update" | "interview", metadata: ChildOrchestratorMetadata, message: string): string {
102
88
  const heading = kind === "ask"
103
89
  ? "Subagent needs a supervisor decision."
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/intercom",
3
- "version": "0.9.12-alpha.1",
3
+ "version": "0.9.13-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
6
6
  "contributors": [
@@ -1,11 +1,6 @@
1
- import { APP_NAME, getEnvValue } from "@bastani/atomic";
1
+ import { type SubagentChildPolicy } from "@bastani/atomic";
2
2
  import type { Message } from "./types.js";
3
3
 
4
- const ENV_PREFIX = APP_NAME.toUpperCase();
5
- const SUBAGENT_RUN_ID_ENV = `${ENV_PREFIX}_SUBAGENT_RUN_ID`;
6
- const SUBAGENT_CHILD_AGENT_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD_AGENT`;
7
- const SUBAGENT_CHILD_INDEX_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD_INDEX`;
8
-
9
4
  export function buildSubagentMessageSource(
10
5
  runIdValue: string | undefined,
11
6
  agentValue: string | undefined,
@@ -25,10 +20,12 @@ export function buildSubagentMessageSource(
25
20
  };
26
21
  }
27
22
 
28
- export function readSubagentMessageSource(): Message["source"] | undefined {
29
- return buildSubagentMessageSource(
30
- getEnvValue(SUBAGENT_RUN_ID_ENV),
31
- getEnvValue(SUBAGENT_CHILD_AGENT_ENV),
32
- getEnvValue(SUBAGENT_CHILD_INDEX_ENV),
33
- );
23
+ export function readSubagentMessageSource(policy?: SubagentChildPolicy): Message["source"] | undefined {
24
+ const identity = policy?.intercom;
25
+ if (!identity) return undefined;
26
+ return {
27
+ subagentRunId: identity.runId,
28
+ subagentAgent: identity.agent,
29
+ subagentIndex: identity.index,
30
+ };
34
31
  }
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.13-alpha.1] - 2026-08-05
11
+
12
+ ### Changed
13
+
14
+ - In-process subagents now receive MCP direct-tool selection through typed admission policy. Omitted selection preserves MCP configuration defaults, a list selects exact server/tool entries, and an empty list disables direct tools; the process-era environment bridge has been removed ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
15
+
16
+ ## [0.9.12] - 2026-08-04
17
+
18
+ ### Fixed
19
+
20
+ - Fixed bundled MCP resources failing to load on Windows when shared modules used mixed `.ts` and `.js` import spellings.
21
+
10
22
  ## [0.9.12-alpha.1] - 2026-08-04
11
23
 
12
24
  ### Fixed
@@ -240,7 +240,9 @@ To exclude specific tools while still using `directTools: true`, add `excludeToo
240
240
 
241
241
  Each direct tool costs ~150-300 tokens in the system prompt (name + description + schema). Good for targeted sets of 5-20 tools. For servers with 75+ tools, stick with the proxy or pick specific tools with a `string[]`.
242
242
 
243
- Direct tools register from the metadata cache in the Pi agent dir (`~/.pi/agent/mcp-cache.json` by default, or `$PI_CODING_AGENT_DIR/mcp-cache.json` when set), so no server connections are needed at startup when the cache is warm. On the first session after adding `directTools` to a new server, or when a child/subagent selects tools through `MCP_DIRECT_TOOLS`, the cache may not exist yet — tools fall back to proxy-only while the selected/configured direct-tool servers populate in the background, then the extension refreshes tool registration so the warmed direct tools become available in the current session. To force it immediately: `/mcp reconnect <server>`.
243
+ Direct tools register from the metadata cache in the Pi agent dir (`~/.pi/agent/mcp-cache.json` by default, or `$PI_CODING_AGENT_DIR/mcp-cache.json` when set), so no server connections are needed at startup when the cache is warm. On the first session after adding `directTools` to a new server, or when a child/subagent selects tools, the cache may not exist yet — tools fall back to proxy-only while the selected/configured direct-tool servers populate in the background, then the extension refreshes tool registration so the warmed direct tools become available in the current session. To force it immediately: `/mcp reconnect <server>`.
244
+
245
+ In-process subagents receive direct-tool selection through the typed admission policy rather than an environment bridge. An omitted `mcpDirectTools` field preserves the session's MCP configuration defaults, a list selects exactly those server/tool names, and an empty list explicitly disables direct tools. The legacy environment override is removed; parent sessions should use MCP configuration instead.
244
246
 
245
247
  When you change direct-tool toggles in `/mcp` or write new config through `/mcp setup`, the extension triggers Pi's normal reload flow automatically. That refreshes extensions, prompts, skills, and MCP tool registration in one shot, so newly configured direct tools can appear without a manual restart.
246
248
 
@@ -1,4 +1,4 @@
1
- import type { AgentToolUpdateCallback, ExtensionAPI, ExtensionContext, ToolInfo } from "@bastani/atomic";
1
+ import type { AgentToolUpdateCallback, ExtensionAPI, ExtensionContext, SubagentChildPolicy, ToolInfo } from "@bastani/atomic";
2
2
  import type { McpExtensionState } from "./state.js";
3
3
  import type { McpConfig } from "./types.ts";
4
4
  import type { MetadataCache } from "./metadata-cache.js";
@@ -55,22 +55,15 @@ export default function mcpAdapter(pi: ExtensionAPI) {
55
55
  async function registerDirectToolsFromConfig(
56
56
  config: McpConfig,
57
57
  cache: MetadataCache | null,
58
+ subagentPolicy?: SubagentChildPolicy,
58
59
  ): Promise<{ directToolCount: number; missingConfiguredDirectToolServers: string[] }> {
59
60
  const [{ resolveDirectTools, createDirectToolExecutor, getMissingConfiguredDirectToolServers }, { truncateAtWord }] = await Promise.all([
60
61
  import("./direct-tools.ts"),
61
62
  import("./utils.js"),
62
63
  ]);
63
64
  const prefix = config.settings?.toolPrefix ?? "server";
64
- const envRaw = process.env.MCP_DIRECT_TOOLS;
65
- const envDirectTools = envRaw?.split(",").map(s => s.trim()).filter(Boolean);
66
- const directSpecs = envRaw === "__none__"
67
- ? []
68
- : resolveDirectTools(
69
- config,
70
- cache,
71
- prefix,
72
- envDirectTools,
73
- );
65
+ const directTools = subagentPolicy?.mcpDirectTools;
66
+ const directSpecs = resolveDirectTools(config, cache, prefix, directTools === undefined ? undefined : [...directTools]);
74
67
  for (const spec of directSpecs) {
75
68
  if (registeredDirectToolNames.has(spec.prefixedName)) continue;
76
69
  registeredDirectToolNames.add(spec.prefixedName);
@@ -92,13 +85,13 @@ export default function mcpAdapter(pi: ExtensionAPI) {
92
85
  refreshTools?.();
93
86
  return {
94
87
  directToolCount: directSpecs.length,
95
- missingConfiguredDirectToolServers: getMissingConfiguredDirectToolServers(config, cache, envDirectTools),
88
+ missingConfiguredDirectToolServers: getMissingConfiguredDirectToolServers(config, cache, directTools),
96
89
  };
97
90
  }
98
91
 
99
- async function registerDirectTools(nextState: McpExtensionState): Promise<{ directToolCount: number; missingConfiguredDirectToolServers: string[] }> {
92
+ async function registerDirectTools(nextState: McpExtensionState, subagentPolicy?: SubagentChildPolicy): Promise<{ directToolCount: number; missingConfiguredDirectToolServers: string[] }> {
100
93
  const { loadMetadataCache } = await import("./metadata-cache.js");
101
- return registerDirectToolsFromConfig(nextState.config, loadMetadataCache());
94
+ return registerDirectToolsFromConfig(nextState.config, loadMetadataCache(), subagentPolicy);
102
95
  }
103
96
 
104
97
  async function shutdownOAuthFlow(reason: string): Promise<void> {
@@ -196,7 +189,7 @@ export default function mcpAdapter(pi: ExtensionAPI) {
196
189
  throw new Error(`${STALE_INITIALIZATION_PREFIX} after startup`);
197
190
  }
198
191
 
199
- const directToolState = await registerDirectTools(initializedState);
192
+ const directToolState = await registerDirectTools(initializedState, session.ctx.subagentPolicy);
200
193
  if (!isCurrentSession(session) || initPromise !== expectedPromise.current) {
201
194
  throw new Error(`${STALE_INITIALIZATION_PREFIX} after tool registration`);
202
195
  }
@@ -211,10 +204,11 @@ export default function mcpAdapter(pi: ExtensionAPI) {
211
204
  updateStatusBar(initializedState);
212
205
  let cancelWarmup: (() => void) | null = null;
213
206
  const warmup = scheduleMcpStartupWarmup(initializedState, {
207
+ subagentPolicy: session.ctx.subagentPolicy,
214
208
  shouldContinue: () => isCurrentSession(session) && state === initializedState,
215
209
  onDirectToolsChanged: async () => {
216
210
  if (!isCurrentSession(session) || state !== initializedState) return;
217
- await registerDirectTools(initializedState);
211
+ await registerDirectTools(initializedState, session.ctx.subagentPolicy);
218
212
  },
219
213
  onSettled: () => {
220
214
  if (isCurrentSession(session) && state === initializedState && startupWarmupCancel === cancelWarmup) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/mcp",
3
- "version": "0.9.12-alpha.1",
3
+ "version": "0.9.13-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension that adapts MCP (Model Context Protocol) servers into the coding agent. Fork of: https://github.com/nicobailon/pi-mcp-adapter",
6
6
  "contributors": [
@@ -1,3 +1,4 @@
1
+ import type { SubagentChildPolicy } from "@bastani/atomic";
1
2
  import type { McpExtensionState } from "./state.js";
2
3
  import { getMissingConfiguredDirectToolServers } from "./direct-tools.ts";
3
4
  import { loadMetadataCache } from "./metadata-cache.js";
@@ -7,9 +8,11 @@ import { logger } from "./logger.ts";
7
8
  import { updateMetadataCache, updateStatusBar } from "./init.js";
8
9
 
9
10
  export interface McpStartupWarmupOptions {
10
- shouldContinue?: () => boolean;
11
- onDirectToolsChanged?: () => void | Promise<void>;
12
- onSettled?: () => void;
11
+ /** Typed child selection issued during in-process admission. */
12
+ subagentPolicy?: SubagentChildPolicy;
13
+ shouldContinue?: () => boolean;
14
+ onDirectToolsChanged?: () => void | Promise<void>;
15
+ onSettled?: () => void;
13
16
  }
14
17
 
15
18
  export interface McpStartupWarmupHandle {
@@ -17,6 +20,17 @@ export interface McpStartupWarmupHandle {
17
20
  cancel(): void;
18
21
  }
19
22
 
23
+ export interface McpDirectToolsSelection {
24
+ readonly disabled: boolean;
25
+ readonly tools?: readonly string[];
26
+ }
27
+
28
+ /** Resolve direct-tool selection exclusively from typed admission policy. */
29
+ export function resolveMcpDirectToolsSelection(subagentPolicy?: SubagentChildPolicy): McpDirectToolsSelection {
30
+ const tools = subagentPolicy?.mcpDirectTools;
31
+ return { disabled: tools !== undefined && tools.length === 0, ...(tools === undefined ? {} : { tools: [...tools] }) };
32
+ }
33
+
20
34
  function deferToMacrotask(): Promise<void> {
21
35
  return new Promise((resolve) => setImmediate(resolve));
22
36
  }
@@ -31,12 +45,10 @@ export function scheduleMcpStartupWarmup(
31
45
  const promise = (async () => {
32
46
  await deferToMacrotask();
33
47
  if (!shouldContinue()) return;
48
+ const selection = resolveMcpDirectToolsSelection(options.subagentPolicy);
49
+ if (selection.disabled) return;
34
50
 
35
- const envDirect = process.env.MCP_DIRECT_TOOLS;
36
- if (envDirect === "__none__") return;
37
-
38
- const envDirectTools = envDirect?.split(",").map((item) => item.trim()).filter(Boolean);
39
- const missingCacheServers = getMissingConfiguredDirectToolServers(state.config, loadMetadataCache(), envDirectTools)
51
+ const missingCacheServers = getMissingConfiguredDirectToolServers(state.config, loadMetadataCache(), selection.tools)
40
52
  .filter((name) => state.manager.getConnection(name)?.status !== "connected");
41
53
  if (missingCacheServers.length === 0) return;
42
54