@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,993 @@
1
+ ---
2
+ title: Have your Assistant write a Machine
3
+ description: Ask your Assistant for a Machine, read its graph in the Console, then run it and approve the push.
4
+ ---
5
+
6
+ # Have your Assistant write a Machine
7
+
8
+ On this page, your [Assistant](../reference/glossary.md#assistant) writes a [Machine](../reference/glossary.md#machine)
9
+ for you. You read its graph before it runs. At the end, a [Workflow](../reference/glossary.md#workflow) named `fix`
10
+ fixes the bug in the tutorial fixture. It tests the fix, waits for you, and pushes the branch to your fork.
11
+
12
+ You do not write the Machine. You read it. An Assistant writes most Machines. It reads the jr2 docs that your
13
+ [Instance](../reference/glossary.md#instance) holds. Your work is to read the graph and to decide whether the work
14
+ happens in the correct way.
15
+
16
+ ## Before you start
17
+
18
+ - Do [An Agent in a Sandbox](an-agent-in-a-sandbox.md) first. This page uses its fork, its token and its
19
+ `workflows/task.ts`.
20
+ - You need an Assistant: Claude Code, Codex or Cursor.
21
+ - Keep the port forward to the [Console](../reference/glossary.md#console) from
22
+ [Create an Instance](create-an-instance.md). If it stopped, start it again:
23
+
24
+ ```sh
25
+ kubectl -n my-instance port-forward svc/jr2-orchestrator 4000:4000
26
+ ```
27
+
28
+ ## Give the token to jr2
29
+
30
+ On the last page, you pushed the branch by hand. On this page, a `push` [Effect](../reference/glossary.md#effect) pushes
31
+ it. The Effect uses the token that the [`git.credentials`](../reference/config.md#git-credentials) entry of
32
+ `jr2.config.ts` names. That entry names `JR2_GIT_TOKEN`.
33
+
34
+ Add the token from the last page to `.env`. Replace `<token>` with the token:
35
+
36
+ ```sh
37
+ echo 'JR2_GIT_TOKEN=<token>' >> .env
38
+ ```
39
+
40
+ The command prints nothing. `.env` is in `.gitignore`, so git does not keep the token.
41
+
42
+ > **Note**
43
+ >
44
+ > The [Agent](../reference/glossary.md#agent) never gets this token. The push Effect uses it, after you approve the work.
45
+ > The [Repo](../reference/glossary.md#repo) cache also uses it to clone your fork. See
46
+ > [Secrets and trust](../concepts/secrets-and-trust.md).
47
+
48
+ ## Open your Assistant in the Instance folder
49
+
50
+ Start your Assistant in `my-instance`. It reads `AGENTS.md` when it starts. Claude Code reads `CLAUDE.md`, which imports
51
+ `AGENTS.md`.
52
+
53
+ `jr2 init` wrote `AGENTS.md`. `jr2 up` keeps the text between its two markers equal to the docs of the
54
+ [Kit version](../reference/glossary.md#kit-version) of the Instance. Look at the start of that text:
55
+
56
+ ```sh
57
+ head -3 AGENTS.md
58
+ ```
59
+
60
+ ```text
61
+ <!-- jr2 up writes the text between the jr2-docs markers. Write your own instructions after the END marker. -->
62
+ <!-- BEGIN:jr2-docs -->
63
+ jr2 is newer than your training data. Before you write a Machine or change jr2.config.ts, read the bundled docs in node_modules/@jr2/orchestrator/docs/. They are the docs of this Instance's Kit version, <version>. Start with guides/write-a-workflow.md and with reference/authoring-surface.md, the contents page of the Authoring surface. Read one page with each call of your file tool, because a file tool cuts off a long output. Before you give a change to the user, run `npx --no jr2 check` in the Instance folder. It does the typecheck and the load of each Workflow that `jr2 up` does first, with no cluster, and it gives the same refusals.
64
+ ```
65
+
66
+ The block also holds an index of those docs. They are the docs of the Kit version that your `package.json` pins. Thus
67
+ your Assistant reads the API that your Instance runs, not the API that its training data holds.
68
+
69
+ ## Ask for the Machine
70
+
71
+ Give your Assistant this prompt. Replace `<you>` with your GitHub user name. Replace `<version>` with the Kit version.
72
+
73
+ ```text
74
+ Write a workflow named fix, in workflows/fix.ts. A coder Agent works in a Workspace on my fork, https://github.com/<you>/jr2.git, from the ref v<version>, in the Repo Slot target. It uses the model that workflows/task.ts uses. The run input is { prompt }, as for the task workflow. When the coder finishes, run node --test in docs/site/tutorial/greet in its Worktree. If the tests fail, send the output back to the coder. If they pass, a human reviews at a Gate named review, with the events request_changes (with notes) and approve. On request_changes, the coder continues with the notes. On approve, push the branch to my fork.
75
+ ```
76
+
77
+ Each Assistant writes a different file, and the same Assistant can write a different file on each try. This page cannot
78
+ show your file. It shows one result that typechecks, and it tells you what to look for in the graph. Your file can
79
+ differ in its names, its comments and its text, and still be correct. [Read one result](#read-one-result) walks through
80
+ it.
81
+
82
+ ## Converge the Instance
83
+
84
+ Run [`jr2 up`](../reference/cli.md#up):
85
+
86
+ ```sh
87
+ jr2 up
88
+ ```
89
+
90
+ `jr2 up` typechecks the Instance first. Then it loads each Workflow and walks its Machine. If your Assistant wrote a
91
+ Machine that does not compile, `jr2 up` stops before it builds anything:
92
+
93
+ ```text
94
+ …
95
+ typecheck: tsc --noEmit (the instance's own compiler)
96
+ refusing: this instance does not typecheck — nothing was built and nothing was applied
97
+ workflows/fix.ts(69,87): error TS2339: Property 'app' does not exist on type 'Record<"target", string>'.
98
+ ```
99
+
100
+ The lines after it are the errors of `tsc`. Here, the Machine reads a Repo Slot, `app`, that its Workspace does not
101
+ have. Give them to your Assistant. Then run `jr2 up` again.
102
+
103
+ The block tells your Assistant to run [`jr2 check`](../reference/cli.md#check) before it gives you the file. `jr2 check`
104
+ does these two steps of `jr2 up`, with no cluster, and gives the same refusals. Thus an Assistant that cannot run
105
+ `jr2 up` finds these errors itself.
106
+
107
+ When `fix` is correct, `jr2 up` tells you what the Machine runs outside itself, and who may send each event. Your lines
108
+ can differ when your Assistant used other names. Other Workflows of the Instance add lines too:
109
+
110
+ ```text
111
+ …
112
+ typecheck: tsc --noEmit (the instance's own compiler)
113
+ effects: workflow "fix" — what it runs outside itself (ADR-0067)
114
+ cut: worktree — 600s, in the Harness
115
+ tests: command ["node","--test","docs/site/tutorial/greet/test/*.test.js"] — 300s, in the Harness
116
+ publish: push — 300s, in the Sandbox Effector
117
+ …
118
+ failures: workflow "fix" — the states that fail the run (ADR-0073)
119
+ fix.notCut: invokes fail
120
+ fix.lost: invokes fail
121
+ …
122
+ seats: workflow "fix" — who may send what, per state (ADR-0015)
123
+ fix.working agent:coder: [finish]
124
+ fix.review gate: [approve, request_changes]
125
+ …
126
+ Workspace of workflow "fix": Sandbox Effector (image the Sandbox Image) holds no Effect secret; pushes Repo Slot "target" with git.credentials "*"
127
+ …
128
+ warning: git.credentials "*": the Secret "jr2-git-ssh" does not exist in namespace my-instance — a push that needs it is refused at provision until it exists and jr2 up runs again (ADR-0051)
129
+ git.credentials "*": push Secret jr2-git-push-684888c0 — pushes over https
130
+ …
131
+ ```
132
+
133
+ Read these lines as a first check:
134
+
135
+ - `effects` shows three Effects: the cut, a command and a push. A Workflow that pushes with no
136
+ [Gate](../reference/glossary.md#gate) before the push shows the same lines. The graph shows where the push is.
137
+ - `failures` shows the two states that end the run as `failed`.
138
+ - `seats` shows that the coder can send only `finish`. Only the Gate in `review` can send `approve` and
139
+ `request_changes`.
140
+ - The `warning` line is about git over ssh. The `jr2-git-ssh` Secret is for an ssh key, and it does not exist. Your fork
141
+ uses `https://`, so the push does not need it. The last line says that the push uses the token over https.
142
+
143
+ If `JR2_GIT_TOKEN` is not set, `jr2 up` stops before it applies the
144
+ [Orchestrator](../reference/glossary.md#orchestrator), with this error:
145
+
146
+ ```text
147
+ …
148
+ git.credentials "*": its token's variable JR2_GIT_TOKEN is not set — set it in .env
149
+ error: Workspace of workflow "fix": the push of Repo Slot "target" (https://github.com/<you>/jr2.git): git.credentials entry "*" cannot push — its token's variable JR2_GIT_TOKEN is not set — set it in .env (ADR-0051)
150
+ ```
151
+
152
+ ## Read the graph before you run it
153
+
154
+ This step is the most important step of the page. The Console draws a Machine as a graph, and you can read it before it
155
+ runs. Read how the work happens before you read the code that comes out of it.
156
+
157
+ Open the graph of `fix` in the Console:
158
+
159
+ ```text
160
+ http://localhost:4000/workflows/fix
161
+ ```
162
+
163
+ The Console shows the Machine with no run. The outer boxes are the states of the
164
+ [Workspace](../reference/glossary.md#workspace): `placing`, `provisioning`, `attaching`, `running`, `teardown`,
165
+ `failing` and `done`. jr2 makes them. The body of your Assistant's Machine is the box `▣ body`, inside `running`. Read
166
+ that box.
167
+
168
+ A box is a state. A line `⚙ <name>` in a box is what the state runs. An arrow is a transition. Its label is the event
169
+ that moves the run, and `[<name>]` is the guard that it must pass. Look for these facts:
170
+
171
+ 1. **The coder works in one state.** `working` runs `⚙ coder`. The arrow `finish` is the coder's only pick. The coder
172
+ cannot push, and it cannot approve its own work.
173
+ 2. **The tests decide.** `testing` runs `⚙ tests`. The arrow `done: testing [testsPassed]` goes to `review`. The other
174
+ `done: testing` arrow goes back to `working`. No arrow goes from `testing` to `pushing`.
175
+ 3. **You decide at the Gate.** `review` runs `⚙ gate`. Its arrows are `approve` and `request_changes`. The run waits
176
+ there until you send one of them.
177
+ 4. **The push comes only after `approve`.** `pushing` runs `⚙ publish`. The only arrow into `pushing` is `approve`.
178
+ 5. **Each failure has a place to go.** `agent.fault` goes from `working` to `review`. A push that fails goes back to
179
+ `review`. The line `↺ workspace.lost` in the `▣ body` box applies to every state of the body. The graph does not show
180
+ its target. In this file, it goes to `lost`, which invokes `fail`: the run ends `failed`.
181
+
182
+ Open **who may send what** in the pane of the graph. It shows the same seats as `jr2 up`:
183
+
184
+ ```text
185
+ who may send what · 2 seats
186
+ fix.working agent:coder finish
187
+ fix.review gate approve, request_changes
188
+ ```
189
+
190
+ An arrow can show `[?]` in place of a guard name. That guard is a function with no name. Read the guard in the file. You
191
+ can also ask your Assistant to give it a name.
192
+
193
+ Also look for a loop with no exit. In this result, `working` and `testing` can loop until the tests pass, and no count
194
+ stops them. If you want a limit, ask your Assistant for one. Then read the graph again.
195
+
196
+ ## Run fix
197
+
198
+ Start the run in your first terminal. The prompt is the task text from the last page:
199
+
200
+ ```sh
201
+ jr2 run fix --input '{"prompt":"In docs/site/tutorial/greet, one test fails. Fix the bug in docs/site/tutorial/greet/src/greet.js. To check your fix, run node --test in docs/site/tutorial/greet. Do not change files outside that folder. Do not run the tests of the repo root."}'
202
+ ```
203
+
204
+ [`jr2 run`](../reference/cli.md#run) stays attached until the run ends. Your run id is different:
205
+
206
+ ```text
207
+ …
208
+ → context kind-jr2 / namespace my-instance
209
+ run 790ad78a-db4e-4b09-a248-ab62da088cde (fix) — attached
210
+ → active "placing"
211
+ → active "provisioning"
212
+ → active "attaching"
213
+ → active "running"
214
+ …
215
+ ```
216
+
217
+ Watch the run in the Console. The Console lights the state that the run is in. The run goes through `working` and
218
+ `testing`, and it can go back to `working` when the tests fail. Then it waits at `review`.
219
+
220
+ ## Read the Gate
221
+
222
+ In a second terminal, read the Gate. Replace `<run id>` with the run id from the first terminal, or with its first 4
223
+ characters or more:
224
+
225
+ ```sh
226
+ jr2 status <run id>
227
+ ```
228
+
229
+ [`jr2 status`](../reference/cli.md#status) prints the status of the run as one line of JSON. Its `gates` list holds the
230
+ Gate of `review`. Its `gate` is `body.review`. Give that value to `--gate`. The `meta` of the Gate gives the coder's
231
+ `summary`, the `branch` and the `worktree`. After the JSON, `jr2 status` prints one line for each Worktree that the run
232
+ cut:
233
+
234
+ ```text
235
+ …
236
+ → context kind-jr2 / namespace my-instance
237
+ {…,"gates":[{"gate":"body.review",…,"meta":{"summary":"Fixed the \"trims the name\" test failure in docs/site/tutorial/greet. The bug was that the `greet` function didn't trim whitespace from the name argument. Added `.trim()` to the name extraction so that `greet([\" ada \"])` correctly returns `\"hello, ada\"` instead of `\"hello, ada \"`.","branch":"jr2/fix-a78c793e-607a-4b33-9784-ccf2cfb6f395","worktree":"/work/target/fix"}}]}
238
+ worktree: /work/target/fix (target), branch jr2/fix-a78c793e-607a-4b33-9784-ccf2cfb6f395
239
+ ```
240
+
241
+ The `summary` is in the words of the model, so your summary is different.
242
+
243
+ ## Approve
244
+
245
+ Send `approve` to the Gate with [`jr2 send`](../reference/cli.md#send):
246
+
247
+ ```sh
248
+ jr2 send <run id> --gate body.review --event approve
249
+ ```
250
+
251
+ ```text
252
+ …
253
+ → context kind-jr2 / namespace my-instance
254
+ delivered approve to gate "body.review" on 790ad78a-db4e-4b09-a248-ab62da088cde
255
+ ```
256
+
257
+ The run goes to `pushing`, and the push Effect pushes the branch. Then the run ends, and jr2 removes the
258
+ [Sandbox](../reference/glossary.md#sandbox). In the first terminal, `jr2 run` prints its last line, then the final
259
+ status as one line of JSON:
260
+
261
+ ```text
262
+ …
263
+ → active "teardown"
264
+ → done "done"
265
+ {"runId":"790ad78a-db4e-4b09-a248-ab62da088cde","workflow":"fix",…,"output":{"outcome":"pushed","branch":"jr2/fix-a78c793e-607a-4b33-9784-ccf2cfb6f395","commit":"ee7f5d8084db32c3610efb5c9b889a710ef30f70"},"worktrees":[{"slot":"target","path":"/work/target/fix","branch":"jr2/fix-a78c793e-607a-4b33-9784-ccf2cfb6f395"}]}
266
+ ```
267
+
268
+ In that JSON, `context.output` and `output` are the output of `fix`. In this result, it is
269
+ `{"outcome":"pushed","branch":"jr2/fix-<instance id>","commit":"<commit>"}`. `<instance id>` is the seed
270
+ [Instance ID](../reference/glossary.md#instance-id) of the run. It is not the run id. `<commit>` is the commit on your
271
+ fork.
272
+
273
+ ## Find the branch on your fork
274
+
275
+ List the branches of `fix` on your fork:
276
+
277
+ ```sh
278
+ git ls-remote https://github.com/<you>/jr2.git 'jr2/fix-*'
279
+ ```
280
+
281
+ ```text
282
+ <commit> refs/heads/jr2/fix-<instance id>
283
+ ```
284
+
285
+ You can also open the branch on GitHub. The commit holds the coder's fix of `docs/site/tutorial/greet/src/greet.js`.
286
+
287
+ ## Read one result
288
+
289
+ This is one `fix.ts` that does what the prompt asks, with the model of the tab:
290
+
291
+ **Anthropic**
292
+
293
+ ```ts
294
+ import { assign } from "xstate";
295
+ import { z } from "zod";
296
+ import {
297
+ agent,
298
+ command,
299
+ defineEvent,
300
+ fail,
301
+ isReady,
302
+ jr2Setup,
303
+ push,
304
+ workspace,
305
+ worktree,
306
+ type CommandOutput,
307
+ type HostInjectedInput,
308
+ type PushOutput,
309
+ type Workspaced,
310
+ } from "@jr2/orchestrator";
311
+
312
+ // The run input: what you give `jr2 run fix --input`. It has the `prompt` of the run input of `task`.
313
+ const door = z.object({
314
+ prompt: z.string().describe("What to do, in prose. The coder's first Turn is this prompt."),
315
+ });
316
+ type Door = z.infer<typeof door>;
317
+
318
+ // The coder's one pick. It is a tool on the coder's Menu.
319
+ const finish = defineEvent({
320
+ name: "finish",
321
+ description: "End the turn: the fix is committed on the branch and ready for the tests.",
322
+ input: z.object({ summary: z.string().describe("What you did, in a few sentences.") }),
323
+ });
324
+ // Your two replies at the `review` Gate.
325
+ const approve = defineEvent({
326
+ name: "approve",
327
+ description: "Accept the work. jr2 pushes the branch to the fork.",
328
+ input: z.object({}),
329
+ });
330
+ const requestChanges = defineEvent({
331
+ name: "request_changes",
332
+ description: "Send the work back to the coder with notes. The coder continues the same conversation.",
333
+ input: z.object({ notes: z.string().describe("What to change, in prose.") }),
334
+ });
335
+
336
+ // The body gets the run input, the seed Instance ID of the run, and the Workspace handles of its one Repo Slot.
337
+ type BodyInput = Workspaced<Door & HostInjectedInput, "target">;
338
+ type Context = BodyInput & {
339
+ // The next Turn is the first of its conversation: it must carry the whole task.
340
+ fresh: boolean;
341
+ // The text of the next Turn after the first: the failed tests, or your notes.
342
+ feedback?: string;
343
+ // The coder's summary of its last Turn, for the Gate.
344
+ summary?: string;
345
+ // Why the run is at the Gate with no summary: a Turn that failed, or a push that did not happen.
346
+ reason?: string;
347
+ // The commit on the fork, after the push.
348
+ commit?: string;
349
+ };
350
+ // The output of a run that ends `done`. A lost Sandbox fails the run, with no output of this type.
351
+ type Output = { outcome: "pushed"; branch: string; commit: string };
352
+
353
+ // The Worktree of the coder. The Machine names the folder, and each Effect that works there names it.
354
+ function fixTree(context: BodyInput) {
355
+ return `${context.workspace.repos.target}/fix` as const;
356
+ }
357
+ // One branch for each run, from its seed Instance ID.
358
+ function branchOf(context: BodyInput): string {
359
+ return `jr2/fix-${context.instanceId}`;
360
+ }
361
+
362
+ // Two guards. A guard with a name shows that name on its arrow in the Console's graph.
363
+ function testsPassed({ event }: { event: { output: CommandOutput } }): boolean {
364
+ return event.output.outcome === "exited" && event.output.code === 0;
365
+ }
366
+ function pushed({ event }: { event: { output: PushOutput } }): boolean {
367
+ return event.output.outcome === "pushed";
368
+ }
369
+
370
+ const body = jr2Setup({
371
+ types: {} as { context: Context; input: BodyInput; output: Output },
372
+ events: [finish, approve, requestChanges],
373
+ actors: {
374
+ coder: agent({
375
+ model: "anthropic/claude-haiku-5-5",
376
+ description: "Fixes one bug in its own Workspace, and commits the fix.",
377
+ workspace: "write",
378
+ instructions: `You are a software engineer. You fix one bug, in a container of your own.
379
+
380
+ - Work only in the worktree that your turn names. Your tools are rooted there.
381
+ - Commit your fix on the branch. You cannot push. jr2 pushes the branch after a human approves it.
382
+ - Make the smallest change that fixes the bug.
383
+ - End your turn with exactly one call to \`finish\`.`,
384
+ }),
385
+ // Cut a Worktree of `target`: the Workspace only clones.
386
+ cut: worktree(),
387
+ // A program in the Harness container of the Sandbox, in the Worktree that its input names. Node expands the glob itself.
388
+ tests: command(["node", "--test", "docs/site/tutorial/greet/test/*.test.js"], { timeout: "5m" }),
389
+ // Push the tip of the coder's branch to the Repo of `target`, with the token of `git.credentials`.
390
+ publish: push(),
391
+ // Fail the run: the end for work that did not succeed. A final state means `done`.
392
+ fail: fail(),
393
+ },
394
+ }).createMachine({
395
+ id: "fix",
396
+ context: ({ input }) => ({ ...input, fresh: true }),
397
+ initial: "cutting",
398
+ // The Sandbox is gone, and every commit that was not pushed went with it.
399
+ on: { "workspace.lost": { target: ".lost" } },
400
+ states: {
401
+ // The Workspace only clones. The Machine cuts the Worktree that the Agent works in.
402
+ cutting: {
403
+ invoke: {
404
+ src: "cut",
405
+ input: ({ context }) => ({ path: fixTree(context), branch: branchOf(context) }),
406
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "working" }, { target: "notCut" }],
407
+ },
408
+ },
409
+ working: {
410
+ invoke: {
411
+ src: "coder",
412
+ input: ({ context }) => ({
413
+ prompt: promptOf(context),
414
+ cwd: fixTree(context),
415
+ // Each Turn continues the coder's one conversation, so the coder remembers its work.
416
+ continue: true,
417
+ }),
418
+ },
419
+ on: {
420
+ finish: {
421
+ target: "testing",
422
+ actions: assign({
423
+ summary: ({ event }) => event.summary,
424
+ feedback: undefined,
425
+ reason: undefined,
426
+ fresh: false,
427
+ }),
428
+ },
429
+ // jr2 could not get a pick from the coder. A human decides at the Gate.
430
+ "agent.fault": {
431
+ target: "review",
432
+ actions: assign({ reason: ({ event }) => event.reason, summary: undefined, fresh: true }),
433
+ },
434
+ },
435
+ },
436
+ testing: {
437
+ invoke: {
438
+ src: "tests",
439
+ input: ({ context }) => ({ worktree: fixTree(context) }),
440
+ onDone: [
441
+ { guard: testsPassed, target: "review" },
442
+ {
443
+ target: "working",
444
+ actions: assign({ feedback: ({ event }) => testFeedback(event.output) }),
445
+ },
446
+ ],
447
+ },
448
+ },
449
+ // The run waits here for you. Its Gate id is body.review: the Workspace runs this Machine as body.
450
+ review: {
451
+ invoke: {
452
+ src: "gate",
453
+ input: ({ context }) => ({
454
+ meta: {
455
+ ...(context.summary !== undefined ? { summary: context.summary } : {}),
456
+ ...(context.reason !== undefined ? { reason: context.reason } : {}),
457
+ branch: branchOf(context),
458
+ worktree: fixTree(context),
459
+ },
460
+ }),
461
+ },
462
+ on: {
463
+ approve: { target: "pushing" },
464
+ request_changes: {
465
+ target: "working",
466
+ actions: assign({
467
+ feedback: ({ event }) => `A human reviewed your work and asks for changes:\n${event.notes}`,
468
+ summary: undefined,
469
+ }),
470
+ },
471
+ },
472
+ },
473
+ pushing: {
474
+ invoke: {
475
+ src: "publish",
476
+ input: ({ context }) => ({ worktree: fixTree(context) }),
477
+ onDone: [
478
+ {
479
+ guard: pushed,
480
+ target: "done",
481
+ actions: assign({ commit: ({ event }) => publishedOf(event.output) }),
482
+ },
483
+ // Nothing was pushed, or jr2 cannot tell. The Sandbox stays, and the run waits at the Gate again.
484
+ { target: "review", actions: assign({ reason: ({ event }) => pushFailure(event.output) }) },
485
+ ],
486
+ },
487
+ },
488
+ done: {
489
+ type: "final",
490
+ output: ({ context }): Output => ({
491
+ outcome: "pushed",
492
+ branch: branchOf(context),
493
+ commit: context.commit ?? "",
494
+ }),
495
+ },
496
+ // Not final states: the run ends `failed`, and jr2 deletes the Sandbox.
497
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
498
+ lost: { invoke: { src: "fail", input: { reason: "the Sandbox was lost, with every commit that was not pushed" } } },
499
+ },
500
+ // The output of the run. xstate reads only this root `output` as the output of the Machine. It
501
+ // gets the output of the final state that ended the run as `event.output`.
502
+ output: ({ event }) => event.output as Output,
503
+ });
504
+
505
+ // The text of each Turn. The first Turn of a conversation carries the task. Each later Turn carries only what is new.
506
+ function promptOf(context: Context): string {
507
+ const feedback = context.feedback ?? "";
508
+ if (!context.fresh) return feedback || "Continue.";
509
+ const reason = context.reason ? `\n\nThe last attempt ended: ${context.reason}` : "";
510
+ return (
511
+ `${context.prompt}${reason}${feedback ? `\n\n${feedback}` : ""}\n\n` +
512
+ `Work in ${fixTree(context)}, on the branch ${branchOf(context)}. ` +
513
+ "Commit your fix there, then call finish."
514
+ );
515
+ }
516
+
517
+ // What the coder reads when the tests fail: the end of the output of `node --test`.
518
+ function testFeedback(output: CommandOutput): string {
519
+ const text = "tail" in output ? output.tail : output.reason;
520
+ return (
521
+ `The tests do not pass (${output.outcome}). The end of their output:\n${text}\n\n` +
522
+ "Fix the code, commit, then call finish."
523
+ );
524
+ }
525
+
526
+ // The commit that the fork has now.
527
+ function publishedOf(output: PushOutput): string {
528
+ return output.outcome === "pushed" ? output.published : "";
529
+ }
530
+
531
+ // Why the push did not happen, in the words of jr2 and git.
532
+ function pushFailure(output: PushOutput): string {
533
+ return output.outcome === "pushed" ? "" : `The push did not happen (${output.outcome}): ${output.reason}`;
534
+ }
535
+
536
+ export const machine = workspace(body, {
537
+ input: door,
538
+ repos: { target: { url: "https://github.com/<you>/jr2.git", ref: "v<version>" } },
539
+ });
540
+ ```
541
+
542
+ **Local**
543
+
544
+ ```ts
545
+ import { assign } from "xstate";
546
+ import { z } from "zod";
547
+ import {
548
+ agent,
549
+ command,
550
+ defineEvent,
551
+ fail,
552
+ isReady,
553
+ jr2Setup,
554
+ push,
555
+ workspace,
556
+ worktree,
557
+ type CommandOutput,
558
+ type HostInjectedInput,
559
+ type PushOutput,
560
+ type Workspaced,
561
+ } from "@jr2/orchestrator";
562
+
563
+ // The run input: what you give `jr2 run fix --input`. It has the `prompt` of the run input of `task`.
564
+ const door = z.object({
565
+ prompt: z.string().describe("What to do, in prose. The coder's first Turn is this prompt."),
566
+ });
567
+ type Door = z.infer<typeof door>;
568
+
569
+ // The coder's one pick. It is a tool on the coder's Menu.
570
+ const finish = defineEvent({
571
+ name: "finish",
572
+ description: "End the turn: the fix is committed on the branch and ready for the tests.",
573
+ input: z.object({ summary: z.string().describe("What you did, in a few sentences.") }),
574
+ });
575
+ // Your two replies at the `review` Gate.
576
+ const approve = defineEvent({
577
+ name: "approve",
578
+ description: "Accept the work. jr2 pushes the branch to the fork.",
579
+ input: z.object({}),
580
+ });
581
+ const requestChanges = defineEvent({
582
+ name: "request_changes",
583
+ description: "Send the work back to the coder with notes. The coder continues the same conversation.",
584
+ input: z.object({ notes: z.string().describe("What to change, in prose.") }),
585
+ });
586
+
587
+ // The body gets the run input, the seed Instance ID of the run, and the Workspace handles of its one Repo Slot.
588
+ type BodyInput = Workspaced<Door & HostInjectedInput, "target">;
589
+ type Context = BodyInput & {
590
+ // The next Turn is the first of its conversation: it must carry the whole task.
591
+ fresh: boolean;
592
+ // The text of the next Turn after the first: the failed tests, or your notes.
593
+ feedback?: string;
594
+ // The coder's summary of its last Turn, for the Gate.
595
+ summary?: string;
596
+ // Why the run is at the Gate with no summary: a Turn that failed, or a push that did not happen.
597
+ reason?: string;
598
+ // The commit on the fork, after the push.
599
+ commit?: string;
600
+ };
601
+ // The output of a run that ends `done`. A lost Sandbox fails the run, with no output of this type.
602
+ type Output = { outcome: "pushed"; branch: string; commit: string };
603
+
604
+ // The Worktree of the coder. The Machine names the folder, and each Effect that works there names it.
605
+ function fixTree(context: BodyInput) {
606
+ return `${context.workspace.repos.target}/fix` as const;
607
+ }
608
+ // One branch for each run, from its seed Instance ID.
609
+ function branchOf(context: BodyInput): string {
610
+ return `jr2/fix-${context.instanceId}`;
611
+ }
612
+
613
+ // Two guards. A guard with a name shows that name on its arrow in the Console's graph.
614
+ function testsPassed({ event }: { event: { output: CommandOutput } }): boolean {
615
+ return event.output.outcome === "exited" && event.output.code === 0;
616
+ }
617
+ function pushed({ event }: { event: { output: PushOutput } }): boolean {
618
+ return event.output.outcome === "pushed";
619
+ }
620
+
621
+ const body = jr2Setup({
622
+ types: {} as { context: Context; input: BodyInput; output: Output },
623
+ events: [finish, approve, requestChanges],
624
+ actors: {
625
+ coder: agent({
626
+ model: "local/qwen3.6-35b-a3b",
627
+ description: "Fixes one bug in its own Workspace, and commits the fix.",
628
+ workspace: "write",
629
+ instructions: `You are a software engineer. You fix one bug, in a container of your own.
630
+
631
+ - Work only in the worktree that your turn names. Your tools are rooted there.
632
+ - Commit your fix on the branch. You cannot push. jr2 pushes the branch after a human approves it.
633
+ - Make the smallest change that fixes the bug.
634
+ - End your turn with exactly one call to \`finish\`.`,
635
+ }),
636
+ // Cut a Worktree of `target`: the Workspace only clones.
637
+ cut: worktree(),
638
+ // A program in the Harness container of the Sandbox, in the Worktree that its input names. Node expands the glob itself.
639
+ tests: command(["node", "--test", "docs/site/tutorial/greet/test/*.test.js"], { timeout: "5m" }),
640
+ // Push the tip of the coder's branch to the Repo of `target`, with the token of `git.credentials`.
641
+ publish: push(),
642
+ // Fail the run: the end for work that did not succeed. A final state means `done`.
643
+ fail: fail(),
644
+ },
645
+ }).createMachine({
646
+ id: "fix",
647
+ context: ({ input }) => ({ ...input, fresh: true }),
648
+ initial: "cutting",
649
+ // The Sandbox is gone, and every commit that was not pushed went with it.
650
+ on: { "workspace.lost": { target: ".lost" } },
651
+ states: {
652
+ // The Workspace only clones. The Machine cuts the Worktree that the Agent works in.
653
+ cutting: {
654
+ invoke: {
655
+ src: "cut",
656
+ input: ({ context }) => ({ path: fixTree(context), branch: branchOf(context) }),
657
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "working" }, { target: "notCut" }],
658
+ },
659
+ },
660
+ working: {
661
+ invoke: {
662
+ src: "coder",
663
+ input: ({ context }) => ({
664
+ prompt: promptOf(context),
665
+ cwd: fixTree(context),
666
+ // Each Turn continues the coder's one conversation, so the coder remembers its work.
667
+ continue: true,
668
+ }),
669
+ },
670
+ on: {
671
+ finish: {
672
+ target: "testing",
673
+ actions: assign({
674
+ summary: ({ event }) => event.summary,
675
+ feedback: undefined,
676
+ reason: undefined,
677
+ fresh: false,
678
+ }),
679
+ },
680
+ // jr2 could not get a pick from the coder. A human decides at the Gate.
681
+ "agent.fault": {
682
+ target: "review",
683
+ actions: assign({ reason: ({ event }) => event.reason, summary: undefined, fresh: true }),
684
+ },
685
+ },
686
+ },
687
+ testing: {
688
+ invoke: {
689
+ src: "tests",
690
+ input: ({ context }) => ({ worktree: fixTree(context) }),
691
+ onDone: [
692
+ { guard: testsPassed, target: "review" },
693
+ {
694
+ target: "working",
695
+ actions: assign({ feedback: ({ event }) => testFeedback(event.output) }),
696
+ },
697
+ ],
698
+ },
699
+ },
700
+ // The run waits here for you. Its Gate id is body.review: the Workspace runs this Machine as body.
701
+ review: {
702
+ invoke: {
703
+ src: "gate",
704
+ input: ({ context }) => ({
705
+ meta: {
706
+ ...(context.summary !== undefined ? { summary: context.summary } : {}),
707
+ ...(context.reason !== undefined ? { reason: context.reason } : {}),
708
+ branch: branchOf(context),
709
+ worktree: fixTree(context),
710
+ },
711
+ }),
712
+ },
713
+ on: {
714
+ approve: { target: "pushing" },
715
+ request_changes: {
716
+ target: "working",
717
+ actions: assign({
718
+ feedback: ({ event }) => `A human reviewed your work and asks for changes:\n${event.notes}`,
719
+ summary: undefined,
720
+ }),
721
+ },
722
+ },
723
+ },
724
+ pushing: {
725
+ invoke: {
726
+ src: "publish",
727
+ input: ({ context }) => ({ worktree: fixTree(context) }),
728
+ onDone: [
729
+ {
730
+ guard: pushed,
731
+ target: "done",
732
+ actions: assign({ commit: ({ event }) => publishedOf(event.output) }),
733
+ },
734
+ // Nothing was pushed, or jr2 cannot tell. The Sandbox stays, and the run waits at the Gate again.
735
+ { target: "review", actions: assign({ reason: ({ event }) => pushFailure(event.output) }) },
736
+ ],
737
+ },
738
+ },
739
+ done: {
740
+ type: "final",
741
+ output: ({ context }): Output => ({
742
+ outcome: "pushed",
743
+ branch: branchOf(context),
744
+ commit: context.commit ?? "",
745
+ }),
746
+ },
747
+ // Not final states: the run ends `failed`, and jr2 deletes the Sandbox.
748
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
749
+ lost: { invoke: { src: "fail", input: { reason: "the Sandbox was lost, with every commit that was not pushed" } } },
750
+ },
751
+ // The output of the run. xstate reads only this root `output` as the output of the Machine. It
752
+ // gets the output of the final state that ended the run as `event.output`.
753
+ output: ({ event }) => event.output as Output,
754
+ });
755
+
756
+ // The text of each Turn. The first Turn of a conversation carries the task. Each later Turn carries only what is new.
757
+ function promptOf(context: Context): string {
758
+ const feedback = context.feedback ?? "";
759
+ if (!context.fresh) return feedback || "Continue.";
760
+ const reason = context.reason ? `\n\nThe last attempt ended: ${context.reason}` : "";
761
+ return (
762
+ `${context.prompt}${reason}${feedback ? `\n\n${feedback}` : ""}\n\n` +
763
+ `Work in ${fixTree(context)}, on the branch ${branchOf(context)}. ` +
764
+ "Commit your fix there, then call finish."
765
+ );
766
+ }
767
+
768
+ // What the coder reads when the tests fail: the end of the output of `node --test`.
769
+ function testFeedback(output: CommandOutput): string {
770
+ const text = "tail" in output ? output.tail : output.reason;
771
+ return (
772
+ `The tests do not pass (${output.outcome}). The end of their output:\n${text}\n\n` +
773
+ "Fix the code, commit, then call finish."
774
+ );
775
+ }
776
+
777
+ // The commit that the fork has now.
778
+ function publishedOf(output: PushOutput): string {
779
+ return output.outcome === "pushed" ? output.published : "";
780
+ }
781
+
782
+ // Why the push did not happen, in the words of jr2 and git.
783
+ function pushFailure(output: PushOutput): string {
784
+ return output.outcome === "pushed" ? "" : `The push did not happen (${output.outcome}): ${output.reason}`;
785
+ }
786
+
787
+ export const machine = workspace(body, {
788
+ input: door,
789
+ repos: { target: { url: "https://github.com/<you>/jr2.git", ref: "v<version>" } },
790
+ });
791
+ ```
792
+
793
+ Read it in the order of the graph. Each part below links to its entry in the Reference.
794
+
795
+ **The events.** Each [`defineEvent`](../reference/authoring-surface/defineevent.md) is an event that the Machine takes.
796
+ `finish` is in a state that invokes the coder, so it is a tool on the coder's [Menu](../reference/glossary.md#menu).
797
+ `approve` and `request_changes` are in a state that invokes the Gate, so only the Gate takes them. This file sets no
798
+ `audience` on its events, so the place of each event says who sends it. The `defineEvent` field `audience` can change
799
+ that. The seats show the result.
800
+
801
+ ```ts
802
+ // The coder's one pick. It is a tool on the coder's Menu.
803
+ const finish = defineEvent({
804
+ name: "finish",
805
+ description: "End the turn: the fix is committed on the branch and ready for the tests.",
806
+ input: z.object({ summary: z.string().describe("What you did, in a few sentences.") }),
807
+ });
808
+ // Your two replies at the `review` Gate.
809
+ const approve = defineEvent({
810
+ name: "approve",
811
+ description: "Accept the work. jr2 pushes the branch to the fork.",
812
+ input: z.object({}),
813
+ });
814
+ const requestChanges = defineEvent({
815
+ name: "request_changes",
816
+ description: "Send the work back to the coder with notes. The coder continues the same conversation.",
817
+ input: z.object({ notes: z.string().describe("What to change, in prose.") }),
818
+ });
819
+ ```
820
+
821
+ **The Effects.** `cut`, `tests` and `publish` are actor slots, as the coder is. A state runs one when it invokes it.
822
+ [`worktree()`](../reference/authoring-surface/worktree.md) cuts a [Worktree](../reference/glossary.md#worktree) of the
823
+ [Repo Slot](../reference/glossary.md#repo-slot). [`command()`](../reference/authoring-surface/command.md) takes a list
824
+ of arguments, not a line of shell text. Its input names the Worktree. A command runs in the root of the Worktree, so
825
+ `tests` names the test files by their path from that root. [`push()`](../reference/authoring-surface/push.md) pushes the
826
+ tip of the coder's branch. Its input names the Worktree too, and jr2 reads the branch from the cut.
827
+ [`fail()`](../reference/authoring-surface/fail.md) is a Part, not an Effect. The `lost` state invokes it to end the run
828
+ `failed`, because a final state means `done`.
829
+
830
+ ```ts
831
+ // Cut a Worktree of `target`: the Workspace only clones.
832
+ cut: worktree(),
833
+ // A program in the Harness container of the Sandbox, in the Worktree that its input names. Node expands the glob itself.
834
+ tests: command(["node", "--test", "docs/site/tutorial/greet/test/*.test.js"], { timeout: "5m" }),
835
+ // Push the tip of the coder's branch to the Repo of `target`, with the token of `git.credentials`.
836
+ publish: push(),
837
+ // Fail the run: the end for work that did not succeed. A final state means `done`.
838
+ fail: fail(),
839
+ ```
840
+
841
+ **The cut.** The Workspace only clones. `cutting` is the first state, and it makes the coder's Worktree. The path is
842
+ `/work/target/fix`, and the branch has the Instance ID of the run in it. See
843
+ [Cut a Worktree](../guides/cut-a-worktree.md).
844
+
845
+ ```ts
846
+ // The Workspace only clones. The Machine cuts the Worktree that the Agent works in.
847
+ cutting: {
848
+ invoke: {
849
+ src: "cut",
850
+ input: ({ context }) => ({ path: fixTree(context), branch: branchOf(context) }),
851
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "working" }, { target: "notCut" }],
852
+ },
853
+ },
854
+ ```
855
+
856
+ **The coder's state.** `working` invokes the coder. Each [Turn](../reference/glossary.md#turn) gets a prompt and the
857
+ folder to work in. `continue: true` keeps one conversation, so the coder remembers its last Turn. `finish` is the
858
+ coder's pick: the run goes to `testing`. [`agent.fault`](../reference/mechanism-events.md#agent-fault) is an event from
859
+ jr2, when it cannot get a pick from the coder.
860
+
861
+ ```ts
862
+ working: {
863
+ invoke: {
864
+ src: "coder",
865
+ input: ({ context }) => ({
866
+ prompt: promptOf(context),
867
+ cwd: fixTree(context),
868
+ // Each Turn continues the coder's one conversation, so the coder remembers its work.
869
+ continue: true,
870
+ }),
871
+ },
872
+ on: {
873
+ finish: {
874
+ target: "testing",
875
+ actions: assign({
876
+ summary: ({ event }) => event.summary,
877
+ feedback: undefined,
878
+ reason: undefined,
879
+ fresh: false,
880
+ }),
881
+ },
882
+ // jr2 could not get a pick from the coder. A human decides at the Gate.
883
+ "agent.fault": {
884
+ target: "review",
885
+ actions: assign({ reason: ({ event }) => event.reason, summary: undefined, fresh: true }),
886
+ },
887
+ },
888
+ },
889
+ ```
890
+
891
+ **The tests.** Every outcome of a command is output. A failed test is output too. The `onDone` list routes on that
892
+ output. The first transition whose guard passes is the one that the run takes. The second transition has no guard, so it
893
+ catches every other outcome. See [`CommandOutput`](../reference/authoring-surface/type-commandoutput.md).
894
+
895
+ ```ts
896
+ testing: {
897
+ invoke: {
898
+ src: "tests",
899
+ input: ({ context }) => ({ worktree: fixTree(context) }),
900
+ onDone: [
901
+ { guard: testsPassed, target: "review" },
902
+ {
903
+ target: "working",
904
+ actions: assign({ feedback: ({ event }) => testFeedback(event.output) }),
905
+ },
906
+ ],
907
+ },
908
+ },
909
+ ```
910
+
911
+ **The Gate.** `review` invokes `gate`. jr2 makes the id of the Gate from the invoke ids. `workspace()` runs your Machine
912
+ as `body`, and the state is `review`, so the id is `body.review`. You give `--gate body.review` to `jr2 send`. See
913
+ [the id of a Gate](../concepts/gates.md#the-id). `meta` is what `jr2 status` and the Console show you at the Gate.
914
+
915
+ ```ts
916
+ // The run waits here for you. Its Gate id is body.review: the Workspace runs this Machine as body.
917
+ review: {
918
+ invoke: {
919
+ src: "gate",
920
+ input: ({ context }) => ({
921
+ meta: {
922
+ ...(context.summary !== undefined ? { summary: context.summary } : {}),
923
+ ...(context.reason !== undefined ? { reason: context.reason } : {}),
924
+ branch: branchOf(context),
925
+ worktree: fixTree(context),
926
+ },
927
+ }),
928
+ },
929
+ on: {
930
+ approve: { target: "pushing" },
931
+ request_changes: {
932
+ target: "working",
933
+ actions: assign({
934
+ feedback: ({ event }) => `A human reviewed your work and asks for changes:\n${event.notes}`,
935
+ summary: undefined,
936
+ }),
937
+ },
938
+ },
939
+ },
940
+ ```
941
+
942
+ **The push.** `pushing` invokes `publish`. A push that fails is output too: `rejected`, `diverged` or `unknown`. Here it
943
+ goes back to `review`, and the Sandbox stays. If the run went to a final state, jr2 would remove the Sandbox and the
944
+ commits in it. See [`PushOutput`](../reference/authoring-surface/type-pushoutput.md).
945
+
946
+ ```ts
947
+ pushing: {
948
+ invoke: {
949
+ src: "publish",
950
+ input: ({ context }) => ({ worktree: fixTree(context) }),
951
+ onDone: [
952
+ {
953
+ guard: pushed,
954
+ target: "done",
955
+ actions: assign({ commit: ({ event }) => publishedOf(event.output) }),
956
+ },
957
+ // Nothing was pushed, or jr2 cannot tell. The Sandbox stays, and the run waits at the Gate again.
958
+ { target: "review", actions: assign({ reason: ({ event }) => pushFailure(event.output) }) },
959
+ ],
960
+ },
961
+ },
962
+ ```
963
+
964
+ **The Workspace.** [`workspace()`](../reference/authoring-surface/workspace.md) runs the body in a Sandbox. `input` is
965
+ the schema of the run input that `jr2 run --input` sends. `repos` binds the Repo Slot `target` to your fork, at the
966
+ release tag. A new branch starts from that tag. The body also gets `instanceId`, an id that jr2 makes for each run, so
967
+ each run gets a branch of its own.
968
+
969
+ ```ts
970
+ export const machine = workspace(body, {
971
+ input: door,
972
+ repos: { target: { url: "https://github.com/<you>/jr2.git", ref: "v<version>" } },
973
+ });
974
+ ```
975
+
976
+ ## What happened
977
+
978
+ - Your Assistant wrote a Machine from the docs that your Instance holds. `jr2 up` keeps the index of those docs in
979
+ `AGENTS.md`, so the docs match the Kit version of the Instance.
980
+ - `jr2 up` typechecked the Machine and walked it before it built anything. It showed the Effects and the seats.
981
+ - You read the graph before the run. The graph showed that the push comes only after your `approve`.
982
+ - A `command` Effect ran the tests in the Sandbox, and a `push` Effect pushed the branch. Each Effect runs in a state of
983
+ the graph, so you can see where it runs. See [Effects](../concepts/effects.md).
984
+ - The coder and you sent different events. In this Machine, the place of each event decides who sends it. See
985
+ [The Menu](../concepts/the-menu.md) and [Gates](../concepts/gates.md).
986
+
987
+ To change a Machine with your Assistant on kind, see
988
+ [Iterate on a Machine on kind](../guides/iterate-on-a-machine-on-kind.md). The decision about the docs in the Kit is
989
+ [ADR-0072](../reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md).
990
+
991
+ ## Next
992
+
993
+ Read [Machines and Workflows](../concepts/machines-and-workflows.md).