@jr2/orchestrator 0.3.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/README.md +20 -2
  2. package/bin/server.ts +7 -4
  3. package/console/canvas.ts +27 -14
  4. package/console/components/app.ts +12 -1
  5. package/console/components/fleet.ts +52 -6
  6. package/console/components/machine-pane.ts +128 -2
  7. package/console/components/nav.ts +1 -1
  8. package/console/components/schema-form.ts +12 -4
  9. package/console/json-field.ts +23 -0
  10. package/console/main.ts +122 -39
  11. package/console/store.ts +321 -21
  12. package/console/style.css +111 -0
  13. package/docs/agents-block.md +5 -0
  14. package/docs/concepts/agents-and-turns.md +442 -0
  15. package/docs/concepts/architecture.md +230 -0
  16. package/docs/concepts/charts.md +143 -0
  17. package/docs/concepts/composition.md +357 -0
  18. package/docs/concepts/converge.md +254 -0
  19. package/docs/concepts/durable-runs.md +189 -0
  20. package/docs/concepts/effects.md +603 -0
  21. package/docs/concepts/gates.md +208 -0
  22. package/docs/concepts/machines-and-workflows.md +289 -0
  23. package/docs/concepts/pools-and-sources.md +230 -0
  24. package/docs/concepts/secrets-and-trust.md +222 -0
  25. package/docs/concepts/the-menu.md +378 -0
  26. package/docs/concepts/workspaces.md +678 -0
  27. package/docs/get-started/a-model-decides.md +563 -0
  28. package/docs/get-started/an-agent-in-a-sandbox.md +381 -0
  29. package/docs/get-started/connect-a-model.md +248 -0
  30. package/docs/get-started/create-an-instance.md +194 -0
  31. package/docs/get-started/have-your-assistant-write-a-machine.md +922 -0
  32. package/docs/get-started/install.md +126 -0
  33. package/docs/guides/add-tools-to-the-sandbox.md +295 -0
  34. package/docs/guides/answer-a-gate.md +304 -0
  35. package/docs/guides/bind-open-parts.md +223 -0
  36. package/docs/guides/cancel-a-run.md +146 -0
  37. package/docs/guides/clean-up.md +206 -0
  38. package/docs/guides/fix-a-failed-converge.md +361 -0
  39. package/docs/guides/give-the-cluster-git-credentials.md +222 -0
  40. package/docs/guides/iterate-on-a-machine-on-kind.md +190 -0
  41. package/docs/guides/let-an-agent-write-a-chart.md +226 -0
  42. package/docs/guides/look-inside-a-sandbox.md +174 -0
  43. package/docs/guides/mirror-the-kit-images.md +176 -0
  44. package/docs/guides/move-from-kind-to-a-shared-cluster.md +302 -0
  45. package/docs/guides/open-the-console.md +91 -0
  46. package/docs/guides/publish-a-machine-as-an-npm-package.md +350 -0
  47. package/docs/guides/push-and-sign-a-branch.md +486 -0
  48. package/docs/guides/run-a-chart-by-name.md +270 -0
  49. package/docs/guides/run-a-command-or-call-a-url.md +544 -0
  50. package/docs/guides/run-one-worker-per-item.md +321 -0
  51. package/docs/guides/set-an-agents-access-and-dials.md +375 -0
  52. package/docs/guides/size-a-workspace.md +204 -0
  53. package/docs/guides/start-a-run-from-a-run.md +237 -0
  54. package/docs/guides/start-a-run.md +207 -0
  55. package/docs/guides/upgrade-the-kit-version.md +240 -0
  56. package/docs/guides/use-a-hosted-provider.md +208 -0
  57. package/docs/guides/use-a-local-model.md +313 -0
  58. package/docs/guides/watch-a-run.md +326 -0
  59. package/docs/guides/write-a-workflow.md +318 -0
  60. package/docs/index.md +44 -0
  61. package/docs/llms.txt +216 -0
  62. package/docs/reference/authoring-surface/agent.md +128 -0
  63. package/docs/reference/authoring-surface/answer.md +140 -0
  64. package/docs/reference/authoring-surface/arg.md +60 -0
  65. package/docs/reference/authoring-surface/basic.md +62 -0
  66. package/docs/reference/authoring-surface/bearer.md +53 -0
  67. package/docs/reference/authoring-surface/chartschema.md +23 -0
  68. package/docs/reference/authoring-surface/chartschemafor.md +48 -0
  69. package/docs/reference/authoring-surface/command.md +191 -0
  70. package/docs/reference/authoring-surface/customize.md +64 -0
  71. package/docs/reference/authoring-surface/defineconfig.md +41 -0
  72. package/docs/reference/authoring-surface/defineevent.md +114 -0
  73. package/docs/reference/authoring-surface/dispatch.md +126 -0
  74. package/docs/reference/authoring-surface/fail.md +83 -0
  75. package/docs/reference/authoring-surface/file.md +122 -0
  76. package/docs/reference/authoring-surface/frompick.md +277 -0
  77. package/docs/reference/authoring-surface/http.md +159 -0
  78. package/docs/reference/authoring-surface/isfailure.md +58 -0
  79. package/docs/reference/authoring-surface/jr2setup.md +237 -0
  80. package/docs/reference/authoring-surface/open.md +74 -0
  81. package/docs/reference/authoring-surface/openbody.md +86 -0
  82. package/docs/reference/authoring-surface/paramsof.md +125 -0
  83. package/docs/reference/authoring-surface/pool.md +186 -0
  84. package/docs/reference/authoring-surface/push.md +112 -0
  85. package/docs/reference/authoring-surface/secret.md +118 -0
  86. package/docs/reference/authoring-surface/sentby.md +83 -0
  87. package/docs/reference/authoring-surface/source.md +51 -0
  88. package/docs/reference/authoring-surface/text.md +62 -0
  89. package/docs/reference/authoring-surface/type-agentdeclaration.md +27 -0
  90. package/docs/reference/authoring-surface/type-agentdefinition.md +80 -0
  91. package/docs/reference/authoring-surface/type-agentlogic.md +15 -0
  92. package/docs/reference/authoring-surface/type-agentslots.md +12 -0
  93. package/docs/reference/authoring-surface/type-answeraction.md +12 -0
  94. package/docs/reference/authoring-surface/type-arg.md +19 -0
  95. package/docs/reference/authoring-surface/type-argnames.md +12 -0
  96. package/docs/reference/authoring-surface/type-binding.md +62 -0
  97. package/docs/reference/authoring-surface/type-bindingof.md +12 -0
  98. package/docs/reference/authoring-surface/type-bodyacceptsdoor.md +15 -0
  99. package/docs/reference/authoring-surface/type-bodyacceptsslots.md +17 -0
  100. package/docs/reference/authoring-surface/type-ceilings.md +41 -0
  101. package/docs/reference/authoring-surface/type-chainlink.md +19 -0
  102. package/docs/reference/authoring-surface/type-chartaction.md +46 -0
  103. package/docs/reference/authoring-surface/type-chartagent.md +28 -0
  104. package/docs/reference/authoring-surface/type-chartevent.md +20 -0
  105. package/docs/reference/authoring-surface/type-chartguard.md +20 -0
  106. package/docs/reference/authoring-surface/type-chartinvoke.md +28 -0
  107. package/docs/reference/authoring-surface/type-chartjson.md +14 -0
  108. package/docs/reference/authoring-surface/type-chartstate.md +46 -0
  109. package/docs/reference/authoring-surface/type-charttext.md +40 -0
  110. package/docs/reference/authoring-surface/type-charttransition.md +22 -0
  111. package/docs/reference/authoring-surface/type-charttransitions.md +14 -0
  112. package/docs/reference/authoring-surface/type-chartvalue.md +15 -0
  113. package/docs/reference/authoring-surface/type-childat.md +12 -0
  114. package/docs/reference/authoring-surface/type-childslots.md +12 -0
  115. package/docs/reference/authoring-surface/type-commandenv.md +15 -0
  116. package/docs/reference/authoring-surface/type-commandinput.md +19 -0
  117. package/docs/reference/authoring-surface/type-commandoptions.md +78 -0
  118. package/docs/reference/authoring-surface/type-commandoutput.md +104 -0
  119. package/docs/reference/authoring-surface/type-customize.md +109 -0
  120. package/docs/reference/authoring-surface/type-dispatchdefinition.md +39 -0
  121. package/docs/reference/authoring-surface/type-dispatchinput.md +14 -0
  122. package/docs/reference/authoring-surface/type-dispatchopenparts.md +14 -0
  123. package/docs/reference/authoring-surface/type-dispatchoutput.md +65 -0
  124. package/docs/reference/authoring-surface/type-duration.md +15 -0
  125. package/docs/reference/authoring-surface/type-effectbinding.md +93 -0
  126. package/docs/reference/authoring-surface/type-effectlogic.md +12 -0
  127. package/docs/reference/authoring-surface/type-envopenparts.md +14 -0
  128. package/docs/reference/authoring-surface/type-eventaudience.md +27 -0
  129. package/docs/reference/authoring-surface/type-eventdef.md +45 -0
  130. package/docs/reference/authoring-surface/type-eventfrom.md +16 -0
  131. package/docs/reference/authoring-surface/type-eventsemantics.md +26 -0
  132. package/docs/reference/authoring-surface/type-execoutcome.md +34 -0
  133. package/docs/reference/authoring-surface/type-failslot.md +14 -0
  134. package/docs/reference/authoring-surface/type-failure.md +19 -0
  135. package/docs/reference/authoring-surface/type-failureinput.md +20 -0
  136. package/docs/reference/authoring-surface/type-filebody.md +41 -0
  137. package/docs/reference/authoring-surface/type-frominput.md +14 -0
  138. package/docs/reference/authoring-surface/type-hostinjectedinput.md +58 -0
  139. package/docs/reference/authoring-surface/type-httpdefinition.md +101 -0
  140. package/docs/reference/authoring-surface/type-httpinput.md +12 -0
  141. package/docs/reference/authoring-surface/type-httpmethod.md +14 -0
  142. package/docs/reference/authoring-surface/type-httpopenparts.md +12 -0
  143. package/docs/reference/authoring-surface/type-httpoutput.md +89 -0
  144. package/docs/reference/authoring-surface/type-httprequestparts.md +33 -0
  145. package/docs/reference/authoring-surface/type-jr2config.md +126 -0
  146. package/docs/reference/authoring-surface/type-lends.md +38 -0
  147. package/docs/reference/authoring-surface/type-logicat.md +12 -0
  148. package/docs/reference/authoring-surface/type-markedif.md +12 -0
  149. package/docs/reference/authoring-surface/type-mergedactors.md +12 -0
  150. package/docs/reference/authoring-surface/type-namedsecret.md +25 -0
  151. package/docs/reference/authoring-surface/type-noslotspec.md +26 -0
  152. package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +32 -0
  153. package/docs/reference/authoring-surface/type-openbodydeclaration.md +40 -0
  154. package/docs/reference/authoring-surface/type-openbodylogic.md +14 -0
  155. package/docs/reference/authoring-surface/type-openbodyoutput.md +42 -0
  156. package/docs/reference/authoring-surface/type-openbodyslot.md +18 -0
  157. package/docs/reference/authoring-surface/type-opencommandinput.md +17 -0
  158. package/docs/reference/authoring-surface/type-openeffect.md +12 -0
  159. package/docs/reference/authoring-surface/type-openeffectslots.md +12 -0
  160. package/docs/reference/authoring-surface/type-openof.md +12 -0
  161. package/docs/reference/authoring-surface/type-opensecret.md +23 -0
  162. package/docs/reference/authoring-surface/type-opensecretmark.md +12 -0
  163. package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +31 -0
  164. package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +32 -0
  165. package/docs/reference/authoring-surface/type-poolmachine.md +28 -0
  166. package/docs/reference/authoring-surface/type-poolspec.md +60 -0
  167. package/docs/reference/authoring-surface/type-pushinput.md +15 -0
  168. package/docs/reference/authoring-surface/type-pushoptions.md +79 -0
  169. package/docs/reference/authoring-surface/type-pushoutput.md +124 -0
  170. package/docs/reference/authoring-surface/type-pushwireoutput.md +12 -0
  171. package/docs/reference/authoring-surface/type-quantity.md +14 -0
  172. package/docs/reference/authoring-surface/type-reached.md +12 -0
  173. package/docs/reference/authoring-surface/type-reposlot.md +70 -0
  174. package/docs/reference/authoring-surface/type-reposlotsof.md +16 -0
  175. package/docs/reference/authoring-surface/type-sandboxoptions.md +77 -0
  176. package/docs/reference/authoring-surface/type-secret.md +25 -0
  177. package/docs/reference/authoring-surface/type-sender.md +19 -0
  178. package/docs/reference/authoring-surface/type-sentbyguards.md +12 -0
  179. package/docs/reference/authoring-surface/type-size.md +85 -0
  180. package/docs/reference/authoring-surface/type-slothandles.md +32 -0
  181. package/docs/reference/authoring-surface/type-sourcenextresult.md +17 -0
  182. package/docs/reference/authoring-surface/type-sourcespec.md +44 -0
  183. package/docs/reference/authoring-surface/type-syncstate.md +12 -0
  184. package/docs/reference/authoring-surface/type-text.md +19 -0
  185. package/docs/reference/authoring-surface/type-textpart.md +24 -0
  186. package/docs/reference/authoring-surface/type-thinkinglevel.md +39 -0
  187. package/docs/reference/authoring-surface/type-toparameterizedobject.md +14 -0
  188. package/docs/reference/authoring-surface/type-toprovidedactor.md +14 -0
  189. package/docs/reference/authoring-surface/type-unknown.md +21 -0
  190. package/docs/reference/authoring-surface/type-usercontainer.md +77 -0
  191. package/docs/reference/authoring-surface/type-withoutemptyindex.md +20 -0
  192. package/docs/reference/authoring-surface/type-workflowevent.md +46 -0
  193. package/docs/reference/authoring-surface/type-workspaceaccess.md +16 -0
  194. package/docs/reference/authoring-surface/type-workspaced.md +94 -0
  195. package/docs/reference/authoring-surface/type-workspacehandles.md +23 -0
  196. package/docs/reference/authoring-surface/type-workspacemachine.md +29 -0
  197. package/docs/reference/authoring-surface/type-workspaceof.md +13 -0
  198. package/docs/reference/authoring-surface/type-workspaceoptions.md +39 -0
  199. package/docs/reference/authoring-surface/type-workspacespec.md +37 -0
  200. package/docs/reference/authoring-surface/workspace.md +259 -0
  201. package/docs/reference/authoring-surface.md +197 -0
  202. package/docs/reference/cli.md +433 -0
  203. package/docs/reference/config.md +756 -0
  204. package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +113 -0
  205. package/docs/reference/decisions/0002-duplex-streaming-actor.md +110 -0
  206. package/docs/reference/decisions/0004-worktree-provisioning-model.md +124 -0
  207. package/docs/reference/decisions/0005-sandbox-pod-composition.md +230 -0
  208. package/docs/reference/decisions/0006-agent-control-surface.md +47 -0
  209. package/docs/reference/decisions/0007-durable-machine-state.md +109 -0
  210. package/docs/reference/decisions/0008-orchestrator-as-deployed-app.md +60 -0
  211. package/docs/reference/decisions/0009-cli-and-instance-interface.md +275 -0
  212. package/docs/reference/decisions/0010-bdd-acceptance-tests.md +160 -0
  213. package/docs/reference/decisions/0011-workflow-defined-events.md +141 -0
  214. package/docs/reference/decisions/0012-workspace-wrapper-machine.md +103 -0
  215. package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +157 -0
  216. package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +95 -0
  217. package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +265 -0
  218. package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +124 -0
  219. package/docs/reference/decisions/0017-pool-over-a-source-port.md +69 -0
  220. package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +111 -0
  221. package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +275 -0
  222. package/docs/reference/decisions/0020-private-ca-trust-is-a-named-concept.md +60 -0
  223. package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +100 -0
  224. package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +103 -0
  225. package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +176 -0
  226. package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +439 -0
  227. package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +65 -0
  228. package/docs/reference/decisions/0026-a-turn-that-is-over-is-never-prompted.md +62 -0
  229. package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +237 -0
  230. package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +89 -0
  231. package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +154 -0
  232. package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +100 -0
  233. package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +190 -0
  234. package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +61 -0
  235. package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +127 -0
  236. package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +57 -0
  237. package/docs/reference/decisions/0035-a-runaway-turn-is-ended-rerolled-once-then-a-fault.md +92 -0
  238. package/docs/reference/decisions/0036-a-turn-compacts-its-own-context-mid-flight.md +138 -0
  239. package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +196 -0
  240. package/docs/reference/decisions/0038-jr2-up-builds-every-image-it-deploys.md +170 -0
  241. package/docs/reference/decisions/0039-image-garbage-collects-by-reachability.md +115 -0
  242. package/docs/reference/decisions/0041-a-build-the-host-already-holds-is-not-spent-again.md +64 -0
  243. package/docs/reference/decisions/0042-ready-is-not-routable-an-admission-retries-its-connection.md +142 -0
  244. package/docs/reference/decisions/0043-the-kit-is-tested-as-installed-a-local-registry-stands-in-for-npm.md +170 -0
  245. package/docs/reference/decisions/0044-kit-images-live-at-a-canonical-home-a-self-host-mirrors-it.md +85 -0
  246. package/docs/reference/decisions/0045-the-platform-joins-the-image-address-and-the-cluster-chooses-it.md +82 -0
  247. package/docs/reference/decisions/0046-a-converge-failure-carries-its-diagnosis.md +34 -0
  248. package/docs/reference/decisions/0047-the-git-ssh-key-source-is-the-users-choice.md +47 -0
  249. package/docs/reference/decisions/0048-the-orchestrator-boots-without-its-repos.md +36 -0
  250. package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +126 -0
  251. package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +73 -0
  252. package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +227 -0
  253. package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +81 -0
  254. package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +111 -0
  255. package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +126 -0
  256. package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +107 -0
  257. package/docs/reference/decisions/0056-a-global-jr2-hands-off-to-the-instances-own-and-an-instance-has-one-kit-version.md +62 -0
  258. package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +152 -0
  259. package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +106 -0
  260. package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +384 -0
  261. package/docs/reference/decisions/0060-a-workspace-states-its-size-and-jr2-reserves-all-of-it.md +111 -0
  262. package/docs/reference/decisions/0061-a-memory-kill-ends-the-agents-processes-not-the-harness.md +83 -0
  263. package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +212 -0
  264. package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +83 -0
  265. package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +79 -0
  266. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +65 -0
  267. package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +550 -0
  268. package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +430 -0
  269. package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +464 -0
  270. package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +180 -0
  271. package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +323 -0
  272. package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +183 -0
  273. package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +144 -0
  274. package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +122 -0
  275. package/docs/reference/decisions/0074-an-unrouted-mechanism-event-is-refused-at-load-and-faults-the-run.md +76 -0
  276. package/docs/reference/decisions.md +83 -0
  277. package/docs/reference/glossary.md +648 -0
  278. package/docs/reference/http-api.md +1348 -0
  279. package/docs/reference/machines.md +190 -0
  280. package/docs/reference/mechanism-events.md +72 -0
  281. package/docs/why.md +206 -0
  282. package/package.json +6 -4
  283. package/src/actor.ts +976 -61
  284. package/src/agent.ts +114 -38
  285. package/src/ambient.ts +4 -1
  286. package/src/assembly-checks.ts +347 -0
  287. package/src/assembly-tar.ts +494 -0
  288. package/src/assembly.ts +721 -0
  289. package/src/cause.ts +234 -0
  290. package/src/chart.ts +2182 -0
  291. package/src/charts.ts +748 -0
  292. package/src/config.ts +520 -162
  293. package/src/content-hash.ts +105 -0
  294. package/src/custodian.lua +6 -5
  295. package/src/custodian.ts +143 -39
  296. package/src/customize.ts +388 -55
  297. package/src/dispatch-effect.ts +945 -0
  298. package/src/door-compat.ts +217 -0
  299. package/src/durability.ts +11 -4
  300. package/src/effect-checks.ts +557 -0
  301. package/src/effect.ts +1202 -0
  302. package/src/effector-wire.ts +674 -0
  303. package/src/fail.ts +209 -0
  304. package/src/fingerprint.ts +4 -3
  305. package/src/gate.ts +8 -0
  306. package/src/git-clone.ts +65 -0
  307. package/src/git-push.ts +336 -0
  308. package/src/harness-client.ts +764 -48
  309. package/src/held-secrets.ts +82 -26
  310. package/src/holds.ts +156 -0
  311. package/src/http-effect.ts +1423 -0
  312. package/src/http.ts +916 -113
  313. package/src/images.ts +47 -21
  314. package/src/index.ts +62 -43
  315. package/src/instance.ts +505 -59
  316. package/src/internal.ts +84 -0
  317. package/src/kube-client.ts +333 -0
  318. package/src/machine-doc.ts +106 -6
  319. package/src/mechanism-routes.ts +168 -0
  320. package/src/model-keys.generated.ts +53 -0
  321. package/src/model-keys.ts +18 -58
  322. package/src/mount-digest.ts +53 -0
  323. package/src/names.ts +66 -8
  324. package/src/notices.ts +141 -0
  325. package/src/open-body.ts +1580 -0
  326. package/src/open-effect.ts +217 -0
  327. package/src/open.ts +59 -6
  328. package/src/parts.ts +709 -41
  329. package/src/party.ts +534 -0
  330. package/src/pick.ts +761 -0
  331. package/src/pool.ts +248 -37
  332. package/src/registration.ts +382 -19
  333. package/src/repo-fetch.ts +60 -85
  334. package/src/repos.ts +65 -75
  335. package/src/rest.ts +133 -0
  336. package/src/run-host.ts +2383 -115
  337. package/src/run-output.ts +38 -0
  338. package/src/sandbox-effect.ts +1126 -0
  339. package/src/sandbox-effector.ts +111 -0
  340. package/src/sandbox-kube.ts +1721 -0
  341. package/src/sandbox-watch.ts +260 -0
  342. package/src/secret-placement.ts +529 -0
  343. package/src/server.ts +284 -84
  344. package/src/setup.ts +819 -117
  345. package/src/size.ts +454 -0
  346. package/src/snapshot-store.ts +115 -20
  347. package/src/stub-harness.ts +49 -16
  348. package/src/sync-client.ts +54 -0
  349. package/src/timers.ts +191 -0
  350. package/src/tokens.ts +35 -4
  351. package/src/vocabulary.ts +135 -15
  352. package/src/wire.ts +238 -10
  353. package/src/workspace.ts +1195 -338
  354. package/src/sandbox-kubectl.ts +0 -1108
