@jr2/orchestrator 0.4.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) 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 +442 -0
  10. package/docs/concepts/architecture.md +230 -0
  11. package/docs/concepts/charts.md +143 -0
  12. package/docs/concepts/composition.md +357 -0
  13. package/docs/concepts/converge.md +254 -0
  14. package/docs/concepts/durable-runs.md +189 -0
  15. package/docs/concepts/effects.md +603 -0
  16. package/docs/concepts/gates.md +208 -0
  17. package/docs/concepts/machines-and-workflows.md +289 -0
  18. package/docs/concepts/pools-and-sources.md +230 -0
  19. package/docs/concepts/secrets-and-trust.md +222 -0
  20. package/docs/concepts/the-menu.md +378 -0
  21. package/docs/concepts/workspaces.md +678 -0
  22. package/docs/get-started/a-model-decides.md +563 -0
  23. package/docs/get-started/an-agent-in-a-sandbox.md +381 -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 +922 -0
  27. package/docs/get-started/install.md +126 -0
  28. package/docs/guides/add-tools-to-the-sandbox.md +295 -0
  29. package/docs/guides/answer-a-gate.md +304 -0
  30. package/docs/guides/bind-open-parts.md +223 -0
  31. package/docs/guides/cancel-a-run.md +146 -0
  32. package/docs/guides/clean-up.md +206 -0
  33. package/docs/guides/fix-a-failed-converge.md +361 -0
  34. package/docs/guides/give-the-cluster-git-credentials.md +222 -0
  35. package/docs/guides/iterate-on-a-machine-on-kind.md +190 -0
  36. package/docs/guides/let-an-agent-write-a-chart.md +226 -0
  37. package/docs/guides/look-inside-a-sandbox.md +174 -0
  38. package/docs/guides/mirror-the-kit-images.md +176 -0
  39. package/docs/guides/move-from-kind-to-a-shared-cluster.md +302 -0
  40. package/docs/guides/open-the-console.md +91 -0
  41. package/docs/guides/publish-a-machine-as-an-npm-package.md +350 -0
  42. package/docs/guides/push-and-sign-a-branch.md +486 -0
  43. package/docs/guides/run-a-chart-by-name.md +270 -0
  44. package/docs/guides/run-a-command-or-call-a-url.md +544 -0
  45. package/docs/guides/run-one-worker-per-item.md +321 -0
  46. package/docs/guides/set-an-agents-access-and-dials.md +375 -0
  47. package/docs/guides/size-a-workspace.md +204 -0
  48. package/docs/guides/start-a-run-from-a-run.md +237 -0
  49. package/docs/guides/start-a-run.md +207 -0
  50. package/docs/guides/upgrade-the-kit-version.md +240 -0
  51. package/docs/guides/use-a-hosted-provider.md +208 -0
  52. package/docs/guides/use-a-local-model.md +313 -0
  53. package/docs/guides/watch-a-run.md +326 -0
  54. package/docs/guides/write-a-workflow.md +318 -0
  55. package/docs/index.md +44 -0
  56. package/docs/llms.txt +216 -0
  57. package/docs/reference/authoring-surface/agent.md +128 -0
  58. package/docs/reference/authoring-surface/answer.md +140 -0
  59. package/docs/reference/authoring-surface/arg.md +60 -0
  60. package/docs/reference/authoring-surface/basic.md +62 -0
  61. package/docs/reference/authoring-surface/bearer.md +53 -0
  62. package/docs/reference/authoring-surface/chartschema.md +23 -0
  63. package/docs/reference/authoring-surface/chartschemafor.md +48 -0
  64. package/docs/reference/authoring-surface/command.md +191 -0
  65. package/docs/reference/authoring-surface/customize.md +64 -0
  66. package/docs/reference/authoring-surface/defineconfig.md +41 -0
  67. package/docs/reference/authoring-surface/defineevent.md +114 -0
  68. package/docs/reference/authoring-surface/dispatch.md +126 -0
  69. package/docs/reference/authoring-surface/fail.md +83 -0
  70. package/docs/reference/authoring-surface/file.md +122 -0
  71. package/docs/reference/authoring-surface/frompick.md +277 -0
  72. package/docs/reference/authoring-surface/http.md +159 -0
  73. package/docs/reference/authoring-surface/isfailure.md +58 -0
  74. package/docs/reference/authoring-surface/jr2setup.md +237 -0
  75. package/docs/reference/authoring-surface/open.md +74 -0
  76. package/docs/reference/authoring-surface/openbody.md +86 -0
  77. package/docs/reference/authoring-surface/paramsof.md +125 -0
  78. package/docs/reference/authoring-surface/pool.md +186 -0
  79. package/docs/reference/authoring-surface/push.md +112 -0
  80. package/docs/reference/authoring-surface/secret.md +118 -0
  81. package/docs/reference/authoring-surface/sentby.md +83 -0
  82. package/docs/reference/authoring-surface/source.md +51 -0
  83. package/docs/reference/authoring-surface/text.md +62 -0
  84. package/docs/reference/authoring-surface/type-agentdeclaration.md +27 -0
  85. package/docs/reference/authoring-surface/type-agentdefinition.md +80 -0
  86. package/docs/reference/authoring-surface/type-agentlogic.md +15 -0
  87. package/docs/reference/authoring-surface/type-agentslots.md +12 -0
  88. package/docs/reference/authoring-surface/type-answeraction.md +12 -0
  89. package/docs/reference/authoring-surface/type-arg.md +19 -0
  90. package/docs/reference/authoring-surface/type-argnames.md +12 -0
  91. package/docs/reference/authoring-surface/type-binding.md +62 -0
  92. package/docs/reference/authoring-surface/type-bindingof.md +12 -0
  93. package/docs/reference/authoring-surface/type-bodyacceptsdoor.md +15 -0
  94. package/docs/reference/authoring-surface/type-bodyacceptsslots.md +17 -0
  95. package/docs/reference/authoring-surface/type-ceilings.md +41 -0
  96. package/docs/reference/authoring-surface/type-chainlink.md +19 -0
  97. package/docs/reference/authoring-surface/type-chartaction.md +46 -0
  98. package/docs/reference/authoring-surface/type-chartagent.md +28 -0
  99. package/docs/reference/authoring-surface/type-chartevent.md +20 -0
  100. package/docs/reference/authoring-surface/type-chartguard.md +20 -0
  101. package/docs/reference/authoring-surface/type-chartinvoke.md +28 -0
  102. package/docs/reference/authoring-surface/type-chartjson.md +14 -0
  103. package/docs/reference/authoring-surface/type-chartstate.md +46 -0
  104. package/docs/reference/authoring-surface/type-charttext.md +40 -0
  105. package/docs/reference/authoring-surface/type-charttransition.md +22 -0
  106. package/docs/reference/authoring-surface/type-charttransitions.md +14 -0
  107. package/docs/reference/authoring-surface/type-chartvalue.md +15 -0
  108. package/docs/reference/authoring-surface/type-childat.md +12 -0
  109. package/docs/reference/authoring-surface/type-childslots.md +12 -0
  110. package/docs/reference/authoring-surface/type-commandenv.md +15 -0
  111. package/docs/reference/authoring-surface/type-commandinput.md +19 -0
  112. package/docs/reference/authoring-surface/type-commandoptions.md +78 -0
  113. package/docs/reference/authoring-surface/type-commandoutput.md +104 -0
  114. package/docs/reference/authoring-surface/type-customize.md +109 -0
  115. package/docs/reference/authoring-surface/type-dispatchdefinition.md +39 -0
  116. package/docs/reference/authoring-surface/type-dispatchinput.md +14 -0
  117. package/docs/reference/authoring-surface/type-dispatchopenparts.md +14 -0
  118. package/docs/reference/authoring-surface/type-dispatchoutput.md +65 -0
  119. package/docs/reference/authoring-surface/type-duration.md +15 -0
  120. package/docs/reference/authoring-surface/type-effectbinding.md +93 -0
  121. package/docs/reference/authoring-surface/type-effectlogic.md +12 -0
  122. package/docs/reference/authoring-surface/type-envopenparts.md +14 -0
  123. package/docs/reference/authoring-surface/type-eventaudience.md +27 -0
  124. package/docs/reference/authoring-surface/type-eventdef.md +45 -0
  125. package/docs/reference/authoring-surface/type-eventfrom.md +16 -0
  126. package/docs/reference/authoring-surface/type-eventsemantics.md +26 -0
  127. package/docs/reference/authoring-surface/type-execoutcome.md +34 -0
  128. package/docs/reference/authoring-surface/type-failslot.md +14 -0
  129. package/docs/reference/authoring-surface/type-failure.md +19 -0
  130. package/docs/reference/authoring-surface/type-failureinput.md +20 -0
  131. package/docs/reference/authoring-surface/type-filebody.md +41 -0
  132. package/docs/reference/authoring-surface/type-frominput.md +14 -0
  133. package/docs/reference/authoring-surface/type-hostinjectedinput.md +58 -0
  134. package/docs/reference/authoring-surface/type-httpdefinition.md +101 -0
  135. package/docs/reference/authoring-surface/type-httpinput.md +12 -0
  136. package/docs/reference/authoring-surface/type-httpmethod.md +14 -0
  137. package/docs/reference/authoring-surface/type-httpopenparts.md +12 -0
  138. package/docs/reference/authoring-surface/type-httpoutput.md +89 -0
  139. package/docs/reference/authoring-surface/type-httprequestparts.md +33 -0
  140. package/docs/reference/authoring-surface/type-jr2config.md +126 -0
  141. package/docs/reference/authoring-surface/type-lends.md +38 -0
  142. package/docs/reference/authoring-surface/type-logicat.md +12 -0
  143. package/docs/reference/authoring-surface/type-markedif.md +12 -0
  144. package/docs/reference/authoring-surface/type-mergedactors.md +12 -0
  145. package/docs/reference/authoring-surface/type-namedsecret.md +25 -0
  146. package/docs/reference/authoring-surface/type-noslotspec.md +26 -0
  147. package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +32 -0
  148. package/docs/reference/authoring-surface/type-openbodydeclaration.md +40 -0
  149. package/docs/reference/authoring-surface/type-openbodylogic.md +14 -0
  150. package/docs/reference/authoring-surface/type-openbodyoutput.md +42 -0
  151. package/docs/reference/authoring-surface/type-openbodyslot.md +18 -0
  152. package/docs/reference/authoring-surface/type-opencommandinput.md +17 -0
  153. package/docs/reference/authoring-surface/type-openeffect.md +12 -0
  154. package/docs/reference/authoring-surface/type-openeffectslots.md +12 -0
  155. package/docs/reference/authoring-surface/type-openof.md +12 -0
  156. package/docs/reference/authoring-surface/type-opensecret.md +23 -0
  157. package/docs/reference/authoring-surface/type-opensecretmark.md +12 -0
  158. package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +31 -0
  159. package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +32 -0
  160. package/docs/reference/authoring-surface/type-poolmachine.md +28 -0
  161. package/docs/reference/authoring-surface/type-poolspec.md +60 -0
  162. package/docs/reference/authoring-surface/type-pushinput.md +15 -0
  163. package/docs/reference/authoring-surface/type-pushoptions.md +79 -0
  164. package/docs/reference/authoring-surface/type-pushoutput.md +124 -0
  165. package/docs/reference/authoring-surface/type-pushwireoutput.md +12 -0
  166. package/docs/reference/authoring-surface/type-quantity.md +14 -0
  167. package/docs/reference/authoring-surface/type-reached.md +12 -0
  168. package/docs/reference/authoring-surface/type-reposlot.md +70 -0
  169. package/docs/reference/authoring-surface/type-reposlotsof.md +16 -0
  170. package/docs/reference/authoring-surface/type-sandboxoptions.md +77 -0
  171. package/docs/reference/authoring-surface/type-secret.md +25 -0
  172. package/docs/reference/authoring-surface/type-sender.md +19 -0
  173. package/docs/reference/authoring-surface/type-sentbyguards.md +12 -0
  174. package/docs/reference/authoring-surface/type-size.md +85 -0
  175. package/docs/reference/authoring-surface/type-slothandles.md +32 -0
  176. package/docs/reference/authoring-surface/type-sourcenextresult.md +17 -0
  177. package/docs/reference/authoring-surface/type-sourcespec.md +44 -0
  178. package/docs/reference/authoring-surface/type-syncstate.md +12 -0
  179. package/docs/reference/authoring-surface/type-text.md +19 -0
  180. package/docs/reference/authoring-surface/type-textpart.md +24 -0
  181. package/docs/reference/authoring-surface/type-thinkinglevel.md +39 -0
  182. package/docs/reference/authoring-surface/type-toparameterizedobject.md +14 -0
  183. package/docs/reference/authoring-surface/type-toprovidedactor.md +14 -0
  184. package/docs/reference/authoring-surface/type-unknown.md +21 -0
  185. package/docs/reference/authoring-surface/type-usercontainer.md +77 -0
  186. package/docs/reference/authoring-surface/type-withoutemptyindex.md +20 -0
  187. package/docs/reference/authoring-surface/type-workflowevent.md +46 -0
  188. package/docs/reference/authoring-surface/type-workspaceaccess.md +16 -0
  189. package/docs/reference/authoring-surface/type-workspaced.md +94 -0
  190. package/docs/reference/authoring-surface/type-workspacehandles.md +23 -0
  191. package/docs/reference/authoring-surface/type-workspacemachine.md +29 -0
  192. package/docs/reference/authoring-surface/type-workspaceof.md +13 -0
  193. package/docs/reference/authoring-surface/type-workspaceoptions.md +39 -0
  194. package/docs/reference/authoring-surface/type-workspacespec.md +37 -0
  195. package/docs/reference/authoring-surface/workspace.md +259 -0
  196. package/docs/reference/authoring-surface.md +197 -0
  197. package/docs/reference/cli.md +433 -0
  198. package/docs/reference/config.md +756 -0
  199. package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +113 -0
  200. package/docs/reference/decisions/0002-duplex-streaming-actor.md +110 -0
  201. package/docs/reference/decisions/0004-worktree-provisioning-model.md +124 -0
  202. package/docs/reference/decisions/0005-sandbox-pod-composition.md +230 -0
  203. package/docs/reference/decisions/0006-agent-control-surface.md +47 -0
  204. package/docs/reference/decisions/0007-durable-machine-state.md +109 -0
  205. package/docs/reference/decisions/0008-orchestrator-as-deployed-app.md +60 -0
  206. package/docs/reference/decisions/0009-cli-and-instance-interface.md +275 -0
  207. package/docs/reference/decisions/0010-bdd-acceptance-tests.md +160 -0
  208. package/docs/reference/decisions/0011-workflow-defined-events.md +141 -0
  209. package/docs/reference/decisions/0012-workspace-wrapper-machine.md +103 -0
  210. package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +157 -0
  211. package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +95 -0
  212. package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +265 -0
  213. package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +124 -0
  214. package/docs/reference/decisions/0017-pool-over-a-source-port.md +69 -0
  215. package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +111 -0
  216. package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +275 -0
  217. package/docs/reference/decisions/0020-private-ca-trust-is-a-named-concept.md +60 -0
  218. package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +100 -0
  219. package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +103 -0
  220. package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +176 -0
  221. package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +439 -0
  222. package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +65 -0
  223. package/docs/reference/decisions/0026-a-turn-that-is-over-is-never-prompted.md +62 -0
  224. package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +237 -0
  225. package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +89 -0
  226. package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +154 -0
  227. package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +100 -0
  228. package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +190 -0
  229. package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +61 -0
  230. package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +127 -0
  231. package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +57 -0
  232. package/docs/reference/decisions/0035-a-runaway-turn-is-ended-rerolled-once-then-a-fault.md +92 -0
  233. package/docs/reference/decisions/0036-a-turn-compacts-its-own-context-mid-flight.md +138 -0
  234. package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +196 -0
  235. package/docs/reference/decisions/0038-jr2-up-builds-every-image-it-deploys.md +170 -0
  236. package/docs/reference/decisions/0039-image-garbage-collects-by-reachability.md +115 -0
  237. package/docs/reference/decisions/0041-a-build-the-host-already-holds-is-not-spent-again.md +64 -0
  238. package/docs/reference/decisions/0042-ready-is-not-routable-an-admission-retries-its-connection.md +142 -0
  239. package/docs/reference/decisions/0043-the-kit-is-tested-as-installed-a-local-registry-stands-in-for-npm.md +170 -0
  240. package/docs/reference/decisions/0044-kit-images-live-at-a-canonical-home-a-self-host-mirrors-it.md +85 -0
  241. package/docs/reference/decisions/0045-the-platform-joins-the-image-address-and-the-cluster-chooses-it.md +82 -0
  242. package/docs/reference/decisions/0046-a-converge-failure-carries-its-diagnosis.md +34 -0
  243. package/docs/reference/decisions/0047-the-git-ssh-key-source-is-the-users-choice.md +47 -0
  244. package/docs/reference/decisions/0048-the-orchestrator-boots-without-its-repos.md +36 -0
  245. package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +126 -0
  246. package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +73 -0
  247. package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +227 -0
  248. package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +81 -0
  249. package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +111 -0
  250. package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +126 -0
  251. package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +107 -0
  252. package/docs/reference/decisions/0056-a-global-jr2-hands-off-to-the-instances-own-and-an-instance-has-one-kit-version.md +62 -0
  253. package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +152 -0
  254. package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +106 -0
  255. package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +384 -0
  256. package/docs/reference/decisions/0060-a-workspace-states-its-size-and-jr2-reserves-all-of-it.md +111 -0
  257. package/docs/reference/decisions/0061-a-memory-kill-ends-the-agents-processes-not-the-harness.md +83 -0
  258. package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +212 -0
  259. package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +83 -0
  260. package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +79 -0
  261. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +65 -0
  262. package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +550 -0
  263. package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +430 -0
  264. package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +464 -0
  265. package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +180 -0
  266. package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +323 -0
  267. package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +183 -0
  268. package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +144 -0
  269. package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +122 -0
  270. package/docs/reference/decisions/0074-an-unrouted-mechanism-event-is-refused-at-load-and-faults-the-run.md +76 -0
  271. package/docs/reference/decisions.md +83 -0
  272. package/docs/reference/glossary.md +648 -0
  273. package/docs/reference/http-api.md +1348 -0
  274. package/docs/reference/machines.md +190 -0
  275. package/docs/reference/mechanism-events.md +72 -0
  276. package/docs/why.md +206 -0
  277. package/package.json +5 -3
  278. package/src/actor.ts +541 -79
  279. package/src/agent.ts +114 -38
  280. package/src/ambient.ts +2 -1
  281. package/src/assembly-checks.ts +189 -7
  282. package/src/cause.ts +234 -0
  283. package/src/chart.ts +169 -37
  284. package/src/charts.ts +34 -6
  285. package/src/config.ts +430 -178
  286. package/src/custodian.ts +74 -22
  287. package/src/customize.ts +188 -46
  288. package/src/dispatch-effect.ts +945 -0
  289. package/src/door-compat.ts +217 -0
  290. package/src/durability.ts +11 -4
  291. package/src/effect.ts +341 -44
  292. package/src/effector-wire.ts +160 -11
  293. package/src/fail.ts +209 -0
  294. package/src/harness-client.ts +541 -47
  295. package/src/http-effect.ts +495 -53
  296. package/src/http.ts +427 -16
  297. package/src/index.ts +60 -82
  298. package/src/instance.ts +68 -8
  299. package/src/internal.ts +84 -0
  300. package/src/machine-doc.ts +21 -3
  301. package/src/mechanism-routes.ts +168 -0
  302. package/src/model-keys.generated.ts +53 -0
  303. package/src/model-keys.ts +18 -58
  304. package/src/notices.ts +66 -13
  305. package/src/open-body.ts +159 -23
  306. package/src/open-effect.ts +81 -8
  307. package/src/open.ts +59 -6
  308. package/src/parts.ts +184 -13
  309. package/src/party.ts +68 -2
  310. package/src/pick.ts +463 -11
  311. package/src/pool.ts +247 -36
  312. package/src/registration.ts +83 -4
  313. package/src/repos.ts +2 -1
  314. package/src/run-host.ts +565 -31
  315. package/src/run-output.ts +38 -0
  316. package/src/sandbox-effect.ts +273 -38
  317. package/src/sandbox-kube.ts +3 -1
  318. package/src/secret-placement.ts +52 -17
  319. package/src/server.ts +3 -0
  320. package/src/setup.ts +239 -56
  321. package/src/size.ts +121 -9
  322. package/src/snapshot-store.ts +54 -10
  323. package/src/stub-harness.ts +44 -16
  324. package/src/timers.ts +14 -1
  325. package/src/vocabulary.ts +69 -14
  326. package/src/wire.ts +90 -16
  327. package/src/workspace.ts +697 -175
