@jr2/orchestrator 0.5.1 → 0.7.0

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 (350) hide show
  1. package/console/components/app.ts +55 -15
  2. package/console/components/bottom-drawer.ts +259 -0
  3. package/console/components/drawer.ts +14 -6
  4. package/console/components/fleet.ts +36 -13
  5. package/console/components/machine-pane.ts +61 -5
  6. package/console/components/nav.ts +54 -8
  7. package/console/conversation.ts +161 -0
  8. package/console/login.ts +123 -0
  9. package/console/main.ts +600 -60
  10. package/console/store.ts +611 -64
  11. package/console/style.css +231 -0
  12. package/docs/agents-block.md +2 -2
  13. package/docs/concepts/agents-and-turns.md +142 -29
  14. package/docs/concepts/architecture.md +60 -34
  15. package/docs/concepts/callers-and-hooks.md +205 -0
  16. package/docs/concepts/charts.md +13 -8
  17. package/docs/concepts/composition.md +10 -1
  18. package/docs/concepts/converge.md +7 -2
  19. package/docs/concepts/durable-runs.md +43 -16
  20. package/docs/concepts/effects.md +133 -50
  21. package/docs/concepts/gates.md +95 -25
  22. package/docs/concepts/machines-and-workflows.md +14 -4
  23. package/docs/concepts/pools-and-sources.md +193 -17
  24. package/docs/concepts/secrets-and-trust.md +186 -62
  25. package/docs/concepts/the-menu.md +14 -0
  26. package/docs/concepts/workspaces.md +135 -56
  27. package/docs/get-started/a-model-decides.md +14 -13
  28. package/docs/get-started/an-agent-in-a-sandbox.md +46 -35
  29. package/docs/get-started/connect-a-model.md +1 -1
  30. package/docs/get-started/create-an-instance.md +17 -14
  31. package/docs/get-started/have-your-assistant-write-a-machine.md +111 -40
  32. package/docs/get-started/install.md +4 -0
  33. package/docs/guides/add-tools-to-the-sandbox.md +72 -15
  34. package/docs/guides/answer-a-gate-from-a-forge.md +304 -0
  35. package/docs/guides/answer-a-gate.md +74 -37
  36. package/docs/guides/bind-open-parts.md +29 -12
  37. package/docs/guides/call-an-mcp-tool-from-a-machine.md +572 -0
  38. package/docs/guides/cancel-a-run.md +26 -16
  39. package/docs/guides/cut-a-worktree.md +560 -0
  40. package/docs/guides/fix-a-failed-converge.md +19 -7
  41. package/docs/guides/give-a-caller-a-scope.md +203 -0
  42. package/docs/guides/give-an-agent-mcp-tools.md +422 -0
  43. package/docs/guides/iterate-on-a-machine-on-kind.md +10 -9
  44. package/docs/guides/let-an-agent-write-a-chart.md +14 -7
  45. package/docs/guides/look-inside-a-sandbox.md +115 -42
  46. package/docs/guides/move-from-kind-to-a-shared-cluster.md +16 -0
  47. package/docs/guides/open-the-console.md +63 -14
  48. package/docs/guides/push-and-sign-a-branch.md +67 -21
  49. package/docs/guides/read-a-conversation.md +225 -0
  50. package/docs/guides/run-a-chart-by-name.md +17 -16
  51. package/docs/guides/run-a-command-or-call-a-url.md +84 -41
  52. package/docs/guides/run-one-worker-per-item.md +34 -27
  53. package/docs/guides/set-an-agents-access-and-dials.md +69 -22
  54. package/docs/guides/size-a-workspace.md +19 -6
  55. package/docs/guides/start-a-run-for-each-alert.md +290 -0
  56. package/docs/guides/start-a-run-from-a-run.md +18 -16
  57. package/docs/guides/start-a-run.md +24 -18
  58. package/docs/guides/steer-an-agent.md +332 -0
  59. package/docs/guides/use-a-hosted-provider.md +7 -1
  60. package/docs/guides/watch-a-run.md +146 -117
  61. package/docs/guides/write-a-hook-kind.md +238 -0
  62. package/docs/guides/write-a-tool-as-an-mcp-server.md +351 -0
  63. package/docs/guides/write-a-workflow.md +18 -8
  64. package/docs/llms.txt +110 -23
  65. package/docs/reference/authoring-surface/agent.md +35 -12
  66. package/docs/reference/authoring-surface/answer.md +20 -4
  67. package/docs/reference/authoring-surface/arg.md +28 -6
  68. package/docs/reference/authoring-surface/basic.md +1 -1
  69. package/docs/reference/authoring-surface/bearer.md +1 -1
  70. package/docs/reference/authoring-surface/branchname.md +15 -0
  71. package/docs/reference/authoring-surface/carry.md +23 -0
  72. package/docs/reference/authoring-surface/chartschema.md +1 -1
  73. package/docs/reference/authoring-surface/chartschemafor.md +1 -1
  74. package/docs/reference/authoring-surface/command.md +37 -22
  75. package/docs/reference/authoring-surface/customize.md +4 -1
  76. package/docs/reference/authoring-surface/defineconfig.md +1 -1
  77. package/docs/reference/authoring-surface/defineevent.md +1 -1
  78. package/docs/reference/authoring-surface/dispatch.md +5 -4
  79. package/docs/reference/authoring-surface/fail.md +18 -5
  80. package/docs/reference/authoring-surface/file.md +37 -17
  81. package/docs/reference/authoring-surface/frompick.md +1 -1
  82. package/docs/reference/authoring-surface/gate.md +118 -0
  83. package/docs/reference/authoring-surface/group-agents.md +15 -0
  84. package/docs/reference/authoring-surface/group-charts.md +16 -0
  85. package/docs/reference/authoring-surface/group-composition.md +25 -0
  86. package/docs/reference/authoring-surface/group-config.md +17 -0
  87. package/docs/reference/authoring-surface/group-effects.md +48 -0
  88. package/docs/reference/authoring-surface/group-failure.md +13 -0
  89. package/docs/reference/authoring-surface/group-gates.md +16 -0
  90. package/docs/reference/authoring-surface/group-machine-and-events.md +15 -0
  91. package/docs/reference/authoring-surface/group-steering.md +12 -0
  92. package/docs/reference/authoring-surface/group-types-these-signatures-name.md +137 -0
  93. package/docs/reference/authoring-surface/group-workspaces-and-repos.md +15 -0
  94. package/docs/reference/authoring-surface/http.md +109 -9
  95. package/docs/reference/authoring-surface/isfailure.md +1 -1
  96. package/docs/reference/authoring-surface/isready.md +14 -0
  97. package/docs/reference/authoring-surface/jr2setup.md +14 -4
  98. package/docs/reference/authoring-surface/mcp.md +107 -0
  99. package/docs/reference/authoring-surface/open.md +41 -8
  100. package/docs/reference/authoring-surface/openbody.md +1 -1
  101. package/docs/reference/authoring-surface/paramsof.md +23 -5
  102. package/docs/reference/authoring-surface/pool.md +79 -11
  103. package/docs/reference/authoring-surface/push.md +31 -13
  104. package/docs/reference/authoring-surface/readyof.md +21 -0
  105. package/docs/reference/authoring-surface/reread.md +19 -0
  106. package/docs/reference/authoring-surface/secret.md +26 -5
  107. package/docs/reference/authoring-surface/sentby.md +1 -1
  108. package/docs/reference/authoring-surface/skip.md +22 -0
  109. package/docs/reference/authoring-surface/source.md +59 -4
  110. package/docs/reference/authoring-surface/steer.md +93 -0
  111. package/docs/reference/authoring-surface/text.md +1 -1
  112. package/docs/reference/authoring-surface/type-agentdefinition.md +16 -3
  113. package/docs/reference/authoring-surface/type-agentmcpserver.md +54 -0
  114. package/docs/reference/authoring-surface/type-agentslots.md +4 -1
  115. package/docs/reference/authoring-surface/type-anyframepath.md +14 -0
  116. package/docs/reference/authoring-surface/type-anyworktreepath.md +15 -0
  117. package/docs/reference/authoring-surface/type-bindactors.md +14 -0
  118. package/docs/reference/authoring-surface/type-binding.md +6 -7
  119. package/docs/reference/authoring-surface/type-caller.md +40 -0
  120. package/docs/reference/authoring-surface/type-callerrecord.md +32 -0
  121. package/docs/reference/authoring-surface/type-carry.md +19 -0
  122. package/docs/reference/authoring-surface/type-chainlink.md +3 -3
  123. package/docs/reference/authoring-surface/type-commandinput.md +4 -3
  124. package/docs/reference/authoring-surface/type-commandoptions.md +0 -22
  125. package/docs/reference/authoring-surface/type-commandoutput.md +23 -5
  126. package/docs/reference/authoring-surface/type-customize.md +20 -3
  127. package/docs/reference/authoring-surface/type-delivered.md +17 -0
  128. package/docs/reference/authoring-surface/type-deliveredevent.md +18 -0
  129. package/docs/reference/authoring-surface/type-dispatchdefinition.md +4 -3
  130. package/docs/reference/authoring-surface/type-dispatchoutput.md +9 -2
  131. package/docs/reference/authoring-surface/type-doorlessinput.md +19 -0
  132. package/docs/reference/authoring-surface/type-effectbinding.md +12 -2
  133. package/docs/reference/authoring-surface/type-filebody.md +4 -8
  134. package/docs/reference/authoring-surface/type-framepath.md +14 -0
  135. package/docs/reference/authoring-surface/type-gatebinding.md +15 -0
  136. package/docs/reference/authoring-surface/type-gatehooks.md +12 -0
  137. package/docs/reference/authoring-surface/type-gatelook.md +37 -0
  138. package/docs/reference/authoring-surface/type-gateoutcome.md +32 -0
  139. package/docs/reference/authoring-surface/type-gatereply.md +19 -0
  140. package/docs/reference/authoring-surface/type-gateslot.md +21 -0
  141. package/docs/reference/authoring-surface/type-gateslotinput.md +13 -0
  142. package/docs/reference/authoring-surface/type-gateslotparts.md +18 -0
  143. package/docs/reference/authoring-surface/type-gateslots.md +12 -0
  144. package/docs/reference/authoring-surface/type-gatetypesat.md +13 -0
  145. package/docs/reference/authoring-surface/type-hostinjectedinput.md +3 -5
  146. package/docs/reference/authoring-surface/type-httpdefinition.md +6 -3
  147. package/docs/reference/authoring-surface/type-httpfileinput.md +20 -0
  148. package/docs/reference/authoring-surface/type-httpoutput.md +8 -2
  149. package/docs/reference/authoring-surface/type-jr2config.md +37 -2
  150. package/docs/reference/authoring-surface/type-lateroutcome.md +21 -0
  151. package/docs/reference/authoring-surface/type-lends.md +5 -1
  152. package/docs/reference/authoring-surface/type-lookoutput.md +14 -0
  153. package/docs/reference/authoring-surface/type-mcpcalloutput.md +78 -0
  154. package/docs/reference/authoring-surface/type-mcpnotreturned.md +42 -0
  155. package/docs/reference/authoring-surface/type-mcpoptions.md +47 -0
  156. package/docs/reference/authoring-surface/type-mcpoutput.md +50 -0
  157. package/docs/reference/authoring-surface/type-mcpreadoutput.md +53 -0
  158. package/docs/reference/authoring-surface/type-mcpremoteserver.md +50 -0
  159. package/docs/reference/authoring-surface/type-mcpserver.md +41 -0
  160. package/docs/reference/authoring-surface/type-mcpstdioserver.md +42 -0
  161. package/docs/reference/authoring-surface/type-namedsecret.md +4 -4
  162. package/docs/reference/authoring-surface/type-namestart.md +77 -0
  163. package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +1 -6
  164. package/docs/reference/authoring-surface/type-notworktreekeys.md +12 -0
  165. package/docs/reference/authoring-surface/type-openbodydeclaration.md +1 -1
  166. package/docs/reference/authoring-surface/type-openbodyoutput.md +1 -1
  167. package/docs/reference/authoring-surface/type-opencommandinput.md +7 -2
  168. package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +1 -6
  169. package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +5 -10
  170. package/docs/reference/authoring-surface/type-poolnextinput.md +22 -0
  171. package/docs/reference/authoring-surface/type-poolspec.md +11 -6
  172. package/docs/reference/authoring-surface/type-pushinput.md +22 -3
  173. package/docs/reference/authoring-surface/type-pushoutput.md +33 -8
  174. package/docs/reference/authoring-surface/type-pushsourcespec.md +38 -0
  175. package/docs/reference/authoring-surface/type-readsourcespec.md +47 -0
  176. package/docs/reference/authoring-surface/type-reposlot.md +6 -6
  177. package/docs/reference/authoring-surface/type-reread.md +18 -0
  178. package/docs/reference/authoring-surface/type-runsconfig.md +41 -0
  179. package/docs/reference/authoring-surface/type-sandboxoptions.md +11 -4
  180. package/docs/reference/authoring-surface/type-sender.md +26 -1
  181. package/docs/reference/authoring-surface/type-sendercallerfield.md +14 -0
  182. package/docs/reference/authoring-surface/type-size.md +1 -1
  183. package/docs/reference/authoring-surface/type-skip.md +19 -0
  184. package/docs/reference/authoring-surface/type-slothandles.md +5 -13
  185. package/docs/reference/authoring-surface/type-sourcehooks.md +23 -0
  186. package/docs/reference/authoring-surface/type-sourcein.md +25 -0
  187. package/docs/reference/authoring-surface/type-sourcereply.md +18 -0
  188. package/docs/reference/authoring-surface/type-sourcespec.md +26 -17
  189. package/docs/reference/authoring-surface/type-sourceverdict.md +49 -0
  190. package/docs/reference/authoring-surface/type-standingpoolmachine.md +12 -0
  191. package/docs/reference/authoring-surface/type-standingpoolspec.md +51 -0
  192. package/docs/reference/authoring-surface/type-steerargs.md +20 -0
  193. package/docs/reference/authoring-surface/type-thinkinglevel.md +1 -1
  194. package/docs/reference/authoring-surface/type-usercontainer.md +1 -1
  195. package/docs/reference/authoring-surface/type-workspaced.md +30 -9
  196. package/docs/reference/authoring-surface/type-workspacehandles.md +5 -6
  197. package/docs/reference/authoring-surface/type-workspaceoptions.md +1 -13
  198. package/docs/reference/authoring-surface/type-worktreefound.md +16 -0
  199. package/docs/reference/authoring-surface/type-worktreeinput.md +56 -0
  200. package/docs/reference/authoring-surface/type-worktreekey.md +14 -0
  201. package/docs/reference/authoring-surface/type-worktreeoptions.md +29 -0
  202. package/docs/reference/authoring-surface/type-worktreeoutput.md +45 -0
  203. package/docs/reference/authoring-surface/type-worktreepath.md +16 -0
  204. package/docs/reference/authoring-surface/type-worktreeready.md +37 -0
  205. package/docs/reference/authoring-surface/type-worktreerefused.md +21 -0
  206. package/docs/reference/authoring-surface/workspace.md +66 -38
  207. package/docs/reference/authoring-surface/worktree.md +71 -0
  208. package/docs/reference/authoring-surface.md +88 -147
  209. package/docs/reference/cli.md +413 -74
  210. package/docs/reference/config.md +248 -6
  211. package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +10 -9
  212. package/docs/reference/decisions/0002-duplex-streaming-actor.md +81 -14
  213. package/docs/reference/decisions/0004-worktree-provisioning-model.md +27 -21
  214. package/docs/reference/decisions/0005-sandbox-pod-composition.md +39 -25
  215. package/docs/reference/decisions/0006-agent-control-surface.md +6 -3
  216. package/docs/reference/decisions/0007-durable-machine-state.md +1 -1
  217. package/docs/reference/decisions/0009-cli-and-instance-interface.md +150 -49
  218. package/docs/reference/decisions/0010-bdd-acceptance-tests.md +5 -3
  219. package/docs/reference/decisions/0011-workflow-defined-events.md +256 -12
  220. package/docs/reference/decisions/0012-workspace-wrapper-machine.md +39 -32
  221. package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +54 -30
  222. package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +53 -27
  223. package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +26 -16
  224. package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +9 -7
  225. package/docs/reference/decisions/0017-pool-over-a-source-port.md +226 -10
  226. package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +15 -7
  227. package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +53 -27
  228. package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +16 -2
  229. package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +4 -4
  230. package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +124 -43
  231. package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +36 -38
  232. package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +10 -5
  233. package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +16 -7
  234. package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +36 -19
  235. package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +18 -10
  236. package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +3 -2
  237. package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +23 -15
  238. package/docs/reference/decisions/0032-the-console-unlocks-with-a-callers-credential.md +101 -0
  239. package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +22 -22
  240. package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +6 -6
  241. package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +13 -12
  242. package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +23 -23
  243. package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +6 -1
  244. package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +57 -46
  245. package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +5 -0
  246. package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +20 -8
  247. package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +55 -40
  248. package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +14 -13
  249. package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +31 -24
  250. package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +18 -10
  251. package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +137 -86
  252. package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +165 -91
  253. package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +7 -7
  254. package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +2 -2
  255. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-kept-for-a-set-time.md +109 -0
  256. package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +53 -23
  257. package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +221 -153
  258. package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +161 -96
  259. package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +32 -9
  260. package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +48 -33
  261. package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +56 -30
  262. package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +35 -25
  263. package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +1 -1
  264. package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +296 -0
  265. package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +347 -0
  266. package/docs/reference/decisions/0077-jr2-requires-landlock-on-every-sandbox-node.md +79 -0
  267. package/docs/reference/decisions/0078-a-caller-comes-from-one-authenticator-seam-and-acts-within-its-scopes.md +285 -0
  268. package/docs/reference/decisions/0079-an-agent-holds-mcp-tools-a-machine-calls-them-as-an-effect-and-the-machine-is-the-approval.md +198 -0
  269. package/docs/reference/decisions.md +9 -4
  270. package/docs/reference/glossary.md +138 -45
  271. package/docs/reference/hooks.md +1077 -0
  272. package/docs/reference/http-api.md +988 -123
  273. package/docs/reference/machines.md +0 -1
  274. package/docs/why.md +7 -5
  275. package/package.json +10 -3
  276. package/src/actor.ts +194 -42
  277. package/src/agent.ts +56 -6
  278. package/src/ambient.ts +3 -5
  279. package/src/assembly-checks.ts +530 -4
  280. package/src/callers.ts +245 -0
  281. package/src/chart.ts +238 -26
  282. package/src/charts.ts +9 -2
  283. package/src/config.ts +566 -7
  284. package/src/conversations.ts +453 -0
  285. package/src/custodian.lua +17 -5
  286. package/src/custodian.ts +257 -77
  287. package/src/customize.ts +154 -7
  288. package/src/dispatch-effect.ts +142 -26
  289. package/src/durability.ts +2 -0
  290. package/src/duration.ts +20 -0
  291. package/src/effect-checks.ts +52 -4
  292. package/src/effect.ts +401 -132
  293. package/src/effector-wire.ts +278 -30
  294. package/src/fail.ts +17 -4
  295. package/src/gate-brand.ts +16 -0
  296. package/src/gate.ts +634 -48
  297. package/src/harness-client.ts +84 -35
  298. package/src/harness-env.ts +33 -0
  299. package/src/held-secrets.ts +197 -39
  300. package/src/holds.ts +5 -2
  301. package/src/hook-kinds/discord.ts +92 -0
  302. package/src/hook-kinds/door.ts +107 -0
  303. package/src/hook-kinds/github.ts +89 -0
  304. package/src/hook-kinds/gitlab.ts +72 -0
  305. package/src/hook-kinds/hook.ts +7 -0
  306. package/src/hook-kinds/index.ts +465 -0
  307. package/src/hook-kinds/slack.ts +151 -0
  308. package/src/hook-kinds/webhook.ts +113 -0
  309. package/src/hooks.ts +506 -0
  310. package/src/http-effect.ts +164 -70
  311. package/src/http.ts +933 -99
  312. package/src/index.ts +30 -5
  313. package/src/instance.ts +196 -26
  314. package/src/internal.ts +23 -3
  315. package/src/kube-client.ts +6 -3
  316. package/src/machine-doc.ts +29 -5
  317. package/src/mcp-effect.ts +424 -0
  318. package/src/model-keys.ts +24 -0
  319. package/src/mount-digest.ts +41 -7
  320. package/src/names.ts +82 -7
  321. package/src/notices.ts +576 -59
  322. package/src/open-body.ts +110 -30
  323. package/src/open-effect.ts +17 -4
  324. package/src/open.ts +40 -7
  325. package/src/parts.ts +125 -35
  326. package/src/party.ts +35 -1
  327. package/src/pick.ts +43 -9
  328. package/src/pool.ts +1172 -172
  329. package/src/registration.ts +249 -17
  330. package/src/repo-identity.ts +7 -3
  331. package/src/repos.ts +20 -2
  332. package/src/run-host.ts +1614 -190
  333. package/src/run-list.ts +191 -0
  334. package/src/sandbox-effect.ts +217 -66
  335. package/src/sandbox-kube.ts +116 -21
  336. package/src/secret-placement.ts +248 -35
  337. package/src/server.ts +53 -4
  338. package/src/setup.ts +158 -38
  339. package/src/snapshot-store.ts +565 -48
  340. package/src/steer.ts +111 -0
  341. package/src/stub-harness.ts +6 -2
  342. package/src/tokens.ts +362 -46
  343. package/src/vocabulary.ts +23 -4
  344. package/src/wire.ts +27 -10
  345. package/src/workspace.ts +314 -259
  346. package/src/worktree.ts +249 -0
  347. package/docs/reference/authoring-surface/type-noslotspec.md +0 -26
  348. package/docs/reference/authoring-surface/type-workspacespec.md +0 -37
  349. package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +0 -61
  350. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +0 -65
