@bastani/atomic 0.9.12 → 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 (264) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +6 -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 +6 -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 +30 -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/package.json +1 -1
  82. package/dist/builtin/workflows/CHANGELOG.md +25 -0
  83. package/dist/builtin/workflows/README.md +13 -3
  84. package/dist/builtin/workflows/package.json +1 -1
  85. package/dist/builtin/workflows/src/durable/backend.ts +7 -0
  86. package/dist/builtin/workflows/src/durable/dbos-metadata.ts +11 -1
  87. package/dist/builtin/workflows/src/durable/resume-runtime.ts +1 -0
  88. package/dist/builtin/workflows/src/durable/tool-primitive.ts +4 -28
  89. package/dist/builtin/workflows/src/durable/types.ts +5 -0
  90. package/dist/builtin/workflows/src/engine/run.ts +17 -1
  91. package/dist/builtin/workflows/src/extension/atomic-stage-session.ts +12 -39
  92. package/dist/builtin/workflows/src/extension/config-file-loader.ts +10 -1
  93. package/dist/builtin/workflows/src/extension/config-loader.ts +1 -1
  94. package/dist/builtin/workflows/src/extension/dispatcher.ts +4 -0
  95. package/dist/builtin/workflows/src/extension/index.bundle.mjs +1151 -737
  96. package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +303 -38
  97. package/dist/builtin/workflows/src/extension/render-result.ts +4 -0
  98. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -3
  99. package/dist/builtin/workflows/src/extension/runtime.ts +7 -1
  100. package/dist/builtin/workflows/src/extension/wiring.ts +53 -11
  101. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +12 -3
  102. package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +5 -2
  103. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +9 -7
  104. package/dist/builtin/workflows/src/extension/workflow-status-summary.ts +11 -0
  105. package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +18 -1
  106. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +10 -8
  107. package/dist/builtin/workflows/src/extension/workflow-tool.ts +9 -4
  108. package/dist/builtin/workflows/src/runs/background/quit.ts +28 -4
  109. package/dist/builtin/workflows/src/runs/background/resume-acknowledgements.ts +2 -1
  110. package/dist/builtin/workflows/src/runs/background/status.ts +55 -8
  111. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +4 -0
  112. package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +3 -1
  113. package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +1 -1
  114. package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +1 -1
  115. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +688 -38
  116. package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +3 -1
  117. package/dist/builtin/workflows/src/runs/shared/model-fallback-failures.ts +19 -514
  118. package/dist/builtin/workflows/src/runs/shared/retry.ts +44 -0
  119. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +5 -0
  120. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +6 -0
  121. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +5 -1
  122. package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +5 -0
  123. package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +5 -0
  124. package/dist/builtin/workflows/src/shared/persistence-restore.ts +3 -0
  125. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
  126. package/dist/builtin/workflows/src/shared/run-indicator-status.ts +75 -0
  127. package/dist/builtin/workflows/src/shared/store-public-types.ts +43 -7
  128. package/dist/builtin/workflows/src/shared/store-run-methods.ts +42 -8
  129. package/dist/builtin/workflows/src/shared/store-stage-methods.ts +31 -8
  130. package/dist/builtin/workflows/src/shared/store-types.ts +34 -0
  131. package/dist/builtin/workflows/src/shared/timing.ts +10 -0
  132. package/dist/builtin/workflows/src/tui/chat-surface-message.ts +22 -2
  133. package/dist/builtin/workflows/src/tui/session-list.ts +1 -1
  134. package/dist/builtin/workflows/src/tui/session-overlays.ts +14 -10
  135. package/dist/builtin/workflows/src/tui/session-picker.ts +20 -4
  136. package/dist/builtin/workflows/src/tui/status-list.ts +31 -47
  137. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +9 -1
  138. package/dist/builtin/workflows/src/tui/widget.ts +16 -46
  139. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  140. package/dist/core/agent-session-auto-compaction.js +54 -11
  141. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  142. package/dist/core/agent-session-events.d.ts.map +1 -1
  143. package/dist/core/agent-session-events.js +49 -14
  144. package/dist/core/agent-session-events.js.map +1 -1
  145. package/dist/core/agent-session-methods.d.ts +13 -0
  146. package/dist/core/agent-session-methods.d.ts.map +1 -1
  147. package/dist/core/agent-session-methods.js.map +1 -1
  148. package/dist/core/agent-session-models.d.ts.map +1 -1
  149. package/dist/core/agent-session-models.js +12 -1
  150. package/dist/core/agent-session-models.js.map +1 -1
  151. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  152. package/dist/core/agent-session-prompt.js +4 -0
  153. package/dist/core/agent-session-prompt.js.map +1 -1
  154. package/dist/core/agent-session-retry.d.ts +21 -4
  155. package/dist/core/agent-session-retry.d.ts.map +1 -1
  156. package/dist/core/agent-session-retry.js +232 -106
  157. package/dist/core/agent-session-retry.js.map +1 -1
  158. package/dist/core/agent-session-state.d.ts.map +1 -1
  159. package/dist/core/agent-session-state.js +2 -1
  160. package/dist/core/agent-session-state.js.map +1 -1
  161. package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
  162. package/dist/core/agent-session-tool-hooks.js +12 -0
  163. package/dist/core/agent-session-tool-hooks.js.map +1 -1
  164. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  165. package/dist/core/agent-session-tool-registry.js +1 -1
  166. package/dist/core/agent-session-tool-registry.js.map +1 -1
  167. package/dist/core/agent-session-types.d.ts +3 -1
  168. package/dist/core/agent-session-types.d.ts.map +1 -1
  169. package/dist/core/agent-session-types.js.map +1 -1
  170. package/dist/core/agent-session.d.ts +12 -1
  171. package/dist/core/agent-session.d.ts.map +1 -1
  172. package/dist/core/agent-session.js +7 -0
  173. package/dist/core/agent-session.js.map +1 -1
  174. package/dist/core/extensions/context-types.d.ts +25 -0
  175. package/dist/core/extensions/context-types.d.ts.map +1 -1
  176. package/dist/core/extensions/context-types.js.map +1 -1
  177. package/dist/core/extensions/index.d.ts +1 -1
  178. package/dist/core/extensions/index.d.ts.map +1 -1
  179. package/dist/core/extensions/index.js.map +1 -1
  180. package/dist/core/extensions/runner-context.d.ts +2 -1
  181. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  182. package/dist/core/extensions/runner-context.js +4 -0
  183. package/dist/core/extensions/runner-context.js.map +1 -1
  184. package/dist/core/extensions/runner.d.ts +3 -2
  185. package/dist/core/extensions/runner.d.ts.map +1 -1
  186. package/dist/core/extensions/runner.js +3 -1
  187. package/dist/core/extensions/runner.js.map +1 -1
  188. package/dist/core/model-fallback-failures.d.ts +30 -0
  189. package/dist/core/model-fallback-failures.d.ts.map +1 -0
  190. package/dist/core/model-fallback-failures.js +610 -0
  191. package/dist/core/model-fallback-failures.js.map +1 -0
  192. package/dist/core/retry-policy.d.ts +30 -0
  193. package/dist/core/retry-policy.d.ts.map +1 -0
  194. package/dist/core/retry-policy.js +25 -0
  195. package/dist/core/retry-policy.js.map +1 -0
  196. package/dist/core/sdk-types.d.ts +8 -2
  197. package/dist/core/sdk-types.d.ts.map +1 -1
  198. package/dist/core/sdk-types.js.map +1 -1
  199. package/dist/core/sdk.d.ts.map +1 -1
  200. package/dist/core/sdk.js +6 -1
  201. package/dist/core/sdk.js.map +1 -1
  202. package/dist/core/session-manager-core.d.ts +2 -0
  203. package/dist/core/session-manager-core.d.ts.map +1 -1
  204. package/dist/core/session-manager-core.js +7 -0
  205. package/dist/core/session-manager-core.js.map +1 -1
  206. package/dist/index-extensions.d.ts +1 -1
  207. package/dist/index-extensions.d.ts.map +1 -1
  208. package/dist/index-extensions.js.map +1 -1
  209. package/dist/index.d.ts +3 -0
  210. package/dist/index.d.ts.map +1 -1
  211. package/dist/index.js +2 -0
  212. package/dist/index.js.map +1 -1
  213. package/docs/intercom.md +5 -10
  214. package/docs/settings.md +7 -1
  215. package/docs/subagents.md +19 -19
  216. package/docs/workflows.md +21 -5
  217. package/examples/extensions/gondolin/package-lock.json +3 -3
  218. package/npm-shrinkwrap.json +29 -29
  219. package/package.json +2 -2
  220. package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +0 -112
  221. package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +0 -543
  222. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +0 -140
  223. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +0 -279
  224. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +0 -99
  225. package/dist/builtin/subagents/src/runs/background/async-execution.ts +0 -17
  226. package/dist/builtin/subagents/src/runs/background/async-resume.ts +0 -402
  227. package/dist/builtin/subagents/src/runs/background/async-status.ts +0 -411
  228. package/dist/builtin/subagents/src/runs/background/completion-claims.ts +0 -196
  229. package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +0 -102
  230. package/dist/builtin/subagents/src/runs/background/parallel-groups.ts +0 -59
  231. package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +0 -300
  232. package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +0 -166
  233. package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +0 -77
  234. package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +0 -48
  235. package/dist/builtin/subagents/src/runs/background/result-status.ts +0 -87
  236. package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +0 -72
  237. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +0 -320
  238. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +0 -105
  239. package/dist/builtin/subagents/src/runs/background/run-status.ts +0 -358
  240. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +0 -457
  241. package/dist/builtin/subagents/src/runs/background/subagent-runner-dynamic.ts +0 -376
  242. package/dist/builtin/subagents/src/runs/background/subagent-runner-finalize.ts +0 -150
  243. package/dist/builtin/subagents/src/runs/background/subagent-runner-output.ts +0 -109
  244. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel-helpers.ts +0 -128
  245. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel.ts +0 -309
  246. package/dist/builtin/subagents/src/runs/background/subagent-runner-sequential.ts +0 -173
  247. package/dist/builtin/subagents/src/runs/background/subagent-runner-state.ts +0 -578
  248. package/dist/builtin/subagents/src/runs/background/subagent-runner-step.ts +0 -330
  249. package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +0 -330
  250. package/dist/builtin/subagents/src/runs/background/subagent-runner-types.ts +0 -210
  251. package/dist/builtin/subagents/src/runs/background/subagent-runner-utils.ts +0 -69
  252. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +0 -90
  253. package/dist/builtin/subagents/src/runs/background/top-level-async.ts +0 -12
  254. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-control.ts +0 -140
  255. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +0 -108
  256. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-types.ts +0 -17
  257. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +0 -558
  258. package/dist/builtin/subagents/src/runs/shared/attempt-watchdog.ts +0 -126
  259. package/dist/builtin/subagents/src/runs/shared/final-drain.ts +0 -39
  260. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +0 -339
  261. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +0 -165
  262. package/dist/builtin/subagents/src/runs/shared/spawn-env.ts +0 -21
  263. package/dist/builtin/subagents/src/shared/post-exit-stdio-guard.ts +0 -86
  264. /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,26 @@
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
+
5
25
  ## [0.9.12] - 2026-08-04
