@jr2/orchestrator 0.4.1 → 0.6.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 (361) hide show
  1. package/README.md +20 -2
  2. package/console/components/app.ts +2 -0
  3. package/console/components/fleet.ts +14 -1
  4. package/console/components/machine-pane.ts +41 -2
  5. package/console/main.ts +13 -1
  6. package/console/store.ts +102 -6
  7. package/console/style.css +21 -0
  8. package/docs/agents-block.md +5 -0
  9. package/docs/concepts/agents-and-turns.md +478 -0
  10. package/docs/concepts/architecture.md +243 -0
  11. package/docs/concepts/charts.md +146 -0
  12. package/docs/concepts/composition.md +357 -0
  13. package/docs/concepts/converge.md +257 -0
  14. package/docs/concepts/durable-runs.md +189 -0
  15. package/docs/concepts/effects.md +658 -0
  16. package/docs/concepts/gates.md +208 -0
  17. package/docs/concepts/machines-and-workflows.md +298 -0
  18. package/docs/concepts/pools-and-sources.md +230 -0
  19. package/docs/concepts/secrets-and-trust.md +306 -0
  20. package/docs/concepts/the-menu.md +381 -0
  21. package/docs/concepts/workspaces.md +756 -0
  22. package/docs/get-started/a-model-decides.md +563 -0
  23. package/docs/get-started/an-agent-in-a-sandbox.md +383 -0
  24. package/docs/get-started/connect-a-model.md +248 -0
  25. package/docs/get-started/create-an-instance.md +194 -0
  26. package/docs/get-started/have-your-assistant-write-a-machine.md +993 -0
  27. package/docs/get-started/install.md +130 -0
  28. package/docs/guides/add-tools-to-the-sandbox.md +308 -0
  29. package/docs/guides/answer-a-gate.md +304 -0
  30. package/docs/guides/bind-open-parts.md +224 -0
  31. package/docs/guides/cancel-a-run.md +146 -0
  32. package/docs/guides/clean-up.md +206 -0
  33. package/docs/guides/cut-a-worktree.md +560 -0
  34. package/docs/guides/fix-a-failed-converge.md +361 -0
  35. package/docs/guides/give-the-cluster-git-credentials.md +222 -0
  36. package/docs/guides/iterate-on-a-machine-on-kind.md +190 -0
  37. package/docs/guides/let-an-agent-write-a-chart.md +230 -0
  38. package/docs/guides/look-inside-a-sandbox.md +177 -0
  39. package/docs/guides/mirror-the-kit-images.md +176 -0
  40. package/docs/guides/move-from-kind-to-a-shared-cluster.md +318 -0
  41. package/docs/guides/open-the-console.md +91 -0
  42. package/docs/guides/publish-a-machine-as-an-npm-package.md +350 -0
  43. package/docs/guides/push-and-sign-a-branch.md +532 -0
  44. package/docs/guides/run-a-chart-by-name.md +270 -0
  45. package/docs/guides/run-a-command-or-call-a-url.md +587 -0
  46. package/docs/guides/run-one-worker-per-item.md +322 -0
  47. package/docs/guides/set-an-agents-access-and-dials.md +420 -0
  48. package/docs/guides/size-a-workspace.md +217 -0
  49. package/docs/guides/start-a-run-from-a-run.md +237 -0
  50. package/docs/guides/start-a-run.md +207 -0
  51. package/docs/guides/upgrade-the-kit-version.md +240 -0
  52. package/docs/guides/use-a-hosted-provider.md +214 -0
  53. package/docs/guides/use-a-local-model.md +313 -0
  54. package/docs/guides/watch-a-run.md +349 -0
  55. package/docs/guides/write-a-workflow.md +318 -0
  56. package/docs/index.md +44 -0
  57. package/docs/llms.txt +237 -0
  58. package/docs/reference/authoring-surface/agent.md +151 -0
  59. package/docs/reference/authoring-surface/answer.md +156 -0
  60. package/docs/reference/authoring-surface/arg.md +82 -0
  61. package/docs/reference/authoring-surface/basic.md +62 -0
  62. package/docs/reference/authoring-surface/bearer.md +53 -0
  63. package/docs/reference/authoring-surface/branchname.md +15 -0
  64. package/docs/reference/authoring-surface/chartschema.md +23 -0
  65. package/docs/reference/authoring-surface/chartschemafor.md +48 -0
  66. package/docs/reference/authoring-surface/command.md +206 -0
  67. package/docs/reference/authoring-surface/customize.md +64 -0
  68. package/docs/reference/authoring-surface/defineconfig.md +41 -0
  69. package/docs/reference/authoring-surface/defineevent.md +114 -0
  70. package/docs/reference/authoring-surface/dispatch.md +126 -0
  71. package/docs/reference/authoring-surface/fail.md +96 -0
  72. package/docs/reference/authoring-surface/file.md +142 -0
  73. package/docs/reference/authoring-surface/frompick.md +277 -0
  74. package/docs/reference/authoring-surface/http.md +259 -0
  75. package/docs/reference/authoring-surface/isfailure.md +58 -0
  76. package/docs/reference/authoring-surface/isready.md +14 -0
  77. package/docs/reference/authoring-surface/jr2setup.md +237 -0
  78. package/docs/reference/authoring-surface/open.md +105 -0
  79. package/docs/reference/authoring-surface/openbody.md +86 -0
  80. package/docs/reference/authoring-surface/paramsof.md +143 -0
  81. package/docs/reference/authoring-surface/pool.md +186 -0
  82. package/docs/reference/authoring-surface/push.md +130 -0
  83. package/docs/reference/authoring-surface/readyof.md +21 -0
  84. package/docs/reference/authoring-surface/secret.md +139 -0
  85. package/docs/reference/authoring-surface/sentby.md +83 -0
  86. package/docs/reference/authoring-surface/source.md +51 -0
  87. package/docs/reference/authoring-surface/text.md +62 -0
  88. package/docs/reference/authoring-surface/type-agentdeclaration.md +27 -0
  89. package/docs/reference/authoring-surface/type-agentdefinition.md +80 -0
  90. package/docs/reference/authoring-surface/type-agentlogic.md +15 -0
  91. package/docs/reference/authoring-surface/type-agentslots.md +15 -0
  92. package/docs/reference/authoring-surface/type-answeraction.md +12 -0
  93. package/docs/reference/authoring-surface/type-anyframepath.md +14 -0
  94. package/docs/reference/authoring-surface/type-anyworktreepath.md +15 -0
  95. package/docs/reference/authoring-surface/type-arg.md +19 -0
  96. package/docs/reference/authoring-surface/type-argnames.md +12 -0
  97. package/docs/reference/authoring-surface/type-bindactors.md +14 -0
  98. package/docs/reference/authoring-surface/type-binding.md +61 -0
  99. package/docs/reference/authoring-surface/type-bindingof.md +12 -0
  100. package/docs/reference/authoring-surface/type-bodyacceptsdoor.md +15 -0
  101. package/docs/reference/authoring-surface/type-bodyacceptsslots.md +17 -0
  102. package/docs/reference/authoring-surface/type-ceilings.md +41 -0
  103. package/docs/reference/authoring-surface/type-chainlink.md +19 -0
  104. package/docs/reference/authoring-surface/type-chartaction.md +46 -0
  105. package/docs/reference/authoring-surface/type-chartagent.md +28 -0
  106. package/docs/reference/authoring-surface/type-chartevent.md +20 -0
  107. package/docs/reference/authoring-surface/type-chartguard.md +20 -0
  108. package/docs/reference/authoring-surface/type-chartinvoke.md +28 -0
  109. package/docs/reference/authoring-surface/type-chartjson.md +14 -0
  110. package/docs/reference/authoring-surface/type-chartstate.md +46 -0
  111. package/docs/reference/authoring-surface/type-charttext.md +40 -0
  112. package/docs/reference/authoring-surface/type-charttransition.md +22 -0
  113. package/docs/reference/authoring-surface/type-charttransitions.md +14 -0
  114. package/docs/reference/authoring-surface/type-chartvalue.md +15 -0
  115. package/docs/reference/authoring-surface/type-childat.md +12 -0
  116. package/docs/reference/authoring-surface/type-childslots.md +12 -0
  117. package/docs/reference/authoring-surface/type-commandenv.md +15 -0
  118. package/docs/reference/authoring-surface/type-commandinput.md +20 -0
  119. package/docs/reference/authoring-surface/type-commandoptions.md +56 -0
  120. package/docs/reference/authoring-surface/type-commandoutput.md +122 -0
  121. package/docs/reference/authoring-surface/type-customize.md +111 -0
  122. package/docs/reference/authoring-surface/type-dispatchdefinition.md +39 -0
  123. package/docs/reference/authoring-surface/type-dispatchinput.md +14 -0
  124. package/docs/reference/authoring-surface/type-dispatchopenparts.md +14 -0
  125. package/docs/reference/authoring-surface/type-dispatchoutput.md +72 -0
  126. package/docs/reference/authoring-surface/type-doorlessinput.md +19 -0
  127. package/docs/reference/authoring-surface/type-duration.md +15 -0
  128. package/docs/reference/authoring-surface/type-effectbinding.md +93 -0
  129. package/docs/reference/authoring-surface/type-effectlogic.md +12 -0
  130. package/docs/reference/authoring-surface/type-envopenparts.md +14 -0
  131. package/docs/reference/authoring-surface/type-eventaudience.md +27 -0
  132. package/docs/reference/authoring-surface/type-eventdef.md +45 -0
  133. package/docs/reference/authoring-surface/type-eventfrom.md +16 -0
  134. package/docs/reference/authoring-surface/type-eventsemantics.md +26 -0
  135. package/docs/reference/authoring-surface/type-execoutcome.md +34 -0
  136. package/docs/reference/authoring-surface/type-failslot.md +14 -0
  137. package/docs/reference/authoring-surface/type-failure.md +19 -0
  138. package/docs/reference/authoring-surface/type-failureinput.md +20 -0
  139. package/docs/reference/authoring-surface/type-filebody.md +37 -0
  140. package/docs/reference/authoring-surface/type-framepath.md +14 -0
  141. package/docs/reference/authoring-surface/type-frominput.md +14 -0
  142. package/docs/reference/authoring-surface/type-hostinjectedinput.md +56 -0
  143. package/docs/reference/authoring-surface/type-httpdefinition.md +104 -0
  144. package/docs/reference/authoring-surface/type-httpfileinput.md +20 -0
  145. package/docs/reference/authoring-surface/type-httpinput.md +12 -0
  146. package/docs/reference/authoring-surface/type-httpmethod.md +14 -0
  147. package/docs/reference/authoring-surface/type-httpopenparts.md +12 -0
  148. package/docs/reference/authoring-surface/type-httpoutput.md +95 -0
  149. package/docs/reference/authoring-surface/type-httprequestparts.md +33 -0
  150. package/docs/reference/authoring-surface/type-jr2config.md +126 -0
  151. package/docs/reference/authoring-surface/type-lateroutcome.md +21 -0
  152. package/docs/reference/authoring-surface/type-lends.md +38 -0
  153. package/docs/reference/authoring-surface/type-logicat.md +12 -0
  154. package/docs/reference/authoring-surface/type-markedif.md +12 -0
  155. package/docs/reference/authoring-surface/type-mergedactors.md +12 -0
  156. package/docs/reference/authoring-surface/type-namedsecret.md +25 -0
  157. package/docs/reference/authoring-surface/type-namestart.md +77 -0
  158. package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +27 -0
  159. package/docs/reference/authoring-surface/type-notworktreekeys.md +12 -0
  160. package/docs/reference/authoring-surface/type-openbodydeclaration.md +40 -0
  161. package/docs/reference/authoring-surface/type-openbodylogic.md +14 -0
  162. package/docs/reference/authoring-surface/type-openbodyoutput.md +42 -0
  163. package/docs/reference/authoring-surface/type-openbodyslot.md +18 -0
  164. package/docs/reference/authoring-surface/type-opencommandinput.md +22 -0
  165. package/docs/reference/authoring-surface/type-openeffect.md +12 -0
  166. package/docs/reference/authoring-surface/type-openeffectslots.md +12 -0
  167. package/docs/reference/authoring-surface/type-openof.md +12 -0
  168. package/docs/reference/authoring-surface/type-opensecret.md +23 -0
  169. package/docs/reference/authoring-surface/type-opensecretmark.md +12 -0
  170. package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +26 -0
  171. package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +27 -0
  172. package/docs/reference/authoring-surface/type-poolmachine.md +28 -0
  173. package/docs/reference/authoring-surface/type-poolnextinput.md +22 -0
  174. package/docs/reference/authoring-surface/type-poolspec.md +60 -0
  175. package/docs/reference/authoring-surface/type-pushinput.md +34 -0
  176. package/docs/reference/authoring-surface/type-pushoptions.md +79 -0
  177. package/docs/reference/authoring-surface/type-pushoutput.md +149 -0
  178. package/docs/reference/authoring-surface/type-pushwireoutput.md +12 -0
  179. package/docs/reference/authoring-surface/type-quantity.md +14 -0
  180. package/docs/reference/authoring-surface/type-reached.md +12 -0
  181. package/docs/reference/authoring-surface/type-reposlot.md +70 -0
  182. package/docs/reference/authoring-surface/type-reposlotsof.md +16 -0
  183. package/docs/reference/authoring-surface/type-sandboxoptions.md +84 -0
  184. package/docs/reference/authoring-surface/type-secret.md +25 -0
  185. package/docs/reference/authoring-surface/type-sender.md +19 -0
  186. package/docs/reference/authoring-surface/type-sentbyguards.md +12 -0
  187. package/docs/reference/authoring-surface/type-size.md +85 -0
  188. package/docs/reference/authoring-surface/type-slothandles.md +24 -0
  189. package/docs/reference/authoring-surface/type-sourcenextresult.md +17 -0
  190. package/docs/reference/authoring-surface/type-sourcespec.md +44 -0
  191. package/docs/reference/authoring-surface/type-syncstate.md +12 -0
  192. package/docs/reference/authoring-surface/type-text.md +19 -0
  193. package/docs/reference/authoring-surface/type-textpart.md +24 -0
  194. package/docs/reference/authoring-surface/type-thinkinglevel.md +39 -0
  195. package/docs/reference/authoring-surface/type-toparameterizedobject.md +14 -0
  196. package/docs/reference/authoring-surface/type-toprovidedactor.md +14 -0
  197. package/docs/reference/authoring-surface/type-unknown.md +21 -0
  198. package/docs/reference/authoring-surface/type-usercontainer.md +77 -0
  199. package/docs/reference/authoring-surface/type-withoutemptyindex.md +20 -0
  200. package/docs/reference/authoring-surface/type-workflowevent.md +46 -0
  201. package/docs/reference/authoring-surface/type-workspaceaccess.md +16 -0
  202. package/docs/reference/authoring-surface/type-workspaced.md +115 -0
  203. package/docs/reference/authoring-surface/type-workspacehandles.md +22 -0
  204. package/docs/reference/authoring-surface/type-workspacemachine.md +29 -0
  205. package/docs/reference/authoring-surface/type-workspaceof.md +13 -0
  206. package/docs/reference/authoring-surface/type-workspaceoptions.md +27 -0
  207. package/docs/reference/authoring-surface/type-worktreefound.md +16 -0
  208. package/docs/reference/authoring-surface/type-worktreeinput.md +56 -0
  209. package/docs/reference/authoring-surface/type-worktreekey.md +14 -0
  210. package/docs/reference/authoring-surface/type-worktreeoptions.md +29 -0
  211. package/docs/reference/authoring-surface/type-worktreeoutput.md +45 -0
  212. package/docs/reference/authoring-surface/type-worktreepath.md +16 -0
  213. package/docs/reference/authoring-surface/type-worktreeready.md +37 -0
  214. package/docs/reference/authoring-surface/type-worktreerefused.md +21 -0
  215. package/docs/reference/authoring-surface/workspace.md +287 -0
  216. package/docs/reference/authoring-surface/worktree.md +71 -0
  217. package/docs/reference/authoring-surface.md +217 -0
  218. package/docs/reference/cli.md +433 -0
  219. package/docs/reference/config.md +765 -0
  220. package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +114 -0
  221. package/docs/reference/decisions/0002-duplex-streaming-actor.md +117 -0
  222. package/docs/reference/decisions/0004-worktree-provisioning-model.md +130 -0
  223. package/docs/reference/decisions/0005-sandbox-pod-composition.md +240 -0
  224. package/docs/reference/decisions/0006-agent-control-surface.md +50 -0
  225. package/docs/reference/decisions/0007-durable-machine-state.md +109 -0
  226. package/docs/reference/decisions/0008-orchestrator-as-deployed-app.md +60 -0
  227. package/docs/reference/decisions/0009-cli-and-instance-interface.md +275 -0
  228. package/docs/reference/decisions/0010-bdd-acceptance-tests.md +160 -0
  229. package/docs/reference/decisions/0011-workflow-defined-events.md +141 -0
  230. package/docs/reference/decisions/0012-workspace-wrapper-machine.md +103 -0
  231. package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +175 -0
  232. package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +95 -0
  233. package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +271 -0
  234. package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +126 -0
  235. package/docs/reference/decisions/0017-pool-over-a-source-port.md +71 -0
  236. package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +111 -0
  237. package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +287 -0
  238. package/docs/reference/decisions/0020-private-ca-trust-is-a-named-concept.md +60 -0
  239. package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +101 -0
  240. package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +103 -0
  241. package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +175 -0
  242. package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +436 -0
  243. package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +65 -0
  244. package/docs/reference/decisions/0026-a-turn-that-is-over-is-never-prompted.md +62 -0
  245. package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +245 -0
  246. package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +90 -0
  247. package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +154 -0
  248. package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +100 -0
  249. package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +193 -0
  250. package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +61 -0
  251. package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +126 -0
  252. package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +57 -0
  253. package/docs/reference/decisions/0035-a-runaway-turn-is-ended-rerolled-once-then-a-fault.md +92 -0
  254. package/docs/reference/decisions/0036-a-turn-compacts-its-own-context-mid-flight.md +138 -0
  255. package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +196 -0
  256. package/docs/reference/decisions/0038-jr2-up-builds-every-image-it-deploys.md +170 -0
  257. package/docs/reference/decisions/0039-image-garbage-collects-by-reachability.md +115 -0
  258. package/docs/reference/decisions/0041-a-build-the-host-already-holds-is-not-spent-again.md +64 -0
  259. package/docs/reference/decisions/0042-ready-is-not-routable-an-admission-retries-its-connection.md +142 -0
  260. package/docs/reference/decisions/0043-the-kit-is-tested-as-installed-a-local-registry-stands-in-for-npm.md +170 -0
  261. package/docs/reference/decisions/0044-kit-images-live-at-a-canonical-home-a-self-host-mirrors-it.md +85 -0
  262. package/docs/reference/decisions/0045-the-platform-joins-the-image-address-and-the-cluster-chooses-it.md +82 -0
  263. package/docs/reference/decisions/0046-a-converge-failure-carries-its-diagnosis.md +34 -0
  264. package/docs/reference/decisions/0047-the-git-ssh-key-source-is-the-users-choice.md +47 -0
  265. package/docs/reference/decisions/0048-the-orchestrator-boots-without-its-repos.md +36 -0
  266. package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +126 -0
  267. package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +73 -0
  268. package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +238 -0
  269. package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +86 -0
  270. package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +123 -0
  271. package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +126 -0
  272. package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +107 -0
  273. package/docs/reference/decisions/0056-a-global-jr2-hands-off-to-the-instances-own-and-an-instance-has-one-kit-version.md +62 -0
  274. package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +152 -0
  275. package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +108 -0
  276. package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +427 -0
  277. package/docs/reference/decisions/0060-a-workspace-states-its-size-and-jr2-reserves-all-of-it.md +111 -0
  278. package/docs/reference/decisions/0061-a-memory-kill-ends-the-agents-processes-not-the-harness.md +83 -0
  279. package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +239 -0
  280. package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +82 -0
  281. package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +79 -0
  282. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +65 -0
  283. package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +552 -0
  284. package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +458 -0
  285. package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +475 -0
  286. package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +180 -0
  287. package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +334 -0
  288. package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +183 -0
  289. package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +144 -0
  290. package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +122 -0
  291. package/docs/reference/decisions/0074-an-unrouted-mechanism-event-is-refused-at-load-and-faults-the-run.md +76 -0
  292. package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +295 -0
  293. package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +320 -0
  294. package/docs/reference/decisions/0077-jr2-requires-landlock-on-every-sandbox-node.md +79 -0
  295. package/docs/reference/decisions.md +86 -0
  296. package/docs/reference/glossary.md +687 -0
  297. package/docs/reference/http-api.md +1386 -0
  298. package/docs/reference/machines.md +189 -0
  299. package/docs/reference/mechanism-events.md +72 -0
  300. package/docs/why.md +207 -0
  301. package/package.json +5 -3
  302. package/src/actor.ts +694 -106
  303. package/src/agent.ts +114 -38
  304. package/src/ambient.ts +3 -4
  305. package/src/assembly-checks.ts +189 -7
  306. package/src/cause.ts +234 -0
  307. package/src/chart.ts +345 -46
  308. package/src/charts.ts +43 -8
  309. package/src/config.ts +440 -178
  310. package/src/custodian.lua +17 -5
  311. package/src/custodian.ts +325 -99
  312. package/src/customize.ts +199 -49
  313. package/src/dispatch-effect.ts +945 -0
  314. package/src/door-compat.ts +217 -0
  315. package/src/durability.ts +11 -4
  316. package/src/effect-checks.ts +50 -3
  317. package/src/effect.ts +641 -128
  318. package/src/effector-wire.ts +165 -13
  319. package/src/fail.ts +222 -0
  320. package/src/harness-client.ts +587 -50
  321. package/src/harness-env.ts +33 -0
  322. package/src/held-secrets.ts +125 -16
  323. package/src/holds.ts +3 -0
  324. package/src/http-effect.ts +556 -58
  325. package/src/http.ts +480 -30
  326. package/src/index.ts +74 -82
  327. package/src/instance.ts +68 -8
  328. package/src/internal.ts +85 -0
  329. package/src/kube-client.ts +6 -3
  330. package/src/machine-doc.ts +24 -7
  331. package/src/mechanism-routes.ts +168 -0
  332. package/src/model-keys.generated.ts +53 -0
  333. package/src/model-keys.ts +42 -58
  334. package/src/names.ts +19 -6
  335. package/src/notices.ts +483 -41
  336. package/src/open-body.ts +242 -40
  337. package/src/open-effect.ts +81 -8
  338. package/src/open.ts +90 -6
  339. package/src/parts.ts +213 -30
  340. package/src/party.ts +101 -2
  341. package/src/pick.ts +497 -11
  342. package/src/pool.ts +282 -50
  343. package/src/registration.ts +133 -12
  344. package/src/repo-identity.ts +7 -3
  345. package/src/repos.ts +22 -3
  346. package/src/run-host.ts +665 -45
  347. package/src/run-output.ts +38 -0
  348. package/src/sandbox-effect.ts +457 -71
  349. package/src/sandbox-kube.ts +66 -17
  350. package/src/secret-placement.ts +59 -17
  351. package/src/server.ts +3 -0
  352. package/src/setup.ts +325 -62
  353. package/src/size.ts +121 -9
  354. package/src/snapshot-store.ts +54 -10
  355. package/src/stub-harness.ts +44 -16
  356. package/src/timers.ts +14 -1
  357. package/src/tokens.ts +107 -32
  358. package/src/vocabulary.ts +88 -14
  359. package/src/wire.ts +100 -26
  360. package/src/workspace.ts +771 -238
  361. package/src/worktree.ts +249 -0