@@ -7,7 +7,8 @@ description: How a run survives a restart of the Orchestrator, what ends it, and
7
7
 
8
8
  A run is durable. The [Orchestrator](../reference/glossary.md#orchestrator) saves each run after each transition of its
9
9
  [Machine](../reference/glossary.md#machine). When the Orchestrator starts again, it continues each run that did not end,
10
- from the state that it saved. A run that ended stays readable for one week.
10
+ from the state that it saved. A run that ended stays readable for [`runs.retain`](../reference/config.md#runs), 30 days
11
+ by default.
11
12
 
12
13
  ## Why runs are durable
13
14
 
@@ -78,7 +79,7 @@ A run that the Orchestrator does not continue gets one of these results:
78
79
 
79
80
  | Result | When | What stays |
80
81
  | --------- | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
81
- | `lost` | No Workflow has the name of the run's file, or the row holds no snapshot. | The row and the reason, for one week. |
82
+ | `lost` | No Workflow has the name of the run's file, or the row holds no snapshot. | The row and the reason, for `runs.retain`. |
82
83
  | `drifted` | The Orchestrator cannot read the Assembly of the run, or the Machine of the Workflow has a different shape. | The row and the snapshot. |
83
84
  | `failed` | The restore of the run stopped with an error. | The run stays live. The next start tries it again. |
84
85
 
@@ -112,8 +113,9 @@ Orchestrator cannot read the Assembly that the run holds:
112
113
 
113
114
  The Orchestrator keeps a drifted run, and you can read it. [`jr2 status`](../reference/cli.md#status) shows its status,
114
115
  `drifted`, with the reason. The reason names the Workflow and the two digests, or the Assembly and why it cannot load.
115
- [`jr2 runs`](../reference/cli.md#runs) does not show it, because `jr2 runs` shows only the runs that run now. jr2 cannot
116
- move a drifted run to a new Machine. Thus, before you change the Kit version, let the runs end, or cancel them.
116
+ By default, [`jr2 runs`](../reference/cli.md#runs) shows only the live runs, so it does not show a drifted run.
117
+ `jr2 runs --status drifted`, `--status ended` or `--status all` shows it with its reason. jr2 cannot move a drifted run
118
+ to a new Machine. Thus, before you change the Kit version, let the runs end, or cancel them.
117
119
 
118
120
  ## CANCEL and stop
119
121
 
@@ -137,18 +139,40 @@ The operator removes them after the same idle timeout. A run that a Machine fail
137
139
 
138
140
  `jr2 status` shows a cancelled run with the status `cancelled` and the state that it was in.
139
141
 
140
- ## One week of history
142
+ ## History
141
143
 
142
- jr2 keeps the row of a run that ended for 7 days after its last write. This is true for each status that is not live:
143
- `done`, `failed`, `error`, `cancelled`, `lost` and `drifted`. The Orchestrator deletes the older rows when it starts,
144
- and one time each hour after that. A live run stays, whatever its age. A run that waits at a Gate for a month is still
145
- there.
144
+ jr2 keeps the row of a run that ended for 30 days after its last write. `runs.retain` in `jr2.config.ts` changes this
145
+ time, for example `runs: { retain: "90d" }`. It is a number and `m`, `h`, `d` or `w`, and it is at least `1h`. This is
146
+ true for each status that is not live: `done`, `failed`, `error`, `cancelled`, `lost` and `drifted`. The Orchestrator
147
+ deletes the older rows when it starts, and one time each hour after that. A live run stays, whatever its age. A run that
148
+ waits at a Gate for a month is still there.
146
149
 
147
- You cannot change the 7 days. jr2 is not the record of the results of a run. A Machine sends its results where they
148
- belong, such as a pull request. `jr2 status` on a run that ended is for debugging. After the 7 days, `jr2 status` says
149
- that the run does not exist, and a prefix of its id no longer finds it.
150
+ `jr2 runs --status ended` lists the runs that ended, newest first. `--workflow` and `--since` make the list shorter. jr2
151
+ is not the record of the results of a run. A Machine sends its results where they belong, such as a pull request.
152
+ `jr2 status` on a run that ended is for debugging. After `runs.retain`, `jr2 status` says that the run does not exist,
153
+ and a prefix of its id no longer finds it.
150
154
 
151
- The week of a drifted run starts at the restart or the publish that refused it, not at its last transition.
155
+ The time of a drifted run starts at the restart or the publish that refused it, not at its last transition.
156
+
157
+ The same time applies to the [Conversations](../reference/glossary.md#conversation) of a run and to the log of each
158
+ [Hook](../reference/glossary.md#hook). The Orchestrator keeps each conversation of an Agent while the run is kept, and
159
+ deletes it with the row of the run. Thus `jr2 logs` reads the conversations of a run that ended, also after its
160
+ [Sandbox](../reference/glossary.md#sandbox) is gone. [Read a conversation](../guides/read-a-conversation.md) gives the
161
+ commands.
162
+
163
+ ### The state volume
164
+
165
+ The Orchestrator keeps the rows of the runs, the conversations, the Assemblies and the
166
+ [Charts](../reference/glossary.md#chart) on its state volume. A new volume claim is `5Gi` by default, and `jr2 up` keeps
167
+ the size of a claim that exists. `runs.volume` in `jr2.config.ts` sets its size, such as `runs: { volume: "20Gi" }`.
168
+ `jr2 up` makes the claim larger when its StorageClass allows expansion, and refuses otherwise. It never makes a claim
169
+ smaller, because Kubernetes cannot.
170
+
171
+ A space guard keeps the volume from becoming full. When the volume is more than 80% full, the Orchestrator deletes the
172
+ conversations of the runs that ended, the oldest run first, until the volume is less than 80% full. The rows of the runs
173
+ stay, and each one shows that its conversations went for space. The guard never deletes a conversation of a live run.
174
+ When the volume is more than 95% full and no ended run has a conversation left, the Orchestrator keeps no more entries
175
+ of the open conversations. One conversation also has a limit of 8 MiB, after which the Orchestrator keeps no more of it.
152
176
 
153
177
  [`jr2 down`](../reference/cli.md#down) deletes the namespace of the Instance, and the store with it. The live runs go
154
178
  too.
@@ -162,7 +186,9 @@ too.
162
186
  - The Orchestrator never continues a drifted run, and never moves it to a new Machine.
163
187
  - The Orchestrator never continues a cancelled run.
164
188
  - `CANCEL` is the only run event that `jr2 send` sends without `--gate`. `--keep` goes only with `CANCEL`.
165
- - jr2 keeps a run that ended for 7 days. The hourly sweep never deletes a live run.
189
+ - jr2 keeps a run that ended for `runs.retain`, 30 days by default. The hourly sweep never deletes a live run.
190
+ - jr2 keeps the conversations of a run for as long as it keeps the run, unless the space guard deletes them first. The
191
+ space guard never deletes a conversation of a live run.
166
192
 
167
193
  [Cancel a run](../guides/cancel-a-run.md) and [Watch a run](../guides/watch-a-run.md) give the commands and their
168
194
  output.
@@ -170,6 +196,7 @@ output.
170
196
  ## Read next
171
197
 
172
198
  - [Watch a run](../guides/watch-a-run.md)
199
+ - [Read a conversation](../guides/read-a-conversation.md)
173
200
  - [Cancel a run](../guides/cancel-a-run.md)
174
201
  - [Iterate on a Machine on kind](../guides/iterate-on-a-machine-on-kind.md)
175
202
  - [Effects](effects.md), [Workspaces](workspaces.md) and [Converge](converge.md)
@@ -183,7 +210,7 @@ output.
183
210
  - [ADR-0025](../reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md): `CANCEL` ends a run, and a stop parks it
184
211
  - [ADR-0030](../reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md): a snapshot names the
185
212
  Machine that wrote it
186
- - [ADR-0065](../reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md): a save survives a crash,
187
- and jr2 keeps a week of history
213
+ - [ADR-0065](../reference/decisions/0065-a-persist-survives-a-crash-and-history-is-kept-for-a-set-time.md): a save
214
+ survives a crash, and jr2 keeps history for `runs.retain`
188
215
  - [ADR-0069](../reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md): a
189
216
  run holds the Assembly that it started under
@@ -1,15 +1,16 @@
1
1
  ---
2
2
  title: Effects
3
- description: How a Machine runs a command, calls a URL, pushes a branch or starts a run, at most once.
3
+ description: How a Machine runs a command, calls a URL or an MCP tool, pushes a branch or starts a run.
4
4
  ---
5
5
 
6
6
  # Effects
7
7
 
8
8
  An [Effect](../reference/glossary.md#effect) is work that a [Machine](../reference/glossary.md#machine) does outside
9
- itself. jr2 has four kinds: `command` runs a program in the [Workspace](../reference/glossary.md#workspace), `http`
10
- calls a URL, `push` pushes the Workspace's branch, and `dispatch` starts a run of a
11
- [Workflow](../reference/glossary.md#workflow). You write an Effect as an actor slot, beside the
12
- [Agents](../reference/glossary.md#agent) of the Machine.
9
+ itself. jr2 has five kinds: `command` runs a program in the [Workspace](../reference/glossary.md#workspace), `http`
10
+ calls a URL, `push` pushes the branch of a [Worktree](../reference/glossary.md#worktree), `dispatch` starts a run of a
11
+ [Workflow](../reference/glossary.md#workflow), and `mcp` calls a tool of an MCP server. The Kit also gives
12
+ [`worktree()`](../reference/authoring-surface/worktree.md), an Effect on the `command` machinery that cuts a Worktree.
13
+ You write an Effect as an actor slot, beside the [Agents](../reference/glossary.md#agent) of the Machine.
13
14
 
14
15
  ## Why Effects exist
15
16
 
@@ -26,8 +27,8 @@ two times. A plain [xstate](https://xstate.js.org) promise has no such record.
26
27
 
27
28
  Put an Effect under `actors` in [`jr2Setup`](../reference/authoring-surface/jr2setup.md). Invoke it by its key from a
28
29
  state. The state's `onDone` gets the output of the Effect. This example is a Workflow with a Workspace. An Agent fixes
29
- the code, and it can ask for a test run with the pick `run_tests`. When the Agent picks `finished`, the Machine pushes
30
- the branch:
30
+ the code in a Worktree that the Machine cuts first. It can ask for a test run with the pick `run_tests`. When the Agent
31
+ picks `finished`, the Machine pushes the branch:
31
32
 
32
33
  **Anthropic**
33
34
 
@@ -39,9 +40,11 @@ import {
39
40
  command,
40
41
  defineEvent,
41
42
  fail,
43
+ isReady,
42
44
  jr2Setup,
43
45
  push,
44
46
  workspace,
47
+ worktree,
45
48
  type CommandOutput,
46
49
  type Workspaced,
47
50
  } from "@jr2/orchestrator";
@@ -61,6 +64,9 @@ const finished = defineEvent({
61
64
  const runInput = z.object({ prompt: z.string(), branch: z.string() });
62
65
  type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
63
66
 
67
+ // The Worktree that the coder, the tests and the push all name.
68
+ const appTree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
69
+
64
70
  const passed = (output: CommandOutput): boolean => output.outcome === "exited" && output.code === 0;
65
71
 
66
72
  const body = jr2Setup({
@@ -71,7 +77,8 @@ const body = jr2Setup({
71
77
  model: "anthropic/claude-haiku-5-5",
72
78
  instructions: "You are a careful engineer. You commit your work on the branch.",
73
79
  }),
74
- // Two Effects. Each is an actor slot, beside the Agent.
80
+ // Three Effects. Each is an actor slot, beside the Agent.
81
+ cut: worktree(),
75
82
  tests: command(["node", "--test"], { timeout: "5m" }),
76
83
  publish: push(),
77
84
  fail: fail(),
@@ -80,12 +87,20 @@ const body = jr2Setup({
80
87
  id: "test-and-push",
81
88
  context: ({ input }) => input,
82
89
  on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
83
- initial: "coding",
90
+ initial: "cutting",
84
91
  states: {
92
+ // The Workspace only clones. The Machine cuts the Worktree that the Agent works in.
93
+ cutting: {
94
+ invoke: {
95
+ src: "cut",
96
+ input: ({ context }) => ({ path: appTree(context), branch: context.branch }),
97
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
98
+ },
99
+ },
85
100
  coding: {
86
101
  invoke: {
87
102
  src: "coder",
88
- input: ({ context }) => ({ prompt: context.prompt, cwd: context.workspace.repos.app }),
103
+ input: ({ context }) => ({ prompt: context.prompt, cwd: appTree(context) }),
89
104
  },
90
105
  on: { finished: "publishing" },
91
106
  initial: "ready",
@@ -94,6 +109,7 @@ const body = jr2Setup({
94
109
  testing: {
95
110
  invoke: {
96
111
  src: "tests",
112
+ input: ({ context }) => ({ worktree: appTree(context) }),
97
113
  onDone: {
98
114
  target: "ready",
99
115
  // The Agent reads this text as the answer to its run_tests pick.
@@ -110,10 +126,12 @@ const body = jr2Setup({
110
126
  publishing: {
111
127
  invoke: {
112
128
  src: "publish",
129
+ input: ({ context }) => ({ worktree: appTree(context) }),
113
130
  onDone: [{ guard: ({ event }) => event.output.outcome === "pushed", target: "done" }, { target: "notPushed" }],
114
131
  },
115
132
  },
116
133
  done: { type: "final" },
134
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
117
135
  // A Failure ends the body, and jr2 deletes the Sandbox with its commits. To keep them, wait at
118
136
  // a Gate before this state.
119
137
  notPushed: { invoke: { src: "fail", input: { reason: "the push did not publish the fix" } } },
@@ -125,7 +143,6 @@ const body = jr2Setup({
125
143
  export const machine = workspace(body, {
126
144
  input: runInput,
127
145
  repos: { app: "https://github.com/you/app.git" },
128
- spec: ({ input }) => ({ branch: input.branch }),
129
146
  });
130
147
  ```
131
148
 
@@ -139,9 +156,11 @@ import {
139
156
  command,
140
157
  defineEvent,
141
158
  fail,
159
+ isReady,
142
160
  jr2Setup,
143
161
  push,
144
162
  workspace,
163
+ worktree,
145
164
  type CommandOutput,
146
165
  type Workspaced,
147
166
  } from "@jr2/orchestrator";
@@ -161,6 +180,9 @@ const finished = defineEvent({
161
180
  const runInput = z.object({ prompt: z.string(), branch: z.string() });
162
181
  type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
163
182
 
183
+ // The Worktree that the coder, the tests and the push all name.
184
+ const appTree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
185
+
164
186
  const passed = (output: CommandOutput): boolean => output.outcome === "exited" && output.code === 0;
165
187
 
166
188
  const body = jr2Setup({
@@ -171,7 +193,8 @@ const body = jr2Setup({
171
193
  model: "local/qwen3.6-35b-a3b",
172
194
  instructions: "You are a careful engineer. You commit your work on the branch.",
173
195
  }),
174
- // Two Effects. Each is an actor slot, beside the Agent.
196
+ // Three Effects. Each is an actor slot, beside the Agent.
197
+ cut: worktree(),
175
198
  tests: command(["node", "--test"], { timeout: "5m" }),
176
199
  publish: push(),
177
200
  fail: fail(),
@@ -180,12 +203,20 @@ const body = jr2Setup({
180
203
  id: "test-and-push",
181
204
  context: ({ input }) => input,
182
205
  on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
183
- initial: "coding",
206
+ initial: "cutting",
184
207
  states: {
208
+ // The Workspace only clones. The Machine cuts the Worktree that the Agent works in.
209
+ cutting: {
210
+ invoke: {
211
+ src: "cut",
212
+ input: ({ context }) => ({ path: appTree(context), branch: context.branch }),
213
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
214
+ },
215
+ },
185
216
  coding: {
186
217
  invoke: {
187
218
  src: "coder",
188
- input: ({ context }) => ({ prompt: context.prompt, cwd: context.workspace.repos.app }),
219
+ input: ({ context }) => ({ prompt: context.prompt, cwd: appTree(context) }),
189
220
  },
190
221
  on: { finished: "publishing" },
191
222
  initial: "ready",
@@ -194,6 +225,7 @@ const body = jr2Setup({
194
225
  testing: {
195
226
  invoke: {
196
227
  src: "tests",
228
+ input: ({ context }) => ({ worktree: appTree(context) }),
197
229
  onDone: {
198
230
  target: "ready",
199
231
  // The Agent reads this text as the answer to its run_tests pick.
@@ -210,10 +242,12 @@ const body = jr2Setup({
210
242
  publishing: {
211
243
  invoke: {
212
244
  src: "publish",
245
+ input: ({ context }) => ({ worktree: appTree(context) }),
213
246
  onDone: [{ guard: ({ event }) => event.output.outcome === "pushed", target: "done" }, { target: "notPushed" }],
214
247
  },
215
248
  },
216
249
  done: { type: "final" },
250
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
217
251
  // A Failure ends the body, and jr2 deletes the Sandbox with its commits. To keep them, wait at
218
252
  // a Gate before this state.
219
253
  notPushed: { invoke: { src: "fail", input: { reason: "the push did not publish the fix" } } },
@@ -225,7 +259,6 @@ const body = jr2Setup({
225
259
  export const machine = workspace(body, {
226
260
  input: runInput,
227
261
  repos: { app: "https://github.com/you/app.git" },
228
- spec: ({ input }) => ({ branch: input.branch }),
229
262
  });
230
263
  ```
231
264
 
@@ -242,6 +275,7 @@ example above, `jr2 up` prints these lines:
242
275
 
243
276
  ```text
244
277
  effects: workflow "test-and-push" — what it runs outside itself (ADR-0067)
278
+ cut: worktree — 600s, in the Harness
245
279
  tests: command ["node","--test"] — 300s, in the Harness
246
280
  publish: push — 300s, in the Sandbox Effector
247
281
  ```
@@ -253,12 +287,13 @@ run `failed`:
253
287
 
254
288
  ```text
255
289
  failures: workflow "test-and-push" — the states that fail the run (ADR-0073)
290
+ test-and-push.notCut: invokes fail
256
291
  test-and-push.notPushed: invokes fail
257
292
  test-and-push.failed: invokes fail
258
293
  test-and-push.lost: invokes fail
259
294
  ```
260
295
 
261
- ## The four kinds
296
+ ## The five kinds
262
297
 
263
298
  ### `command`
264
299
 
@@ -268,10 +303,9 @@ argument that the input of the Effect fills. Thus an Agent's text cannot become
268
303
  in the argv: `["sh", "-c", "…"]`. Then the result is the result of your script. The Agent can change the files that the
269
304
  script runs, so do not trust its result more than the Agent.
270
305
 
271
- A `command` uses the [Worktree](../reference/glossary.md#worktree) of one
272
- [Repo Slot](../reference/glossary.md#repo-slot): the only slot, or the slot that its `slot` option names. Its default
273
- timeout is 10 minutes. Its output keeps the end of what the program wrote: 4096 characters by default (the `tail`
274
- option). The full output goes to the run's feed.
306
+ Under [Repo Slots](../reference/glossary.md#repo-slot), the input of a `command` names its Worktree: `{ worktree }`, a
307
+ Worktree that a cut made, or `/work/<slot>/default`. Its default timeout is 10 minutes. Its output keeps the end of what
308
+ the program wrote: 4096 characters by default (the `tail` option). The full output goes to the run's feed.
275
309
 
276
310
  ### `http`
277
311
 
@@ -413,15 +447,18 @@ export const machine = jr2Setup({
413
447
  });
414
448
  ```
415
449
 
416
- The body can also be a file of the Worktree: `body: file(path)` (see [`file`](../reference/authoring-surface/file.md)).
417
- The default timeout of an `http` Effect is 30 seconds.
450
+ The body can also be a file of a Worktree: `body: file(path)` (see [`file`](../reference/authoring-surface/file.md)).
451
+ The input then names the Worktree, `{ worktree }`, and a cut must have made it. A path alone does not name the target of
452
+ a credential. The default timeout of an `http` Effect is 30 seconds.
418
453
 
419
454
  ### `push`
420
455
 
421
- [`push`](../reference/authoring-surface/push.md) pushes the Workspace's branch to the
422
- [Binding](../reference/glossary.md#binding) of its Repo Slot. It uses the push credential of the `git.credentials` entry
423
- that the URL matches (see [`git.credentials`](../reference/config.md#git-credentials)). The Agent never reads that
424
- credential. These options change what a push publishes:
456
+ [`push`](../reference/authoring-surface/push.md) pushes the branch of a Worktree to the
457
+ [Binding](../reference/glossary.md#binding) of its Repo Slot. Its input names the Worktree, `{ worktree }`, and has no
458
+ branch. jr2 reads the branch from the cut of that path, so an Agent that moves `HEAD` does not change what jr2 pushes.
459
+ It uses the push credential of the `git.credentials` entry that the URL matches (see
460
+ [`git.credentials`](../reference/config.md#git-credentials)). The Agent never reads that credential. These options
461
+ change what a push publishes:
425
462
 
426
463
  - `pin`: push the commit that the input names, such as a commit that a [Gate](../reference/glossary.md#gate) approved.
427
464
  Without `pin`, jr2 pushes the tip of the Agent's branch when the Effect starts.
@@ -429,18 +466,26 @@ credential. These options change what a push publishes:
429
466
  - `squash`: push one commit that holds all the changes, with the message that the input gives.
430
467
  - `force`: replace what the remote branch holds.
431
468
 
432
- With `pin`, the input gives `{ sha }`. With `squash`, it gives `{ message }`.
469
+ With `pin`, the input also gives `{ sha }`. With `squash`, it also gives `{ message }`.
433
470
 
434
471
  After a signed or a squashed push, the commits on the remote are not the Agent's own commits. Then jr2 moves the Agent's
435
472
  branch to the published commits. The Agent's files, index and stash do not change. The default timeout is 5 minutes.
436
473
 
474
+ ### `worktree`
475
+
476
+ [`worktree()`](../reference/authoring-surface/worktree.md) cuts a Worktree, or reads the one that a cut made at that
477
+ path. Its outcomes are `ready`, `refused` and `unknown`. It runs in the Harness container, and it is idempotent. Each
478
+ thing that an Agent's word can cause is `refused`, and nothing changes. [Workspaces](workspaces.md) tells what a
479
+ Worktree is, and [Cut a Worktree](../guides/cut-a-worktree.md) tells how to use it.
480
+
437
481
  ### `dispatch`
438
482
 
439
483
  [`dispatch`](../reference/authoring-surface/dispatch.md) starts a run of a Workflow. The new run is a run of its own: it
440
484
  has its own line in [`jr2 runs`](../reference/cli.md#runs), its own Workspaces and its own `CANCEL`. Its record names
441
485
  the run that started it: it is **dispatched by** that run. Use `dispatch` when a Machine waits for work, for example at
442
- a [Gate](../reference/glossary.md#gate) that a webhook answers, and each item of work needs a run of a Workflow that you
443
- have. To use a Machine as a part of one run, invoke it in the run instead (see [Composition](composition.md)).
486
+ a [Gate](../reference/glossary.md#gate) that a [Hook](../reference/glossary.md#hook) answers, and each item of work
487
+ needs a run of a Workflow that you have. To use a Machine as a part of one run, invoke it in the run instead (see
488
+ [Composition](composition.md)).
444
489
 
445
490
  - The name of the Workflow is a constant of the definition, as `jr2 run` writes it: `"triage"`, or `"<wrapper>/<name>"`
446
491
  for a named [Chart](../reference/glossary.md#chart). An Agent cannot choose it.
@@ -452,12 +497,27 @@ have. To use a Machine as a part of one run, invoke it in the run instead (see [
452
497
  minutes with `wait`.
453
498
  - With no `target`, the new run starts in the same Orchestrator. With
454
499
  `target: { url: "https://<host>", token: secret("<name>") }`, it starts on a different Orchestrator. `url` is the
455
- origin of that Orchestrator, and the secret holds its Instance token.
500
+ origin of that Orchestrator, and the secret holds the token of a [Caller](../reference/glossary.md#caller) of that
501
+ Orchestrator with the `start` scope for the Workflow, and also `read` when `wait` is `true`.
456
502
  - The new run starts under the current [Assembly](../reference/glossary.md#assembly), as a run of `jr2 run` does.
457
503
 
458
504
  The two runs are independent. A `CANCEL` of one run does not cancel the other. When the run that dispatched ends, the
459
505
  new run continues.
460
506
 
507
+ ### `mcp`
508
+
509
+ [`mcp`](../reference/authoring-surface/mcp.md) calls an MCP server: `mcp.call(server, tool, { input })` calls a tool,
510
+ `mcp.read(server, uri)` reads a resource, and `mcp.prompt(server, name, { input })` gets a prompt. `server` is a name of
511
+ the [`mcp`](../reference/config.md#mcp) block of `jr2.config.ts`, which holds the URL and the secret of the server. Thus
512
+ the definition holds no URL and no credential, and an Agent's word can reach only the arguments, through the input.
513
+
514
+ An Agent can also hold the tools of a server as [MCP tools](../reference/glossary.md#mcp-tools), and call them in its
515
+ Turn with no approval (see [Agents and Turns](agents-and-turns.md#the-mcp-tools)). Use an `mcp` Effect when the call
516
+ needs the approval of a person, or when the Machine makes the call with no model. The Agent picks, a Gate waits for the
517
+ approval, and the Effect calls the tool. The output of the Effect is the answer to the pick. Thus the approval is in the
518
+ record of the run, and the Machine routes on it. The default timeout is the `timeout` of the server: 60 seconds when it
519
+ sets none. [Call an MCP tool from a Machine](../guides/call-an-mcp-tool-from-a-machine.md) has an example.
520
+
461
521
  ## Where an Effect runs
462
522
 
463
523
  You do not choose where an Effect runs. The kind, and what the Effect names, decide it. Each
@@ -467,40 +527,51 @@ commands in it:
467
527
  | The Effect | Where it runs |
468
528
  | --------------------------------------- | ----------------------------------------------------------------------------------- |
469
529
  | A `command` that names no Effect secret | The [Harness](../reference/glossary.md#harness) container of the Sandbox |
530
+ | A `worktree()` | The Harness container of the Sandbox |
470
531
  | A `command` that names an Effect secret | The [Sandbox Effector](../reference/glossary.md#sandbox-effector), against a commit |
471
532
  | An `http` Effect | The [Instance Effector](../reference/glossary.md#instance-effector) |
472
533
  | An `http` Effect with a Worktree file | The Sandbox Effector |
473
534
  | A `push` | The Sandbox Effector |
474
535
  | A `dispatch` with no `target` | The Orchestrator, in its own process |
475
536
  | A `dispatch` with a `target` | The Instance Effector |
537
+ | An `mcp` Effect | The Instance Effector |
476
538
 
477
539
  A `command` that names no Effect secret runs beside the Agent's [Working tools](../reference/glossary.md#working-tools).
478
- It runs as the Agent's user, with the tools of the [Sandbox Image](../reference/glossary.md#sandbox-image). It has the
479
- same [Stand-ins](../reference/glossary.md#stand-in) as the Agent's shell, and no credential of its own.
540
+ It runs as the Agent's user, with the tools of the [Sandbox Image](../reference/glossary.md#sandbox-image). The Harness
541
+ confines it with Landlock, as it confines the Agent's shell. It has the same
542
+ [Stand-ins](../reference/glossary.md#stand-in) as the Agent's shell, and no credential of its own.
480
543
 
481
544
  A `command` that names an Effect secret in its `env` runs in the Sandbox Effector, a container in which the Agent runs
482
545
  nothing. It does not run in the live Worktree. It runs against one commit: the tip of the branch when it starts, or with
483
546
  `pin`, the commit that its input names. When the Worktree held changes that the command did not see, its output has
484
547
  `dirty: true`.
485
548
 
486
- A `command`, a `push` and an `http` Effect with a file body need a Workspace. Invoke them from the body of a
487
- [`workspace()`](../reference/authoring-surface/workspace.md). [Architecture](architecture.md) tells what each Effector
488
- is, and [Secrets and trust](secrets-and-trust.md) tells how an Effector holds the Effect secrets.
549
+ A `command`, a `worktree()`, a `push` and an `http` Effect with a file body need a Workspace. Invoke them from the body
550
+ of a [`workspace()`](../reference/authoring-surface/workspace.md). [Architecture](architecture.md) tells what each
551
+ Effector is, and [Secrets and trust](secrets-and-trust.md) tells how an Effector holds the Effect secrets.
489
552
 
490
553
  ## Every outcome is output
491
554
 
492
555
  An Effect gives each outcome to `onDone`, a failure too. Route on the `outcome` field:
493
556
 
494
- | Kind | The outcomes | The output type |
495
- | ---------- | --------------------------------------------------------- | ------------------------------------------------------------------------- |
496
- | `command` | `exited`, `timeout`, `killed`, `unknown` | [`CommandOutput`](../reference/authoring-surface/type-commandoutput.md) |
497
- | `http` | `response`, `unreachable`, `refused`, `unknown` | [`HttpOutput`](../reference/authoring-surface/type-httpoutput.md) |
498
- | `push` | `pushed`, `rejected`, `diverged`, `unknown` | [`PushOutput`](../reference/authoring-surface/type-pushoutput.md) |
499
- | `dispatch` | `started`, `settled`, `refused`, `unreachable`, `unknown` | [`DispatchOutput`](../reference/authoring-surface/type-dispatchoutput.md) |
557
+ | Kind | The outcomes | The output type |
558
+ | ---------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------- |
559
+ | `worktree` | `ready`, `refused`, `unknown` | [`WorktreeOutput`](../reference/authoring-surface/type-worktreeoutput.md) |
560
+ | `command` | `exited`, `timeout`, `killed`, `unknown` | [`CommandOutput`](../reference/authoring-surface/type-commandoutput.md) |
561
+ | `http` | `response`, `unreachable`, `refused`, `unknown` | [`HttpOutput`](../reference/authoring-surface/type-httpoutput.md) |
562
+ | `push` | `pushed`, `rejected`, `diverged`, `unknown` | [`PushOutput`](../reference/authoring-surface/type-pushoutput.md) |
563
+ | `dispatch` | `started`, `settled`, `refused`, `unreachable`, `unknown` | [`DispatchOutput`](../reference/authoring-surface/type-dispatchoutput.md) |
564
+ | `mcp` | `returned`, `refused`, `unreachable`, `input-required`, `unknown` | [`McpCallOutput`](../reference/authoring-surface/type-mcpcalloutput.md) |
500
565
 
501
566
  A test that fails is `exited` with a code that is not 0. A program that the container does not have is `exited` with
502
567
  code 127. An HTTP 4xx or 5xx status is a `response`. A Workflow that refuses the run input of a `dispatch` is `refused`,
503
- with the status code and the report of the refusal. `unknown` means that jr2 cannot tell what the Effect did.
568
+ with the status code and the report of the refusal. A tool of an `mcp` Effect that ran and failed is `returned` with
569
+ `isError: true`. `unknown` means that jr2 cannot tell what the Effect did.
570
+
571
+ Each union is open: it holds a stand-in member, `LaterOutcome`, so a later release can add an outcome and your Machine
572
+ still works. Route on what you know, and give the rest a last arm with no guard. With no match, the run stays in that
573
+ state and shows no fault. So `createMachine`, `jr2 check`, `jr2 up` and the Chart door refuse an `onDone` with a guard
574
+ on its last arm. An invoke with no `onDone` is legal: the Effect settles, and the state stays.
504
575
 
505
576
  The `onError` route of an Effect is only for a defect in the Machine or in the config. For example, the Effect is not in
506
577
  a Workspace, or an `arg()` has no value, or an Open part has no binding. An outcome that means that the work did not
@@ -521,8 +592,10 @@ jr2 records its output. After an Orchestrator restart, jr2 reads the record:
521
592
  | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
522
593
  | A `command` that names no Effect secret | jr2 attaches to it again. When the Harness does not know it, the outcome is `unknown`. It never runs again. |
523
594
  | A `command` that names an Effect secret | jr2 follows it. When the Sandbox Effector lost it, jr2 runs it again against the same commit. With no commit recorded, the outcome is `unknown`. |
595
+ | A `worktree()` | jr2 attaches to it again. When the Harness does not know it, jr2 sends it again: a cut is idempotent. |
524
596
  | A `push` | jr2 follows it. When the Sandbox Effector lost it, jr2 pushes the same commit again, and no other commit. With no commit recorded, the outcome is `unknown`. |
525
597
  | An `http` Effect | jr2 follows it. When no Effector holds it, jr2 sends it again only if it is `idempotent`. Else the outcome is `unknown`. |
598
+ | An `mcp` Effect | As an `http` Effect. jr2 does not read the `idempotentHint` of a tool: only your `idempotent` mark counts. |
526
599
  | A `dispatch` | jr2 sends the start again, with the same key. The Orchestrator answers with the run that the key started, and it starts no second run. |
527
600
 
528
601
  A `command` that names no Effect secret runs the code of the Worktree, and that code can spend a Stand-in. Thus jr2 does
@@ -530,7 +603,8 @@ not run it two times. A `push`, and a `command` that names an Effect secret, run
530
603
  jr2 can send them again with that commit.
531
604
 
532
605
  To try again, write it in the Machine: a route from the outcome back into the state. Mark an `http` Effect `idempotent`
533
- only when a second call is safe: the call has its own idempotency key, or it only reads.
606
+ only when a second call is safe: the call has its own idempotency key, or it only reads. The same rule is true for an
607
+ `mcp` Effect.
534
608
 
535
609
  ## When the state exits
536
610
 
@@ -539,8 +613,8 @@ When the run leaves the state, the Effect stops:
539
613
  - jr2 kills the process group of a `command` that names no Effect secret.
540
614
  - The Sandbox Effector stops a `command` that names an Effect secret. It sends `SIGTERM`, waits 5 seconds, then sends
541
615
  `SIGKILL`.
542
- - An `http` Effect and a `push` have no stop. jr2 stops waiting for the output, but the Effector can still finish the
543
- work.
616
+ - An `http` Effect, an `mcp` Effect and a `push` have no stop. jr2 stops waiting for the output, but the Effector can
617
+ still finish the work.
544
618
  - A `dispatch` with `wait` stops its wait. The run that it started continues.
545
619
 
546
620
  jr2 records the stop, and the Machine gets no output. There is no "finally" in a Machine: cleanup is a state. Put an
@@ -569,8 +643,10 @@ pick waits for its answer.
569
643
  ## Rules
570
644
 
571
645
  - An Effect is a key of `actors`. `createMachine` refuses an Effect that you write directly in an `invoke`.
572
- - A `command`, a `push` and an `http` Effect with a file body run only inside a `workspace()`.
573
- - Under a Workspace with more than one Repo Slot, a `command`, a `push` and a file body name their slot.
646
+ - The last arm of an Effect's `onDone` has no guard. `createMachine` refuses one that has:
647
+ `machine "<id>": state "<state>" (Effect "<slot>") has an onDone with no unguarded last arm — … (ADR-0075)`.
648
+ - A `command`, a `worktree()`, a `push` and an `http` Effect with a file body run only inside a `workspace()`.
649
+ - Under a Workspace with more than one Repo Slot, a `push` names its `slot`.
574
650
  - The host of an `http` URL is literal. An Effect secret never goes in the host, the query or the fragment of a URL.
575
651
  - Each Effect secret that an Effect names is in the `secrets` list of `jr2.config.ts`, with a value of 8 characters or
576
652
  more. `jr2 up` refuses a name that is not in the list, and a value that is shorter.
@@ -578,11 +654,14 @@ pick waits for its answer.
578
654
  a `committer` field there.
579
655
  - Each param of a pick that enters an Effect's state has a reader: the Effect's input, `fill`, a guard or an `assign`.
580
656
  `createMachine` refuses a param that nothing reads, and a `fill` key that is also a param.
581
- - A packaged Machine can leave an `http` URL, a `command` argv, one Effect secret name or the `target` of a `dispatch`
582
- Open. The composer binds it one time with `customize()`. `jr2 up` refuses an Open part that nobody bound.
657
+ - A packaged Machine can leave an `http` URL, a `command` argv, one Effect secret name, the `target` of a `dispatch`, or
658
+ the server and the tool of an `mcp` Effect Open. The composer binds it one time with `customize()`. `jr2 up` refuses
659
+ an Open part that nobody bound.
583
660
  - A `dispatch` with no `target` names a Workflow that the Assembly has. `jr2 up` refuses a name that it does not have,
584
661
  and an `input` schema that the input of that Workflow does not take.
585
662
  - The `url` of a `dispatch` target is an origin only: a scheme, a host and a port, with no path, no query and no user.
663
+ - An `mcp` Effect names a remote server that the `mcp` block declares. `jr2 up` refuses a server that the block does not
664
+ declare, and a stdio server.
586
665
 
587
666
  The guides give the refusal text of each rule.
588
667
 
@@ -591,13 +670,17 @@ The guides give the refusal text of each rule.
591
670
  - [Run a command or call a URL with an Effect](../guides/run-a-command-or-call-a-url.md)
592
671
  - [Push and sign a branch](../guides/push-and-sign-a-branch.md)
593
672
  - [Start a run from a run](../guides/start-a-run-from-a-run.md)
673
+ - [Call an MCP tool from a Machine](../guides/call-an-mcp-tool-from-a-machine.md)
594
674
  - [Workspaces](workspaces.md), [The Menu](the-menu.md), [Secrets and trust](secrets-and-trust.md)
595
675
  - Reference: [`command`](../reference/authoring-surface/command.md), [`http`](../reference/authoring-surface/http.md),
596
676
  [`push`](../reference/authoring-surface/push.md), [`dispatch`](../reference/authoring-surface/dispatch.md),
597
- [`fromPick`](../reference/authoring-surface/frompick.md), [`answer`](../reference/authoring-surface/answer.md)
677
+ [`mcp`](../reference/authoring-surface/mcp.md), [`fromPick`](../reference/authoring-surface/frompick.md),
678
+ [`answer`](../reference/authoring-surface/answer.md)
598
679
  - [ADR-0067](../reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md):
599
680
  an Effect is an actor slot, and runs at most once unless marked idempotent
600
681
  - [ADR-0068](../reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md): an Effector holds
601
682
  an Effect's secrets and signs its wire
602
683
  - [ADR-0071](../reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md): a run starts a run through a
603
684
  `dispatch` Effect
685
+ - [ADR-0079](../reference/decisions/0079-an-agent-holds-mcp-tools-a-machine-calls-them-as-an-effect-and-the-machine-is-the-approval.md):
686
+ a Machine calls an MCP server as an Effect, and the Machine is the approval