@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,82 @@
1
+ # The platform joins the image address, and the cluster chooses it
2
+
3
+ [ADR-0038](0038-jr2-up-builds-every-image-it-deploys.md)'s invariant — every tag is a content address, so "present
4
+ implies current" — hashed the build's **inputs** and nothing else. But the bytes are a function of (inputs × platform),
5
+ and no build passed `--platform`: the daemon default (or a remembered `DOCKER_DEFAULT_PLATFORM`) decided silently. So
6
+ one tag named an amd64 or an arm64 image depending on who built it last, and both skips that rest on tag equality — the
7
+ cluster record and [ADR-0041](0041-a-build-the-host-already-holds-is-not-spent-again.md)'s host-held listing — delivered
8
+ an amd64 Sandbox Image to an arm64-only cluster, surfacing as an opaque rollout timeout (`exec format error`, found only
9
+ by hand). The hole is in ADR-0038's core invariant, and it covers every image `jr2 up` builds — Orchestrator, Sandbox,
10
+ and the checkout-mode kit three. Published Kit images were already immune
11
+ ([ADR-0044](0044-kit-images-live-at-a-canonical-home-a-self-host-mirrors-it.md): multi-arch manifest lists, mirrored
12
+ whole).
13
+
14
+ ## Decision
15
+
16
+ - **A tag names (inputs × platform set), and says so visibly**: `<repo>:<hash>-<arch>` —
17
+ `jr2-sandbox-x-default:4a77b1-arm64`, and `…:4a77b1-amd64-arm64` for a multi-platform build (sorted, joined). In the
18
+ tag, not the salt: the triggering failure was invisible precisely because the tag did not say, and a self-describing
19
+ tag is diagnosability applied at the naming layer. Every `docker build` passes `--platform` explicitly — the daemon
20
+ default and `DOCKER_DEFAULT_PLATFORM` stop being steering, which deletes the manual step whose forgetting was the
21
+ failure.
22
+ - **The cluster's nodes choose the platform set.** `jr2 up` reads the schedulable nodes' `.status.nodeInfo.architecture`
23
+ — the union of the nodes an ordinary pod lands on (the Orchestrator's placement) and the Instance's Sandbox nodes
24
+ (ADR-0052), so a tainted pool no Sandbox reaches is never built for — and intersects with the **supported set** — the
25
+ platforms the kit releases for (`linux/amd64`, `linux/arm64`), one constant beside `KIT_IMAGES` that `just kit-push`
26
+ builds from too, so the two cannot drift. A node arch outside the supported set is reported and skipped, never built
27
+ for: a Sandbox Image for `s390x` is dead weight, since no kit image could sit beside it in the pod. An empty
28
+ intersection is a loud error. Reading a singleton set is not an assumption; only a non-singleton set involves
29
+ judgement, and that case builds rather than guesses (next bullet).
30
+ - **A multi-arch node set gets a multi-arch build**: `docker buildx build --platform <set> --push`, the `just kit-push`
31
+ mechanism. This path only ever runs where it can deliver, **by construction**: a mixed-arch cluster is never kind
32
+ (kind nodes are containers on one host, one arch), and the non-kind transport branch already requires `registry` — so
33
+ buildx pushes to the registry that must exist, and `kind load` never meets a manifest list. The singleton set keeps
34
+ the plain single-`docker build` and the existing transport branch.
35
+ - **`platforms` is the one escape hatch** — a deployment-varying config key (env-carried, like `registry`) holding
36
+ docker platform strings. **Absolute**: when set, derivation is skipped and the list is the build set — still
37
+ intersected with the supported set, so `s390x` gets the same named error. It exists for the two cases derivation
38
+ cannot see: autoscale-from-zero (the target pool has no nodes yet) and set pollution (an UNTAINTED amd64 pool beside
39
+ arm64 workers costs a needless qemu build; the key trims it — a tainted one is already outside the set, ADR-0052). Not
40
+ additive/subtractive — cleverness the rare case does not earn.
41
+ - **Foreign-arch builds are preflighted.** When the build set contains a platform the host cannot run natively, `RUN`
42
+ steps need binfmt emulation; without it docker fails mid-build with the same cryptic `exec format error` this ADR
43
+ exists to delete. So the converge checks emulation is available before spending any build, and the error names the fix
44
+ (`docker run --privileged --rm tonistiigi/binfmt --install <arch>`).
45
+ - **The host-held skip is honest again — where it can answer at all.** For singleton builds the tag now names the
46
+ platform and jr2 always built with an explicit `--platform`, so tag-equality on the daemon once more means "present
47
+ implies current". A multi-arch ref never lands in the daemon (buildx `--push` goes straight to the registry), so the
48
+ host skip cannot answer for it and a record-silent mixed-arch converge rebuilds — the accepted cost; ADR-0041's
49
+ rejection of registry-truth HEAD checks stands.
50
+ - **`imageUser` follows the artifact**: `docker inspect` on the daemon-held singleton build;
51
+ `docker buildx imagetools inspect` against the registry for a manifest list.
52
+
53
+ ## Considered options
54
+
55
+ - **Multi-arch by default** (every converge, like `just kit-push`). Rejected: nodes in one cluster are almost always one
56
+ arch, so every everyday converge would pay a qemu cross-build to serve the rare mixed case — and `kind load` cannot
57
+ deliver a manifest list from the daemon, so the no-registry path would die or fork the transport branch. Multi-arch
58
+ survives as the _derived_ answer for the set that actually needs it.
59
+ - **Preflight the mismatch only** (compare built image arch to node arch, then say so). Rejected as the whole fix: it
60
+ diagnoses instead of prevents, and the tag stays a lie — the ADR-0038 invariant keeps its hole and the stale host-held
61
+ image still needs `--force` folklore. The comparison survives inside the converge-failure diagnosis (ADR-0046) as
62
+ belt-and-braces messaging.
63
+ - **Platform in the hash salt, not the tag.** Rejected: honest but invisible — two tags would differ inexplicably, and
64
+ the class of failure this ADR closes was an invisibility failure.
65
+ - **Explicit-only** (`platforms` required, no derivation). Rejected: taxes every single-arch user — the overwhelming
66
+ case — with a key they should not need, inverting "the CLI does all the work".
67
+ - **Keep `DOCKER_DEFAULT_PLATFORM` as the steering mechanism.** Rejected: an env var the user must remember is the class
68
+ of manual step jr2 deletes, and forgetting it was the failure.
69
+
70
+ ## Consequences
71
+
72
+ - ADR-0038's "every tag is a content address" is **amended**: the address covers (inputs × platform set). All five built
73
+ image kinds take the suffix — one mechanism, no exceptions.
74
+ - ADR-0041 is **amended**: tag-equality on the host daemon is sound again because the tag names the platform; a
75
+ multi-arch ref is invisible to the host skip by construction.
76
+ - ADR-0044's consequence — "the cross-build workaround of exporting `DOCKER_DEFAULT_PLATFORM` for checkout-mode
77
+ converges against a foreign-arch cluster is unaffected" — is **superseded**: the workaround is deleted, `--platform`
78
+ is derived and explicit.
79
+ - A converge gains one cheap read (`kubectl get nodes`) it mostly already pays in spirit; steady-state skips still spend
80
+ directory walks and no docker.
81
+ - Old un-suffixed tags never collide with new ones (the suffix is always present), so pre-0045 images age out through
82
+ ADR-0039's sweep — no migration.
@@ -0,0 +1,34 @@
1
+ # A converge failure carries its diagnosis
2
+
3
+ The failure that produced [ADR-0045](0045-the-platform-joins-the-image-address-and-the-cluster-chooses-it.md) surfaced
4
+ as `error: timed out waiting for the condition` — kubectl's verdict and nothing else. The cause (`exec format error` in
5
+ a CrashLoopBackOff pod) was found only by hand-running `kubectl get pods` and `kubectl logs`. The repo already holds the
6
+ precedent for what should have happened: `oneShotFailure()` (kube.ts) rethrows a one-shot probe's failure with the pod's
7
+ own output in front of kubectl's verdict, because the line that says WHY is exactly what the verdict drops. The rollout
8
+ wait is the same failure one layer up, and `jr2 up` runs three of them (operator, Orchestrator, Instance Harness), all
9
+ equally blind.
10
+
11
+ ## Decision
12
+
13
+ - **On rollout failure, the error carries the evidence**: for the deployment's pods — phase, container waiting reasons,
14
+ the last events, and a container log tail — gathered after the timeout and rethrown in front of kubectl's verdict. One
15
+ `rolloutFailure()` beside `oneShotFailure()`, used by all three rollout waits, so every layer gets the same eyes.
16
+ - **Named diagnoses annotate the evidence, never replace it.** A small pattern table layered on top names the cause and
17
+ the way back when it matches: `exec format error` → "image platform X, node platform Y" plus `platforms`/`--force`
18
+ (belt-and-braces under ADR-0045, and the only trace left for pre-0045 images and registry-ref Sandbox Images jr2 never
19
+ built); `ImagePullBackOff`/`ErrImagePull` → the ref and the registry it resolved to (the `docker.io/library/`
20
+ normalization trap); `CrashLoopBackOff` → lead with the log tail, which IS the diagnosis; `CreateContainerConfigError`
21
+ → name the missing object (already preflighted for `envFrom` Secrets — this catches what slips past). The hard rule
22
+ that keeps the table honest: a named diagnosis may only interpret evidence that is also printed raw beneath it — a
23
+ table that swallows evidence turns a wrong match into a lie; one that annotates it costs nothing when wrong.
24
+ - **Scope: the rollout wait only.** A converge that never reaches a rollout (config error, build error, apply error)
25
+ keeps its existing errors — no general "dump the namespace on any error" reflex. Those failures already name
26
+ themselves; the rollout timeout was the one that did not.
27
+
28
+ ## Considered options
29
+
30
+ - **Evidence-only** (no pattern table). Rejected: the user still translates `exec format error` into "platform mismatch"
31
+ themselves, which is the folklore step this ADR exists to delete. The table is small, bounded, and each entry is a
32
+ failure someone actually hit.
33
+ - **Diagnosis as a separate command** (`jr2 doctor`-style, run after the failure). Rejected: the moment of failure is
34
+ when the evidence is fresh and the user is looking; a second command is the by-hand loop with a jr2 badge on it.
@@ -0,0 +1,47 @@
1
+ # The git ssh key source is the user's choice
2
+
3
+ [ADR-0019](0019-one-converging-command-against-the-current-context.md) drew a flat line — "personal keys never enter a
4
+ cluster" — and gave ssh repos exactly one path: `jr2 up` generates an in-cluster deploy keypair and prints the public
5
+ key to register. The line had a cost the flow could not pay: GitHub allows one deploy key on exactly one repo, so a
6
+ multi-repo instance means N registrations, and re-using the printed key across repos is rejected — the flow pushed users
7
+ toward machine accounts or hand-rolled Secrets anyway. A key already registered with the git host makes that friction
8
+ zero. The invariant is demoted to a default: jr2 never lifts a personal key silently, but the user may hand one over,
9
+ warned and on purpose.
10
+
11
+ ## Decision
12
+
13
+ - **Three sources, one prompt**, when `up`'s walk of the registered Machines finds an ssh url on a bound Repo Slot
14
+ (ADR-0051) whose matching `git.credentials` entry names an `sshKey` Secret that does not exist (the scaffold's
15
+ wildcard entry names `jr2-git-ssh`): **generate a fresh in-cluster deploy keypair** (recommended, listed first,
16
+ today's behavior); **use a local key** (discovered `~/.ssh` candidates plus "other path"); or **paste one on stdin,
17
+ hidden**. Declining all three bails, as before — the cache agent would only fail on an unauthenticated clone later. A
18
+ per-run slot's url is not on the walk and is never prompted for: an ssh url first seen at attach fails that attach
19
+ with the key hint, as any unregistered key does. The scripting escape stays kubectl: create the Secret yourself,
20
+ `kubectl create secret generic jr2-git-ssh --from-file=identity=…` — the Secret carries Flux's key names
21
+ ([ADR-0051](0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md)), and the cache agent reads no other.
22
+ - **`--yes` means generate.** Non-interactive mode never selects a personal key — the dangerous option is never a
23
+ default. There is no `--git-ssh-key` flag: a scripted supplied-key path is the kubectl escape.
24
+ - **A passphrase-protected key is refused by name** — the in-cluster clone cannot answer a passphrase — detected with
25
+ `ssh-keygen -y -P ""` before anything is applied. Decrypting and storing plaintext would silently strip protection the
26
+ user chose to have.
27
+ - **The supplied-key paths warn at choice time**: the key lands in a namespace Secret, readable by anyone with Secret
28
+ read there and at rest in etcd — a generated deploy key leaks read access to some repos; a personal key leaks
29
+ everything it can reach. The public half (`identity.pub`) is derived via `ssh-keygen -y`; output prints the
30
+ fingerprint, never key material.
31
+ - **The generate path pauses at the moment of truth.** The printed key is useless until registered, and an unregistered
32
+ key makes the repo sync fail ([ADR-0048](0048-the-orchestrator-boots-without-its-repos.md) keeps that from crashing
33
+ the boot). So interactively, `up` prints the key and waits: "register this public key with your git host, then press
34
+ enter to continue" — the wait sits exactly where the user must act anyway. `--yes` proceeds without pausing, and any
35
+ converge that generated a keypair **ends** by repeating the warning: the key, the repos that will not sync until it is
36
+ registered, and that the cache agent retries on its own.
37
+
38
+ ## Considered options
39
+
40
+ - **Keep the invariant, improve the messaging.** Rejected: the multi-repo friction is structural (one deploy key, one
41
+ repo), not informational — no message makes N registrations cheaper than zero.
42
+ - **Agent forwarding instead of copying** (the ADR-0005 pattern for Sandbox sessions). Rejected here: the cache agent
43
+ fetches unattended, in-cluster, on a schedule the user is not present for — forwarding authenticates a session, not a
44
+ daemon.
45
+ - **A `--git-ssh-key <path>` flag.** Rejected: it makes the personal-key path scriptable, which is exactly the silent
46
+ lift the prompt exists to prevent; the kubectl escape already serves automation, with the user's own tooling holding
47
+ the key.
@@ -0,0 +1,36 @@
1
+ # The Orchestrator boots without its repos
2
+
3
+ The Orchestrator's boot-time repo sync was awaited before the server served: a repo that could not clone — an
4
+ unregistered deploy key, a wrong url, a git host outage — threw, the container exited, and the kubelet crash-looped the
5
+ Orchestrator. So one unreachable repo killed the daemon that hosts every Workflow, including ones that never touch a
6
+ repo, and a first converge with a freshly generated deploy key
7
+ ([ADR-0047](0047-the-git-ssh-key-source-is-the-users-choice.md)) was guaranteed to time out its rollout unless the user
8
+ registered the key inside the wait. The codebase already names the correct blast pattern, four lines below the
9
+ violation: a missing `jr2-images` ConfigMap does not stop the boot — the instance serves, and only a provision fails,
10
+ pointing at `jr2 up`.
11
+
12
+ ## Decision
13
+
14
+ - **A failed repo sync does not stop the boot.** The Orchestrator boots, serves, and creates the `Repo` resources its
15
+ Machines bind ([ADR-0051](0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md)); it does not sync them.
16
+ The operator's cache agent clones and fetches each onto its node, retries a failure with backoff, and writes every
17
+ result — synced, or git's own error — to the resource's status. The same blast pattern as the images ConfigMap —
18
+ degrade the capability, not the daemon.
19
+ - **A Workspace provision needing an unsynced repo fails pointedly**, naming the repo and the last sync error — the
20
+ moment the degradation actually bites is the moment it is reported, to the run that owns the consequence. The line is
21
+ the clone (ADR-0051): a cold node whose clone fails fails the provision; a warm cache whose fetch fails lets the
22
+ attach proceed on the objects it holds, announced as stale with git's error. The pod cannot heal it — the worktree's
23
+ `origin` fetches from the cache (ADR-0005) — so stale lasts until the cache agent's next successful fetch, which the
24
+ Agent's own `git fetch` then picks up in place.
25
+ - **Repo sync state is observable**: it lives on each `Repo` resource's status, per node, and `jr2 status` reports repos
26
+ that are not synced with their last error — the place ADR-0047's "register the key, the cache agent retries" points
27
+ at.
28
+
29
+ ## Considered options
30
+
31
+ - **Fail-fast boot, kept.** Rejected: a boot failure is invisible except as a rollout timeout, reported to whoever
32
+ converged, not whoever needs the repo — and it takes unrelated Workflows down with it. Fail-fast is right when serving
33
+ would be wrong; an Orchestrator without one repo serves everything else correctly.
34
+ - **`jr2 up` verifies the clone before finishing.** Rejected: registration is a human act on an external system with no
35
+ deadline — a converge that waits on it hangs CI and re-runs teach nothing. The converge reports the window (ADR-0047);
36
+ the cache agent closes it on its own.
@@ -0,0 +1,126 @@
1
+ # A Machine carries its parts and composes by invoke
2
+
3
+ A workflow could not use another workflow's Machine as a child without re-declaring the child's events at its own root
4
+ (the `triaged-task` example documented the workaround), and a Machine had no way to travel: its Agents lived in the
5
+ Instance's roster by name and its Sandbox Image in the Instance's `images/`, so a packaged Machine depended on someone
6
+ else's config holding the right strings. The grill of 2026-09-06/09 settled composition and packaging as one decision,
7
+ because they are one problem: **what a Machine depends on that is not inside it.**
8
+
9
+ ## Decision
10
+
11
+ - **Composition is Machine composition.** A workflow module imports another module's exported Machine and invokes it as
12
+ an xstate child (`actors: { deep, quick }`, `invoke: { src: "deep" }`). One run, one snapshot, one run id; the child's
13
+ Gates list under the parent's run and its emits ride the same feed. There is no sub-run and no
14
+ invoke-by-registered-name: a nested Machine is reached by `import`, never by the name `jr2 run` uses. Rejected:
15
+ Temporal-style child workflows with their own run ids — a new actor kind, cross-run correlation, and cancel
16
+ propagation, for no requirement that needs a second run id. A run that STARTS a run is not composition: it is the
17
+ `dispatch` Effect ([ADR-0071](0071-a-run-starts-a-run-through-a-dispatch-effect.md)), by the name `jr2 run` uses, and
18
+ the two runs are independent. Two uses, two mechanisms.
19
+ - **Everything a Machine depends on rides the Machine, scoped to it.** Vocabulary already did (ADR-0011, per-Machine
20
+ since this decision). The two remaining dependencies join it:
21
+ - **An Agent is an actor slot.** `jr2Setup({ actors: { researcher: agent({ model, instructions, … }) } })`, invoked as
22
+ `src: "researcher"` with `{ prompt, …dials }` as input. `agent(definition)` is `agentRun` closed over one definition
23
+ and branded with it; `agentRun` and `agent: "name"` leave the authoring surface. The typo check is xstate's own
24
+ `src` typing — a slot the Machine does not declare is a compile error with nothing added — and Stately shows
25
+ `researching → invoke researcher` instead of a uniform `agentRun`. Two Machines in one run may both carry a
26
+ `researcher`; each resolves against its own implementations, and the Instance ID's actor path keeps their
27
+ conversations apart.
28
+ - **An Effect is an actor slot too**
29
+ ([ADR-0067](0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md)), and its plain-data
30
+ parts ride the slot: the kind, where it runs, a `command`'s argv, an `http` Effect's method, fixed host and the
31
+ names of the secrets it names — or the `open` sentinel where a package left the url, the argv or a secret's name for
32
+ its composer ([ADR-0068](0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md)). `jr2 up` reads them
33
+ without running anything, and a secret named there is what places it.
34
+ - **The Sandbox Image is a `workspace()` option**, static: `workspace(body, { input, image, repos, workGroup })`
35
+ (`repos` is ADR-0051's, and follows the same rule). `image` is a string in one of two shapes — a `file:` URL
36
+ (`import.meta.resolve("./image")`, a docker context the module ships) or a registry ref — or absent, which keeps
37
+ ADR-0037's fallback. It is static because `jr2 up` must find it with no run. It is never persisted: the provisioning
38
+ state re-reads it off the Machine on restore.
39
+ - **The definition rides the Turn.** The admission body carries the slot's definition; the Harness runs what it was
40
+ handed and re-reads it per Submission as before. The Instance roster (`agents/`, then `config.agents`), its ConfigMap,
41
+ and `JR2_AGENTS_JSON` retire — a flat roster cannot hold two `researcher`s, and a Machine edit already needs `jr2 up`
42
+ to publish the Assembly again, so the ConfigMap bought nothing a Machine-carried definition loses. Placement
43
+ (ADR-0031) reads `workspace: "none"` off the slot's definition.
44
+ - **Parts resolve at invoke time through the live actor's logic, never a build-time closure.** `agentRun` finds its
45
+ definition in the logic it was invoked as; `provision` reads the image off the wrapper's parts map keyed on
46
+ `machine.config`. This is the one rule that lets xstate's `provide()` and customization coexist, and the same rule
47
+ ADR-0011 adopted for Vocabulary.
48
+ - **Customization is `customize(machine, parts)`**, a plain function in the family of `workspace()` and `pool()`,
49
+ returning a plain `StateMachine`. `parts` has the declaration's own shape, recursively partial:
50
+ `{ agents?: { <slot>?: Partial<AgentDefinition> }, effects?: { <slot>?: { url } | { argv } | { secret } }, image?, user?, repos?: { <slot>?: Binding }, actors?: { <child>?: parts } }`
51
+ — the two image seats together, since ADR-0005 gives the User Container the same static option, and the Repo Slots
52
+ beside them, since ADR-0051 makes a Repo a `workspace()` slot a composer binds. `effects` binds an Effect's Open url,
53
+ argv or secret name, once — an Effect with an Open secret and an Open url or argv takes one object with both keys,
54
+ `{ url, secret }` or `{ argv, secret }`
55
+ ([ADR-0054](0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md)): the slot's logic is built
56
+ again with the bound part and substituted as an Agent override is. Internally an Agent override is xstate's
57
+ `machine.provide({ actors: { researcher: agent(merged) } })`, with the override layered over the stock definition; a
58
+ child override is the same call one level down, recursing — each level is exactly the one-level reach ADR-0015 found
59
+ `provide` has, held by the composer who owns the child object, never host-side injection. jr2's wrappers are
60
+ transparent: `customize(research, { agents })` reaches the body through the `body` slot (and `pool()`'s `worker`, at
61
+ any depth), so a consumer never writes `body`. The images and the Repo bindings are the parts `provide` cannot carry
62
+ (xstate copies only implementations, and every part is keyed on the config it passes through by reference), so those
63
+ fields clone the wrapper's config and rebuild it with the same implementations, re-attaching what the original
64
+ carried. A bound argv's load warnings are such a part too: `customize()` rebuilds the Machine the author wrote the
65
+ same way, with the vocabulary, the seats and the door it carried and the warnings the walk gives for the bound argv,
66
+ so no attachment is keyed on anything but the config. Only DECLARED parts can be retuned, and the compiler is what
67
+ says so: the slots are read off xstate's own `TActor` parameter, so an Agent, a Repo Slot, or a child the Machine does
68
+ not carry is a type error (ADR-0050), and the runtime refuses the same call naming the Machine's own slots. Rejected:
69
+ a `.with()` method on the machine — it needs a jr2-owned machine type over xstate's, which ADR-0015 avoided, and it
70
+ vanishes after any `.provide()`; a callable-machine hybrid — verified to work, reads as a trick.
71
+ - **A package exports a Machine, nothing beside it.** The door (ADR-0033), the vocabulary, the Agents, and the image all
72
+ ride the exported object. The three uses:
73
+
74
+ ```ts
75
+ export const machine = research; // as-is
76
+ export const machine = customize(research, { agents: { researcher: { model } }, image }); // retuned
77
+ const deep = customize(research, { agents: { researcher: { model: opus } } }); // nested twice,
78
+ const quick = customize(research, { agents: { researcher: { model: haiku } } }); // differently
79
+ export const machine = jr2Setup({ events: [route], actors: { triager: agent(triager), deep, quick } }).createMachine(…);
80
+ ```
81
+
82
+ A local `workflows/*.ts` is written exactly the same way; there is no package-side API.
83
+
84
+ - **The wrapper's body is a named slot** (`invoke: { id: "body", src: "body" }` over `setup({ actors: { body } })`), and
85
+ `pool()`'s worker likewise. That is what lets `provide`, `customize`, Stately, and the `jr2 up` walk reach it
86
+ uniformly.
87
+ - **A Part is a key of `actors`.** An `agent()`, an Effect (ADR-0067) or a `workspace()` written inline on an
88
+ `invoke.src` is refused at build (`jr2Setup.createMachine`) and at load (the walk), with the slot form in the message.
89
+ xstate gives an inline `src` a generated key (`xstate.invoke.<n>.<state id>`) that moves when a state is renamed, so
90
+ the ledger, `jr2 up`'s report and the Machine doc would name the Part by a number, and `customize()` — `provide`,
91
+ keyed on `actors` — could not reach it at all. A plain child Machine written inline is not a Part: the walk descends
92
+ it, with no `customize()` route below it.
93
+ - **`jr2 up` walks the registered Machines** — `implementations.actors`, descending into child Machines — to collect
94
+ models to preflight and `file:` image contexts to build. A context is keyed by its content digest (the same digest
95
+ ADR-0038 tags by), taken over its copy in the staged Assembly, the bytes the Orchestrator holds
96
+ ([ADR-0069](0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md)), so the host at `jr2 up`
97
+ and the Orchestrator agree without a path table even where staging dropped a `.env` or a `node_modules` the folder
98
+ holds. Repos are slots on the same walk (ADR-0051): a bound slot's url is collected, so its `Repo` resource is warm
99
+ before a run asks; an open slot nobody bound is refused, naming the Machine, the slot, and the `customize` line that
100
+ fixes it; a per-run slot is the run's business and the walk leaves it alone.
101
+
102
+ ## Consequences
103
+
104
+ - **Agent identity moves from the Instance to the Machine.** GLOSSARY.md's Agent entry restates: an Agent is a part of a
105
+ Machine, not an Instance-scoped roster entry; `customize` is a definition-level act by the composer, so ADR-0018's
106
+ identity-vs-Dial line is untouched — a Turn still sets `model`/`thinkingLevel` and nothing else.
107
+ - **A Workflow is a Machine registered under a name.** The "wired to its Agents and config" clause retires: the wiring
108
+ is inside the Machine.
109
+ - `defineAgent` retires in favor of `agent()`; `AgentTurnInput.agent` goes; `deriveMenus` keys on agent-slot logic
110
+ instead of `src === "agentRun"`; the unit-test seam becomes `provide({ actors: { researcher: fake } })`.
111
+ - Only declared parts can be customized; none can be added. A consumer who needs a third Agent composes a new Machine. A
112
+ `workspace()` that declares its Repo Slot map Open (`repos: open`, ADR-0051) has declared every slot as the composer's
113
+ to name, so the map they write is the declaration, not an addition.
114
+ - **`import.meta.resolve` stays** in any Machine that ships a context; there is no other way for an ES module to name a
115
+ folder it owns.
116
+ - The ledger records which slot a Turn ran as, not the definition's text. If per-Turn auditability of instructions is
117
+ ever needed, the admission marker can carry a definition digest.
118
+ - `jr2 dev`'s reload cache-busts the workflow module only; an edit to an imported Machine module is not picked up until
119
+ the next full reload. Known, unaddressed here.
120
+ - A `workflows/` file that is both discovered and imported by another registers as its own Workflow too; a Machine meant
121
+ only for composition lives in a `_`-prefixed file or outside `workflows/`.
122
+ - A conversation belongs to one Agent slot in one Machine instance by construction — the continued iid is
123
+ `<run>/<machine actor path>/<agent>` (ADR-0057) — so no continuation can cross personas. What a continuation does NOT
124
+ check is that the definition behind the slot is the one that started it: a run whose `instructions` were edited before
125
+ a redeploy continues, which ADR-0030 deliberately allows (shape decides restorability, not behavior). A definition
126
+ digest on the ledger record would refuse exactly that, so it is not taken.
@@ -0,0 +1,73 @@
1
+ # What code names, config declares; what the CLI names, discovery finds
2
+
3
+ A Machine names things outside itself by string, and until now the first sign of a wrong string was an invoke-time
4
+ failure mid-run. ADR-0049 moved Agents and Sandbox Images INTO the Machine — actor slots and a `workspace()` option — so
5
+ those names are typed by xstate's own `src` typing and by the Machine's own parts. ADR-0051 moved the last one, the
6
+ **Repo**, the same way: a slot on the `workspace()`, bound by url. What this decision fixes is the rule that says where
7
+ a definition lives, and the gate that enforces it.
8
+
9
+ ## Decision
10
+
11
+ - **One rule decides where a definition lives.** A thing that **code refers to by name** and that a Machine cannot carry
12
+ is declared in `jr2.config.ts`, so the type system sees the name. A thing that **only the CLI or HTTP API refers to by
13
+ name** is discovered from files. Workflows are the latter — `jr2 run` and `POST /workflows/:name/runs` name them, a
14
+ nested Machine is reached by `import` (ADR-0049) — so `workflows/` stays filename-discovered. Agents, images, and
15
+ Repos are neither: they ride the Machine (ADR-0049, ADR-0051), and the `agents/` folder, `config.agents`,
16
+ `config.images`, and `config.repos` all retire. One thing code names and a Machine cannot carry is a secret's value:
17
+ an Effect names it with `secret("name")`, and the Instance declares it in the top-level `secrets` list
18
+ ([ADR-0068](0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md)). The name is a string, not a type: the
19
+ walk after the typecheck refuses an Effect that names a secret the list does not hold, before anything is built.
20
+ `jr2.config.ts` holds reach and credentials (`harness`, `secrets`, `git.credentials`, `registry`).
21
+ - **The slot key types a Repo.** A `workspace()` declares its Repos as slots —
22
+ `repos: { target: open, docs: { url, ref } }` — and the keys are a phantom on the wrapper type, read through
23
+ `pool()`'s `worker` and `workspace()`'s `body` as the image is (ADR-0049). A
24
+ `customize(machine, { repos: { <slot>: url } })` of a slot the Machine does not declare is a compile error, never a
25
+ silent widening to `string`, and the body's `workspace.repos.<slot>` handle is typed by the same keys. There is no
26
+ `Register`, no `RepoName`, and no `repoNames()`: the url a Machine writes is the thing, not a reference into someone
27
+ else's file (ADR-0051). A door that offers a menu of Repos is the Instance's own `z.enum` of urls.
28
+ - **`jr2 up` typechecks the Instance before it builds anything**, and refuses on errors, naming them. The scaffold's
29
+ `tsc --noEmit` and pinned compiler already exist (ADR-0043's rule for the checker); this makes them a gate instead of
30
+ a script the user may run. A wrong slot name, a `customize()` of an Agent or a Repo Slot the Machine does not carry:
31
+ all stop here. One Repo check is converge-time and not compile-time: a registered Machine with an open slot nobody
32
+ bound. A `workflows/` export has no type to hang it on, so the walk that follows the typecheck refuses it, before it
33
+ builds anything, naming the Machine, the slot, and the `customize` line that fixes it (ADR-0051).
34
+ - **`jr2 check` runs the gate and the walk with no cluster.** The typecheck and the walk are one function of the CLI,
35
+ `checkInstance`. `jr2 up` and `jr2 check` both call it, so the two give the same refusals with the same text. The walk
36
+ loads each registered module. Thus `jr2 check` also gives each refusal that a module throws when it loads. These are
37
+ refusals of `createMachine`, `defineEvent` and `workspace()`, and `npm run typecheck` cannot give them. `jr2 check`
38
+ reads no kube context. Thus an Assistant that may not run `jr2 up` can run it before it gives a change to the user. It
39
+ runs in a kit checkout and in an installed Instance. The name is the verb that a user types for "is this folder
40
+ correct". The glossary's _check_ of a Check pod is a different noun in a different place: one model call in the
41
+ provider preflight. Thus the name stays, and the glossary entry tells the two apart.
42
+
43
+ ## Considered options
44
+
45
+ - **A generated declaration** (`jr2-env.d.ts` written by `init`/`up` from directory discovery), to keep `agents/` and
46
+ `images/` as folders and still type their names. Rejected: a generated-file class jr2 does not have, an editor
47
+ staleness window, and — decisive — ADR-0049 removed the need by making the names part of the Machine.
48
+ - **Agents and images as config entries** (`agents: { scribe }`, `images: { default: "./images/default" }`), the shape
49
+ this ADR first took. Rejected the same day: it typed the names but kept them Instance-scoped, so a packaged Machine
50
+ still depended on someone else's config holding the right strings, and one run could not hold two Machines each
51
+ carrying a `coder`.
52
+ - **A Repo catalog in config, typed back through a `Register` interface** (`repos: [{ name, url }]`, a `RepoName`
53
+ derived from `typeof config`, `z.enum(repoNames(config))` on a door), the shape this ADR took for the one dependency
54
+ it left in config. Rejected in ADR-0051 by the argument above: a packaged Machine still could not say which repository
55
+ it works on, and a consumer could bind one only by holding the right NAME. The slot key is the type now.
56
+
57
+ - **A flag on `jr2 up`** (`jr2 up --check`, or `--dry-run`) in place of a verb. Rejected: `up` reads the kube context
58
+ first and its flags are converge flags; a flag that stops it after the walk still asks an Assistant to run the
59
+ converging verb, which a permission rule that forbids `jr2 up` also forbids. A verb is the line a permission rule can
60
+ allow.
61
+ - **A copy of the walk in `jr2 check`.** Rejected: two walks drift, and then the check passes a folder that `jr2 up`
62
+ refuses — the failure that `jr2 check` exists to remove.
63
+ - **Stage the Assembly in `jr2 check` too.** Rejected: staging runs a frozen install from the lockfile (ADR-0043), which
64
+ needs the registry and takes minutes, and its refusals are about the install, not the code an Assistant writes.
65
+
66
+ ## Consequences
67
+
68
+ - Only Machines the Instance's program typechecks get the compile-time guarantee — those under `workflows/` and what
69
+ they import. A packaged Machine compiled elsewhere carries its own parts, so its internal names are checked where it
70
+ was built; the Repo it works on is an open slot the consumer binds with `customize`, typed by the package's own slot
71
+ keys, or a per-run slot typed by the consumer's mapper over the door.
72
+ - Runtime validation stays: an open slot nobody bound is a `jr2 up` walk refusal, and the attach still refuses a per-run
73
+ url no `git.credentials` entry matches (ADR-0051). The type error is the earlier check, not the only one.