6
26
 
7
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.
@@ -4,6 +4,12 @@ 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
+
7
13
  ## [0.9.12] - 2026-08-04
8
14
 
9
15
  ### 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",
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,12 @@ 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
+
10
16
  ## [0.9.12] - 2026-08-04
11
17
 
12
18
  ### 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",
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
 
@@ -2,6 +2,36 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.9.13-alpha.1] - 2026-08-05
6
+
7
+ ### Breaking Changes
8
+
9
+ - `async: true` no longer survives parent exit. Async subagents now run as in-process children of the parent session on the same foreground executor, so quitting Atomic ends any in-flight async run. The child's canonical identity and its session file persist on disk and can be reloaded on a later start, but the running work does not continue in the background across a restart. The detached runner process that previously provided parent-exit survival has been deleted ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
10
+ - Removed the `ATOMIC_SUBAGENT_*` process-era environment bridge variables consumed by the deleted spawn path and the synthesized numeric child-result exit-code protocol (`0/1/-1/-2/143`). Child identity, policy, supervisor capability, and terminal outcomes now cross typed admission; results use required `status` (`ok | error | skipped | interrupted | continued`) plus `cause` and `stats` ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
11
+
12
+ ### Added
13
+
14
+ - Added the in-process subagent control-plane doors and `InProcessChildRunner` foundation backed by the Rust N-API registry, typed statuses, session statistics, and bounded result envelopes ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
15
+
16
+ ### Changed
17
+
18
+ - Nested in-process children now route live `interrupt` and cold `resume` actions directly through the Rust control plane. Nested event and control records use an in-memory host route while retaining the validated file shape for cold-start compatibility; session JSONL is flushed before forced interruption, and the former 200 ms nested-control polling loop is replaced by event-driven delivery ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
19
+ - In-process children now advance through their model-fallback ladder via the SDK session's `fallbackModels` — the exact classification, same-model retry, and candidate-advancement behavior main chat and workflow stages converged on ([#2170](https://github.com/bastani-inc/atomic/issues/2170)) — instead of a subagents-local walk. Pre-spawn auth filtering still builds the ladder, and results report the effective `model`, `attemptedModels`, and skipped pre-spawn attempts ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
20
+ - Foreground subagent attempts now enter through the in-process session runner, expose typed terminal status and `SessionStats`, and record typed run-history statuses; the foreground process-attempt implementation was removed ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
21
+ - In-process admission now resolves child management and fanout capabilities as a typed policy carried into the session and tool executor; restricted children cannot create, update, or delete agent definitions, and fanout authorization cannot be widened by a descendant ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
22
+ - `async: true` chain and parallel runs now execute on the same in-process foreground executor as their synchronous counterparts, un-awaited, instead of a separately serialized detached runner. Chain `{previous}` substitution, chain output bindings, dynamic fanout, worktree setup and cleanup, structured-output schemas, skills resolution, progress files, fail-fast, and per-step model-candidate ladders are now served by one implementation for both modes ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
23
+ - Child prompt behavior now enters in-process `AgentSession` construction through typed admission policy: boundary instructions, project-context and inherited-skill filtering, orchestration-skill removal, and parent-only message filtering no longer depend on the process-era extension injection path ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
24
+ - Child MCP direct-tool selection and Intercom identity/capability now cross the in-process admission boundary as typed policy; omitted MCP selection preserves defaults, empty selection disables direct tools, and supervisor grants are never inherited through environment ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
25
+
26
+ ### Fixed
27
+
28
+ - Fixed in-process parallel siblings colliding on the same canonical identity and terminal artifact path, and fixed async completions omitting their persisted result envelope from the parent notification ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
29
+ - Fixed model-failure classification sharing so subagent fallback decisions stay aligned with main chat and workflow candidates for auth, unavailable-model, request-incompatible, quota, and transport failures ([#2170](https://github.com/bastani-inc/atomic/issues/2170)).
30
+
31
+ ### Removed
32
+
33
+ - Removed every remaining OS child-process code path from subagent execution, satisfying the spec's zero-process goal: the detached jiti async runner and its twelve `subagent-runner*` modules, the `async-execution-*` spawn layer, the async event journal, the idle/wall attempt watchdog, the stdout drain grace, the CLI spawn resolver, the environment-bridge builder, and the post-exit stdio guard ([#2188](https://github.com/bastani-inc/atomic/issues/2188)).
34
+
5
35
  ## [0.9.12] - 2026-08-04
6
36
 
7
37
  ### Fixed