@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
package/src/party.ts CHANGED
@@ -24,9 +24,75 @@ import { vocabularyOf } from "./vocabulary.ts";
24
24
  /** The guard type `sentBy` names: dotted, so no author guard can take the name. */
25
25
  export const SENT_BY = "jr2.sentBy";
26
26
 
27
- /** A writing runs for this party's events, and for the Machine's own: `guard: sentBy("coder")`. The
28
- * id is an Agent slot, or a Gate's invoke id, of this Machine — an unknown id is refused at load. */
27
+ /**
28
+ * A guard that is true for an event that one party sent, and false for an event that another party
29
+ * sent: `guard: sentBy("coder")`. Use it where two parties may send the same event to one state,
30
+ * and the transition must run for one of them only. It is also true for an event that the Machine
31
+ * sends itself, which has no sender.
32
+ *
33
+ * It can only make a transition decline the events of other parties. It never lets a party send
34
+ * an event that the party may not send at that state: the position of the `on` key decides that.
35
+ * When the guard is false, xstate tries the next transition for the event, as for any guard. Use
36
+ * it alone, or inside `and([…])`.
37
+ *
38
+ * `createMachine` refuses an id that is not a party of the Machine: ``machine "<id>":
39
+ * sentBy("<party>") on "<event>" at "<state>" names no party of this Machine (Agent slots:
40
+ * <slots>; Gate invoke ids: <ids>)``
41
+ *
42
+ * @param id - The party: the slot key of an Agent of this Machine, or the invoke `id` of one of its
43
+ * Gates.
44
+ * @returns A named guard object, for a transition's `guard`.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * import { z } from "zod";
49
+ * import { agent, defineEvent, fail, jr2Setup, sentBy } from "@jr2/orchestrator";
50
+ *
51
+ * const done = defineEvent({
52
+ * name: "done",
53
+ * description: "Call this when the draft is ready for review.",
54
+ * input: z.object({}),
55
+ * });
56
+ *
57
+ * export const machine = jr2Setup({
58
+ * events: [done],
59
+ * actors: {
60
+ * writer: agent({
61
+ * model: "anthropic/claude-haiku-5-5",
62
+ * instructions: "You write release notes.",
63
+ * workspace: "none",
64
+ * }),
65
+ * fail: fail(),
66
+ * },
67
+ * }).createMachine({
68
+ * id: "notes",
69
+ * on: { "agent.fault": ".failed" },
70
+ * initial: "drafting",
71
+ * states: {
72
+ * drafting: {
73
+ * invoke: [
74
+ * { src: "writer", input: { prompt: "Draft the release notes." } },
75
+ * { src: "gate", id: "editor" },
76
+ * ],
77
+ * on: {
78
+ * // The writer's `done` goes to review; the editor's `done` skips it.
79
+ * done: [{ guard: sentBy("writer"), target: "review" }, { target: "published" }],
80
+ * },
81
+ * },
82
+ * review: { invoke: { src: "gate" }, on: { done: "published" } },
83
+ * published: { type: "final" },
84
+ * failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
85
+ * },
86
+ * });
87
+ * ```
88
+ *
89
+ * @see docs/concepts/the-menu.md
90
+ * @see docs/concepts/gates.md
91
+ * @see docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md
92
+ */
29
93
  export function sentBy<const Id extends string>(id: Id): { type: typeof SENT_BY; params: { id: Id } } {
94
+ // A NAMED guard with params, so the load walk can read it (see the module header). The id is
95
+ // refused at load by `refuseUnknownSentBy` when no Agent slot or Gate invoke id has it.
30
96
  return { type: SENT_BY, params: { id } };
31
97
  }
32
98
 