@@ -0,0 +1,375 @@
1
+ ---
2
+ title: "Set an Agent's access and Dials"
3
+ description: Choose what an Agent can do to the Workspace, and set the Dials and continue of one Turn.
4
+ ---
5
+
6
+ # Set an Agent's access and Dials
7
+
8
+ Set what an [Agent](../reference/glossary.md#agent) can do to the [Workspace](../reference/glossary.md#workspace), and
9
+ set the [Dials](../reference/glossary.md#dials) and `continue` of one [Turn](../reference/glossary.md#turn).
10
+
11
+ The definition of the Agent sets its access, in the `workspace` field of
12
+ [`agent()`](../reference/authoring-surface/agent.md). The state that invokes the Agent sets the Dials and `continue`, in
13
+ the `input` of the invoke. In this [Workflow](../reference/glossary.md#workflow), a reviewer reads one commit and asks
14
+ for changes. A coder makes the changes on the branch. Then a Menu-only checker decides if the changes are complete. Save
15
+ the file as `workflows/review.ts` in your [Instance](../reference/glossary.md#instance):
16
+
17
+ **Anthropic**
18
+
19
+ ```ts
20
+ import { z } from "zod";
21
+ import { assign } from "xstate";
22
+ import { agent, defineEvent, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";
23
+
24
+ const approve = defineEvent({
25
+ name: "approve",
26
+ description: "Call this when the change is complete and correct.",
27
+ input: z.object({}),
28
+ });
29
+ const requestChanges = defineEvent({
30
+ name: "request_changes",
31
+ description: "Call this when the change is not complete or not correct. Say what to change.",
32
+ input: z.object({ notes: z.string() }),
33
+ });
34
+ const finished = defineEvent({
35
+ name: "finished",
36
+ description: "Call this when you committed the changes. Say what you changed.",
37
+ input: z.object({ summary: z.string() }),
38
+ });
39
+
40
+ // The run input: the branch, the commit to review, and an optional model for the coder's Turns.
41
+ const runInput = z.object({ branch: z.string(), sha: z.string(), model: z.string().optional() });
42
+ type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
43
+ type Context = BodyInput & { notes: string; summary: string };
44
+
45
+ const body = jr2Setup({
46
+ types: {} as { input: BodyInput; context: Context },
47
+ events: [approve, requestChanges, finished],
48
+ actors: {
49
+ // "read": no write tool and no edit tool. It keeps bash.
50
+ reviewer: agent({
51
+ model: "anthropic/claude-haiku-5-5",
52
+ instructions: "You review one commit. You do not change files.",
53
+ workspace: "read",
54
+ }),
55
+ // No `workspace` field: "write", all the Working tools.
56
+ coder: agent({
57
+ model: "anthropic/claude-haiku-5-5",
58
+ instructions: "You change code as the review asks, and you commit each change.",
59
+ }),
60
+ // "none": a Menu-only Agent. It has no Working tools, and it runs on the Instance Harness.
61
+ checker: agent({
62
+ model: "anthropic/claude-haiku-5-5",
63
+ instructions: "You read review notes and the summary of a change, and you decide if the change is complete.",
64
+ workspace: "none",
65
+ thinkingLevel: "low",
66
+ }),
67
+ fail: fail(),
68
+ },
69
+ }).createMachine({
70
+ id: "review",
71
+ context: ({ input }) => ({ ...input, notes: "", summary: "" }),
72
+ on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
73
+ initial: "reviewing",
74
+ states: {
75
+ reviewing: {
76
+ invoke: {
77
+ src: "reviewer",
78
+ input: ({ context }) => ({
79
+ prompt: `Review commit ${context.sha}.`,
80
+ // The review Worktree holds the commit of `reviewSha`, detached from the branch.
81
+ cwd: context.workspace.review?.app ?? context.workspace.repos.app,
82
+ // A Dial: this Turn thinks harder than the default of the model.
83
+ thinkingLevel: "high",
84
+ }),
85
+ },
86
+ on: {
87
+ approve: "done",
88
+ request_changes: { target: "fixing", actions: assign({ notes: ({ event }) => event.notes }) },
89
+ },
90
+ },
91
+ fixing: {
92
+ invoke: {
93
+ src: "coder",
94
+ input: ({ context }) => ({
95
+ prompt: `Change the code on the branch as the review asks:\n\n${context.notes}`,
96
+ cwd: context.workspace.repos.app,
97
+ // Each Turn of the coder continues the same conversation.
98
+ continue: true,
99
+ // A Dial: the model of this Turn, from the run input. Absent, the model of the definition.
100
+ model: context.model,
101
+ }),
102
+ },
103
+ on: { finished: { target: "checking", actions: assign({ summary: ({ event }) => event.summary }) } },
104
+ },
105
+ checking: {
106
+ invoke: {
107
+ src: "checker",
108
+ input: ({ context }) => ({
109
+ prompt: `The review asked for this:\n\n${context.notes}\n\nThe coder did this:\n\n${context.summary}`,
110
+ }),
111
+ },
112
+ on: {
113
+ approve: "done",
114
+ request_changes: { target: "fixing", actions: assign({ notes: ({ event }) => event.notes }) },
115
+ },
116
+ },
117
+ done: { type: "final" },
118
+ failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
119
+ lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
120
+ },
121
+ });
122
+
123
+ export const machine = workspace(body, {
124
+ input: runInput,
125
+ repos: { app: "https://github.com/<you>/app.git" },
126
+ spec: ({ input }) => ({ branch: input.branch, reviewSha: input.sha }),
127
+ });
128
+ ```
129
+
130
+ **Local**
131
+
132
+ ```ts
133
+ import { z } from "zod";
134
+ import { assign } from "xstate";
135
+ import { agent, defineEvent, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";
136
+
137
+ const approve = defineEvent({
138
+ name: "approve",
139
+ description: "Call this when the change is complete and correct.",
140
+ input: z.object({}),
141
+ });
142
+ const requestChanges = defineEvent({
143
+ name: "request_changes",
144
+ description: "Call this when the change is not complete or not correct. Say what to change.",
145
+ input: z.object({ notes: z.string() }),
146
+ });
147
+ const finished = defineEvent({
148
+ name: "finished",
149
+ description: "Call this when you committed the changes. Say what you changed.",
150
+ input: z.object({ summary: z.string() }),
151
+ });
152
+
153
+ // The run input: the branch, the commit to review, and an optional model for the coder's Turns.
154
+ const runInput = z.object({ branch: z.string(), sha: z.string(), model: z.string().optional() });
155
+ type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
156
+ type Context = BodyInput & { notes: string; summary: string };
157
+
158
+ const body = jr2Setup({
159
+ types: {} as { input: BodyInput; context: Context },
160
+ events: [approve, requestChanges, finished],
161
+ actors: {
162
+ // "read": no write tool and no edit tool. It keeps bash.
163
+ reviewer: agent({
164
+ model: "local/qwen3.6-35b-a3b",
165
+ instructions: "You review one commit. You do not change files.",
166
+ workspace: "read",
167
+ }),
168
+ // No `workspace` field: "write", all the Working tools.
169
+ coder: agent({
170
+ model: "local/qwen3.6-35b-a3b",
171
+ instructions: "You change code as the review asks, and you commit each change.",
172
+ }),
173
+ // "none": a Menu-only Agent. It has no Working tools, and it runs on the Instance Harness.
174
+ checker: agent({
175
+ model: "local/qwen3.6-35b-a3b",
176
+ instructions: "You read review notes and the summary of a change, and you decide if the change is complete.",
177
+ workspace: "none",
178
+ thinkingLevel: "low",
179
+ }),
180
+ fail: fail(),
181
+ },
182
+ }).createMachine({
183
+ id: "review",
184
+ context: ({ input }) => ({ ...input, notes: "", summary: "" }),
185
+ on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
186
+ initial: "reviewing",
187
+ states: {
188
+ reviewing: {
189
+ invoke: {
190
+ src: "reviewer",
191
+ input: ({ context }) => ({
192
+ prompt: `Review commit ${context.sha}.`,
193
+ // The review Worktree holds the commit of `reviewSha`, detached from the branch.
194
+ cwd: context.workspace.review?.app ?? context.workspace.repos.app,
195
+ // A Dial: this Turn thinks harder than the default of the model.
196
+ thinkingLevel: "high",
197
+ }),
198
+ },
199
+ on: {
200
+ approve: "done",
201
+ request_changes: { target: "fixing", actions: assign({ notes: ({ event }) => event.notes }) },
202
+ },
203
+ },
204
+ fixing: {
205
+ invoke: {
206
+ src: "coder",
207
+ input: ({ context }) => ({
208
+ prompt: `Change the code on the branch as the review asks:\n\n${context.notes}`,
209
+ cwd: context.workspace.repos.app,
210
+ // Each Turn of the coder continues the same conversation.
211
+ continue: true,
212
+ // A Dial: the model of this Turn, from the run input. Absent, the model of the definition.
213
+ model: context.model,
214
+ }),
215
+ },
216
+ on: { finished: { target: "checking", actions: assign({ summary: ({ event }) => event.summary }) } },
217
+ },
218
+ checking: {
219
+ invoke: {
220
+ src: "checker",
221
+ input: ({ context }) => ({
222
+ prompt: `The review asked for this:\n\n${context.notes}\n\nThe coder did this:\n\n${context.summary}`,
223
+ }),
224
+ },
225
+ on: {
226
+ approve: "done",
227
+ request_changes: { target: "fixing", actions: assign({ notes: ({ event }) => event.notes }) },
228
+ },
229
+ },
230
+ done: { type: "final" },
231
+ failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
232
+ lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
233
+ },
234
+ });
235
+
236
+ export const machine = workspace(body, {
237
+ input: runInput,
238
+ repos: { app: "https://github.com/<you>/app.git" },
239
+ spec: ({ input }) => ({ branch: input.branch, reviewSha: input.sha }),
240
+ });
241
+ ```
242
+
243
+ Write your GitHub user name in place of `<you>`. Each Agent uses the model of the tab.
244
+
245
+ ## Set the access
246
+
247
+ The `workspace` field selects the [Working tools](../reference/glossary.md#working-tools) of the Agent. It also selects
248
+ where its Turns run. The default is `"write"`.
249
+
250
+ | `workspace` | The Working tools | Where the Turn runs |
251
+ | ------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------- |
252
+ | `"write"` (default) | read, write, edit, bash, grep and glob | The [Sandbox](../reference/glossary.md#sandbox) of the Workspace |
253
+ | `"read"` | read, bash, grep and glob: no write, no edit | The Sandbox of the Workspace |
254
+ | `"none"` | none | The [Instance Harness](../reference/glossary.md#instance-harness), with no Sandbox |
255
+
256
+ An Agent with `"write"` or `"read"` works in a Sandbox. Thus invoke it in the body of a
257
+ [`workspace()`](../reference/authoring-surface/workspace.md). An Agent with `"none"` is a Menu-only Agent. It reads its
258
+ prompt and picks from its [Menu](../reference/glossary.md#menu). You can invoke it in the body of a `workspace()`, as
259
+ the example does, or in a [Machine](../reference/glossary.md#machine) with no Workspace.
260
+
261
+ A `"read"` Agent keeps bash, so a command can still change a file or the branch. To keep a reviewer away from the
262
+ branch, give its Turn the review [Worktree](../reference/glossary.md#worktree):
263
+
264
+ 1. In the `spec` of the `workspace()`, set `reviewSha` to the commit to review.
265
+ 2. In the Turn, set `cwd` to `context.workspace.review?.<slot>`.
266
+
267
+ The review Worktree is `/work/<slot>/<branch>-review`, with each `/` in the branch changed to `-`. It holds the commit
268
+ of `reviewSha`, detached from the branch. In the example, `<slot>` is `app`, and the commit comes from the run input.
269
+
270
+ The access is a part of the identity of the Agent. Only the definition sets it. A Turn cannot change it.
271
+
272
+ ## Set the Dials of a Turn
273
+
274
+ The Dials are `model` and `thinkingLevel`. Write them in the `input` of the invoke, beside the
275
+ [Frame](../reference/glossary.md#frame) (`prompt` and `cwd`). A Dial changes only that Turn. When the Turn sets no Dial,
276
+ it uses the value of the definition.
277
+
278
+ - `thinkingLevel` is one of `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"` and `"xhigh"`. In the example, the
279
+ definition of `checker` sets `"low"`, and the `reviewing` state sets `"high"` for the reviewer's Turn. A definition
280
+ with no `thinkingLevel` uses `"off"`. A model can lack a level. Then the [Harness](../reference/glossary.md#harness)
281
+ runs the Turn at a different level, and the printed conversation names it in a `[thinking level]` line. See
282
+ [Watch a run](watch-a-run.md).
283
+ - `model` is `<provider>/<model id>`, as in the definition. In the example, the `fixing` state gives the coder the
284
+ `model` of the run input. When the run input has no `model`, the value is `undefined`, and the Turn uses the model of
285
+ the definition.
286
+
287
+ Run [`jr2 up`](../reference/cli.md#up) to converge the new Workflow:
288
+
289
+ ```sh
290
+ jr2 up
291
+ ```
292
+
293
+ `jr2 up` prints no line that is special to this Workflow. The `seats:` lines show the picks of the three Agents.
294
+
295
+ To give a model to the coder's Turns, add `model` to the run input:
296
+
297
+ ```sh
298
+ jr2 run review --input '{"branch":"<branch>","sha":"<commit>","model":"<provider>/<model id>"}' --detach
299
+ ```
300
+
301
+ ```text
302
+ → context kind-jr2 / namespace my-instance
303
+ {"runId":"48401e39-f8b2-4246-a24e-6ee2665ee892"}
304
+ ```
305
+
306
+ The first line gives your kubectl context and the namespace of the Instance. `runId` is the id of the new run. Your run
307
+ id is different.
308
+
309
+ Write a new branch name for the coder in place of `<branch>`. The branch starts from the default branch of the
310
+ [Repo](../reference/glossary.md#repo). Thus write the full id of a commit on the default branch in place of `<commit>`,
311
+ such as its tip. [Start a run](start-a-run.md) tells how to follow the run.
312
+
313
+ [`jr2 up`](../reference/cli.md#up) reads the models of the definitions. It cannot read a model that a Turn sets as a
314
+ Dial. Thus:
315
+
316
+ - The Harness checks a Dial model only when it admits the Turn. A model that it cannot find gives
317
+ [`agent.fault`](../reference/mechanism-events.md#agent-fault).
318
+ - `jr2 up` gives each pod the model key of the providers that the definitions of its Agents name. For an Agent in a
319
+ Sandbox, use a Dial model of a provider that a definition in that Sandbox names. For a Menu-only Agent, use a provider
320
+ that a Menu-only definition of the Instance names.
321
+
322
+ ## Continue a conversation
323
+
324
+ Without `continue`, each Turn starts a new conversation. With `continue: true`, the Turn continues the conversation of
325
+ this Agent in this Machine instance. In the example, the first `fixing` Turn starts the coder's conversation. When the
326
+ checker picks `request_changes`, the run goes back to `fixing`, and the coder continues with what it did before.
327
+
328
+ Set `continue: true` on each Turn that must join the conversation. A Turn without it starts a new conversation and does
329
+ not join.
330
+
331
+ After `agent.fault` on a Turn with `continue: true`, the next Turn with `continue: true` starts a new conversation. A
332
+ Harness restart that cut only the Turn is the exception: the conversation stays. Thus write a prompt that gives the full
333
+ task, also on a Turn that continues. In the example, each `fixing` prompt gives the notes of the review.
334
+
335
+ ## Rules
336
+
337
+ - jr2 refuses a Turn whose `input` has a key that a Turn does not have, such as `instructions` or `workspace`. Only the
338
+ definition sets those two. `<keys>` is each key that is not correct, in backticks, with a comma between them:
339
+ ``agent "<slot>": the Turn's input carries <keys>, which a Turn has no use for — its input is its Frame (`prompt`, `cwd`), its Dials (`model`, `thinkingLevel`), and `continue` (ADR-0057)``
340
+ - Under a Workspace with more than one [Repo Slot](../reference/glossary.md#repo-slot), jr2 refuses a Turn of an Agent
341
+ with Working tools that sets no `cwd`:
342
+ ``turn <id>: agent "<slot>" works under a Workspace carrying more than one Repo Slot (<slots>) and its Turn framed no `cwd` — say which Worktree it works in (`cwd: context.workspace.repos.<slot>`, one of those), because the kit gives no slot a meaning (ADR-0051) and a Turn's Frame is where it works (ADR-0057)``
343
+ - The Harness refuses a `cwd` that is not an absolute path. The run gets `agent.fault`, with this reason:
344
+ ``harness admission failed (400): agent "<slot>": the Turn's Frame carries a `cwd` that is not an absolute path — the Frame says WHERE this Turn works (ADR-0057), and a Turn rooted anywhere else would work in the wrong directory silently``
345
+ - The Harness refuses a model that is not in its catalog and not a model of the custom provider. The run gets
346
+ `agent.fault`, with this reason:
347
+ `harness admission failed (400): agent "<slot>": model "<provider>/<model id>" resolves to nothing — not in pi's catalog, and no custom provider "<provider>" is configured (ADR-0018)`
348
+ - The Harness refuses a model that is not in the form `<provider>/<modelId>`. The run gets `agent.fault`, with this
349
+ reason:
350
+ `harness admission failed (400): agent "<slot>": model "<model>" is not a <provider>/<modelId> specifier (ADR-0018)`
351
+ - jr2 refuses a Turn of a `"write"` or `"read"` Agent outside a `workspace()`:
352
+ ``turn <id>: agent "<slot>" has workspace: "<access>" — invoke it inside a workspace() (ambient resolution), or pass an explicit `endpoint` (workspace-less stub path)``
353
+ - `model` is required in each definition. A Machine from a package can leave it [Open](../reference/glossary.md#open).
354
+ `jr2 up` refuses an Open model that nobody bound:
355
+ `refusing: workflow "<workflow>" leaves Agent "<slot>" open — bind it where the Machine is registered: export const machine = customize(<import>, { agents: { <slot>: { model: "<provider>/<model>" } } }) (ADR-0054)`
356
+ - When a Turn starts with an Open model, jr2 refuses it:
357
+ ``agent "<slot>" has an Open model — nobody bound it; bind it where the Machine is registered (`customize(<machine>, { agents: { <slot>: { model: "<provider>/<model>" } } })`), because a packaged Machine cannot pick a model on your behalf (ADR-0054)``
358
+
359
+ ## Read next
360
+
361
+ - [Agents and Turns](../concepts/agents-and-turns.md): the definition, the Frame, the Dials and `continue`.
362
+ - [Workspaces](../concepts/workspaces.md): the Worktrees and the review Worktree.
363
+ - [The Menu](../concepts/the-menu.md): the picks of an Agent.
364
+ - [Bind a shipped Machine's Open parts](bind-open-parts.md): bind an Open model.
365
+ - Reference: [`agent`](../reference/authoring-surface/agent.md),
366
+ [`AgentDefinition`](../reference/authoring-surface/type-agentdefinition.md),
367
+ [`ThinkingLevel`](../reference/authoring-surface/type-thinkinglevel.md),
368
+ [`WorkspaceAccess`](../reference/authoring-surface/type-workspaceaccess.md) and
369
+ [`agent.fault`](../reference/mechanism-events.md#agent-fault).
370
+ - [ADR-0028](../reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md): what an
371
+ Agent can do to the Workspace is a part of its definition.
372
+ - [ADR-0057](../reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md): a Turn is its
373
+ Frame, its Dials, and `continue`.
374
+ - [ADR-0018](../reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md): an Agent is a
375
+ definition.
@@ -0,0 +1,204 @@
1
+ ---
2
+ title: Size a Workspace
3
+ description: Give a Workspace the memory and cpu that its Sandbox needs, and see how jr2 divides them in the pod.
4
+ ---
5
+
6
+ # Size a Workspace
7
+
8
+ Give a [Workspace](../reference/glossary.md#workspace) the memory and cpu that its
9
+ [Sandbox](../reference/glossary.md#sandbox) needs.
10
+
11
+ The [Size](../reference/glossary.md#size) is the most memory and cpu that the whole Sandbox can use. jr2 reserves all of
12
+ it on a node, so the Sandbox always has it. Write it in the `resources` option of `workspace()`. In this example, the
13
+ [Workflow](../reference/glossary.md#workflow) `workflows/e2e.ts` runs Playwright with 4 GiB of memory and 2 cpus:
14
+
15
+ ```ts
16
+ import { z } from "zod";
17
+ import { command, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";
18
+
19
+ const runInput = z.object({ branch: z.string() });
20
+ type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
21
+
22
+ const body = jr2Setup({
23
+ types: {} as { input: BodyInput },
24
+ actors: {
25
+ // JR2_CPUS holds the cpu limit of the container. Playwright does not read that limit.
26
+ e2e: command(["sh", "-c", "npx playwright test --workers=$JR2_CPUS"], { timeout: "30m" }),
27
+ fail: fail(),
28
+ },
29
+ }).createMachine({
30
+ id: "e2e",
31
+ on: { "workspace.lost": ".lost" },
32
+ initial: "testing",
33
+ states: {
34
+ testing: {
35
+ invoke: {
36
+ src: "e2e",
37
+ onDone: [
38
+ {
39
+ guard: ({ event }) => event.output.outcome === "exited" && event.output.code === 0,
40
+ target: "passed",
41
+ },
42
+ { target: "failed" },
43
+ ],
44
+ },
45
+ },
46
+ passed: { type: "final" },
47
+ // Not final states: each one fails the run, and the run ends `failed`.
48
+ failed: { invoke: { src: "fail", input: { reason: "the Playwright tests did not pass" } } },
49
+ lost: { invoke: { src: "fail", input: { reason: "the Sandbox was lost" } } },
50
+ },
51
+ });
52
+
53
+ export const machine = workspace(body, {
54
+ input: runInput,
55
+ // The Size of the whole Sandbox: 4 GiB of memory and 2 cpus. jr2 reserves all of it on a node.
56
+ resources: { limits: { memory: "4Gi", cpu: "2" } },
57
+ repos: { app: "https://github.com/you/app.git" },
58
+ spec: ({ input }) => ({ branch: input.branch }),
59
+ });
60
+ ```
61
+
62
+ The [Sandbox Image](../reference/glossary.md#sandbox-image) must have Playwright and its browsers.
63
+ [Add tools to the Sandbox](add-tools-to-the-sandbox.md) tells how.
64
+
65
+ ## Choose the numbers
66
+
67
+ A Size is `{ limits: { memory, cpu } }`, and nothing else. Each value is a Kubernetes quantity: `"4Gi"` or `"512Mi"` for
68
+ memory, `"2"` or `"1500m"` for cpu.
69
+
70
+ The kit default is memory `2Gi` and cpu `1`. It is enough for `tsc` and vitest, for `cargo build`, and for Playwright
71
+ with 2 workers. State a larger Size for Playwright with more workers, or for a large monorepo.
72
+
73
+ A larger Size is not free. The Sandbox holds all of its Size while the run waits, also at a
74
+ [Gate](../reference/glossary.md#gate). When no node has room for the Size, the Workspace waits in the
75
+ [Placing](../reference/glossary.md#placing) state, with no time limit. [Workspaces](../concepts/workspaces.md#placing)
76
+ tells how to see the wait.
77
+
78
+ `jr2 up` warns when no node can hold a Size now. It does not stop, because the nodes can change. For example, a kind
79
+ node with 16 cpus cannot hold a Size of memory `64Gi` and cpu `32`:
80
+
81
+ ```text
82
+ …
83
+ sandbox nodes: jr2-control-plane
84
+ warning: no Sandbox node right now has the allocatable for a Size of memory 64Gi, cpu 32 (workflow "e2e") — its Sandbox stays Pending until one does
85
+ …
86
+ ```
87
+
88
+ ## Where the Size comes from
89
+
90
+ The Size is a fact of the [Machine](../reference/glossary.md#machine). A run cannot change it. jr2 uses the first of
91
+ these that states a Size:
92
+
93
+ 1. [`customize(machine, { resources })`](../reference/authoring-surface/customize.md), in the
94
+ [Instance](../reference/glossary.md#instance) that registers the Machine.
95
+ 2. `resources` on the `workspace()`.
96
+ 3. [`sandbox.resources`](../reference/config.md#sandbox-resources) in `jr2.config.ts`, such as
97
+ `sandbox: { resources: { limits: { memory: "3Gi" } } }`.
98
+ 4. The kit default.
99
+
100
+ These rules apply to the order:
101
+
102
+ - `customize()` writes over the Size of the `workspace()` one field at a time. Thus
103
+ `customize(machine, { resources: { limits: { memory: "6Gi" } } })` keeps the cpu of the Machine.
104
+ - `sandbox.resources` applies only to a Workspace that states no Size. It never changes a Size that a Machine states.
105
+ - A field that the chosen Size does not state comes from the kit default. For example, under
106
+ `resources: { limits: { memory: "4Gi" } }`, the cpu is `1`, also when `sandbox.resources` states a cpu.
107
+
108
+ Use `customize()` to change the Size of a Machine from a package, such as `task` from
109
+ [`@jr2/machines`](../reference/machines.md). See [Bind a shipped Machine's Open parts](bind-open-parts.md).
110
+
111
+ ## How jr2 divides the Size in the pod
112
+
113
+ The pod has the Size as one limit. Inside the pod, jr2 divides it among the containers:
114
+
115
+ | Container | Its part |
116
+ | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
117
+ | The [Custodian](../reference/glossary.md#custodian) | A fixed part: memory `64Mi`, cpu `50m`. |
118
+ | The [User Container](../reference/glossary.md#user-container) | The part that `user.resources` gives. With no part, it shares the rest. |
119
+ | The [Sandbox Effector](../reference/glossary.md#sandbox-effector) | No part of its own. It shares the rest. |
120
+ | The `harness` container | The rest, as its own limit. The [Agent](../reference/glossary.md#agent)'s processes and the `command`s run here. |
121
+
122
+ `jr2 up` refuses a Size that leaves the `harness` container less than `256Mi` of memory, or no cpu.
123
+
124
+ To give the User Container a part, write `user` as an object:
125
+ `user: { image: import.meta.resolve("./shell"), resources: { limits: { memory: "256Mi", cpu: "250m" } } }`. The part
126
+ comes out of the part of the `harness` container. It is not added to the Size.
127
+
128
+ The Size holds only memory and cpu. jr2 also sets these, and you cannot change them:
129
+
130
+ - `/dev/shm` in the `harness` container is 25% of the container's memory, and not less than `64Mi`. It counts in that
131
+ memory. To get more, state a larger Size.
132
+ - `/work` has a disk request of `10Gi`, with no limit. The disk is not part of the Size.
133
+
134
+ ## Use the cpus
135
+
136
+ jr2 enforces the cpu limit. Many tools read the limit, such as Node's `availableParallelism()`, Go, cargo and the JVM.
137
+ For tools that do not read it, these environment variables in the `harness` container hold its cpu limit, rounded up to
138
+ a whole number: `JR2_CPUS`, `OMP_NUM_THREADS`, `PYTHON_CPU_COUNT` and `GOMAXPROCS`.
139
+
140
+ Node's `os.cpus()` gives the cpus of the node, not the limit. Playwright uses it to choose its number of workers. Thus
141
+ the example gives `--workers=$JR2_CPUS`. A `command` sees these variables.
142
+
143
+ ## When the memory is not enough
144
+
145
+ The [Harness](../reference/glossary.md#harness) watches the memory of its container. Near the limit, it stops all of the
146
+ Agent's processes. Then the Agent's `bash` call returns this text, and the Agent can try again with less:
147
+
148
+ ```text
149
+ killed: memory limit (peak <peak> of <limit>); use fewer workers or a larger Size
150
+ ```
151
+
152
+ The Harness also watches when no `bash` call runs. A process that a Turn left running, such as a dev server, can pass
153
+ the limit while the workflow waits at a [Gate](../reference/glossary.md#gate). Then no `bash` call returns the text. jr2
154
+ tells the next Agent that works in the Workspace: the next Turn, or an open Turn that jr2 asks again.
155
+
156
+ The Harness can miss a fast increase. Then the kernel stops the whole container, and the
157
+ [Turn](../reference/glossary.md#turn) faults. The reason starts with `memory limit`:
158
+
159
+ ```text
160
+ memory limit (OOMKilled, limit <memory>): the Workspace's processes passed the Harness container's memory limit and the kernel killed the container, the conversation with it. Use fewer workers, or give the Workspace a larger Size (ADR-0060, ADR-0061).
161
+ ```
162
+
163
+ The next Agent in the Workspace gets a notice of the kill. When you see either text again and again, state a larger
164
+ Size.
165
+
166
+ ## Rules
167
+
168
+ - `workspace()`, `customize()` and the config refuse a key other than `limits`, where you write it. `<where>` is
169
+ `workspace(): resources`, `customize(): resources`, `<file> at sandbox.resources`, `workspace() user.resources` or
170
+ `customize() user.resources`:
171
+ `<where>.requests is not accepted — jr2 reserves the whole Size, so every request equals its limit — a Size is { limits: { memory?, cpu? } } and nothing else — Agent Substrate's template size (ADR-0060)`
172
+ and
173
+ `<where>.<key> is not accepted — a Size is { limits: { memory?, cpu? } } and nothing else — Agent Substrate's template size (ADR-0060)`.
174
+ - They refuse a key in `limits` other than `memory` and `cpu`:
175
+ `<where>.limits.<key> is not accepted — a Size is { limits: { memory?, cpu? } } and nothing else — Agent Substrate's template size (ADR-0060)`.
176
+ - They refuse a value that is not a quantity more than zero:
177
+ `<where>.limits.memory: <value> is not a positive quantity (e.g. "2Gi", "512Mi")` and
178
+ `<where>.limits.cpu: <value> is not a positive quantity (e.g. "2", "1500m")`.
179
+ - They refuse a Size, or a `limits`, that is not an object:
180
+ `<where>: expected an object (got <value>) — a Size is { limits: { memory?, cpu? } } and nothing else — Agent Substrate's template size (ADR-0060)`
181
+ and the same text for `<where>.limits`.
182
+ - `customize()` refuses `resources` for a Machine that has no `workspace()`:
183
+ ``customize(): `resources` say what a SANDBOX is made of, how big it is and which Repos it attaches, and machine "<id>" composes none — only a workspace() wrapper carries those seats, that Size and those slots (ADR-0049, ADR-0037, ADR-0051, ADR-0060).``
184
+ - `jr2 up` refuses a Size that leaves the `harness` container less than `256Mi` of memory. The text names each number
185
+ and where it came from. The part `− the User Container's <memory> (its user.resources.limits.memory)` is there only
186
+ when `user.resources` gives a memory:
187
+ `refusing: workflow "<workflow>": the Size leaves the Harness container <memory> memory, below its 256Mi floor: memory <size> (<source>) − the Custodian's 64Mi − the User Container's <memory> (its user.resources.limits.memory) — raise the Size's limits.memory, or shrink the User Container's split (ADR-0060)`.
188
+ The text can also name the Machine that states the Size, and it can end with the `customize()` line that changes the
189
+ Size. For cpu, the text holds `the Size leaves the Harness container no cpu:`.
190
+ - `jr2 up` refuses a cluster that drops pod-level resources:
191
+ `refusing: <context> (Kubernetes <version>) drops pod-level resources — the PodLevelResources feature gate is off, and a Workspace's Size cannot hold (ADR-0060). Enable the gate on the API server and kubelets. The namespace was created; nothing else was applied.`
192
+
193
+ ## Read next
194
+
195
+ - [Workspaces](../concepts/workspaces.md#size): the Size, and Placing.
196
+ - [Add tools to the Sandbox](add-tools-to-the-sandbox.md): the User Container.
197
+ - Reference: [`Size`](../reference/authoring-surface/type-size.md),
198
+ [`UserContainer`](../reference/authoring-surface/type-usercontainer.md),
199
+ [`sandbox.resources`](../reference/config.md#sandbox-resources), [`jr2 up`](../reference/cli.md#up)
200
+ - [ADR-0060](../reference/decisions/0060-a-workspace-states-its-size-and-jr2-reserves-all-of-it.md): a Workspace states
201
+ its Size, and jr2 reserves all of it.
202
+ - [ADR-0061](../reference/decisions/0061-a-memory-kill-ends-the-agents-processes-not-the-harness.md): a memory kill ends
203
+ the Agent's processes, not the Harness.
204
+ - [ADR-0064](../reference/decisions/0064-a-workspace-waits-for-capacity.md): a Workspace waits for capacity.