@@ -0,0 +1,658 @@
1
+ ---
2
+ title: Effects
3
+ description: How a Machine runs a command, calls a URL, pushes a branch or starts a run, at most once.
4
+ ---
5
+
6
+ # Effects
7
+
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 branch of a [Worktree](../reference/glossary.md#worktree), and `dispatch` starts a run of
11
+ a [Workflow](../reference/glossary.md#workflow). 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.
14
+
15
+ ## Why Effects exist
16
+
17
+ A Machine often needs a fact from the world: do the tests pass, did the call succeed, is the branch on the remote.
18
+ Without an Effect, the Machine can only ask an Agent to do the work. Then the Machine must trust what the Agent says. An
19
+ Effect gives the Machine its own result, and the Machine routes on it.
20
+
21
+ An Effect also keeps a credential away from the Agent. A `push` uses a push credential, and an `http` call uses an
22
+ [Effect secret](../reference/glossary.md#effect-secret). The Agent never reads either one. jr2 also records each Effect
23
+ before it starts, so that a restart of the [Orchestrator](../reference/glossary.md#orchestrator) does not do the work
24
+ two times. A plain [xstate](https://xstate.js.org) promise has no such record.
25
+
26
+ ## An Effect is an actor slot
27
+
28
+ Put an Effect under `actors` in [`jr2Setup`](../reference/authoring-surface/jr2setup.md). Invoke it by its key from a
29
+ state. The state's `onDone` gets the output of the Effect. This example is a Workflow with a Workspace. An Agent fixes
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:
32
+
33
+ **Anthropic**
34
+
35
+ ```ts
36
+ import { z } from "zod";
37
+ import {
38
+ agent,
39
+ answer,
40
+ command,
41
+ defineEvent,
42
+ fail,
43
+ isReady,
44
+ jr2Setup,
45
+ push,
46
+ workspace,
47
+ worktree,
48
+ type CommandOutput,
49
+ type Workspaced,
50
+ } from "@jr2/orchestrator";
51
+
52
+ // The two picks of the Agent.
53
+ const runTests = defineEvent({
54
+ name: "run_tests",
55
+ description: "Run the tests. The result is the answer to this call.",
56
+ input: z.object({}),
57
+ });
58
+ const finished = defineEvent({
59
+ name: "finished",
60
+ description: "Call this when the tests pass and your fix is committed.",
61
+ input: z.object({}),
62
+ });
63
+
64
+ const runInput = z.object({ prompt: z.string(), branch: z.string() });
65
+ type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
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
+
70
+ const passed = (output: CommandOutput): boolean => output.outcome === "exited" && output.code === 0;
71
+
72
+ const body = jr2Setup({
73
+ types: {} as { context: BodyInput; input: BodyInput },
74
+ events: [runTests, finished],
75
+ actors: {
76
+ coder: agent({
77
+ model: "anthropic/claude-haiku-5-5",
78
+ instructions: "You are a careful engineer. You commit your work on the branch.",
79
+ }),
80
+ // Three Effects. Each is an actor slot, beside the Agent.
81
+ cut: worktree(),
82
+ tests: command(["node", "--test"], { timeout: "5m" }),
83
+ publish: push(),
84
+ fail: fail(),
85
+ },
86
+ }).createMachine({
87
+ id: "test-and-push",
88
+ context: ({ input }) => input,
89
+ on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
90
+ initial: "cutting",
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
+ },
100
+ coding: {
101
+ invoke: {
102
+ src: "coder",
103
+ input: ({ context }) => ({ prompt: context.prompt, cwd: appTree(context) }),
104
+ },
105
+ on: { finished: "publishing" },
106
+ initial: "ready",
107
+ states: {
108
+ ready: { on: { run_tests: "testing" } },
109
+ testing: {
110
+ invoke: {
111
+ src: "tests",
112
+ input: ({ context }) => ({ worktree: appTree(context) }),
113
+ onDone: {
114
+ target: "ready",
115
+ // The Agent reads this text as the answer to its run_tests pick.
116
+ actions: answer(({ event }) =>
117
+ passed(event.output)
118
+ ? "The tests pass."
119
+ : `The tests fail:\n${"tail" in event.output ? event.output.tail : event.output.reason}`,
120
+ ),
121
+ },
122
+ },
123
+ },
124
+ },
125
+ },
126
+ publishing: {
127
+ invoke: {
128
+ src: "publish",
129
+ input: ({ context }) => ({ worktree: appTree(context) }),
130
+ onDone: [{ guard: ({ event }) => event.output.outcome === "pushed", target: "done" }, { target: "notPushed" }],
131
+ },
132
+ },
133
+ done: { type: "final" },
134
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
135
+ // A Failure ends the body, and jr2 deletes the Sandbox with its commits. To keep them, wait at
136
+ // a Gate before this state.
137
+ notPushed: { invoke: { src: "fail", input: { reason: "the push did not publish the fix" } } },
138
+ failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
139
+ lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
140
+ },
141
+ });
142
+
143
+ export const machine = workspace(body, {
144
+ input: runInput,
145
+ repos: { app: "https://github.com/you/app.git" },
146
+ });
147
+ ```
148
+
149
+ **Local**
150
+
151
+ ```ts
152
+ import { z } from "zod";
153
+ import {
154
+ agent,
155
+ answer,
156
+ command,
157
+ defineEvent,
158
+ fail,
159
+ isReady,
160
+ jr2Setup,
161
+ push,
162
+ workspace,
163
+ worktree,
164
+ type CommandOutput,
165
+ type Workspaced,
166
+ } from "@jr2/orchestrator";
167
+
168
+ // The two picks of the Agent.
169
+ const runTests = defineEvent({
170
+ name: "run_tests",
171
+ description: "Run the tests. The result is the answer to this call.",
172
+ input: z.object({}),
173
+ });
174
+ const finished = defineEvent({
175
+ name: "finished",
176
+ description: "Call this when the tests pass and your fix is committed.",
177
+ input: z.object({}),
178
+ });
179
+
180
+ const runInput = z.object({ prompt: z.string(), branch: z.string() });
181
+ type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
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
+
186
+ const passed = (output: CommandOutput): boolean => output.outcome === "exited" && output.code === 0;
187
+
188
+ const body = jr2Setup({
189
+ types: {} as { context: BodyInput; input: BodyInput },
190
+ events: [runTests, finished],
191
+ actors: {
192
+ coder: agent({
193
+ model: "local/qwen3.6-35b-a3b",
194
+ instructions: "You are a careful engineer. You commit your work on the branch.",
195
+ }),
196
+ // Three Effects. Each is an actor slot, beside the Agent.
197
+ cut: worktree(),
198
+ tests: command(["node", "--test"], { timeout: "5m" }),
199
+ publish: push(),
200
+ fail: fail(),
201
+ },
202
+ }).createMachine({
203
+ id: "test-and-push",
204
+ context: ({ input }) => input,
205
+ on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
206
+ initial: "cutting",
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
+ },
216
+ coding: {
217
+ invoke: {
218
+ src: "coder",
219
+ input: ({ context }) => ({ prompt: context.prompt, cwd: appTree(context) }),
220
+ },
221
+ on: { finished: "publishing" },
222
+ initial: "ready",
223
+ states: {
224
+ ready: { on: { run_tests: "testing" } },
225
+ testing: {
226
+ invoke: {
227
+ src: "tests",
228
+ input: ({ context }) => ({ worktree: appTree(context) }),
229
+ onDone: {
230
+ target: "ready",
231
+ // The Agent reads this text as the answer to its run_tests pick.
232
+ actions: answer(({ event }) =>
233
+ passed(event.output)
234
+ ? "The tests pass."
235
+ : `The tests fail:\n${"tail" in event.output ? event.output.tail : event.output.reason}`,
236
+ ),
237
+ },
238
+ },
239
+ },
240
+ },
241
+ },
242
+ publishing: {
243
+ invoke: {
244
+ src: "publish",
245
+ input: ({ context }) => ({ worktree: appTree(context) }),
246
+ onDone: [{ guard: ({ event }) => event.output.outcome === "pushed", target: "done" }, { target: "notPushed" }],
247
+ },
248
+ },
249
+ done: { type: "final" },
250
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
251
+ // A Failure ends the body, and jr2 deletes the Sandbox with its commits. To keep them, wait at
252
+ // a Gate before this state.
253
+ notPushed: { invoke: { src: "fail", input: { reason: "the push did not publish the fix" } } },
254
+ failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
255
+ lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
256
+ },
257
+ });
258
+
259
+ export const machine = workspace(body, {
260
+ input: runInput,
261
+ repos: { app: "https://github.com/you/app.git" },
262
+ });
263
+ ```
264
+
265
+ [Agents and Turns](agents-and-turns.md) tells how to define an Agent.
266
+
267
+ The Effect has the life of the state that invokes it. It starts when the run enters the state, and it stops when the run
268
+ leaves the state. Its input goes into the run's snapshot. A typo in `src` is a compile error.
269
+ [`customize()`](../reference/authoring-surface/customize.md) binds an [Open](../reference/glossary.md#open) part of the
270
+ Effect by its slot key (see [Composition](composition.md)).
271
+
272
+ [`jr2 up`](../reference/cli.md#up) reads each Effect slot without running it, and prints what it found. For each
273
+ Workflow, it lists each Effect with its kind, its argv or its method and host, its timeout, and where it runs. For the
274
+ example above, `jr2 up` prints these lines:
275
+
276
+ ```text
277
+ effects: workflow "test-and-push" — what it runs outside itself (ADR-0067)
278
+ cut: worktree — 600s, in the Harness
279
+ tests: command ["node","--test"] — 300s, in the Harness
280
+ publish: push — 300s, in the Sandbox Effector
281
+ ```
282
+
283
+ The first line gives the name of the Workflow. Each next line gives the slot of one Effect.
284
+
285
+ `jr2 up` also lists each state that invokes [`fail`](../reference/authoring-surface/fail.md), because each one ends the
286
+ run `failed`:
287
+
288
+ ```text
289
+ failures: workflow "test-and-push" — the states that fail the run (ADR-0073)
290
+ test-and-push.notCut: invokes fail
291
+ test-and-push.notPushed: invokes fail
292
+ test-and-push.failed: invokes fail
293
+ test-and-push.lost: invokes fail
294
+ ```
295
+
296
+ ## The four kinds
297
+
298
+ ### `command`
299
+
300
+ [`command`](../reference/authoring-surface/command.md) runs one program. Its argv is a list, and each entry is one
301
+ argument. jr2 starts `argv[0]` with no shell. An [`arg("name")`](../reference/authoring-surface/arg.md) entry is one
302
+ argument that the input of the Effect fills. Thus an Agent's text cannot become shell syntax. To use a shell, write it
303
+ in the argv: `["sh", "-c", "…"]`. Then the result is the result of your script. The Agent can change the files that the
304
+ script runs, so do not trust its result more than the Agent.
305
+
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.
309
+
310
+ ### `http`
311
+
312
+ [`http`](../reference/authoring-surface/http.md) calls a URL. The definition fixes the method, the URL, the headers and
313
+ the auth. The scheme and the host of the URL are literal text. An Effect secret can be in the path of the URL, in a
314
+ header or in the auth, but never in the host. A `request` function makes the part that changes for each run: path
315
+ segments, and a JSON or text body. Thus a value from the run can change a path segment or the body, but not where the
316
+ call goes.
317
+
318
+ In the second example, an Agent with `workspace: "none"` writes one comment, and the Machine posts it on a ticket. This
319
+ Agent has no [Sandbox](../reference/glossary.md#sandbox). The `jira` Effect secret must be in the
320
+ [`secrets`](../reference/config.md#secrets) list of `jr2.config.ts`:
321
+
322
+ **Anthropic**
323
+
324
+ ```ts
325
+ import { z } from "zod";
326
+ import { agent, bearer, defineEvent, fail, fromPick, http, jr2Setup, secret } from "@jr2/orchestrator";
327
+
328
+ const postComment = defineEvent({
329
+ name: "post_comment",
330
+ description: "Post one comment on the ticket.",
331
+ input: z.object({ body: z.string() }),
332
+ });
333
+
334
+ // The host is fixed here. No input can change it.
335
+ const comment = http({
336
+ method: "POST",
337
+ url: "https://jira.example.com/rest/api/2/issue",
338
+ auth: bearer(secret("jira")),
339
+ input: z.object({ ticket: z.string(), body: z.string() }),
340
+ request: ({ ticket, body }) => ({ path: [ticket, "comment"], json: { body } }),
341
+ });
342
+
343
+ export const machine = jr2Setup({
344
+ types: {} as { context: { ticket: string }; input: { ticket: string } },
345
+ events: [postComment],
346
+ actors: {
347
+ triager: agent({
348
+ model: "anthropic/claude-haiku-5-5",
349
+ instructions: "You triage tickets.",
350
+ workspace: "none",
351
+ }),
352
+ comment,
353
+ fail: fail(),
354
+ },
355
+ }).createMachine({
356
+ id: "comment",
357
+ input: z.object({ ticket: z.string() }),
358
+ context: ({ input }) => input,
359
+ on: { "agent.fault": ".failed" },
360
+ initial: "triaging",
361
+ states: {
362
+ triaging: {
363
+ invoke: {
364
+ src: "triager",
365
+ input: ({ context }) => ({ prompt: `Write one comment for ticket ${context.ticket}.` }),
366
+ },
367
+ initial: "ready",
368
+ states: {
369
+ ready: { on: { post_comment: "posting" } },
370
+ posting: {
371
+ invoke: {
372
+ src: "comment",
373
+ // The Agent gives `body`. The Machine gives `ticket`.
374
+ input: fromPick(postComment, ({ context }) => ({ ticket: context.ticket })),
375
+ onDone: "#done",
376
+ },
377
+ },
378
+ },
379
+ },
380
+ done: { id: "done", type: "final" },
381
+ failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
382
+ },
383
+ });
384
+ ```
385
+
386
+ **Local**
387
+
388
+ ```ts
389
+ import { z } from "zod";
390
+ import { agent, bearer, defineEvent, fail, fromPick, http, jr2Setup, secret } from "@jr2/orchestrator";
391
+
392
+ const postComment = defineEvent({
393
+ name: "post_comment",
394
+ description: "Post one comment on the ticket.",
395
+ input: z.object({ body: z.string() }),
396
+ });
397
+
398
+ // The host is fixed here. No input can change it.
399
+ const comment = http({
400
+ method: "POST",
401
+ url: "https://jira.example.com/rest/api/2/issue",
402
+ auth: bearer(secret("jira")),
403
+ input: z.object({ ticket: z.string(), body: z.string() }),
404
+ request: ({ ticket, body }) => ({ path: [ticket, "comment"], json: { body } }),
405
+ });
406
+
407
+ export const machine = jr2Setup({
408
+ types: {} as { context: { ticket: string }; input: { ticket: string } },
409
+ events: [postComment],
410
+ actors: {
411
+ triager: agent({
412
+ model: "local/qwen3.6-35b-a3b",
413
+ instructions: "You triage tickets.",
414
+ workspace: "none",
415
+ }),
416
+ comment,
417
+ fail: fail(),
418
+ },
419
+ }).createMachine({
420
+ id: "comment",
421
+ input: z.object({ ticket: z.string() }),
422
+ context: ({ input }) => input,
423
+ on: { "agent.fault": ".failed" },
424
+ initial: "triaging",
425
+ states: {
426
+ triaging: {
427
+ invoke: {
428
+ src: "triager",
429
+ input: ({ context }) => ({ prompt: `Write one comment for ticket ${context.ticket}.` }),
430
+ },
431
+ initial: "ready",
432
+ states: {
433
+ ready: { on: { post_comment: "posting" } },
434
+ posting: {
435
+ invoke: {
436
+ src: "comment",
437
+ // The Agent gives `body`. The Machine gives `ticket`.
438
+ input: fromPick(postComment, ({ context }) => ({ ticket: context.ticket })),
439
+ onDone: "#done",
440
+ },
441
+ },
442
+ },
443
+ },
444
+ done: { id: "done", type: "final" },
445
+ failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
446
+ },
447
+ });
448
+ ```
449
+
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.
453
+
454
+ ### `push`
455
+
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:
462
+
463
+ - `pin`: push the commit that the input names, such as a commit that a [Gate](../reference/glossary.md#gate) approved.
464
+ Without `pin`, jr2 pushes the tip of the Agent's branch when the Effect starts.
465
+ - `sign`: push signed copies of the commits.
466
+ - `squash`: push one commit that holds all the changes, with the message that the input gives.
467
+ - `force`: replace what the remote branch holds.
468
+
469
+ With `pin`, the input also gives `{ sha }`. With `squash`, it also gives `{ message }`.
470
+
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
472
+ branch to the published commits. The Agent's files, index and stash do not change. The default timeout is 5 minutes.
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
+
481
+ ### `dispatch`
482
+
483
+ [`dispatch`](../reference/authoring-surface/dispatch.md) starts a run of a Workflow. The new run is a run of its own: it
484
+ has its own line in [`jr2 runs`](../reference/cli.md#runs), its own Workspaces and its own `CANCEL`. Its record names
485
+ the run that started it: it is **dispatched by** that run. Use `dispatch` when a Machine waits for work, for example at
486
+ a [Gate](../reference/glossary.md#gate) that a webhook answers, and each item of work needs a run of a Workflow that you
487
+ have. To use a Machine as a part of one run, invoke it in the run instead (see [Composition](composition.md)).
488
+
489
+ - The name of the Workflow is a constant of the definition, as `jr2 run` writes it: `"triage"`, or `"<wrapper>/<name>"`
490
+ for a named [Chart](../reference/glossary.md#chart). An Agent cannot choose it.
491
+ - The `input` of the invoke is the run input of the new run: the same JSON that `jr2 run --input` sends. The `input`
492
+ option of the definition is a zod schema of that run input. It types the invoke, and `jr2 up` compares it with the
493
+ input that the Workflow declares.
494
+ - By default, the Effect ends when the Orchestrator accepts the new run. With `wait: true`, the Effect ends when the new
495
+ run ends, and its output holds the status and the output of that run. The default timeout is 30 seconds, and 10
496
+ minutes with `wait`.
497
+ - With no `target`, the new run starts in the same Orchestrator. With
498
+ `target: { url: "https://<host>", token: secret("<name>") }`, it starts on a different Orchestrator. `url` is the
499
+ origin of that Orchestrator, and the secret holds its Instance token.
500
+ - The new run starts under the current [Assembly](../reference/glossary.md#assembly), as a run of `jr2 run` does.
501
+
502
+ The two runs are independent. A `CANCEL` of one run does not cancel the other. When the run that dispatched ends, the
503
+ new run continues.
504
+
505
+ ## Where an Effect runs
506
+
507
+ You do not choose where an Effect runs. The kind, and what the Effect names, decide it. Each
508
+ [Effector](../reference/glossary.md#effector) is a container that runs jr2's own process, and the Agent cannot run
509
+ commands in it:
510
+
511
+ | The Effect | Where it runs |
512
+ | --------------------------------------- | ----------------------------------------------------------------------------------- |
513
+ | A `command` that names no Effect secret | The [Harness](../reference/glossary.md#harness) container of the Sandbox |
514
+ | A `worktree()` | The Harness container of the Sandbox |
515
+ | A `command` that names an Effect secret | The [Sandbox Effector](../reference/glossary.md#sandbox-effector), against a commit |
516
+ | An `http` Effect | The [Instance Effector](../reference/glossary.md#instance-effector) |
517
+ | An `http` Effect with a Worktree file | The Sandbox Effector |
518
+ | A `push` | The Sandbox Effector |
519
+ | A `dispatch` with no `target` | The Orchestrator, in its own process |
520
+ | A `dispatch` with a `target` | The Instance Effector |
521
+
522
+ A `command` that names no Effect secret runs beside the Agent's [Working tools](../reference/glossary.md#working-tools).
523
+ It runs as the Agent's user, with the tools of the [Sandbox Image](../reference/glossary.md#sandbox-image). The Harness
524
+ confines it with Landlock, as it confines the Agent's shell. It has the same
525
+ [Stand-ins](../reference/glossary.md#stand-in) as the Agent's shell, and no credential of its own.
526
+
527
+ A `command` that names an Effect secret in its `env` runs in the Sandbox Effector, a container in which the Agent runs
528
+ nothing. It does not run in the live Worktree. It runs against one commit: the tip of the branch when it starts, or with
529
+ `pin`, the commit that its input names. When the Worktree held changes that the command did not see, its output has
530
+ `dirty: true`.
531
+
532
+ A `command`, a `worktree()`, a `push` and an `http` Effect with a file body need a Workspace. Invoke them from the body
533
+ of a [`workspace()`](../reference/authoring-surface/workspace.md). [Architecture](architecture.md) tells what each
534
+ Effector is, and [Secrets and trust](secrets-and-trust.md) tells how an Effector holds the Effect secrets.
535
+
536
+ ## Every outcome is output
537
+
538
+ An Effect gives each outcome to `onDone`, a failure too. Route on the `outcome` field:
539
+
540
+ | Kind | The outcomes | The output type |
541
+ | ---------- | --------------------------------------------------------- | ------------------------------------------------------------------------- |
542
+ | `worktree` | `ready`, `refused`, `unknown` | [`WorktreeOutput`](../reference/authoring-surface/type-worktreeoutput.md) |
543
+ | `command` | `exited`, `timeout`, `killed`, `unknown` | [`CommandOutput`](../reference/authoring-surface/type-commandoutput.md) |
544
+ | `http` | `response`, `unreachable`, `refused`, `unknown` | [`HttpOutput`](../reference/authoring-surface/type-httpoutput.md) |
545
+ | `push` | `pushed`, `rejected`, `diverged`, `unknown` | [`PushOutput`](../reference/authoring-surface/type-pushoutput.md) |
546
+ | `dispatch` | `started`, `settled`, `refused`, `unreachable`, `unknown` | [`DispatchOutput`](../reference/authoring-surface/type-dispatchoutput.md) |
547
+
548
+ A test that fails is `exited` with a code that is not 0. A program that the container does not have is `exited` with
549
+ code 127. An HTTP 4xx or 5xx status is a `response`. A Workflow that refuses the run input of a `dispatch` is `refused`,
550
+ with the status code and the report of the refusal. `unknown` means that jr2 cannot tell what the Effect did.
551
+
552
+ Each union is open: it holds a stand-in member, `LaterOutcome`, so a later release can add an outcome and your Machine
553
+ 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
554
+ state and shows no fault. So `createMachine`, `jr2 check`, `jr2 up` and the Chart door refuse an `onDone` with a guard
555
+ on its last arm. An invoke with no `onDone` is legal: the Effect settles, and the state stays.
556
+
557
+ 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
558
+ a Workspace, or an `arg()` has no value, or an Open part has no binding. An outcome that means that the work did not
559
+ succeed goes to a state that invokes [`fail`](../reference/authoring-surface/fail.md). Then the run ends `failed`, with
560
+ a reason (see [How a run ends](machines-and-workflows.md#how-a-run-ends)). Do not throw to fail: a throw is a defect,
561
+ and the run ends `error`.
562
+
563
+ ## At most once
564
+
565
+ jr2 writes a record of each Effect before the Effect starts, and saves it with the run's snapshot. When the Effect ends,
566
+ jr2 records its output. After an Orchestrator restart, jr2 reads the record:
567
+
568
+ - An Effect that ended gives its output. jr2 does not run it again.
569
+ - An Effect that did not start, starts.
570
+ - An Effect that started follows the rule of its kind.
571
+
572
+ | Kind | After a restart, when the Effect started |
573
+ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
574
+ | 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. |
575
+ | 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`. |
576
+ | A `worktree()` | jr2 attaches to it again. When the Harness does not know it, jr2 sends it again: a cut is idempotent. |
577
+ | 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`. |
578
+ | 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`. |
579
+ | 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. |
580
+
581
+ A `command` that names no Effect secret runs the code of the Worktree, and that code can spend a Stand-in. Thus jr2 does
582
+ not run it two times. A `push`, and a `command` that names an Effect secret, run against a commit that jr2 records. Thus
583
+ jr2 can send them again with that commit.
584
+
585
+ To try again, write it in the Machine: a route from the outcome back into the state. Mark an `http` Effect `idempotent`
586
+ only when a second call is safe: the call has its own idempotency key, or it only reads.
587
+
588
+ ## When the state exits
589
+
590
+ When the run leaves the state, the Effect stops:
591
+
592
+ - jr2 kills the process group of a `command` that names no Effect secret.
593
+ - The Sandbox Effector stops a `command` that names an Effect secret. It sends `SIGTERM`, waits 5 seconds, then sends
594
+ `SIGKILL`.
595
+ - An `http` Effect and a `push` have no stop. jr2 stops waiting for the output, but the Effector can still finish the
596
+ work.
597
+ - A `dispatch` with `wait` stops its wait. The run that it started continues.
598
+
599
+ jr2 records the stop, and the Machine gets no output. There is no "finally" in a Machine: cleanup is a state. Put an
600
+ Effect that must not stop in a state of its own. The only exit of that state is its `onDone`. That state handles the
601
+ events of the states above it.
602
+
603
+ ## From a pick to an Effect
604
+
605
+ An Agent can start an Effect with a pick. The pick moves the run into a state that invokes the Effect. Three names help
606
+ you write that state. Each one is optional.
607
+
608
+ - [`fromPick(def, fill)`](../reference/authoring-surface/frompick.md) is the `input` of the state. The params of the
609
+ pick go into the Effect's input, by name. `fill` gives only the keys that the Machine adds. In `comment.ts`, the Agent
610
+ gives `body`, and the Machine gives `ticket`. Thus the Agent cannot post on a different ticket. TypeScript checks the
611
+ sum against the input type of the Effect.
612
+ - [`paramsOf(event, def)`](../reference/authoring-surface/paramsof.md) reads the same params in a plain `input` mapper.
613
+ Use it when the Machine changes a param before the Effect gets it.
614
+ - [`answer(fn)`](../reference/authoring-surface/answer.md) sets what the Agent reads when jr2 answers its pick. In
615
+ `test-and-push.ts`, the Agent reads one line, or the end of the test output. Without `answer`, it reads the
616
+ `CommandOutput` of the command, as JSON. [The Menu](the-menu.md) tells more about `answer`.
617
+
618
+ While the Effect runs below the Agent's state, the Agent's pick is [outstanding](../reference/glossary.md#outstanding).
619
+ The state is not at [Rest](../reference/glossary.md#rest) until the Effect ends. [The Menu](the-menu.md) tells how a
620
+ pick waits for its answer.
621
+
622
+ ## Rules
623
+
624
+ - An Effect is a key of `actors`. `createMachine` refuses an Effect that you write directly in an `invoke`.
625
+ - The last arm of an Effect's `onDone` has no guard. `createMachine` refuses one that has:
626
+ `machine "<id>": state "<state>" (Effect "<slot>") has an onDone with no unguarded last arm — … (ADR-0075)`.
627
+ - A `command`, a `worktree()`, a `push` and an `http` Effect with a file body run only inside a `workspace()`.
628
+ - Under a Workspace with more than one Repo Slot, a `push` names its `slot`.
629
+ - The host of an `http` URL is literal. An Effect secret never goes in the host, the query or the fragment of a URL.
630
+ - Each Effect secret that an Effect names is in the `secrets` list of `jr2.config.ts`, with a value of 8 characters or
631
+ more. `jr2 up` refuses a name that is not in the list, and a value that is shorter.
632
+ - A `push` with `sign` needs a `sign` field on its `git.credentials` entry. A `squash` without `sign` needs a `sign` or
633
+ a `committer` field there.
634
+ - Each param of a pick that enters an Effect's state has a reader: the Effect's input, `fill`, a guard or an `assign`.
635
+ `createMachine` refuses a param that nothing reads, and a `fill` key that is also a param.
636
+ - A packaged Machine can leave an `http` URL, a `command` argv, one Effect secret name or the `target` of a `dispatch`
637
+ Open. The composer binds it one time with `customize()`. `jr2 up` refuses an Open part that nobody bound.
638
+ - A `dispatch` with no `target` names a Workflow that the Assembly has. `jr2 up` refuses a name that it does not have,
639
+ and an `input` schema that the input of that Workflow does not take.
640
+ - 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.
641
+
642
+ The guides give the refusal text of each rule.
643
+
644
+ ## Read next
645
+
646
+ - [Run a command or call a URL with an Effect](../guides/run-a-command-or-call-a-url.md)
647
+ - [Push and sign a branch](../guides/push-and-sign-a-branch.md)
648
+ - [Start a run from a run](../guides/start-a-run-from-a-run.md)
649
+ - [Workspaces](workspaces.md), [The Menu](the-menu.md), [Secrets and trust](secrets-and-trust.md)
650
+ - Reference: [`command`](../reference/authoring-surface/command.md), [`http`](../reference/authoring-surface/http.md),
651
+ [`push`](../reference/authoring-surface/push.md), [`dispatch`](../reference/authoring-surface/dispatch.md),
652
+ [`fromPick`](../reference/authoring-surface/frompick.md), [`answer`](../reference/authoring-surface/answer.md)
653
+ - [ADR-0067](../reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md):
654
+ an Effect is an actor slot, and runs at most once unless marked idempotent
655
+ - [ADR-0068](../reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md): an Effector holds
656
+ an Effect's secrets and signs its wire
657
+ - [ADR-0071](../reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md): a run starts a run through a
658
+ `dispatch` Effect