@@ -0,0 +1,357 @@
1
+ ---
2
+ title: Composition
3
+ description: How a Machine composes Machines that you import, and how you bind the parts that they leave Open.
4
+ ---
5
+
6
+ # Composition
7
+
8
+ Composition is how you make a [Workflow](../reference/glossary.md#workflow) from
9
+ [Machines](../reference/glossary.md#machine) that exist already. It has three parts. A Machine invokes a different
10
+ Machine as its child. [`customize()`](../reference/authoring-surface/customize.md) changes the parts that a Machine
11
+ carries. And you bind the parts that a Machine leaves [Open](../reference/glossary.md#open). The kit ships Machines for
12
+ you to compose in this way, in the package [`@jr2/machines`](../reference/machines.md).
13
+
14
+ ## Why it exists
15
+
16
+ A Machine that you import must work in your [Instance](../reference/glossary.md#instance) with no change to its module.
17
+ Thus a Machine carries all that it needs: its [Vocabulary](../reference/glossary.md#vocabulary), its
18
+ [Agents](../reference/glossary.md#agent), its [Effects](../reference/glossary.md#effect), its
19
+ [Sandbox Image](../reference/glossary.md#sandbox-image) and its [Repo Slots](../reference/glossary.md#repo-slot). The
20
+ Machine does not need an Agent list or event names from the Instance. The Instance gives only access and defaults.
21
+ Access is the model provider and its key, the secrets, and the git credentials. A default is a Sandbox Image or a
22
+ [Size](../reference/glossary.md#size) for a Machine that states none.
23
+
24
+ A package cannot know some parts. It does not know your [Repo](../reference/glossary.md#repo), and it cannot pay for
25
+ your model. The package leaves these parts Open. You bind them where you register the Machine as a Workflow, or where
26
+ you compose it. If you do not bind an Open part, [`jr2 up`](../reference/cli.md#up) stops before it converges. Thus a
27
+ missing part does not become a run that spends money on a model that nobody chose.
28
+
29
+ ## A Machine inside a Machine
30
+
31
+ A Machine composes a different Machine as an [xstate](https://xstate.js.org) child. It imports the Machine, puts it
32
+ under `actors`, and a state invokes it by its key. The key is a slot, the same as the slot of an Agent.
33
+
34
+ This Machine composes the shipped Machine [`task`](../reference/machines.md#task) two times. A
35
+ [Menu](../reference/glossary.md#menu)-only Agent, `triager`, reads the prompt first. Then the run goes to one of the two
36
+ copies of `task`. The copies differ only in the thinking level of their coder.
37
+
38
+ The Workflow, with the model of the tab:
39
+
40
+ **Anthropic**
41
+
42
+ ```ts
43
+ import { z } from "zod";
44
+ import { agent, customize, defineEvent, fail, jr2Setup, type HostInjectedInput } from "@jr2/orchestrator";
45
+ import { task } from "@jr2/machines";
46
+
47
+ const model = "anthropic/claude-haiku-5-5";
48
+
49
+ // Bind the two Open parts of `task`: the Repo that the coder works in, and the coder's model.
50
+ const coding = customize(task, {
51
+ repos: { target: { url: "https://github.com/you/app.git" } },
52
+ agents: { coder: { model } },
53
+ });
54
+
55
+ // Two changed copies of one Machine. `coding` does not change.
56
+ const deep = customize(coding, { agents: { coder: { thinkingLevel: "high" } } });
57
+ const quick = customize(coding, { agents: { coder: { thinkingLevel: "low" } } });
58
+
59
+ const door = z.object({ prompt: z.string().describe("What to do, in prose.") });
60
+
61
+ const route = defineEvent({
62
+ name: "route",
63
+ description: "Say how much care the task needs.",
64
+ audience: "agent",
65
+ input: z.object({
66
+ size: z.enum(["small", "large"]).describe("small: a change to one file. large: any other change."),
67
+ }),
68
+ });
69
+
70
+ type Input = HostInjectedInput & z.infer<typeof door>;
71
+
72
+ export const machine = jr2Setup({
73
+ types: {} as { input: Input; context: Input },
74
+ events: [route],
75
+ actors: {
76
+ triager: agent({
77
+ model,
78
+ workspace: "none",
79
+ thinkingLevel: "off",
80
+ instructions: "Read the task. Call route once: small for a change to one file, large for any other change.",
81
+ }),
82
+ // Each composed Machine is a slot, like an Agent.
83
+ deep,
84
+ quick,
85
+ fail: fail(),
86
+ },
87
+ }).createMachine({
88
+ id: "route",
89
+ input: door,
90
+ context: ({ input }) => input,
91
+ on: { "agent.fault": ".failed" },
92
+ initial: "triaging",
93
+ states: {
94
+ triaging: {
95
+ invoke: { src: "triager", input: ({ context }) => ({ prompt: context.prompt }) },
96
+ on: {
97
+ route: [{ guard: ({ event }) => event.size === "large", target: "deep" }, { target: "quick" }],
98
+ },
99
+ },
100
+ // A composed `task` gets its input from this Machine, so it needs a branch.
101
+ deep: {
102
+ invoke: {
103
+ src: "deep",
104
+ input: ({ context }) => ({ prompt: context.prompt, branch: `jr2/route-${context.instanceId}` }),
105
+ onDone: "done",
106
+ },
107
+ },
108
+ quick: {
109
+ invoke: {
110
+ src: "quick",
111
+ input: ({ context }) => ({ prompt: context.prompt, branch: `jr2/route-${context.instanceId}` }),
112
+ onDone: "done",
113
+ },
114
+ },
115
+ done: { type: "final" },
116
+ failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
117
+ },
118
+ });
119
+ ```
120
+
121
+ **Local**
122
+
123
+ ```ts
124
+ import { z } from "zod";
125
+ import { agent, customize, defineEvent, fail, jr2Setup, type HostInjectedInput } from "@jr2/orchestrator";
126
+ import { task } from "@jr2/machines";
127
+
128
+ const model = "local/qwen3.6-35b-a3b";
129
+
130
+ // Bind the two Open parts of `task`: the Repo that the coder works in, and the coder's model.
131
+ const coding = customize(task, {
132
+ repos: { target: { url: "https://github.com/you/app.git" } },
133
+ agents: { coder: { model } },
134
+ });
135
+
136
+ // Two changed copies of one Machine. `coding` does not change.
137
+ const deep = customize(coding, { agents: { coder: { thinkingLevel: "high" } } });
138
+ const quick = customize(coding, { agents: { coder: { thinkingLevel: "low" } } });
139
+
140
+ const door = z.object({ prompt: z.string().describe("What to do, in prose.") });
141
+
142
+ const route = defineEvent({
143
+ name: "route",
144
+ description: "Say how much care the task needs.",
145
+ audience: "agent",
146
+ input: z.object({
147
+ size: z.enum(["small", "large"]).describe("small: a change to one file. large: any other change."),
148
+ }),
149
+ });
150
+
151
+ type Input = HostInjectedInput & z.infer<typeof door>;
152
+
153
+ export const machine = jr2Setup({
154
+ types: {} as { input: Input; context: Input },
155
+ events: [route],
156
+ actors: {
157
+ triager: agent({
158
+ model,
159
+ workspace: "none",
160
+ thinkingLevel: "off",
161
+ instructions: "Read the task. Call route once: small for a change to one file, large for any other change.",
162
+ }),
163
+ // Each composed Machine is a slot, like an Agent.
164
+ deep,
165
+ quick,
166
+ fail: fail(),
167
+ },
168
+ }).createMachine({
169
+ id: "route",
170
+ input: door,
171
+ context: ({ input }) => input,
172
+ on: { "agent.fault": ".failed" },
173
+ initial: "triaging",
174
+ states: {
175
+ triaging: {
176
+ invoke: { src: "triager", input: ({ context }) => ({ prompt: context.prompt }) },
177
+ on: {
178
+ route: [{ guard: ({ event }) => event.size === "large", target: "deep" }, { target: "quick" }],
179
+ },
180
+ },
181
+ // A composed `task` gets its input from this Machine, so it needs a branch.
182
+ deep: {
183
+ invoke: {
184
+ src: "deep",
185
+ input: ({ context }) => ({ prompt: context.prompt, branch: `jr2/route-${context.instanceId}` }),
186
+ onDone: "done",
187
+ },
188
+ },
189
+ quick: {
190
+ invoke: {
191
+ src: "quick",
192
+ input: ({ context }) => ({ prompt: context.prompt, branch: `jr2/route-${context.instanceId}` }),
193
+ onDone: "done",
194
+ },
195
+ },
196
+ done: { type: "final" },
197
+ failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
198
+ },
199
+ });
200
+ ```
201
+
202
+ To use `@jr2/machines`, add it to the Instance at the [Kit version](../reference/glossary.md#kit-version):
203
+ `npm install --save-exact @jr2/machines@<version>`. `<version>` is the version of `@jr2/orchestrator` in your
204
+ `package.json`.
205
+
206
+ A composed Machine is a part of the run of its parent:
207
+
208
+ - The run has one run id and one snapshot. A child Machine does not start a second run.
209
+ - The [Gates](../reference/glossary.md#gate) of the child show in the run of the parent. Its
210
+ [Emits](../reference/glossary.md#emit) go to the same feed.
211
+ - Each Machine keeps its own Vocabulary. The `approve` of a child is not an event of its parent, and the parent does not
212
+ declare it again.
213
+ - The parent gets to the child by `import`. It does not use the Workflow name that [`jr2 run`](../reference/cli.md#run)
214
+ uses.
215
+ - Only the root Machine of a run gets `instanceId`
216
+ ([`HostInjectedInput`](../reference/authoring-surface/type-hostinjectedinput.md)) beside the run input. A child gets
217
+ only the input that its parent gives it. Thus the example gives each `task` a `branch`.
218
+
219
+ ### Composing a Workflow
220
+
221
+ **The Workflow route, and the Machines that it composes**
222
+
223
+ - **route**: the Machine that workflows/route.ts registers as the Workflow route
224
+ - **triager** (Agent): picks deep or quick
225
+ - **deep** (Machine): thinking high
226
+ - **quick** (Machine): thinking low
227
+ - ↓ deep → coding: customize() · quick → coding: customize()
228
+ - **coding**: binds the Open parts of task
229
+ - **Repo Slot target**: your app
230
+ - **coder model**: the model of the tab
231
+ - ↓ coding is a customize() of task
232
+ - **task**: from @jr2/machines
233
+ - **coder** (Agent): edits and commits
234
+ - **Repo Slots**: Open
235
+ - **coder model**: Open
236
+
237
+ The file `workflows/route.ts` registers the Machine `route` as the Workflow `route`. The Machine declares three slots of
238
+ its own: the Agent `triager` and the two Machines `deep` and `quick`. Each of the two is a `customize()` of `coding`,
239
+ and `coding` is a `customize()` of `task`. `task` leaves its Repo Slots and the model of its coder Open. `coding` binds
240
+ them, so `deep` and `quick` have them too.
241
+
242
+ ## customize()
243
+
244
+ [`customize(machine, parts)`](../reference/authoring-surface/customize.md) gives a new Machine with the parts changed.
245
+ The Machine that you give it does not change. Thus two calls on one import give two Machines, as `deep` and `quick`
246
+ show.
247
+
248
+ [`Customize`](../reference/authoring-surface/type-customize.md) gives the parts that you can change:
249
+
250
+ | Key | What it changes |
251
+ | ----------- | ------------------------------------------------------------------------------------- |
252
+ | `agents` | The definition of an Agent, by slot, field by field. `{ model }` keeps the rest. |
253
+ | `effects` | The Open url, argv or secret of an Effect, by slot. |
254
+ | `actors` | A Machine that this Machine composes, by slot. The value has the same keys, one down. |
255
+ | `repos` | The Repo Slots of the [`workspace()`](../reference/authoring-surface/workspace.md). |
256
+ | `image` | The Sandbox Image of the `workspace()`. |
257
+ | `user` | The [User Container](../reference/glossary.md#user-container) of the `workspace()`. |
258
+ | `resources` | The Size of the `workspace()`, field by field. |
259
+
260
+ The type comes from the Machine. It offers only the Agents, Effects, Machines and Repo Slots that the Machine declares.
261
+ A slot that the Machine does not have does not compile.
262
+
263
+ `workspace()` and [`pool()`](../reference/authoring-surface/pool.md) wrap a Machine. `customize()` goes through each
264
+ wrapper to the Machine inside it. Thus `customize(task, { agents })` changes the Agents of the Machine in the
265
+ `workspace()` of `task`, and you do not name the wrapper's own slot. `repos`, `image`, `user` and `resources` go down to
266
+ the first `workspace()` on that path.
267
+
268
+ ## Open parts
269
+
270
+ A Machine marks a part Open with [`open`](../reference/authoring-surface/open.md). These parts can be Open:
271
+
272
+ - a Repo Slot with no url, or the whole Repo Slot map (`repos: open`)
273
+ - the model of an Agent (`agent({ model: open, … })`)
274
+ - the url of an `http` Effect, the argv of a `command`, or the name of the secret of an Effect (`secret(open)`)
275
+
276
+ An Open part has no default. You bind it with `customize()`. Each Open part has two checks:
277
+
278
+ - `jr2 up` reads every registered Machine. It refuses an Open part that nobody bound, and it prints the `customize()`
279
+ line that binds it.
280
+ - At run time, the part refuses too. An Agent does not start a [Turn](../reference/glossary.md#turn) with an Open model.
281
+ An Effect does not run while it is Open.
282
+
283
+ [Bind a shipped Machine's Open parts](../guides/bind-open-parts.md) shows each binding.
284
+
285
+ ## @jr2/machines
286
+
287
+ `@jr2/machines` is the package of Machines that the kit ships. It ships Machines and never Workflows. A Machine becomes
288
+ a Workflow only when a file in your `workflows/` folder exports it.
289
+
290
+ It ships `task`: a coder Agent works on one prompt in a [Workspace](../reference/glossary.md#workspace), and a person
291
+ approves the work at the `review` Gate. `task` leaves two parts Open: the whole Repo Slot map and the model of `coder`.
292
+ The first Repo Slot that you name is the Repo that the coder works in. The coder can read the other Repos. It also ships
293
+ [`body`](../reference/machines.md#body), the Machine inside `task`, for a `workspace()` of your own.
294
+
295
+ The version of `@jr2/machines` is the Kit version. It names `@jr2/orchestrator` at that exact version as a peer
296
+ dependency.
297
+
298
+ ## A Machine as an npm package
299
+
300
+ A package exports a Machine and nothing more. The run input, the Vocabulary, the Agents, the Effects, the Sandbox Image
301
+ and the Repo Slots are all on the Machine. A Workflow uses an imported Machine in one of three ways:
302
+
303
+ - as it is, when it leaves no part Open: `export const machine = imported;`
304
+ - changed: `export const machine = customize(task, { … });`
305
+ - composed in a Machine of your own, as in the example above
306
+
307
+ `task` cannot be used as it is, because it leaves two parts Open.
308
+
309
+ A file in `workflows/` uses the same code. A package has no API of its own.
310
+
311
+ A Machine package names `@jr2/orchestrator`, `xstate` and `zod` as peer dependencies, never as dependencies. jr2 keeps
312
+ the parts of a Machine in the one copy of `@jr2/orchestrator` and of `xstate` that the Instance loads. A Machine made
313
+ with a second copy of either has empty Menus and Gates that accept nothing. `jr2 up` shows no error for it, and prints
314
+ no `seats:` line for it. Its run stops with the status `error` when an Agent or a Gate of the Machine starts.
315
+ `@jr2/machines` has this shape, and your package copies it.
316
+
317
+ A package can ship a docker context for its Sandbox Image. The Machine names the folder with
318
+ `import.meta.resolve("./image")`, and `jr2 up` builds it.
319
+
320
+ ## Rules
321
+
322
+ - A nested Machine is a child in the same run. jr2 has no second run for a child, and no invoke by Workflow name.
323
+ - An [`agent()`](../reference/authoring-surface/agent.md), an Effect or a `workspace()` is a key of `actors`. jr2
324
+ refuses one that a state writes in its `invoke.src`.
325
+ [`jr2Setup()`](../reference/authoring-surface/jr2setup.md)`.createMachine` refuses it, and `jr2 up` refuses it too.
326
+ - `customize()` changes only the parts that a Machine declares. You cannot add a part. A Machine that needs one more
327
+ Agent is a new Machine.
328
+ - For a part that the Machine does not declare, the compiler refuses the key, and `customize()` refuses it at run time.
329
+ `image`, `user` and `resources` compile on every Machine. `customize()` refuses them when the Machine composes no
330
+ `workspace()`.
331
+ - `jr2 up` refuses a registered Machine that leaves a part Open, and it names the Workflow and the part.
332
+ - `jr2 up` also refuses an Open part on a Machine that a state writes in its `invoke.src`, because no `customize()` can
333
+ get to it. Put that Machine under `actors`.
334
+ - A Repo Slot map that is Open takes the slots that you name. Name one slot or more. Their order means what the Machine
335
+ says it means.
336
+ - An Effect's Open part is bound one time, to a value. A run does not choose it, and a second `customize()` cannot
337
+ change it.
338
+ - A file in `workflows/` that a different Workflow imports is also a Workflow. Give a Machine that is only for
339
+ composition a file name that starts with `_`, or keep it outside `workflows/`.
340
+ - `task` inside a different Machine needs `branch` in its input. Without it, `task` refuses to start.
341
+
342
+ ## Read next
343
+
344
+ - [Bind a shipped Machine's Open parts](../guides/bind-open-parts.md)
345
+ - [Publish a Machine as an npm package](../guides/publish-a-machine-as-an-npm-package.md)
346
+ - [Machines and Workflows](machines-and-workflows.md)
347
+ - [Workspaces](workspaces.md)
348
+ - [Pools and Sources](pools-and-sources.md)
349
+ - Reference: [`customize()`](../reference/authoring-surface/customize.md),
350
+ [`Customize`](../reference/authoring-surface/type-customize.md), [`open`](../reference/authoring-surface/open.md),
351
+ [`@jr2/machines`](../reference/machines.md), [`jr2 up`](../reference/cli.md#up)
352
+ - [ADR-0049](../reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md): a Machine carries its
353
+ parts and composes by invoke
354
+ - [ADR-0051](../reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md): a Repo is a slot
355
+ on the Workspace
356
+ - [ADR-0054](../reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md): the kit
357
+ ships Machines, and a shipped Machine leaves its parts Open
@@ -0,0 +1,254 @@
1
+ ---
2
+ title: Converge
3
+ description: What jr2 up makes in the cluster from your Instance folder, and the Assembly that it publishes.
4
+ ---
5
+
6
+ # Converge
7
+
8
+ To converge is to make a cluster agree with your [Instance](../reference/glossary.md#instance) folder. One command does
9
+ it: [`jr2 up`](../reference/cli.md#up). It reads the folder, builds the images that the folder needs, and applies the
10
+ objects to the cluster of your current kubectl context. Then it publishes your Workflows to the
11
+ [Orchestrator](../reference/glossary.md#orchestrator) as an [Assembly](../reference/glossary.md#assembly). You can run
12
+ it again at any time. When nothing changed, it changes nothing.
13
+
14
+ ## Why one command
15
+
16
+ A [Workflow](../reference/glossary.md#workflow) needs many parts in the cluster: the Orchestrator, its Secret, its
17
+ images and the operator. Some Workflows also need a [Sandbox Image](../reference/glossary.md#sandbox-image) or the
18
+ [Instance Harness](../reference/glossary.md#instance-harness). If you put each part there by hand, you must remember the
19
+ steps and their order. When you forget a step, the cluster is not correct, and you find the problem only when a run
20
+ fails. `jr2 up` does every step, in the correct order, each time. It tells you what it does at each step.
21
+
22
+ The Instance folder holds no record of a cluster. The kubectl context is the address, and the namespace is the identity.
23
+ Thus the same folder converges into kind on your computer and into a shared cluster. Only the kubectl context changes,
24
+ and, for a cluster that is not kind, the value that [`registry`](../reference/config.md#registry) reads from `.env`.
25
+
26
+ ## Setup and usage
27
+
28
+ The diagram shows what `jr2 up` makes, and what [`jr2 run`](../reference/cli.md#run) and
29
+ [`jr2 send`](../reference/cli.md#send) use after it.
30
+
31
+ **What jr2 up makes, and what jr2 run and jr2 send use**
32
+
33
+ - **You**: the Instance folder, on your computer
34
+ - **jr2 up**: converges the cluster
35
+ - **jr2 run, jr2 send**: use what jr2 up made
36
+ - ↓ jr2 up → the cluster: applies, then publishes · ↓ jr2 run, jr2 send → Orchestrator: read the token, then call
37
+ - **the cluster**: of the current kubectl context
38
+ - **Instance**: in the namespace of the Instance
39
+ - **Orchestrator**: loads your Workflows
40
+ - **Assembly**: your Workflows and your config
41
+ - **jr2-instance Secret**: holds the Instance token
42
+ - **Instance Harness**: when an Agent is Menu-only
43
+ - **Instance Effector**: when an Effect runs there
44
+ - **Repo cache**: when a Machine has a Sandbox
45
+ - ↓ the Orchestrator asks for each Sandbox · ↑ the operator makes its pod
46
+ - **jr2-system**: one for each cluster
47
+ - **operator**: makes each Sandbox pod
48
+ - **images**: that the pods run
49
+ - **Kit images**: jr2 up pulls them
50
+ - **Pinned image**: the Envoy of the Custodian
51
+ - **Sandbox Images**: jr2 up builds them
52
+
53
+ `jr2 up` reads the Instance folder. It applies the objects, and then it publishes the Assembly to the Orchestrator,
54
+ which loads it. `jr2 run` and `jr2 send` do not apply objects to the cluster. They read the Instance token from the
55
+ `jr2-instance` Secret. Then they open a port forward to the Orchestrator for the time of the command. The Orchestrator
56
+ starts the run, and it makes each [Sandbox](../reference/glossary.md#sandbox) that the run needs. For all the parts of
57
+ the cluster, see [Architecture](architecture.md).
58
+
59
+ ## What jr2 up does
60
+
61
+ `jr2 up` does its steps in this order. Steps 1 to 4 change nothing in the cluster.
62
+ [`jr2 check`](../reference/cli.md#check) does steps 2 and 3 alone, with the same code and no cluster:
63
+
64
+ 1. It writes the docs index of the [Kit version](../reference/glossary.md#kit-version) between the two `jr2-docs`
65
+ markers in `AGENTS.md`. This step changes the folder, not the cluster. Thus a converge that fails still leaves the
66
+ index correct.
67
+ 2. It typechecks the Instance with the Instance's own TypeScript compiler.
68
+ 3. It loads each Workflow in `workflows/`. It reads the parts that each [Machine](../reference/glossary.md#machine)
69
+ carries: its [Agents](../reference/glossary.md#agent), its [Repos](../reference/glossary.md#repo), its Sandbox Images
70
+ and its [Effects](../reference/glossary.md#effect). It also checks each [Chart](../reference/glossary.md#chart) file.
71
+ 4. It makes the Assembly from the folder, and calculates its hash. See [The Assembly](#the-assembly).
72
+ 5. It checks the Kubernetes version of the cluster.
73
+ 6. It checks that the namespace is this Instance's. Before it uses a namespace for the first time, it asks you.
74
+ 7. It checks that the cluster keeps pod-level resources.
75
+ 8. It finds the platforms of the nodes, and it decides the address of each image.
76
+ 9. It builds the Sandbox Images.
77
+ 10. It makes the values of the Secrets, and checks each Secret that the config names but that `jr2 up` does not write.
78
+ 11. It checks each model that an Agent uses: a pod in the cluster asks the provider for one tool call for each model.
79
+ Until each check passes, `jr2 up` writes nothing that the Instance or the operator reads. The pod has up to 5
80
+ minutes to start, and each model has up to 6 minutes. `jr2 up` writes each model's result as it comes. With
81
+ `--skip-provider-preflight`, no pod checks the models, and `jr2 up` writes a warning that names each model that it
82
+ did not check.
83
+ 12. It applies the operator. For a Repo with an ssh url, it asks where the deploy key comes from.
84
+ 13. It applies the Secrets and the Orchestrator, and waits for the rollout. When the Machines need them, it also waits
85
+ for the Repo cache, the Instance Harness and the [Instance Effector](../reference/glossary.md#instance-effector).
86
+ 14. It publishes the Assembly to the Orchestrator. When the Orchestrator already has this Assembly, it publishes
87
+ nothing.
88
+ 15. It removes the images that nothing uses now.
89
+
90
+ `jr2 up` says `converged` only when each pod that it rolled out runs the image that it expected. The labels and the
91
+ records that `jr2 up` writes help it to skip work. They do not prove that the cluster is correct. The pods do.
92
+
93
+ The Machines decide some parts. When no registered Machine makes a Sandbox, `jr2 up` builds no Sandbox Image and runs no
94
+ Repo cache. When no Agent has `workspace: "none"`, there is no Instance Harness. When the Machines stop using the Repo
95
+ cache or the Instance Harness, `jr2 up` removes it from the namespace. The image sweep removes a Sandbox Image that
96
+ nothing names.
97
+
98
+ ## The images
99
+
100
+ Each image that a converge uses is one of these kinds:
101
+
102
+ | Image | Who owns it | What `jr2 up` does |
103
+ | ----------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
104
+ | [Kit image](../reference/glossary.md#kit-image) | jr2 | It builds nothing. The cluster pulls `jr2-orchestrator`, `jr2-harness` and `jr2-operator` at the tag of the Kit version. |
105
+ | [Pinned image](../reference/glossary.md#pinned-image) | Upstream | It builds nothing. The cluster pulls the Envoy image of the [Custodian](../reference/glossary.md#custodian), by its tag and its digest. |
106
+ | Sandbox Image, from a `file:` URL | You | It builds the folder that a [`workspace()`](../reference/authoring-surface/workspace.md) names, and the `images/default/` folder that [`jr2 init`](../reference/cli.md#init) writes. |
107
+ | Sandbox Image, from a registry | You | It builds nothing. The cluster pulls the image. |
108
+
109
+ The Custodian is a container in each [Harness](../reference/glossary.md#harness) pod.
110
+ [Workspaces](workspaces.md#the-sandbox-image) explains what a Sandbox Image holds.
111
+
112
+ The tag of each image that `jr2 up` builds is a hash of the inputs of that image and of its platforms. Thus a new tag
113
+ means new content, and the same tag means the same content. This rule has three results:
114
+
115
+ - When the inputs of an image do not change, `jr2 up` does not build it again. A converge with no change builds no
116
+ image.
117
+ - When an input changes, the tag changes. A Sandbox that starts after the converge uses the new image. A Sandbox that
118
+ runs does not, as the text below explains.
119
+ - `--force` builds each image again, even when its tag did not change.
120
+
121
+ The Kit images are at `ghcr.io/snapwich` by default. A cluster that cannot pull from there pulls from a mirror. A mirror
122
+ holds the same tags. [`kitRegistry`](../reference/config.md#kitregistry) names the mirror, and
123
+ [`jr2 kit push`](../reference/cli.md#kit-push) fills it. `jr2 up` never pushes to `kitRegistry`. `kitRegistry` also
124
+ changes where the cluster pulls the Pinned image, and `jr2 kit push` copies it to the mirror too.
125
+
126
+ `jr2 up` sends each image that it builds to the nodes in one of two ways:
127
+
128
+ - When you set `registry`, it pushes the image to that registry, and the nodes pull it.
129
+ - When you do not set `registry`, on a kind cluster it loads the image into the nodes with `kind load`. A context whose
130
+ name starts with `kind-` is a kind cluster.
131
+
132
+ A change to a Sandbox Image changes only the Sandboxes that start after the converge. A Sandbox that runs keeps its
133
+ image, because a new pod would lose its [Worktrees](../reference/glossary.md#worktree) and the commits that you did not
134
+ push. `jr2 up` tells you how many running [Workspaces](../reference/glossary.md#workspace) keep each older image.
135
+
136
+ `jr2 up` uses Docker only to build a Sandbox Image. When no registered Machine makes a Sandbox, it builds no image, and
137
+ your computer does not need Docker for `jr2 up`.
138
+
139
+ ## The Assembly
140
+
141
+ The Assembly is what the Orchestrator loads from your Instance folder: the Workflows in `workflows/`, `jr2.config.ts`,
142
+ the folders of the `file:` Sandbox Images, and the packages that they import. The image of the Orchestrator is a Kit
143
+ image, the same for each Instance. Your code is not in it. `jr2 up` makes the Assembly and publishes it to the
144
+ Orchestrator that runs.
145
+
146
+ - **No restart.** The Orchestrator loads a new Assembly in its process. A change to a Machine or to `jr2.config.ts`
147
+ starts no pod again. Thus a port forward to the [Console](../reference/glossary.md#console) stays open.
148
+ - **The Kit packages come from the image.** `jr2 up` removes `@jr2/orchestrator` and each package that it needs, such as
149
+ `xstate` and `zod`, from the Assembly. The Orchestrator uses its own copies. A second copy of one of these packages
150
+ makes Machines whose Menus are empty, so `jr2 up` refuses it.
151
+ - **One hash for each Assembly.** The hash comes from the files and the paths of the Assembly. When the Orchestrator
152
+ already has the Assembly with this hash, `jr2 up` does not publish it again.
153
+ - **The Orchestrator checks it again.** Before it makes an Assembly current, the Orchestrator loads each Workflow and
154
+ does the same checks as `jr2 up`. When it refuses the Assembly, the Assembly that was current stays current.
155
+ - **A run keeps its Assembly.** A new run starts under the current Assembly. A live run keeps the Assembly that it
156
+ started under, also after a restart. Thus a publish does not stop a run that waits at a
157
+ [Gate](../reference/glossary.md#gate). `jr2 run`, `jr2 runs` and the Console use the current Assembly. The
158
+ Orchestrator removes an older Assembly when no live run holds it.
159
+ - **Only `jr2 up` publishes.** The publish needs the publish token, which is in the `jr2-instance` Secret. `jr2 up`
160
+ reads it through the kubectl context. The Instance token does not publish, and an Agent cannot publish code.
161
+
162
+ [`jr2 status`](../reference/cli.md#status), with no run id, shows the current Assembly and each Assembly that a live run
163
+ holds.
164
+
165
+ ## Kit version and Handoff
166
+
167
+ An Instance has one Kit version: the version of the `@jr2/orchestrator` package that the Instance pins. It is the tag of
168
+ each Kit image, the image of the Orchestrator too. `jr2 init` pins `@jr2/orchestrator` and `@jr2/cli` to one exact
169
+ version in `package.json`. The Assembly records the Kit version, and the Orchestrator refuses an Assembly for a
170
+ different Kit version. When you change the Kit version, one `jr2 up` starts the Orchestrator on its new image first, and
171
+ then it publishes the Assembly for the new version.
172
+
173
+ You install the [jr2 CLI](../reference/glossary.md#jr2-cli) two times: one time with `npm i -g`, and one time in the
174
+ Instance, from its `package.json`. In an Instance folder, the global `jr2` runs the Instance's own `@jr2/cli`, with the
175
+ same arguments. This is the [Handoff](../reference/glossary.md#handoff). Thus the CLI that runs is always the one that
176
+ the Instance pins. In the Instance, the version of your global `jr2` does not matter.
177
+ [`jr2 version`](../reference/cli.md#version) shows the CLI that runs, the global CLI that handed off, the Kit version of
178
+ the Instance, and what the cluster runs.
179
+
180
+ All the Instances on a cluster share one operator. `jr2 up` upgrades an older operator. It does not downgrade an
181
+ operator that a different Instance upgraded to a later version.
182
+
183
+ ## Clean up
184
+
185
+ When each tag is a content hash, each change makes a new image. Ten changes to a Dockerfile make ten images. Thus
186
+ `jr2 up` removes the old images at the end of each converge that succeeds.
187
+
188
+ An image is garbage when no live root in the cluster names it. The roots are the image map of each Instance on the
189
+ cluster, the image of each Sandbox, and the images of the pods that run. jr2 removes only an image that it built and
190
+ labeled. It removes the image from your computer and, on a kind cluster, from the nodes. It never removes an image that
191
+ it did not build, such as the Pinned image. The output gives the size that it removed:
192
+ `swept <count> image(s) (<size>)`.
193
+
194
+ `jr2 up` and [`jr2 down`](../reference/cli.md#down) remove the images. [`jr2 gc`](../reference/cli.md#gc) does the same
195
+ work at a different time, for example when your disk is full. It also removes each Repo resource that no Machine binds
196
+ and that no run used in the last 7 days, by default. `--repo-ttl` changes the time. `jr2 gc --dry-run` shows what it
197
+ would remove, and removes nothing.
198
+
199
+ `jr2 down` deletes the namespace of the Instance. The runs, the store of the runs and the Sandboxes go with it.
200
+ `jr2 down --all` also removes the operator.
201
+
202
+ ## Rules
203
+
204
+ - `jr2 up` changes nothing in the cluster when the Instance does not typecheck.
205
+ - `jr2 up` changes nothing in the cluster when the Assembly holds a second copy of a Kit package, or when its Kit
206
+ version is not the Kit version of the CLI.
207
+ - `jr2 up` changes nothing in the cluster when a registered Machine has an [Open](../reference/glossary.md#open) part
208
+ that is not bound. Examples are a [Repo Slot](../reference/glossary.md#repo-slot) with no url and an Agent with no
209
+ model.
210
+ - `jr2 up` refuses a cluster that runs a Kubernetes version earlier than 1.35. It also refuses a cluster that does not
211
+ keep pod-level resources.
212
+ - `jr2 up` refuses a namespace that belongs to a different Instance. It asks you before it uses a namespace for the
213
+ first time. `--yes` gives the answer for CI.
214
+ - `jr2 up` refuses a cluster that is not kind when `registry` is not set.
215
+ - Each verb that reads the Instance, other than `jr2 version`, refuses when the Instance and the CLI do not use the same
216
+ copy of `@jr2/orchestrator`.
217
+ - `jr2 up` never downgrades the operator.
218
+ - `jr2 up` never replaces the pod of a Sandbox that runs.
219
+ - The Orchestrator refuses an Assembly that fails its checks, and the Assembly that was current stays current.
220
+ - Only the publish token publishes an Assembly.
221
+ - A converge that fails removes no image.
222
+ - `jr2 gc`, `jr2 up` and `jr2 down` remove only images that jr2 built and that no live root names.
223
+
224
+ [Fix a failed converge](../guides/fix-a-failed-converge.md) gives the refusal text of each rule, and the fix.
225
+
226
+ ## Read next
227
+
228
+ - [Iterate on a Machine on kind](../guides/iterate-on-a-machine-on-kind.md)
229
+ - [Move from kind to a shared cluster](../guides/move-from-kind-to-a-shared-cluster.md)
230
+ - [Mirror the Kit images](../guides/mirror-the-kit-images.md)
231
+ - [Upgrade the Kit version](../guides/upgrade-the-kit-version.md)
232
+ - [Clean up](../guides/clean-up.md)
233
+ - [Fix a failed converge](../guides/fix-a-failed-converge.md)
234
+ - Reference: [`jr2 up`](../reference/cli.md#up), [`jr2 down`](../reference/cli.md#down),
235
+ [`jr2 gc`](../reference/cli.md#gc), [`jr2 kit push`](../reference/cli.md#kit-push),
236
+ [`jr2 version`](../reference/cli.md#version), [`registry`](../reference/config.md#registry),
237
+ [`kitRegistry`](../reference/config.md#kitregistry) and [`platforms`](../reference/config.md#platforms)
238
+ - [ADR-0019](../reference/decisions/0019-one-converging-command-against-the-current-context.md): one converging command
239
+ against the current context
240
+ - [ADR-0038](../reference/decisions/0038-jr2-up-builds-every-image-it-deploys.md): `jr2 up` builds each image that the
241
+ Instance runs
242
+ - [ADR-0039](../reference/decisions/0039-image-garbage-collects-by-reachability.md): `jr2 gc` removes the images that
243
+ nothing reaches
244
+ - [ADR-0041](../reference/decisions/0041-a-build-the-host-already-holds-is-not-spent-again.md): a build that the
245
+ computer already holds is not done again
246
+ - [ADR-0044](../reference/decisions/0044-kit-images-live-at-a-canonical-home-a-self-host-mirrors-it.md): the Kit images
247
+ and their mirror
248
+ - [ADR-0045](../reference/decisions/0045-the-platform-joins-the-image-address-and-the-cluster-chooses-it.md): the
249
+ platform is a part of the image tag
250
+ - [ADR-0046](../reference/decisions/0046-a-converge-failure-carries-its-diagnosis.md): a failed converge says why
251
+ - [ADR-0056](../reference/decisions/0056-a-global-jr2-hands-off-to-the-instances-own-and-an-instance-has-one-kit-version.md):
252
+ the Handoff, and one Kit version for each Instance
253
+ - [ADR-0069](../reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md): the
254
+ Orchestrator is a Kit image, and an Instance publishes its Assembly