@@ -356,6 +422,39 @@ function orthogonal(a: Node, b: Node): boolean {
356
422
  /** Can the two states be active at the same time? */
357
423
  const together = (a: Node, b: Node): boolean => isAncestorOrSelf(a, b) || isAncestorOrSelf(b, a) || orthogonal(a, b);
358
424
 
425
+ /**
426
+ * Refuse one Agent slot invoked by two states that can be active together (ADR-0015): in two
427
+ * parallel regions, one state inside the other, or twice by one state. A slot is one Agent of this
428
+ * Machine: its Turns share one sender, so `sentBy` cannot tell them apart and one pick matches both
429
+ * writings, and they share one conversation, so `continue` cannot hold two. Two Agents at once are
430
+ * two slots (one definition can fill both), a child Machine in each region, or a Pool (ADR-0075).
431
+ */
432
+ export function refuseSlotActiveTwice(machine: AnyStateMachine): void {
433
+ const bySlot = new Map<string, Node[]>();
434
+ for (const node of allNodes(machine))
435
+ for (const p of partiesAt(node, machine))
436
+ if (p.party === "agent") bySlot.set(p.id, [...(bySlot.get(p.id) ?? []), node]);
437
+ for (const [slot, nodes] of bySlot) {
438
+ for (let i = 0; i < nodes.length; i++) {
439
+ for (let j = i + 1; j < nodes.length; j++) {
440
+ const [a, b] = [nodes[i]!, nodes[j]!];
441
+ if (!together(a, b)) continue;
442
+ const how =
443
+ a === b
444
+ ? `state "${a.id}" invokes it twice`
445
+ : `"${a.id}" and "${b.id}" invoke it and can be active together ` +
446
+ (orthogonal(a, b) ? "(parallel regions)" : "(one inside the other)");
447
+ throw new Error(
448
+ `machine "${machine.id}": Agent "${slot}" would run two Turns at once: ${how}. A slot is one Agent, with ` +
449
+ "one sender and one conversation, so `sentBy` cannot tell its two Turns apart and `continue` cannot " +
450
+ "hold both. For two Agents at once, use two slots (one definition can fill both), a child Machine in " +
451
+ "each region, or a Pool (ADR-0075)",
452
+ );
453
+ }
454
+ }
455
+ }
456
+ }
457
+
359
458
  /** One writing: one `on` key on one state, with its candidates (an array writing has several). */
360
459
  type Writing = { node: Node; name: string; candidates: Transition[] };
361
460
 
package/src/pick.ts CHANGED
@@ -33,9 +33,129 @@ import { isAgent } from "./agent.ts";
33
33
  import { boundRun } from "./registration.ts";
34
34
  import type { PickAnswer } from "./wire.ts";
35
35
 
36
- /** The pick's params, read off the event that entered the state. Throws — a jr2 or author defect
37
- * the load walk refuses first — when the event is not this pick. */
36
+ /**
37
+ * Read the params of a pick from the event that entered the state. Use it in a plain `input`
38
+ * mapper when the Machine must change a param before the invoked actor gets it. When the params go
39
+ * to the input as they are, use `fromPick`.
40
+ *
41
+ * It parses the params with the `input` schema of the pick. It refuses an event that is not this
42
+ * pick: `state entered by "<event>", but its input reads the params of pick "<pick>"`.
43
+ *
44
+ * `createMachine` calls each mapper one time to see which params it reads. When the mapper throws
45
+ * there, `jr2 up` prints a warning before a run starts: `pick "<pick>" enters state "<state>"
46
+ * (Effect "<slot>"): could not probe the input mapper (<error>); its params are unchecked`.
47
+ *
48
+ * `createMachine` refuses a param of a pick that enters a state that invokes an Effect, when
49
+ * nothing reads the param: `machine "<id>": pick "<pick>" enters state "<state>" (Effect
50
+ * "<slot>"), which never reads "<param>": the Agent supplies it and nothing uses it — map it in an
51
+ * invoke's input, store it with assign, or drop it from the def`.
52
+ *
53
+ * @param event - The event that entered the state: the `event` that the mapper gets.
54
+ * @param def - The pick, as `defineEvent` made it.
55
+ * @returns The params of the pick, typed by its `input` schema.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * import { z } from "zod";
60
+ * import {
61
+ * agent,
62
+ * arg,
63
+ * command,
64
+ * defineEvent,
65
+ * fail,
66
+ * isReady,
67
+ * jr2Setup,
68
+ * paramsOf,
69
+ * workspace,
70
+ * worktree,
71
+ * type Workspaced,
72
+ * } from "@jr2/orchestrator";
73
+ *
74
+ * const runTest = defineEvent({
75
+ * name: "run_test",
76
+ * description: "Run the tests of one module.",
77
+ * input: z.object({ module: z.string() }),
78
+ * });
79
+ *
80
+ * const finished = defineEvent({
81
+ * name: "finished",
82
+ * description: "Say that all the tests pass.",
83
+ * input: z.object({}),
84
+ * });
85
+ *
86
+ * type Input = Workspaced<{}, "app">;
87
+ *
88
+ * const fixTree = (context: Input) => `${context.workspace.repos.app}/fix` as const;
89
+ *
90
+ * const body = jr2Setup({
91
+ * types: {} as { context: Input; input: Input },
92
+ * events: [runTest, finished],
93
+ * actors: {
94
+ * coder: agent({
95
+ * model: "anthropic/claude-haiku-5-5",
96
+ * instructions: "You are a careful engineer.",
97
+ * }),
98
+ * cut: worktree(),
99
+ * test: command(["node", "--test", arg("file")]),
100
+ * fail: fail(),
101
+ * },
102
+ * }).createMachine({
103
+ * id: "fix-tests",
104
+ * context: ({ input }) => input,
105
+ * on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
106
+ * initial: "cutting",
107
+ * states: {
108
+ * cutting: {
109
+ * invoke: {
110
+ * src: "cut",
111
+ * input: ({ context }) => ({ path: fixTree(context), branch: "fix-tests" }),
112
+ * onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
113
+ * },
114
+ * },
115
+ * coding: {
116
+ * invoke: {
117
+ * src: "coder",
118
+ * input: ({ context }) => ({
119
+ * prompt: "Make the tests pass. Run the tests of one module at a time.",
120
+ * cwd: fixTree(context),
121
+ * }),
122
+ * },
123
+ * on: { finished: "done" },
124
+ * initial: "ready",
125
+ * states: {
126
+ * ready: { on: { run_test: "testing" } },
127
+ * testing: {
128
+ * invoke: {
129
+ * src: "test",
130
+ * // A plain mapper: the Machine makes the file name from the pick's `module`.
131
+ * input: ({ context, event }) => ({
132
+ * file: `test/${paramsOf(event, runTest).module}.test.js`,
133
+ * worktree: fixTree(context),
134
+ * }),
135
+ * onDone: "ready",
136
+ * },
137
+ * },
138
+ * },
139
+ * },
140
+ * done: { type: "final" },
141
+ * notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
142
+ * failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
143
+ * lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
144
+ * },
145
+ * });
146
+ *
147
+ * export const machine = workspace(body, {
148
+ * repos: { app: { url: "https://github.com/you/app.git" } },
149
+ * });
150
+ * ```
151
+ *
152
+ * @see docs/concepts/effects.md
153
+ * @see docs/guides/run-a-command-or-call-a-url.md
154
+ * @see docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md
155
+ */
38
156
  export function paramsOf<N extends string, I extends z.ZodObject>(event: EventObject, def: EventDef<N, I>): z.infer<I> {
157
+ // Throws on a jr2 or author defect, which the load walk (effect-checks.ts) finds first: it probes
158
+ // the mapper before the Machine runs.
39
159
  if (event.type !== def.name) {
40
160
  throw new Error(`state entered by "${event.type}", but its input reads the params of pick "${def.name}"`);
41
161
  }
@@ -55,9 +175,239 @@ export function isPickMapper(value: unknown): value is PickMapper & ((args: unkn
55
175
  return typeof value === "function" && "pick" in value;
56
176
  }
57
177
 
178
+ /**
179
+ * Make the `input` of the invoke of a state that a pick enters: the params of the pick go to the
180
+ * input of the invoked actor by name. With `fill`, the Machine adds the keys that the Agent must
181
+ * not choose. So one expression shows the security boundary: the pick is what the Agent gives, and
182
+ * `fill` is what the Machine adds.
183
+ *
184
+ * TypeScript checks the params and the keys of `fill` together against the input type of the
185
+ * invoked actor. It finds a missing key or a key of the wrong type, but it accepts an extra key.
186
+ *
187
+ * So `createMachine` refuses:
188
+ * - a param that is no key of the input of the Effect, and that nothing else reads: ``machine
189
+ * "<id>": pick "<pick>" enters state "<state>" (Effect "<slot>") with fromPick: "<param>" is no
190
+ * key of the Effect's input (<keys>), and nothing else reads it — the Agent supplies it and it
191
+ * reaches nothing; name an argv slot for it, read it in `fill`, store it with assign, or drop it
192
+ * from the def``
193
+ * - a key that `fill` sets and that is also a param: ``machine "<id>": pick "<pick>" enters state
194
+ * "<state>" (Effect "<slot>"): `fill` sets "<param>", which is also a param of the pick — the
195
+ * Machine's value wins and the Agent's is dropped; rename one, or drop it from the def``
196
+ * - a `fromPick` in a state that another event enters: `machine "<id>": state "<state>" (Effect
197
+ * "<slot>") reads the params of pick "<pick>" but is entered on "<event>" — that event does not
198
+ * carry them`
199
+ *
200
+ * The input of an Open argv is one string for each key, so TypeScript checks no key for it. A key
201
+ * that the bound argv names and the input does not give stops the Effect when it starts.
202
+ *
203
+ * The state that the pick enters has one of two places:
204
+ * - A child state of the Agent's state, as in the first example. The Turn stays open, and the
205
+ * pick is outstanding until the Effect ends. Use this shape when the Agent must see the result.
206
+ * The Agent reads the Effect's output as the answer only when the route after the Effect stays
207
+ * in the Agent's state, as `onDone: "ready"` does. Then the Agent can pick again. A route that
208
+ * leaves the Agent's state ends the Turn when the Effect ends, and no Agent reads the output.
209
+ * - A sibling state of the Agent's state, as in the second example. The pick leaves the Agent's
210
+ * state, so the Turn ends before the Effect runs, and the Agent does not see the output. Use
211
+ * this shape for a pick that ends the work of the Agent.
212
+ *
213
+ * @param def - The pick, as `defineEvent` made it.
214
+ * @returns An `input` mapper for the `invoke` of the state.
215
+ *
216
+ * @example
217
+ * ```ts
218
+ * import { z } from "zod";
219
+ * import { agent, defineEvent, fail, fromPick, http, jr2Setup } from "@jr2/orchestrator";
220
+ *
221
+ * const postNote = defineEvent({
222
+ * name: "post_note",
223
+ * description: "Post a note to the team channel.",
224
+ * input: z.object({ text: z.string() }),
225
+ * });
226
+ *
227
+ * const finish = defineEvent({
228
+ * name: "finish",
229
+ * description: "The note is posted. This ends your work.",
230
+ * input: z.object({}),
231
+ * });
232
+ *
233
+ * export const machine = jr2Setup({
234
+ * types: {} as { context: {}; input: {} },
235
+ * events: [postNote, finish],
236
+ * actors: {
237
+ * writer: agent({
238
+ * model: "anthropic/claude-haiku-5-5",
239
+ * instructions: "You write one short note for the team.",
240
+ * workspace: "none",
241
+ * }),
242
+ * note: http({
243
+ * method: "POST",
244
+ * url: "https://hooks.example.com/notes",
245
+ * input: z.object({ text: z.string() }),
246
+ * request: ({ text }) => ({ json: { text } }),
247
+ * }),
248
+ * fail: fail(),
249
+ * },
250
+ * }).createMachine({
251
+ * id: "note",
252
+ * on: { "agent.fault": ".failed" },
253
+ * initial: "writing",
254
+ * states: {
255
+ * writing: {
256
+ * invoke: {
257
+ * src: "writer",
258
+ * input: {
259
+ * prompt: "Write a note that says the release is out, post it, and check the reply.",
260
+ * },
261
+ * },
262
+ * initial: "ready",
263
+ * states: {
264
+ * ready: { on: { post_note: "posting", finish: "#done" } },
265
+ * posting: {
266
+ * // The `text` of the pick goes to the input of `note` as it is. The route goes back
267
+ * // to `ready`, in `writing`: the writer reads the output and picks again.
268
+ * invoke: { src: "note", input: fromPick(postNote), onDone: "ready" },
269
+ * },
270
+ * },
271
+ * },
272
+ * done: { id: "done", type: "final" },
273
+ * failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
274
+ * },
275
+ * });
276
+ * ```
277
+ *
278
+ * @example
279
+ * ```ts
280
+ * import { z } from "zod";
281
+ * import { agent, defineEvent, fail, fromPick, http, jr2Setup } from "@jr2/orchestrator";
282
+ *
283
+ * const postNote = defineEvent({
284
+ * name: "post_note",
285
+ * description: "Post the note to the team channel. This ends your work.",
286
+ * input: z.object({ text: z.string() }),
287
+ * });
288
+ *
289
+ * export const machine = jr2Setup({
290
+ * types: {} as { context: {}; input: {} },
291
+ * events: [postNote],
292
+ * actors: {
293
+ * writer: agent({
294
+ * model: "anthropic/claude-haiku-5-5",
295
+ * instructions: "You write one short note for the team.",
296
+ * workspace: "none",
297
+ * }),
298
+ * note: http({
299
+ * method: "POST",
300
+ * url: "https://hooks.example.com/notes",
301
+ * input: z.object({ text: z.string() }),
302
+ * request: ({ text }) => ({ json: { text } }),
303
+ * }),
304
+ * fail: fail(),
305
+ * },
306
+ * }).createMachine({
307
+ * id: "note",
308
+ * on: { "agent.fault": ".failed" },
309
+ * initial: "writing",
310
+ * states: {
311
+ * // The pick leaves this state, so it ends the Turn of the writer.
312
+ * writing: {
313
+ * invoke: {
314
+ * src: "writer",
315
+ * input: { prompt: "Write a note that says the release is out, and post it." },
316
+ * },
317
+ * on: { post_note: "posting" },
318
+ * },
319
+ * // A sibling of `writing`: the Effect runs after the Turn, and no Agent reads its output.
320
+ * posting: {
321
+ * invoke: { src: "note", input: fromPick(postNote), onDone: "done" },
322
+ * },
323
+ * done: { type: "final" },
324
+ * failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
325
+ * },
326
+ * });
327
+ * ```
328
+ *
329
+ * @see docs/concepts/effects.md
330
+ * @see docs/guides/run-a-command-or-call-a-url.md
331
+ * @see docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md
332
+ */
58
333
  export function fromPick<N extends string, I extends z.ZodObject, C, E extends EventObject>(
59
334
  def: EventDef<N, I>,
60
335
  ): (args: { context: C; event: E; self: AnyActorRef }) => z.infer<I>;
336
+ /**
337
+ * Make the `input` from the params of the pick and the keys that `fill` adds. {@link fromPick}
338
+ * tells the rest, and what `createMachine` refuses.
339
+ *
340
+ * @param def - The pick, as `defineEvent` made it.
341
+ * @param fill - Gets `{ context, params }` and gives back only the keys that the Machine adds. Do
342
+ * not set a key that is also a param.
343
+ * @returns An `input` mapper for the `invoke` of the state.
344
+ *
345
+ * @example
346
+ * ```ts
347
+ * import { z } from "zod";
348
+ * import { agent, bearer, defineEvent, fail, fromPick, http, jr2Setup, secret } from "@jr2/orchestrator";
349
+ *
350
+ * const postComment = defineEvent({
351
+ * name: "post_comment",
352
+ * description: "Post a comment on the ticket.",
353
+ * input: z.object({ body: z.string() }),
354
+ * });
355
+ *
356
+ * export const machine = jr2Setup({
357
+ * types: {} as { context: { ticket: string }; input: { ticket: string } },
358
+ * events: [postComment],
359
+ * actors: {
360
+ * triager: agent({
361
+ * model: "anthropic/claude-haiku-5-5",
362
+ * instructions: "You triage tickets.",
363
+ * workspace: "none",
364
+ * }),
365
+ * comment: http({
366
+ * method: "POST",
367
+ * url: "https://jira.example.com/rest/api/2/issue",
368
+ * auth: bearer(secret("jira")),
369
+ * input: z.object({ ticket: z.string(), body: z.string() }),
370
+ * request: ({ ticket, body }) => ({ path: [ticket, "comment"], json: { body } }),
371
+ * }),
372
+ * fail: fail(),
373
+ * },
374
+ * }).createMachine({
375
+ * id: "triage",
376
+ * context: ({ input }) => input,
377
+ * on: { "agent.fault": ".failed" },
378
+ * initial: "triaging",
379
+ * states: {
380
+ * triaging: {
381
+ * invoke: {
382
+ * src: "triager",
383
+ * input: ({ context }) => ({
384
+ * prompt: `Read ticket ${context.ticket}, then post one comment on it.`,
385
+ * }),
386
+ * },
387
+ * initial: "ready",
388
+ * states: {
389
+ * ready: { on: { post_comment: "posting" } },
390
+ * posting: {
391
+ * invoke: {
392
+ * src: "comment",
393
+ * // The Agent gives `body`. The Machine gives `ticket`, so the Agent cannot post on
394
+ * // another ticket.
395
+ * input: fromPick(postComment, ({ context }) => ({ ticket: context.ticket })),
396
+ * onDone: "#done",
397
+ * },
398
+ * },
399
+ * },
400
+ * },
401
+ * done: { id: "done", type: "final" },
402
+ * failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
403
+ * },
404
+ * });
405
+ * ```
406
+ *
407
+ * @see docs/concepts/effects.md
408
+ * @see docs/guides/run-a-command-or-call-a-url.md
409
+ * @see docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md
410
+ */
61
411
  export function fromPick<N extends string, I extends z.ZodObject, C, E extends EventObject, R extends object>(
62
412
  def: EventDef<N, I>,
63
413
  fill: (args: { context: C; params: z.infer<I> }) => R,
@@ -113,8 +463,8 @@ export type AnswerSeats = ReadonlySet<Node | null>;
113
463
  /**
114
464
  * The one place an `answer` runs from (ADR-0067): the Agent's state it is written below, or `null`
115
465
  * on a transition below no Agent's state. At a state, it shapes only a pick of the Agent seated
116
- * there. At `null`, the event that took the transition names the Agent whose pick it shapes (the run
117
- * host reads it off the event).
466
+ * there. At `null`, the event that took the transition names the Agent whose pick it shapes (the
467
+ * run host reads it off the event).
118
468
  */
119
469
  export type AnswerSeat = Node | null;
120
470
 
@@ -124,7 +474,8 @@ const seatsCache = new WeakMap<AnyStateMachine, Map<unknown, Set<Node | null>>>(
124
474
  const PLACE = Symbol("jr2.answer.place");
125
475
  type Placeable = { [PLACE]: (seat: AnswerSeat) => unknown; readonly jr2Answer: true };
126
476
 
127
- /** An action of `machine` as it is written — inline, or by name — resolved to its implementation. */
477
+ /** An action of `machine` as it is written — inline, or by name — resolved to its implementation.
478
+ */
128
479
  function resolverOf(machine: AnyStateMachine): (a: unknown) => unknown {
129
480
  const named = (machine.implementations?.actions ?? {}) as Record<string, unknown>;
130
481
  return (a) => {
@@ -177,11 +528,11 @@ function paramsAt(written: unknown, args: EnqueueArgs): unknown {
177
528
  * Give every place an `answer` is written in `machine` a copy of its own, bound to that place's
178
529
  * seat (ADR-0067): one action object written in two places then shapes, from each, by that place's
179
530
  * rule alone — below an Agent's state, only that Agent's pick; on a transition below none, the pick
180
- * of the Agent the event names. An entry or an exit below no Agent's state is given an `answer` that
181
- * sets nothing. At run time an action cannot tell where it was written, so the place is decided
182
- * here. Called for each Machine of a run's tree as its actor is created, before its first state is
183
- * entered. Each list is replaced, never written in place: a list the author shared between two
184
- * places stays the author's.
531
+ * of the Agent the event names. An entry or an exit below no Agent's state is given an `answer`
532
+ * that sets nothing. At run time an action cannot tell where it was written, so the place is
533
+ * decided here. Called for each Machine of a run's tree as its actor is created, before its first
534
+ * state is entered. Each list is replaced, never written in place: a list the author shared between
535
+ * two places stays the author's.
185
536
  */
186
537
  export function placeAnswers(machine: AnyStateMachine): void {
187
538
  if (placedMachines.has(machine) || !machine?.root) return;
@@ -257,13 +608,148 @@ export function seatsOfAnswer(machine: AnyStateMachine, action: unknown): Answer
257
608
  return byAction.get(originalOf(action)) ?? new Set<Node | null>([null]);
258
609
  }
259
610
 
260
- /** The brand the load walk reads: this action is an `answer`. */
611
+ /**
612
+ * The brand the load walk reads: this action is an `answer`.
613
+ *
614
+ * @internal
615
+ */
261
616
  export type AnswerAction = { readonly jr2Answer: true };
262
617
 
263
618
  /** Is this action an `answer`? */
264
619
  export const isAnswer = (action: unknown): boolean =>
265
620
  typeof action === "function" && (action as Partial<AnswerAction>).jr2Answer === true;
266
621
 
622
+ /**
623
+ * Set what the Agent reads when jr2 answers its pick. It is an xstate action: write it in
624
+ * `entry`, `exit` or the `actions` of a transition. Without it, the Agent reads the last reply
625
+ * since the pick.
626
+ *
627
+ * `fn` gets `{ context, event, chain }`. `chain` is every reply since the pick, oldest first. Each
628
+ * link is `{ kind: "output", src, output }`, the output of an invoked actor, or `{ kind: "event",
629
+ * event }`, an event that a Gate or a nested Agent sent. TypeScript types each link, but not the
630
+ * order or the number of links. What `fn` gives back goes to the Agent as JSON. A value with no
631
+ * JSON form clears the answer: the Agent then reads the last reply. When more than one `answer`
632
+ * runs, the last one wins.
633
+ *
634
+ * Where you write it decides which pick it answers:
635
+ *
636
+ * - At or below the state of an Agent, it answers only a pick of that Agent.
637
+ * - On a transition below no Agent's state, it answers a pick of the Agent whose event took the
638
+ * transition.
639
+ * - On an `entry` or an `exit` below no Agent's state, it sets nothing, and `jr2 up` prints a
640
+ * warning: `an answer on the <entry|exit> of "<state>" is below no Agent's state, so it shapes
641
+ * no pick — an <entry|exit> there is no transition an Agent's event takes; move it under
642
+ * "<agent state>", or onto a transition (ADR-0067)`.
643
+ *
644
+ * The error of an invoked actor is no link, and the Agent does not see it. To tell the Agent,
645
+ * write `answer` on the `onError` route. An Effect never takes that route for an outcome: every
646
+ * outcome is output.
647
+ *
648
+ * @param fn - Gets `{ context, event, chain }` and gives back what the Agent reads, as a value
649
+ * with a JSON form.
650
+ * @returns An xstate action.
651
+ *
652
+ * @example
653
+ * ```ts
654
+ * import { z } from "zod";
655
+ * import {
656
+ * agent,
657
+ * answer,
658
+ * command,
659
+ * defineEvent,
660
+ * fail,
661
+ * isReady,
662
+ * jr2Setup,
663
+ * workspace,
664
+ * worktree,
665
+ * type Workspaced,
666
+ * } from "@jr2/orchestrator";
667
+ *
668
+ * const runTests = defineEvent({
669
+ * name: "run_tests",
670
+ * description: "Run the test suite. Its result is this call's answer.",
671
+ * input: z.object({}),
672
+ * });
673
+ *
674
+ * const finished = defineEvent({
675
+ * name: "finished",
676
+ * description: "Say that the tests pass.",
677
+ * input: z.object({}),
678
+ * });
679
+ *
680
+ * type Input = Workspaced<{}, "app">;
681
+ *
682
+ * const fixTree = (context: Input) => `${context.workspace.repos.app}/fix` as const;
683
+ *
684
+ * const body = jr2Setup({
685
+ * types: {} as { context: Input; input: Input },
686
+ * events: [runTests, finished],
687
+ * actors: {
688
+ * coder: agent({
689
+ * model: "anthropic/claude-haiku-5-5",
690
+ * instructions: "You are a careful engineer.",
691
+ * }),
692
+ * cut: worktree(),
693
+ * tests: command(["npm", "test"]),
694
+ * fail: fail(),
695
+ * },
696
+ * }).createMachine({
697
+ * id: "fix-tests",
698
+ * context: ({ input }) => input,
699
+ * on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
700
+ * initial: "cutting",
701
+ * states: {
702
+ * cutting: {
703
+ * invoke: {
704
+ * src: "cut",
705
+ * input: ({ context }) => ({ path: fixTree(context), branch: "fix-tests" }),
706
+ * onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
707
+ * },
708
+ * },
709
+ * coding: {
710
+ * invoke: {
711
+ * src: "coder",
712
+ * input: ({ context }) => ({ prompt: "Make the tests pass.", cwd: fixTree(context) }),
713
+ * },
714
+ * on: { finished: "done" },
715
+ * initial: "ready",
716
+ * states: {
717
+ * ready: { on: { run_tests: "testing" } },
718
+ * testing: {
719
+ * invoke: {
720
+ * src: "tests",
721
+ * input: ({ context }) => ({ worktree: fixTree(context) }),
722
+ * onDone: {
723
+ * target: "ready",
724
+ * // The Agent reads this string, not the whole output of the command.
725
+ * actions: answer(({ event }) =>
726
+ * event.output.outcome === "exited" && event.output.code === 0
727
+ * ? "The tests pass."
728
+ * : `The tests fail:\n${"tail" in event.output ? event.output.tail : event.output.reason}`,
729
+ * ),
730
+ * },
731
+ * },
732
+ * },
733
+ * },
734
+ * },
735
+ * done: { type: "final" },
736
+ * notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
737
+ * failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
738
+ * lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
739
+ * },
740
+ * });
741
+ *
742
+ * export const machine = workspace(body, {
743
+ * repos: { app: { url: "https://github.com/you/app.git" } },
744
+ * });
745
+ * ```
746
+ *
747
+ * @see docs/concepts/the-menu.md
748
+ * @see docs/concepts/effects.md
749
+ * @see docs/guides/run-a-command-or-call-a-url.md
750
+ * @see docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md
751
+ * @see docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md
752
+ */
267
753
  export function answer<
268
754
  TContext extends MachineContext,
269
755
  TExpressionEvent extends EventObject,