@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,50 @@
1
+ # The agent picks from a Machine-defined, schema-backed menu; it does not drive the workflow
2
+
3
+ The control plane is Menu tool calls (ADR-0002), but **which** events an Agent may emit is scoped to the current Machine
4
+ state and defined by the Machine, not an open set the Agent invents. The menu derives from the invoking state's
5
+ transitions (ADR-0015 — the consumer authors no tool lists), is read by the Harness through the pod's Custodian
6
+ (ADR-0013), and the Agent **chooses one** (controlled agency); the Machine owns the transition table. The Agent never
7
+ steers the workflow — it answers within a frame the Machine set — and because its only control-plane peer is the
8
+ Custodian (which holds a credential it cannot read), that frame is _enforced_, not advertised. Menus only change at turn
9
+ boundaries, and the Harness re-reads the Menu per Submission (ADR-0013/0027), so no `list_changed` push channel is
10
+ needed.
11
+
12
+ There is no jr2-blessed event vocabulary: every menu entry is a workflow-defined event (ADR-0011).
13
+
14
+ ## Encode flat
15
+
16
+ A named event schema must compile to a flat tagged object (an `enum` discriminator + each option's params as optionals
17
+
18
+ - a validation `check`), **never a top-level `oneOf`/`anyOf`**. Measured (PoC #5b): a strict variant (→ `oneOf`/`const`
19
+ tool schema) is unsatisfiable for Qwen3-Coder — it serializes the tool args as a JSON string and validation fails on
20
+ every retry. A flat object is satisfied first try. A conditional contract ("`notes` required iff `request_changes`")
21
+ is enforced by jr2 after the pick, not by the tool schema.
22
+
23
+ ## A pick declares its input, never its answer
24
+
25
+ A def states what the Agent supplies (`input`) and nothing about what comes back. Every pick is `ack`: delivered and
26
+ answered on the same call. A pick that moves the workflow to work inside the Agent's state is answered when that work is
27
+ done (ADR-0024), and the answer is the Machine's: the last reply since the pick, or what its `answer` action sets
28
+ (ADR-0067). So a def has no `output` schema and no `deferred` semantics; `defineEvent` refuses both. `poll` stays
29
+ reserved (ADR-0013).
30
+
31
+ ## One path: every conversation lives on the agent wire
32
+
33
+ The wire has exactly one conversation surface (ADR-0027): `POST /agents/:name/:id`, resumable by `(name, iid) + offset`.
34
+ There is no separate "workflow run" surface, and nothing on the wire forces a structured result out of a turn — the menu
35
+ is the only structured channel. Consequences:
36
+
37
+ - **All continuing, multi-turn work lives on the agent path**, driven by `agentRun` (ADR-0016).
38
+ - **A turn that settles without a valid pick is re-prompted by jr2** — the budgeted no-signal nudge _inside_ `agentRun`
39
+ (ADR-0016). The workflow sees one terminal `agent.fault` on exhaustion.
40
+ - **Self-contained, single-shot decisions** (an LLM-judge / classifier / "given this diff + this rubric, return a
41
+ verdict") are one-turn conversations whose menu is the verdict — the same path, not a second mechanism.
42
+
43
+ ## Residual
44
+
45
+ jr2's own typed notices now reach a running Agent through the step-boundary read (ADR-0002,
46
+ [ADR-0062](0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md)); the Menu still opens only when the Agent
47
+ reaches a checkpoint or a turn boundary. Free-text human steering is the remaining case, reserved for v1 as a
48
+ Caller-authenticated message on the same channel (ADR-0002, [ADR-0011](0011-workflow-defined-events.md)). Evidence for
49
+ the findings above: `poc/actor/POC-5B-FINDINGS.md`, `poc/actor/POC-5C-FINDINGS.md` (`poc/` is gitignored; conclusions
50
+ live here).
@@ -0,0 +1,109 @@
1
+ # Durable Machine state: serializable context, live things constructed from input
2
+
3
+ The Orchestrator is a forever-running daemon that must survive a `kill -9` and resume in-flight work, so every Machine
4
+ has to be reconstructable from a persisted xstate snapshot. That forces one invariant across everything that runs in a
5
+ Machine:
6
+
7
+ > Machine context and actor input hold **plain serializable data only** — ids, counters, status, data-shaped handles
8
+ > (e.g. a Sandbox's `endpoint` string). Live infrastructure — HTTP servers, clients, live actor references — is
9
+ > **constructed per-invocation from serializable input** (ADR-0011's static-import doctrine) and never persisted.
10
+ > Parent↔child coordination uses `sendParent` events plus serializable ids, never a held child-actor reference.
11
+
12
+ PoC #7 discovered this the hard way (a live `http.Server` in context crashed `JSON.stringify`); PoC #8 was designed to
13
+ it from the start (the top Machine keeps only counts + ids, children report completion UP via
14
+ `sendParent('FEATURE_DONE')`). They are the same invariant — #8's discipline is precisely what makes #7's
15
+ snapshot/restore possible.
16
+
17
+ The store's own durability — what a persist survives, and how long a finished run's row lives — is
18
+ [ADR-0065](0065-a-persist-survives-a-crash-and-history-is-a-week.md).
19
+
20
+ Durable **agent handles** do not ride Machine context at all: the host persists an `iid → admission` ledger beside the
21
+ snapshot in the same save (ADR-0016). Iids are globally unique, so restore needs no context-tree walking to find them.
22
+ An admission names the Turn ID of the Turn that ledgered it, because the continued Turns of one conversation share an
23
+ iid. A restore re-attaches only that Turn (ADR-0016).
24
+
25
+ **Effects** keep a **ledger** beside the snapshot in the same save (ADR-0067): one row per Effect, by its id. An
26
+ `intent` row is written before the call — saved at the write, so the snapshot that holds the Effect and the row land
27
+ together, before the request leaves; a `settled` row is written with the output, saved at the write before the
28
+ transition the output drives and again in the save that carries that transition; an `aborted` row when the Effect's
29
+ state exited while it ran, kept in memory and saved by the save that carries that exit (a cancel's final save included),
30
+ never by a save inside the transition. A restore reads the row and never guesses: settled → the output is delivered (the
31
+ transition's save was lost); intent → per kind: a command that names no secret re-attaches to its exec by id, or settles
32
+ `unknown` when the Harness no longer knows it; an http call (a Worktree file body included) asks every replica of its
33
+ Effector for its id and follows the one that holds it, and when none does it is sent again only when the author marked
34
+ it `idempotent`, else it settles `unknown`; a push and a credentialed command ask their Sandbox Effector for their id,
35
+ and when it no longer holds them are sent again with only the commit the intent row pinned — never the Agent's tip now —
36
+ or settle `unknown` when no commit was pinned; no row → nothing was sent, so it starts. jr2 runs an Effect it started a
37
+ second time only where its author marked it `idempotent`, or where its run is a function of a pinned commit (a push, a
38
+ credentialed command); a command that names no secret never. A row replaces the one before it and is never dropped: a
39
+ restored child that is done or stopped never starts, so no restore reads a finished Effect's row, and the settled and
40
+ aborted rows keep the Effect's id, kind and outcome for the run's life: the record of what the run's Effects did. A
41
+ settled row's output TAIL is dropped once the save that carries its transition is on disk — that save's snapshot no
42
+ longer holds the Effect running, so no restore reads it, and the full stream is on the run's feed. A push row keeps its
43
+ Repo Slot, its published commit, its source, its `squashed` and its sync's answer whole: every later push of its
44
+ Workspace and Repo Slot sends them as one of its pairs, and the newest push's sync, when it did not finish, runs again
45
+ (ADR-0067); git's words are its tail, and so is its bundle, except on the newest push of its Repo Slot while that push's
46
+ sync is `busy` or `not-synced`: that row keeps the bundle, which the sync that runs again moves the branch from. Only
47
+ the newest push's sync runs again, so once a newer push of the slot published, the older row's bundle goes at the next
48
+ save — at most one bundle per Repo Slot. The ledger grows by one short row per Effect a run starts, never by its tails,
49
+ and lives as long as the run's row (ADR-0065). An outstanding pick's hold is saved in the same blob and keeps its
50
+ `chain` whole until the pick is answered (ADR-0067); that is the only place an Effect's tails accumulate.
51
+
52
+ **Pending timers** do not ride the snapshot either. The host persists a **timer table** beside it in the same save: one
53
+ row per pending `after`, named delay, delayed `raise` or delayed `sendTo` in the run's tree, with its absolute deadline.
54
+ The author writes plain xstate `after`; there is no kit timer actor, and `after` is refused nowhere.
55
+
56
+ ## Mechanism (the non-obvious parts)
57
+
58
+ - **Re-attach is driven by the child's persisted input, not the parent `invoke`.** On restore, xstate v5 re-spawns an
59
+ invoked actor from its **persisted input** — it does **not** re-evaluate the parent's `invoke: { input: … }`. So the
60
+ re-attach lever is rewriting the child's persisted input on hydrate (drop `prompt`, mark it attaching) so the run
61
+ resumes its stream instead of re-POSTing. Keep the parent-side input expression as defence-in-depth, but know it is
62
+ not what fires on restore.
63
+ - **A timer is re-armed by the host, because xstate 5 drops it.** xstate 5 keeps a delayed event on the actor SYSTEM's
64
+ scheduler, not in the snapshot, and a restore runs no entry action again, so a pending `after` never fires after a
65
+ restore (Pool's `pollEvery` included, ADR-0017). At each save the host reads the scheduler's table and writes each
66
+ timer as `{ source, target, id, event, delay, deadline }`, actors named by their child-id path below the root. The
67
+ deadline is a time on the host's wall clock (`RunHostOptions.now`, `Date.now` by default; tests pass one that does not
68
+ step). On restore the order is: `start()`, then re-arm each row with `deadline − now` clamped to `[0, delay]`, in
69
+ deadline order. Re-armed before `start()`, a timer is armed twice, because the system's own `start()` schedules its
70
+ table. The id is xstate's own, so a state's exit after the re-arm cancels a re-armed timer. `start()` drains the
71
+ mailbox, so a child that sends on start can exit a state before any row is re-armed; the host records each cancel
72
+ during `start()` and does not re-arm a row it names. A child stopped during `start()` is stopped with xstate's
73
+ `cancelAll`, which sees an empty table, and its parent state entered again puts a new child at the same path; so the
74
+ host resolves each row's actors before `start()` and re-arms a row only on the same actors after it. So a timer fires
75
+ once, after the time that remained; at once if its deadline passed while the Orchestrator was down, and timers that
76
+ are all overdue fire in the order they fell due; never if an exit cancelled it, before the save, during `start()` or
77
+ after the re-arm; and never later than its own delay when the wall clock went backwards. A wall clock that jumped
78
+ forwards fires it early: only the wall clock survives a process. "Once" is with respect to the saved state: a timer
79
+ that fired after the last save fires again on restore, as any event after the last save replays. A delayed send to an
80
+ actor outside the run's tree is not recorded; jr2 has no such idiom.
81
+ - **The re-arm reads an xstate internal** (`system.getSnapshot()._scheduledEvents`, `system.scheduler.schedule`, and
82
+ `system.scheduler.cancel`, wrapped for the length of `start()`; `packages/orchestrator/src/timers.ts`). The same two
83
+ scheduler functions are also wrapped for the life of the run's system, to tell a timer that fires from an event an
84
+ actor sends at once: both reach the inspection stream alike, and the scheduler forgets a timer as it fires it. An
85
+ outstanding pick's stopped answer needs that difference (ADR-0024). Raw-xstate tests that show xstate itself dropping
86
+ the timer are the canary for an xstate bump. xstate 6 persists timers in the snapshot and re-arms them with the same
87
+ deadline and clamp; on xstate 6 the timer table is deleted.
88
+ - **Reconcile against the live world before re-attaching.** Restore is not blind resume: a present Sandbox CR →
89
+ re-attach; an absent one → the defined failure path (`workspace.lost` into the body — ADR-0012), never a silent
90
+ re-provision.
91
+ - **Reconcile against the MACHINE too** (added 2026-08-02,
92
+ [ADR-0030](0030-a-snapshot-names-the-machine-it-was-written-under.md)). "Reconstructable from a persisted snapshot"
93
+ was only ever true of the Machine that WROTE it, and a run resolves its workflow by filename while the state volume
94
+ outlives the image — so a run parked across a deploy meets whatever was baked in next. The snapshot now carries a
95
+ digest of its Machine's shape, and a mismatch is refused rather than interpreted. This is not belt-and-braces: xstate
96
+ accepts a `value` naming a state the chart no longer has and starts with `value: undefined`, so nothing downstream
97
+ would have caught it.
98
+
99
+ ## Consequences
100
+
101
+ - Actors may not stash live connections in context for convenience; anything live is rebuilt per-invocation from
102
+ serializable input (the Harness client from an `endpoint`, the kube client from ambient config) — which is also why a
103
+ mock↔real swap happens at the wire (ADR-0011's stub Harness), never inside actor code.
104
+ - An Effect has no at-most-once sliver: its intent row is on disk before the call leaves, so a restart either finds no
105
+ row (nothing was sent) or finds the intent and settles `unknown` when it cannot re-attach — or, for an http call the
106
+ author marked `idempotent` that no replica holds, sends it again under the same id.
107
+ - The known durability edge stands for Agents: a crash between "run admitted" and "admission persisted" degrades to an
108
+ at-most-once re-POST (a live-run probe replays from `-1`; a genuinely-absent run re-POSTs), and an in-flight POST at
109
+ the instant of the kill is the irreducible at-most-once sliver.
@@ -0,0 +1,60 @@
1
+ # jr2 is a library + CLI; an Orchestrator instance hosts many workflows
2
+
3
+ jr2 ships as a **library** (engine + agent-protocol) and a **CLI** (`jr2`). You don't build a workflow into its own
4
+ image. Instead you `jr2 init` an **Orchestrator instance** — a small, user-owned _code_ project (a folder) that imports
5
+ the kit, configures it, and holds one or more **workflows** (Machines authored via `jr2Setup`, ADR-0015). One instance
6
+ hosts **many** workflows; the CLI publishes that instance's workflow modules to a running Orchestrator as its Assembly
7
+ ([ADR-0069](0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md)). The instance folder is the
8
+ **jr2 Application** — the GitOps unit; the same folder/manifests run on kind locally and on a real cluster.
9
+
10
+ Machine definitions are **code, not declarative config.** We rejected expressing machines as YAML/CRD config: a useful
11
+ agentic Machine is mostly logic (guards, prompt-building, `assign`s), and a declarative form becomes a DSL-over-xstate
12
+ that loses type-safety and still cannot express branching. The instance is a code project (it imports `@jr2/*`), so
13
+ "code, not config" survives — machine definitions simply live in the user's instance folder rather than baked into the
14
+ kit. The rule has one deliberate complement: a human writes code, and what a RUN supplies is data — a Chart bound into a
15
+ Machine's Open body ([ADR-0070](0070-a-machine-lends-its-parts-to-a-chart.md)) carries no logic of its own.
16
+
17
+ ## The Orchestrator instance
18
+
19
+ An instance is a **stateful, single-writer daemon**: it holds the live in-memory xstate actors, so it runs `replicas: 1`
20
+ and persists its snapshots to sqlite on its volume (ADR-0009, ADR-0065). `replicas: 1` means single _writer_ (no
21
+ split-brain on the snapshot) — **not** one workflow per process. One instance registers N workflows and **hosts many
22
+ runs** of any of them. Work arrives two ways that both reduce to injecting events into an actor: a **Source** (pull,
23
+ ADR-0017) and the **HTTP API** (push) — so push/pull coexist with no special machinery. Isolation or independent scaling
24
+ is achieved by running **another instance**, not by replicating one run; the default is one instance, many workflows.
25
+
26
+ ## The Harness stays on the Agent side
27
+
28
+ The Agent/Sandbox Harness is jr2's own server, `@jr2/harness` (ADR-0002/0018/0027) — and the Orchestrator is **not** a
29
+ harness: its state is an xstate snapshot, not an agent session, and its loop is a deterministic state machine, not an
30
+ LLM-in-harness. The two share ergonomics, not implementation: the instance folder convention (`jr2.config.ts` + the
31
+ discovered `workflows/` dir — the Agents ride the Machines it holds, ADR-0049), the `jr2` CLI as the primary interface,
32
+ and an HTTP API shaped as "durable run addressed by id" (`POST` to start/feed, `GET /…/:id` for status, SSE for events)
33
+ — so both sides of the system speak one protocol without sharing a runtime.
34
+
35
+ ## The Orchestrator pod
36
+
37
+ It is sized and prioritised like the other control pods (ADR-0060: requests 500m and 1Gi, memory limit 1Gi, CPU
38
+ unlimited, the `jr2-control` PriorityClass), keeps its store on its own volume (ADR-0065), and carries two probes on
39
+ `/healthz`. Readiness (2s period, 15 failures) takes a stalled process out of its Service after 30s and does nothing
40
+ else: a `replicas: 1` writer that is restarted is an outage plus a restore, so a GC pause or a busy node must never
41
+ trigger one. Liveness (10s period, 30 failures) restarts a process that has answered nothing for five minutes: a process
42
+ silent that long is not stalled but dead, and without it the pod would sit NotReady until a human deleted it, while a
43
+ process that exits is restarted by the container's restart policy regardless.
44
+
45
+ ## Consequences
46
+
47
+ - The deployable unit is the Orchestrator **Kit image** plus the instance's **Assembly**, which `jr2 up` publishes to
48
+ the running Orchestrator ([ADR-0069](0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md);
49
+ a CI-only `jr2 build` is planned), run as one `replicas: 1` `Deployment` + `Service`. The two-repo pattern (instance
50
+ code → Assembly; manifests → GitOps) is expected, and the instance folder carries both.
51
+ - Concrete workflows do **not** live in the jr2 source repo — only the kit, the Machines it ships (`@jr2/machines`,
52
+ ADR-0054), and the `templates/default` model instance do. A user's workflows live in their `jr2 init` instance folder.
53
+ - jr2 ships and deploys only its **`Sandbox` operator** (its own CRD), deployed once per cluster. The snapshot store is
54
+ sqlite on the Instance's own volume (ADR-0065); the model backend is a **dependency you provide** — jr2 points at it
55
+ (model env), it does not own or operate it. Instances are deployed per user/project.
56
+ - Users interact through the **`jr2` CLI** far more than raw HTTP; the HTTP API is the machine-to-machine surface (push
57
+ work, human-in-the-loop, status) the CLI itself sits on top of.
58
+ - Code is never loaded dynamically: only `jr2 up` publishes an Assembly, typechecked on the host first
59
+ ([ADR-0069](0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md)). A run may bind a
60
+ Machine's Open body with a Chart, which is data ([ADR-0070](0070-a-machine-lends-its-parts-to-a-chart.md)).
@@ -0,0 +1,275 @@
1
+ # The `jr2` CLI and instance interface
2
+
3
+ ADR-0008 fixed that jr2 is a library + CLI and that an Orchestrator instance is a user-owned folder hosting many
4
+ workflows. This ADR fixes the **instance folder convention**, the **orchestrator HTTP API**, and the **`jr2` CLI** — one
5
+ set of conventions both sides of the system speak. Operational mechanics (how `jr2 up` converges a cluster, addressing,
6
+ secrets) live in ADR-0019.
7
+
8
+ ## Instance folder convention (filename discovery)
9
+
10
+ ```
11
+ my-orchestrator/
12
+ jr2.config.ts # instance config: reach and credentials — harness, git.credentials, registry; nothing a Machine names (ADR-0050)
13
+ workflows/ # filename-discovered: workflows/review.ts (contract: export const machine) → "review"
14
+ images/default/ # the fallback docker context a `workspace()` with no `image` uses (ADR-0037); a path convention, not discovery
15
+ manifests/ # user-supplied objects applied by `jr2 up` (e.g. SealedSecrets); optional
16
+ .env # local secrets + deployment-varying env; uncommitted
17
+ .jr2/ # scratch; nothing durable lives on the host (state is in-cluster, ADR-0019)
18
+ ```
19
+
20
+ `workflows/<name>.ts` registers a workflow named `<name>` via `export const machine` — the one-export module contract
21
+ (ADR-0015; vocabulary rides the machine object, so there is no manifest export). Workflows are the one discovered kind
22
+ because nothing in code names one: `jr2 run` and the API do. Agents, images, and Repos are named from Machines, so they
23
+ ride the Machine — Agent slots, `workspace()` options, Repo Slots (ADR-0049, ADR-0051) — and nothing in config names
24
+ them (ADR-0050).
25
+
26
+ **The instance repo is a deployment assembly, not a sharing unit** (ADR-0019): reusable workflows/agents are published
27
+ as npm packages and re-exported here; `jr2.config.ts` holds only what is specific to this deployment's reach,
28
+ credentials, and cluster — committed, because the instance repo is the GitOps unit (ADR-0008), with deployment-varying
29
+ values resolved from env.
30
+
31
+ ## Minimum config, and the Repo cache
32
+
33
+ `jr2.config.ts` favors convention over configuration — an Instance whose Machines compose Sandboxes can be as small as:
34
+
35
+ ```ts
36
+ import { defineConfig } from "@jr2/orchestrator";
37
+
38
+ export default defineConfig({
39
+ name: "my-orchestrator",
40
+ git: { credentials: [{ match: "*", token: "JR2_GIT_TOKEN", sshKey: "jr2-git-ssh" }] }, // narrow before untrusted runs
41
+ });
42
+ ```
43
+
44
+ - **`name` is the instance's identity**; its namespace defaults to it (`-n` overrides — ADR-0019).
45
+ - **There is no `repos` list.** A Repo is a slot on a `workspace()`, bound by url (ADR-0051); `jr2.config.ts` holds what
46
+ reaches one — `git.credentials`, the prefix-matched list that is also the fence a per-run slot's url must pass. The
47
+ scaffold writes one wildcard entry, commented, for the user to narrow (ADR-0051). The operator keeps a bare cache per
48
+ node from the `Repo` resources the Orchestrator creates off its Machines (ADR-0004); Sandboxes clone `--shared`
49
+ against it. There is no host-side directory — a Repo pods should see must be fetchable from the cluster.
50
+ - **A registered Machine that composes a Sandbox is the data-plane switch** (ADR-0051), read off `jr2 up`'s walk: with
51
+ one, the instance gets the kubectl Sandbox backend; without one, the instance is workspace-less. There is **no
52
+ `images` config block**: `jr2 up` builds every image it deploys and resolves each to a content-addressed tag
53
+ ([ADR-0038](0038-jr2-up-builds-every-image-it-deploys.md)). Image composition is per Workspace, not per instance — a
54
+ `workspace()` names its Sandbox Image statically (a `file:` docker context the Machine ships or a registry ref,
55
+ [ADR-0037](0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md),
56
+ [ADR-0049](0049-a-machine-carries-its-parts-and-composes-by-invoke.md)) and opts into a User Container the same way
57
+ ([ADR-0005](0005-sandbox-pod-composition.md)); `images/default` is the one path convention `jr2 up` still checks.
58
+ Every Harness pod gets a Custodian — an Agent without one cannot act (ADR-0013, ADR-0059) — and that is not
59
+ configurable. Agent-runtime concerns live in `harness` (ADR-0018).
60
+ - **`harness` is the agent-runtime section** (ADR-0018): custom provider (`api`, `baseUrl`), the gateways pi's catalog
61
+ providers call (`catalog`) and any other env — never which model to use; each definition names its own (ADR-0018).
62
+ - **`secrets` is the Instance's one list of secrets**
63
+ ([ADR-0068](0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md)): the credentials the Agents use — an
64
+ Anthropic key, read from `process.env`/`.env`, held by the Custodian and never by the Harness (ADR-0059) — and the
65
+ ones an Effect names, which only its Effector holds. Where each goes is read, never declared.
66
+ - **`registry`** (deployment-varying, resolve from env): absent → images are `kind load`-ed; present → pushed
67
+ (ADR-0019). **`kitRegistry`** (also env) re-homes the published Kit image refs for self-hosted, air-gapped, or
68
+ mirror-only clusters ([ADR-0044](0044-kit-images-live-at-a-canonical-home-a-self-host-mirrors-it.md)).
69
+ - **The snapshot store is sqlite** on a PVC in the instance's namespace (zero setup); no other store is owed
70
+ ([ADR-0065](0065-a-persist-survives-a-crash-and-history-is-a-week.md)) — the single-table, single-writer snapshot fits
71
+ sqlite, and `replicas: 1` keeps it single-writer.
72
+ - Git credentials for private repos: an HTTPS token from `.env`, or a `jr2-git-ssh` Secret holding the key `jr2 up`
73
+ asked the user to choose — a generated in-cluster deploy keypair (the recommended default), a local key, or one pasted
74
+ on stdin (ADR-0019, [ADR-0047](0047-the-git-ssh-key-source-is-the-users-choice.md)). Kube target: the current
75
+ `kubectl` context (`--context` to override).
76
+
77
+ ## Machines ship as npm; instances compose or customize
78
+
79
+ The kit publishes to npm under `@jr2/*`; stock Agent definitions ship in **`@jr2/agents`** (coder, reviewer, …), and a
80
+ package may ship whole Machines with their Agents and image inside (ADR-0049). Because a definition is plain data
81
+ (ADR-0018), composition needs no API: a Machine carries `agent(coder)`, a workflows file exports a packaged Machine
82
+ as-is or through `customize(machine, { agents: { coder: { model: "…" } } })`. Adding tools/skills waits on the
83
+ definition contract growing that seat (ADR-0018).
84
+
85
+ ## Orchestrator HTTP API (hono, run-addressed-by-id)
86
+
87
+ Push + control + observe only — the **pull** path needs no HTTP (the Orchestrator's Source pulls, ADR-0017). Auth bands
88
+ per ADR-0014: structure + observation open; the Agent surface takes the Sandbox token; run state, control, and gates
89
+ take the Instance token.
90
+
91
+ ```
92
+ GET /workflows # list registered workflows [open]
93
+ GET /workflows/:name/machine /viz/* # machine structure + visualizer [open]
94
+ GET /workflows/:name/runs[, /:runId/events] # observation projection (ADR-0014) [open]
95
+ GET /workflows/:name/events # SSE: the whole workflow, level-triggered (ADR-0022) [open]
96
+ POST /workflows/:name/runs # start a run (push work); body = input → { runId } [instance]
97
+ GET /runs GET /runs/:runId # live list; durable run status (read-through) [instance]
98
+ GET /runs/resolve?prefix=<p> # run ids sharing a prefix, live + settled [instance]
99
+ GET /runs/:runId/events # SSE: status replay + live deltas [instance]
100
+ POST /runs/:runId/events # run-level infra interrupt: CANCEL [instance]
101
+ POST /runs/:runId/gates/:gate/events # deliver a workflow event to an open gate [instance]
102
+ GET /repos # per-Repo node-cache sync state (ADR-0048) [instance]
103
+ GET /agents/:iid/surface POST /agents/:iid/events # the Menu, via the Custodian [sandbox]
104
+ POST /sandboxes/:name/fetch # the ask (ADR-0053) [sandbox]
105
+ GET /healthz GET /readyz
106
+ ```
107
+
108
+ `GET /repos` is [ADR-0048](0048-the-orchestrator-boots-without-its-repos.md)'s observability half: a failed clone
109
+ degrades the Repo, not the boot, so each `Repo` resource's status (per node: synced, or git's own error) is a thing to
110
+ ask the instance for, read off the resources (ADR-0051). `jr2 status` with **no** run id renders it — the place
111
+ ADR-0047's "register the key, the cache agent retries" points at. Instance band, not open: a row names a Repo and
112
+ carries git's error text, exactly the class of author/deployment detail the open projections strip (ADR-0014).
113
+
114
+ Gates are the human/webhook/CI seam (ADR-0011): a gated state registers `{ gate, accepts, meta }`; `GET /runs/:runId`
115
+ lists the open gates (with schemas + `meta`), and the gate POST validates the body against the named event schema and
116
+ delivers it into that state. Per-gate addressing exists because concurrent children park concurrently — a run-level
117
+ events POST is ambiguous. `CANCEL` is the one reserved run-level event; everything else is workflow vocabulary. It
118
+ **ends** the run — its Agents' turns end with it and it does not restore
119
+ ([ADR-0025](0025-cancel-ends-a-run-stop-parks-it.md)).
120
+
121
+ ## The `jr2` CLI
122
+
123
+ ```
124
+ # lifecycle (instance)
125
+ jr2 init [dir] [--name <n>] # scaffold the minimum runnable instance
126
+ jr2 check # the typecheck and the Machine walk of `up`, with no cluster (ADR-0050)
127
+ jr2 up [--yes] [--force] [--skip-provider-preflight]
128
+ # converge the current context to this instance (ADR-0019)
129
+ jr2 down [--all] [--yes] # remove the instance from the cluster (--all: operator too)
130
+ jr2 gc [--dry-run] # sweep unreachable labeled images — the same sweep up/down run (ADR-0039)
131
+
132
+ # kit (instance-less)
133
+ jr2 kit push <registry> # mirror the published Kit images into a self-hosted registry (ADR-0044)
134
+
135
+ # what runs where
136
+ jr2 version [--local] [--json] # this jr2, the global that handed off, the Instance's Kit, and what the cluster runs
137
+
138
+ # runs / workflows (wrap the HTTP API)
139
+ jr2 run <workflow> [--input <json>] [--detach]
140
+ jr2 runs jr2 status [runId|abbrev] jr2 logs <runId|abbrev> [-f] # bare `status` = the instance's repos (ADR-0048)
141
+ jr2 send <runId|abbrev> --event CANCEL
142
+ jr2 send <runId|abbrev> --gate <gate> --event <name> [--input <json>]
143
+
144
+ # workspaces (kubectl-style, over the operator's Sandbox CRs) — decided, not yet in the binary
145
+ jr2 ls # list workspaces + run + status + endpoint
146
+ jr2 ssh <workspace> # exec into the Sandbox's harness container (ADR-0037)
147
+ jr2 logs <workspace> jr2 rm <workspace>
148
+ ```
149
+
150
+ `jr2 ssh` is `kubectl exec -c harness` into the Sandbox Image
151
+ ([ADR-0037](0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md)) — the inspect seat: the agent's own
152
+ tools, worktrees, and filesystem. The optional User Container ([ADR-0005](0005-sandbox-pod-composition.md)) is reached
153
+ by its own front door (its sshd, or `kubectl exec -c user`), not by this verb — its point is sessions and services the
154
+ agent's container must not host.
155
+
156
+ The CLI is the everyday surface; HTTP is the machine-to-machine one. The workspace verbs make the orchestrator feel like
157
+ `kubectl` for agents: the run↔workspace link rides on the CR's labels (`jr2.dev/run`, `jr2.dev/workflow`), so `jr2 ls`
158
+ can group without the orchestrator being reachable. CLI and hono app sit on one shared API client.
159
+
160
+ A planned `jr2 build` (build + push + render manifests, no apply — the pure-GitOps CI verb) is deferred; `jr2 up` in CI
161
+ covers the interim (ADR-0019).
162
+
163
+ ## Settled CLI behavior (v1)
164
+
165
+ **Instance addressing.** The CLI finds its instance by walking up from cwd to the directory containing `jr2.config.ts` —
166
+ the root marker. The _deployment_ is addressed by the current kube context + the instance's namespace: run-verbs
167
+ port-forward the Orchestrator Service for the duration of the command and read the Instance token from its in-cluster
168
+ Secret (kube RBAC is the gate). `--url` / `JR2_URL` (+ token env) overrides both — the ingress-exposed/remote-caller
169
+ case — and skips the folder walk entirely. Every run-verb prints the context it targets on stderr, so ambient-context
170
+ drift is visible (ADR-0019).
171
+
172
+ **The command table.** Each verb is an entry in `packages/cli/src/command-table.ts`: its arguments, its flags, the env
173
+ vars it reads, what it prints, and its ADRs, as data. The verb's `parseArgs` options come from its entry, and so does
174
+ the help, so a flag cannot be accepted and not documented, or documented and not read. `jr2 --help` prints the whole
175
+ table. `jr2 <verb> --help` or `-h` prints that verb's entry, runs nothing, and exits 0. A usage error prints the verb's
176
+ usage line. The CLI Reference of the docs is generated from the same table
177
+ ([ADR-0072](0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md)).
178
+
179
+ **Two output classes (amended 2026-09-20).** The stream rule below — JSON result on stdout, activity on stderr — was
180
+ written for `jr2 run`, whose reason is the pipe: `jr2 run … | jq` must yield the result alone. It generalises to every
181
+ **result verb** — `run`, `runs`, `status <runId>`, `logs`, `kit push` — because their result is small and the stderr
182
+ lines beside it are advisory. It does not generalise to a **report verb** — `version`, and `status` with no run id —
183
+ whose output is a diagnosis a human reads whole: dual-printing there shows a JSON blob and a partial table, and the
184
+ readable form exists nowhere. So a report verb prints its human table on **stdout**, and `--json` swaps the table for
185
+ the one object. No `isatty` sniffing: output that changes with how it is invoked is a debugging trap of its own. `init`,
186
+ `check`, `up`, `down`, `gc` and `send` are neither class — activity only, no result.
187
+
188
+ **`jr2 version` (amended 2026-09-20).** The report you paste into a bug: what is _here_ and what is _deployed_, side by
189
+ side, so the gap between the halves is the answer ("you edited the pin and never ran `jr2 up`"). The local half: `cli`
190
+ (the copy that runs — version + real path, so the path says global or Instance), `global` (the copy that handed off,
191
+ ADR-0056), `kit` (the `@jr2/orchestrator` the Instance resolves + the ADR-0056 check result, and
192
+ `package.json pins X, reinstall` when the manifest disagrees with what is installed), `instance` (name, root, and mode:
193
+ kit checkout or installed from which registry — the reader needs the mode to know whether deployed Kit tags are versions
194
+ or content hashes), `node`. The deployed half, best-effort: `orchestrator` (what the pod answers on `/healthz` —
195
+ version + hash, flagging a Deployment label that disagrees as an incomplete rollout), `operator` (its version label —
196
+ never downgraded, so no skew verdict on it), `harness`/`custodian` and any Sandbox Image refs from the `jr2-images`
197
+ ConfigMap pods actually read, and one `skew` verdict comparing the two kit numbers: `same`/`behind`/`ahead`/`unknown`,
198
+ with the `jr2 up` consequence spelled out and, in checkout mode, a reminder that `same` is weak and the hash is the
199
+ address. Nothing is computed that `jr2 up` computes: no bundle staging, no local hash. It is the one Instance verb that
200
+ reads the Instance without asserting it — a Kit mismatch is a line, never the ADR-0056 refusal, because this is the verb
201
+ you reach for when that refusal fires. It hands off like every verb. The shared addressing flags (`--url`, `-n`,
202
+ `--context`) as every run verb; `--url` leaves only the orchestrator line; `--local` skips the cluster. Exit 0 whatever
203
+ it finds: a report. No registry lookup: "out of date" here means behind the Instance, and `npm view` answers the other
204
+ question.
205
+
206
+ **`jr2 check`.** It runs the Instance check of `jr2 up` and nothing more. First it runs the Instance's own
207
+ `tsc --noEmit`. Then it loads each registered Workflow and walks its Machine. The load and the walk find the refusals
208
+ that the compiler cannot make: a refusal of `createMachine`, `defineEvent` or `workspace()` when a module loads, an Open
209
+ part, a Chart file, a dispatch, an Effect secret, a Size. It reads no kube context. It touches no cluster, docker or
210
+ registry, and it writes no file. When it refuses, it exits 1 with the `refusing:` or `error:` line of `jr2 up`. It is
211
+ one function with `jr2 up` (`checkInstance`), not a copy, so the two cannot disagree.
212
+
213
+ It is for an Assistant that may not run `jr2 up`. `npm run typecheck` loads no module. And `node` cannot import a
214
+ workflow module of an installed Instance. The kit's `.ts` sources are under `node_modules`, and Node does not strip
215
+ types there. The `jr2` binary strips them. The scaffold names `jr2 check` as its `check` script. The AGENTS.md block
216
+ names it as the step before the Assistant gives a change to the user (ADR-0072).
217
+
218
+ It does not stage the Assembly. Staging installs the production dependencies from the lockfile, and its refusals are
219
+ about that install. It also does not write the AGENTS.md block. An Assistant or CI must be able to run a check with no
220
+ diff as a result.
221
+
222
+ **`jr2 run` — blocking, attach-by-default.** Start the run, stream activity to **stderr**, print the terminal
223
+ `RunStatus` as JSON to **stdout**, exit — so `jr2 run … | jq` yields just the result. It **attaches to the running
224
+ orchestrator**, not a temporary per-invocation runtime — a jr2 run is durable and may park on a Gate indefinitely,
225
+ outliving the CLI call. `--detach` starts the run, prints its `runId`, returns.
226
+
227
+ **Attach / detach / re-attach.** A run lives server-side, so attaching = opening `GET /runs/:runId/events` and detaching
228
+ = closing it (Ctrl-C); neither affects the run. `jr2 logs <runId> -f` re-attaches to any running run. On attach, the SSE
229
+ **replays the run's current status immediately** (so a parked run shows where it is) before streaming live deltas; it
230
+ carries `status` events (auto, per transition) and `emit` events (the workflow author's `emit({…})`).
231
+
232
+ **Terminal runs stay readable.** The final snapshot persists to the store before the run drops from the live registry,
233
+ so `status` / `GET /runs/:runId` **read through to the store** — a completed run reports its terminal status/context
234
+ instead of `404`. (`GET /runs` stays live-only; history via `?all` is deferred.)
235
+
236
+ **Run ids abbreviate to a unique prefix.** A run id is a bare uuid, so every id-taking verb takes a git-style short
237
+ form: `jr2 status 1a2b3c4d`. **Prefix only** — not fuzzy, not suffix — which keeps it an indexed range scan and keeps
238
+ the mental model borrowed intact. Four characters is the floor, and that floor is about **noise, not safety**: a short
239
+ prefix never resolves to the wrong run, it resolves to a list. Safety comes from ambiguity being an error — matching
240
+ more than one id prints the candidates and fails (exit 1), never guesses. A malformed or too-short argument is a usage
241
+ failure (exit 2); a full id short-circuits resolution entirely, so scripted pipelines issue unchanged traffic.
242
+
243
+ **The CLI resolves; the addressed routes stay full-id.** Abbreviation is a human affordance and lives on the human
244
+ surface — `GET /runs/resolve` answers prefix→ids, and the CLI then addresses the run by its full id. `/runs/:runId` and
245
+ both event POSTs never accept a prefix, because **a prefix is not an identity**: one that resolves today goes ambiguous
246
+ tomorrow when an unrelated run starts, and `jr2 send <prefix> --event CANCEL` is a write. Resolving as a separate
247
+ read-only step is what guarantees no write is ever prefix-sensitive. (It also gives a bad id a real error: `host.stop()`
248
+ returns silently for an unknown run, so an unresolved CANCEL used to report success.)
249
+
250
+ The candidate set is the ids that **exist**, not the ones that read: `lost` runs are included, because dropping them
251
+ would let a prefix they share with a live run resolve silently to the live one. The set unions the live registry with
252
+ the store — neither alone is complete, since `persist()` is microtask-scheduled (a just-started run is live before it is
253
+ stored) and a settled run is stored but not live. Note the deliberate tension with `GET /runs`'s deferred `?all`: this
254
+ route does reveal that settled run **ids** exist to an Instance-token holder. It answers ids only — no status, no
255
+ context, no gates — to keep that widening as small as the feature allows, and it is Instance-only rather than open,
256
+ since prefix probing on an open route would be a run-id enumeration oracle.
257
+
258
+ **`jr2 init` (v1).** Scaffolds the minimum runnable instance: `jr2.config.ts` (root marker), `package.json` (deps on
259
+ `@jr2/*` + xstate), one starter `workflows/<name>.ts`, `images/default/Dockerfile` (the Sandbox Image every Workspace
260
+ falls back to, ADR-0037), `.gitignore` (`.jr2/`, `.env`, `node_modules/`), and `AGENTS.md` with a `CLAUDE.md` that
261
+ imports it (the index of the Kit's bundled docs for an Assistant, ADR-0072). `[dir]` positional (default cwd); `--name`
262
+ for the package name (default: the folder's name). It skips each file that exists, and says so; for an `AGENTS.md` with
263
+ no markers, or a `CLAUDE.md` that does not import `AGENTS.md`, it also says what to add. `manifests/` and `.env` are
264
+ added by their later slices. No auto-install — it prints the next step, naming no package manager, since the instance's
265
+ lockfile is what picks one ([ADR-0043](0043-the-kit-is-tested-as-installed-a-local-registry-stands-in-for-npm.md)).
266
+
267
+ ## Consequences
268
+
269
+ - The instance-facing packages (`@jr2/cli`, `@jr2/orchestrator`, `@jr2/agent-protocol`) publish to npm; `@jr2/harness`
270
+ ships inside a Kit image, never via npm
271
+ ([ADR-0043](0043-the-kit-is-tested-as-installed-a-local-registry-stands-in-for-npm.md)). The CLI ships as the `jr2`
272
+ bin (`npx jr2`).
273
+ - Workspaces are a first-class CLI resource backed by the operator's `Sandbox` CRs, label-linked to their runs.
274
+ - Code is never loaded from a third party at run time (ADR-0008, ADR-0069): discovery is over the instance's own
275
+ Assembly, which only `jr2 up` publishes. A run may bind a Machine's Open body with a Chart, which is data (ADR-0070).