@jr2/orchestrator 0.5.1 → 0.7.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 (350) hide show
  1. package/console/components/app.ts +55 -15
  2. package/console/components/bottom-drawer.ts +259 -0
  3. package/console/components/drawer.ts +14 -6
  4. package/console/components/fleet.ts +36 -13
  5. package/console/components/machine-pane.ts +61 -5
  6. package/console/components/nav.ts +54 -8
  7. package/console/conversation.ts +161 -0
  8. package/console/login.ts +123 -0
  9. package/console/main.ts +600 -60
  10. package/console/store.ts +611 -64
  11. package/console/style.css +231 -0
  12. package/docs/agents-block.md +2 -2
  13. package/docs/concepts/agents-and-turns.md +142 -29
  14. package/docs/concepts/architecture.md +60 -34
  15. package/docs/concepts/callers-and-hooks.md +205 -0
  16. package/docs/concepts/charts.md +13 -8
  17. package/docs/concepts/composition.md +10 -1
  18. package/docs/concepts/converge.md +7 -2
  19. package/docs/concepts/durable-runs.md +43 -16
  20. package/docs/concepts/effects.md +133 -50
  21. package/docs/concepts/gates.md +95 -25
  22. package/docs/concepts/machines-and-workflows.md +14 -4
  23. package/docs/concepts/pools-and-sources.md +193 -17
  24. package/docs/concepts/secrets-and-trust.md +186 -62
  25. package/docs/concepts/the-menu.md +14 -0
  26. package/docs/concepts/workspaces.md +135 -56
  27. package/docs/get-started/a-model-decides.md +14 -13
  28. package/docs/get-started/an-agent-in-a-sandbox.md +46 -35
  29. package/docs/get-started/connect-a-model.md +1 -1
  30. package/docs/get-started/create-an-instance.md +17 -14
  31. package/docs/get-started/have-your-assistant-write-a-machine.md +111 -40
  32. package/docs/get-started/install.md +4 -0
  33. package/docs/guides/add-tools-to-the-sandbox.md +72 -15
  34. package/docs/guides/answer-a-gate-from-a-forge.md +304 -0
  35. package/docs/guides/answer-a-gate.md +74 -37
  36. package/docs/guides/bind-open-parts.md +29 -12
  37. package/docs/guides/call-an-mcp-tool-from-a-machine.md +572 -0
  38. package/docs/guides/cancel-a-run.md +26 -16
  39. package/docs/guides/cut-a-worktree.md +560 -0
  40. package/docs/guides/fix-a-failed-converge.md +19 -7
  41. package/docs/guides/give-a-caller-a-scope.md +203 -0
  42. package/docs/guides/give-an-agent-mcp-tools.md +422 -0
  43. package/docs/guides/iterate-on-a-machine-on-kind.md +10 -9
  44. package/docs/guides/let-an-agent-write-a-chart.md +14 -7
  45. package/docs/guides/look-inside-a-sandbox.md +115 -42
  46. package/docs/guides/move-from-kind-to-a-shared-cluster.md +16 -0
  47. package/docs/guides/open-the-console.md +63 -14
  48. package/docs/guides/push-and-sign-a-branch.md +67 -21
  49. package/docs/guides/read-a-conversation.md +225 -0
  50. package/docs/guides/run-a-chart-by-name.md +17 -16
  51. package/docs/guides/run-a-command-or-call-a-url.md +84 -41
  52. package/docs/guides/run-one-worker-per-item.md +34 -27
  53. package/docs/guides/set-an-agents-access-and-dials.md +69 -22
  54. package/docs/guides/size-a-workspace.md +19 -6
  55. package/docs/guides/start-a-run-for-each-alert.md +290 -0
  56. package/docs/guides/start-a-run-from-a-run.md +18 -16
  57. package/docs/guides/start-a-run.md +24 -18
  58. package/docs/guides/steer-an-agent.md +332 -0
  59. package/docs/guides/use-a-hosted-provider.md +7 -1
  60. package/docs/guides/watch-a-run.md +146 -117
  61. package/docs/guides/write-a-hook-kind.md +238 -0
  62. package/docs/guides/write-a-tool-as-an-mcp-server.md +351 -0
  63. package/docs/guides/write-a-workflow.md +18 -8
  64. package/docs/llms.txt +110 -23
  65. package/docs/reference/authoring-surface/agent.md +35 -12
  66. package/docs/reference/authoring-surface/answer.md +20 -4
  67. package/docs/reference/authoring-surface/arg.md +28 -6
  68. package/docs/reference/authoring-surface/basic.md +1 -1
  69. package/docs/reference/authoring-surface/bearer.md +1 -1
  70. package/docs/reference/authoring-surface/branchname.md +15 -0
  71. package/docs/reference/authoring-surface/carry.md +23 -0
  72. package/docs/reference/authoring-surface/chartschema.md +1 -1
  73. package/docs/reference/authoring-surface/chartschemafor.md +1 -1
  74. package/docs/reference/authoring-surface/command.md +37 -22
  75. package/docs/reference/authoring-surface/customize.md +4 -1
  76. package/docs/reference/authoring-surface/defineconfig.md +1 -1
  77. package/docs/reference/authoring-surface/defineevent.md +1 -1
  78. package/docs/reference/authoring-surface/dispatch.md +5 -4
  79. package/docs/reference/authoring-surface/fail.md +18 -5
  80. package/docs/reference/authoring-surface/file.md +37 -17
  81. package/docs/reference/authoring-surface/frompick.md +1 -1
  82. package/docs/reference/authoring-surface/gate.md +118 -0
  83. package/docs/reference/authoring-surface/group-agents.md +15 -0
  84. package/docs/reference/authoring-surface/group-charts.md +16 -0
  85. package/docs/reference/authoring-surface/group-composition.md +25 -0
  86. package/docs/reference/authoring-surface/group-config.md +17 -0
  87. package/docs/reference/authoring-surface/group-effects.md +48 -0
  88. package/docs/reference/authoring-surface/group-failure.md +13 -0
  89. package/docs/reference/authoring-surface/group-gates.md +16 -0
  90. package/docs/reference/authoring-surface/group-machine-and-events.md +15 -0
  91. package/docs/reference/authoring-surface/group-steering.md +12 -0
  92. package/docs/reference/authoring-surface/group-types-these-signatures-name.md +137 -0
  93. package/docs/reference/authoring-surface/group-workspaces-and-repos.md +15 -0
  94. package/docs/reference/authoring-surface/http.md +109 -9
  95. package/docs/reference/authoring-surface/isfailure.md +1 -1
  96. package/docs/reference/authoring-surface/isready.md +14 -0
  97. package/docs/reference/authoring-surface/jr2setup.md +14 -4
  98. package/docs/reference/authoring-surface/mcp.md +107 -0
  99. package/docs/reference/authoring-surface/open.md +41 -8
  100. package/docs/reference/authoring-surface/openbody.md +1 -1
  101. package/docs/reference/authoring-surface/paramsof.md +23 -5
  102. package/docs/reference/authoring-surface/pool.md +79 -11
  103. package/docs/reference/authoring-surface/push.md +31 -13
  104. package/docs/reference/authoring-surface/readyof.md +21 -0
  105. package/docs/reference/authoring-surface/reread.md +19 -0
  106. package/docs/reference/authoring-surface/secret.md +26 -5
  107. package/docs/reference/authoring-surface/sentby.md +1 -1
  108. package/docs/reference/authoring-surface/skip.md +22 -0
  109. package/docs/reference/authoring-surface/source.md +59 -4
  110. package/docs/reference/authoring-surface/steer.md +93 -0
  111. package/docs/reference/authoring-surface/text.md +1 -1
  112. package/docs/reference/authoring-surface/type-agentdefinition.md +16 -3
  113. package/docs/reference/authoring-surface/type-agentmcpserver.md +54 -0
  114. package/docs/reference/authoring-surface/type-agentslots.md +4 -1
  115. package/docs/reference/authoring-surface/type-anyframepath.md +14 -0
  116. package/docs/reference/authoring-surface/type-anyworktreepath.md +15 -0
  117. package/docs/reference/authoring-surface/type-bindactors.md +14 -0
  118. package/docs/reference/authoring-surface/type-binding.md +6 -7
  119. package/docs/reference/authoring-surface/type-caller.md +40 -0
  120. package/docs/reference/authoring-surface/type-callerrecord.md +32 -0
  121. package/docs/reference/authoring-surface/type-carry.md +19 -0
  122. package/docs/reference/authoring-surface/type-chainlink.md +3 -3
  123. package/docs/reference/authoring-surface/type-commandinput.md +4 -3
  124. package/docs/reference/authoring-surface/type-commandoptions.md +0 -22
  125. package/docs/reference/authoring-surface/type-commandoutput.md +23 -5
  126. package/docs/reference/authoring-surface/type-customize.md +20 -3
  127. package/docs/reference/authoring-surface/type-delivered.md +17 -0
  128. package/docs/reference/authoring-surface/type-deliveredevent.md +18 -0
  129. package/docs/reference/authoring-surface/type-dispatchdefinition.md +4 -3
  130. package/docs/reference/authoring-surface/type-dispatchoutput.md +9 -2
  131. package/docs/reference/authoring-surface/type-doorlessinput.md +19 -0
  132. package/docs/reference/authoring-surface/type-effectbinding.md +12 -2
  133. package/docs/reference/authoring-surface/type-filebody.md +4 -8
  134. package/docs/reference/authoring-surface/type-framepath.md +14 -0
  135. package/docs/reference/authoring-surface/type-gatebinding.md +15 -0
  136. package/docs/reference/authoring-surface/type-gatehooks.md +12 -0
  137. package/docs/reference/authoring-surface/type-gatelook.md +37 -0
  138. package/docs/reference/authoring-surface/type-gateoutcome.md +32 -0
  139. package/docs/reference/authoring-surface/type-gatereply.md +19 -0
  140. package/docs/reference/authoring-surface/type-gateslot.md +21 -0
  141. package/docs/reference/authoring-surface/type-gateslotinput.md +13 -0
  142. package/docs/reference/authoring-surface/type-gateslotparts.md +18 -0
  143. package/docs/reference/authoring-surface/type-gateslots.md +12 -0
  144. package/docs/reference/authoring-surface/type-gatetypesat.md +13 -0
  145. package/docs/reference/authoring-surface/type-hostinjectedinput.md +3 -5
  146. package/docs/reference/authoring-surface/type-httpdefinition.md +6 -3
  147. package/docs/reference/authoring-surface/type-httpfileinput.md +20 -0
  148. package/docs/reference/authoring-surface/type-httpoutput.md +8 -2
  149. package/docs/reference/authoring-surface/type-jr2config.md +37 -2
  150. package/docs/reference/authoring-surface/type-lateroutcome.md +21 -0
  151. package/docs/reference/authoring-surface/type-lends.md +5 -1
  152. package/docs/reference/authoring-surface/type-lookoutput.md +14 -0
  153. package/docs/reference/authoring-surface/type-mcpcalloutput.md +78 -0
  154. package/docs/reference/authoring-surface/type-mcpnotreturned.md +42 -0
  155. package/docs/reference/authoring-surface/type-mcpoptions.md +47 -0
  156. package/docs/reference/authoring-surface/type-mcpoutput.md +50 -0
  157. package/docs/reference/authoring-surface/type-mcpreadoutput.md +53 -0
  158. package/docs/reference/authoring-surface/type-mcpremoteserver.md +50 -0
  159. package/docs/reference/authoring-surface/type-mcpserver.md +41 -0
  160. package/docs/reference/authoring-surface/type-mcpstdioserver.md +42 -0
  161. package/docs/reference/authoring-surface/type-namedsecret.md +4 -4
  162. package/docs/reference/authoring-surface/type-namestart.md +77 -0
  163. package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +1 -6
  164. package/docs/reference/authoring-surface/type-notworktreekeys.md +12 -0
  165. package/docs/reference/authoring-surface/type-openbodydeclaration.md +1 -1
  166. package/docs/reference/authoring-surface/type-openbodyoutput.md +1 -1
  167. package/docs/reference/authoring-surface/type-opencommandinput.md +7 -2
  168. package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +1 -6
  169. package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +5 -10
  170. package/docs/reference/authoring-surface/type-poolnextinput.md +22 -0
  171. package/docs/reference/authoring-surface/type-poolspec.md +11 -6
  172. package/docs/reference/authoring-surface/type-pushinput.md +22 -3
  173. package/docs/reference/authoring-surface/type-pushoutput.md +33 -8
  174. package/docs/reference/authoring-surface/type-pushsourcespec.md +38 -0
  175. package/docs/reference/authoring-surface/type-readsourcespec.md +47 -0
  176. package/docs/reference/authoring-surface/type-reposlot.md +6 -6
  177. package/docs/reference/authoring-surface/type-reread.md +18 -0
  178. package/docs/reference/authoring-surface/type-runsconfig.md +41 -0
  179. package/docs/reference/authoring-surface/type-sandboxoptions.md +11 -4
  180. package/docs/reference/authoring-surface/type-sender.md +26 -1
  181. package/docs/reference/authoring-surface/type-sendercallerfield.md +14 -0
  182. package/docs/reference/authoring-surface/type-size.md +1 -1
  183. package/docs/reference/authoring-surface/type-skip.md +19 -0
  184. package/docs/reference/authoring-surface/type-slothandles.md +5 -13
  185. package/docs/reference/authoring-surface/type-sourcehooks.md +23 -0
  186. package/docs/reference/authoring-surface/type-sourcein.md +25 -0
  187. package/docs/reference/authoring-surface/type-sourcereply.md +18 -0
  188. package/docs/reference/authoring-surface/type-sourcespec.md +26 -17
  189. package/docs/reference/authoring-surface/type-sourceverdict.md +49 -0
  190. package/docs/reference/authoring-surface/type-standingpoolmachine.md +12 -0
  191. package/docs/reference/authoring-surface/type-standingpoolspec.md +51 -0
  192. package/docs/reference/authoring-surface/type-steerargs.md +20 -0
  193. package/docs/reference/authoring-surface/type-thinkinglevel.md +1 -1
  194. package/docs/reference/authoring-surface/type-usercontainer.md +1 -1
  195. package/docs/reference/authoring-surface/type-workspaced.md +30 -9
  196. package/docs/reference/authoring-surface/type-workspacehandles.md +5 -6
  197. package/docs/reference/authoring-surface/type-workspaceoptions.md +1 -13
  198. package/docs/reference/authoring-surface/type-worktreefound.md +16 -0
  199. package/docs/reference/authoring-surface/type-worktreeinput.md +56 -0
  200. package/docs/reference/authoring-surface/type-worktreekey.md +14 -0
  201. package/docs/reference/authoring-surface/type-worktreeoptions.md +29 -0
  202. package/docs/reference/authoring-surface/type-worktreeoutput.md +45 -0
  203. package/docs/reference/authoring-surface/type-worktreepath.md +16 -0
  204. package/docs/reference/authoring-surface/type-worktreeready.md +37 -0
  205. package/docs/reference/authoring-surface/type-worktreerefused.md +21 -0
  206. package/docs/reference/authoring-surface/workspace.md +66 -38
  207. package/docs/reference/authoring-surface/worktree.md +71 -0
  208. package/docs/reference/authoring-surface.md +88 -147
  209. package/docs/reference/cli.md +413 -74
  210. package/docs/reference/config.md +248 -6
  211. package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +10 -9
  212. package/docs/reference/decisions/0002-duplex-streaming-actor.md +81 -14
  213. package/docs/reference/decisions/0004-worktree-provisioning-model.md +27 -21
  214. package/docs/reference/decisions/0005-sandbox-pod-composition.md +39 -25
  215. package/docs/reference/decisions/0006-agent-control-surface.md +6 -3
  216. package/docs/reference/decisions/0007-durable-machine-state.md +1 -1
  217. package/docs/reference/decisions/0009-cli-and-instance-interface.md +150 -49
  218. package/docs/reference/decisions/0010-bdd-acceptance-tests.md +5 -3
  219. package/docs/reference/decisions/0011-workflow-defined-events.md +256 -12
  220. package/docs/reference/decisions/0012-workspace-wrapper-machine.md +39 -32
  221. package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +54 -30
  222. package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +53 -27
  223. package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +26 -16
  224. package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +9 -7
  225. package/docs/reference/decisions/0017-pool-over-a-source-port.md +226 -10
  226. package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +15 -7
  227. package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +53 -27
  228. package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +16 -2
  229. package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +4 -4
  230. package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +124 -43
  231. package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +36 -38
  232. package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +10 -5
  233. package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +16 -7
  234. package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +36 -19
  235. package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +18 -10
  236. package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +3 -2
  237. package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +23 -15
  238. package/docs/reference/decisions/0032-the-console-unlocks-with-a-callers-credential.md +101 -0
  239. package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +22 -22
  240. package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +6 -6
  241. package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +13 -12
  242. package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +23 -23
  243. package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +6 -1
  244. package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +57 -46
  245. package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +5 -0
  246. package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +20 -8
  247. package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +55 -40
  248. package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +14 -13
  249. package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +31 -24
  250. package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +18 -10
  251. package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +137 -86
  252. package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +165 -91
  253. package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +7 -7
  254. package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +2 -2
  255. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-kept-for-a-set-time.md +109 -0
  256. package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +53 -23
  257. package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +221 -153
  258. package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +161 -96
  259. package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +32 -9
  260. package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +48 -33
  261. package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +56 -30
  262. package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +35 -25
  263. package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +1 -1
  264. package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +296 -0
  265. package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +347 -0
  266. package/docs/reference/decisions/0077-jr2-requires-landlock-on-every-sandbox-node.md +79 -0
  267. package/docs/reference/decisions/0078-a-caller-comes-from-one-authenticator-seam-and-acts-within-its-scopes.md +285 -0
  268. package/docs/reference/decisions/0079-an-agent-holds-mcp-tools-a-machine-calls-them-as-an-effect-and-the-machine-is-the-approval.md +198 -0
  269. package/docs/reference/decisions.md +9 -4
  270. package/docs/reference/glossary.md +138 -45
  271. package/docs/reference/hooks.md +1077 -0
  272. package/docs/reference/http-api.md +988 -123
  273. package/docs/reference/machines.md +0 -1
  274. package/docs/why.md +7 -5
  275. package/package.json +10 -3
  276. package/src/actor.ts +194 -42
  277. package/src/agent.ts +56 -6
  278. package/src/ambient.ts +3 -5
  279. package/src/assembly-checks.ts +530 -4
  280. package/src/callers.ts +245 -0
  281. package/src/chart.ts +238 -26
  282. package/src/charts.ts +9 -2
  283. package/src/config.ts +566 -7
  284. package/src/conversations.ts +453 -0
  285. package/src/custodian.lua +17 -5
  286. package/src/custodian.ts +257 -77
  287. package/src/customize.ts +154 -7
  288. package/src/dispatch-effect.ts +142 -26
  289. package/src/durability.ts +2 -0
  290. package/src/duration.ts +20 -0
  291. package/src/effect-checks.ts +52 -4
  292. package/src/effect.ts +401 -132
  293. package/src/effector-wire.ts +278 -30
  294. package/src/fail.ts +17 -4
  295. package/src/gate-brand.ts +16 -0
  296. package/src/gate.ts +634 -48
  297. package/src/harness-client.ts +84 -35
  298. package/src/harness-env.ts +33 -0
  299. package/src/held-secrets.ts +197 -39
  300. package/src/holds.ts +5 -2
  301. package/src/hook-kinds/discord.ts +92 -0
  302. package/src/hook-kinds/door.ts +107 -0
  303. package/src/hook-kinds/github.ts +89 -0
  304. package/src/hook-kinds/gitlab.ts +72 -0
  305. package/src/hook-kinds/hook.ts +7 -0
  306. package/src/hook-kinds/index.ts +465 -0
  307. package/src/hook-kinds/slack.ts +151 -0
  308. package/src/hook-kinds/webhook.ts +113 -0
  309. package/src/hooks.ts +506 -0
  310. package/src/http-effect.ts +164 -70
  311. package/src/http.ts +933 -99
  312. package/src/index.ts +30 -5
  313. package/src/instance.ts +196 -26
  314. package/src/internal.ts +23 -3
  315. package/src/kube-client.ts +6 -3
  316. package/src/machine-doc.ts +29 -5
  317. package/src/mcp-effect.ts +424 -0
  318. package/src/model-keys.ts +24 -0
  319. package/src/mount-digest.ts +41 -7
  320. package/src/names.ts +82 -7
  321. package/src/notices.ts +576 -59
  322. package/src/open-body.ts +110 -30
  323. package/src/open-effect.ts +17 -4
  324. package/src/open.ts +40 -7
  325. package/src/parts.ts +125 -35
  326. package/src/party.ts +35 -1
  327. package/src/pick.ts +43 -9
  328. package/src/pool.ts +1172 -172
  329. package/src/registration.ts +249 -17
  330. package/src/repo-identity.ts +7 -3
  331. package/src/repos.ts +20 -2
  332. package/src/run-host.ts +1614 -190
  333. package/src/run-list.ts +191 -0
  334. package/src/sandbox-effect.ts +217 -66
  335. package/src/sandbox-kube.ts +116 -21
  336. package/src/secret-placement.ts +248 -35
  337. package/src/server.ts +53 -4
  338. package/src/setup.ts +158 -38
  339. package/src/snapshot-store.ts +565 -48
  340. package/src/steer.ts +111 -0
  341. package/src/stub-harness.ts +6 -2
  342. package/src/tokens.ts +362 -46
  343. package/src/vocabulary.ts +23 -4
  344. package/src/wire.ts +27 -10
  345. package/src/workspace.ts +314 -259
  346. package/src/worktree.ts +249 -0
  347. package/docs/reference/authoring-surface/type-noslotspec.md +0 -26
  348. package/docs/reference/authoring-surface/type-workspacespec.md +0 -37
  349. package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +0 -61
  350. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +0 -65
@@ -0,0 +1,560 @@
1
+ ---
2
+ title: Cut a Worktree
3
+ description: Make a Worktree with worktree(), choose what a cut refuses, and remove a Worktree.
4
+ ---
5
+
6
+ # Cut a Worktree
7
+
8
+ Make each [Worktree](../reference/glossary.md#worktree) that your [Machine](../reference/glossary.md#machine) needs,
9
+ with the [`worktree()`](../reference/authoring-surface/worktree.md) [Effect](../reference/glossary.md#effect).
10
+
11
+ A [Workspace](../reference/glossary.md#workspace) only clones each [Repo](../reference/glossary.md#repo). The body of
12
+ the Workspace does a [Cut](../reference/glossary.md#cut) of each Worktree in a state of its own. In this
13
+ [Workflow](../reference/glossary.md#workflow), a coder [Agent](../reference/glossary.md#agent) works on a new branch. A
14
+ reviewer reads the coder's commit in a second Worktree, with no branch. Then the Machine removes the review Worktree,
15
+ and pushes the commit that the reviewer read. Save the file as `workflows/fix-a-bug.ts` in your
16
+ [Instance](../reference/glossary.md#instance):
17
+
18
+ **Anthropic**
19
+
20
+ ```ts
21
+ import { assign } from "xstate";
22
+ import { z } from "zod";
23
+ import {
24
+ agent,
25
+ arg,
26
+ branchName,
27
+ command,
28
+ defineEvent,
29
+ fail,
30
+ isReady,
31
+ jr2Setup,
32
+ push,
33
+ readyOf,
34
+ workspace,
35
+ worktree,
36
+ type Workspaced,
37
+ } from "@jr2/orchestrator";
38
+
39
+ const finished = defineEvent({
40
+ name: "finished",
41
+ description: "Call this when you committed the fix.",
42
+ input: z.object({}),
43
+ });
44
+ const pass = defineEvent({ name: "pass", description: "Call this when the commit is correct.", input: z.object({}) });
45
+ const revise = defineEvent({
46
+ name: "revise",
47
+ description: "Call this when the commit is not correct. Say what to change.",
48
+ input: z.object({ notes: z.string() }),
49
+ });
50
+
51
+ // The run input. `branchName` refuses a name that the cut and the push refuse.
52
+ const runInput = z.object({ prompt: z.string(), branch: branchName });
53
+ type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
54
+ type Context = BodyInput & { reviewed?: string };
55
+
56
+ // Your Machine names each folder. So it knows each path before the cut.
57
+ const coderTree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
58
+ const reviewTree = (context: BodyInput) => `${context.workspace.repos.app}/review` as const;
59
+ const cloneTree = (context: BodyInput) => `${context.workspace.repos.app}/default` as const;
60
+
61
+ const body = jr2Setup({
62
+ types: {} as { input: BodyInput; context: Context },
63
+ events: [finished, pass, revise],
64
+ actors: {
65
+ coder: agent({ model: "anthropic/claude-haiku-5-5", instructions: "You fix the bug. You commit the fix." }),
66
+ reviewer: agent({
67
+ model: "anthropic/claude-haiku-5-5",
68
+ workspace: "read",
69
+ instructions: "You review one commit. You change nothing.",
70
+ }),
71
+ // Each run gets a new branch: the cut refuses a branch that exists.
72
+ cut: worktree({ expect: "new" }),
73
+ // No `--force`: git refuses a Worktree with changes, and the output holds its exit code.
74
+ // The state below goes on with either result: a Worktree that stays does no harm here.
75
+ remove: command(["git", "worktree", "remove", arg("path")], { timeout: "1m" }),
76
+ publish: push({ pin: true }),
77
+ fail: fail(),
78
+ },
79
+ }).createMachine({
80
+ id: "fix-a-bug",
81
+ context: ({ input }) => input,
82
+ on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
83
+ initial: "cutting",
84
+ states: {
85
+ cutting: {
86
+ invoke: {
87
+ src: "cut",
88
+ input: ({ context }) => ({ path: coderTree(context), branch: context.branch }),
89
+ // The last arm has no guard: it takes `refused`, `unknown` and each later outcome.
90
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
91
+ },
92
+ },
93
+ coding: {
94
+ invoke: {
95
+ src: "coder",
96
+ input: ({ context }) => ({ prompt: context.prompt, cwd: coderTree(context), continue: true }),
97
+ },
98
+ on: { finished: "reading" },
99
+ },
100
+ // A cut of the same path reads the Worktree. `head` is the tip of the branch, whatever HEAD the coder left.
101
+ reading: {
102
+ invoke: {
103
+ src: "cut",
104
+ input: ({ context }) => ({ path: coderTree(context), branch: context.branch }),
105
+ onDone: [
106
+ {
107
+ guard: ({ event }) => isReady(event.output),
108
+ target: "detaching",
109
+ actions: assign({ reviewed: ({ event }) => readyOf(event.output).head }),
110
+ },
111
+ { target: "notCut" },
112
+ ],
113
+ },
114
+ },
115
+ // Each round forces this folder to the commit, and cleans it.
116
+ detaching: {
117
+ invoke: {
118
+ src: "cut",
119
+ input: ({ context }) => ({ path: reviewTree(context), detach: context.reviewed! }),
120
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "reviewing" }, { target: "notCut" }],
121
+ },
122
+ },
123
+ reviewing: {
124
+ invoke: {
125
+ src: "reviewer",
126
+ input: ({ context }) => ({ prompt: `Review ${context.reviewed}.`, cwd: reviewTree(context) }),
127
+ },
128
+ on: {
129
+ pass: "removing",
130
+ revise: {
131
+ target: "coding",
132
+ actions: assign({ prompt: ({ event }) => `Change the fix as the review asks:\n\n${event.notes}` }),
133
+ },
134
+ },
135
+ },
136
+ // The clone is not the Worktree that goes, so the command runs there.
137
+ removing: {
138
+ invoke: {
139
+ src: "remove",
140
+ input: ({ context }) => ({ path: reviewTree(context), worktree: cloneTree(context) }),
141
+ onDone: "publishing",
142
+ },
143
+ },
144
+ // The input names the Worktree and the commit. jr2 reads the branch from the cut of that path.
145
+ publishing: {
146
+ invoke: {
147
+ src: "publish",
148
+ input: ({ context }) => ({ worktree: coderTree(context), sha: context.reviewed! }),
149
+ onDone: [{ guard: ({ event }) => event.output.outcome === "pushed", target: "done" }, { target: "notPushed" }],
150
+ },
151
+ },
152
+ done: { type: "final" },
153
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
154
+ notPushed: { invoke: { src: "fail", input: { reason: "the push did not succeed" } } },
155
+ failed: { invoke: { src: "fail", input: { reason: "an Agent's Turn could not go on" } } },
156
+ lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
157
+ },
158
+ });
159
+
160
+ export const machine = workspace(body, {
161
+ input: runInput,
162
+ repos: { app: "https://github.com/<you>/app.git" },
163
+ });
164
+ ```
165
+
166
+ **Local**
167
+
168
+ ```ts
169
+ import { assign } from "xstate";
170
+ import { z } from "zod";
171
+ import {
172
+ agent,
173
+ arg,
174
+ branchName,
175
+ command,
176
+ defineEvent,
177
+ fail,
178
+ isReady,
179
+ jr2Setup,
180
+ push,
181
+ readyOf,
182
+ workspace,
183
+ worktree,
184
+ type Workspaced,
185
+ } from "@jr2/orchestrator";
186
+
187
+ const finished = defineEvent({
188
+ name: "finished",
189
+ description: "Call this when you committed the fix.",
190
+ input: z.object({}),
191
+ });
192
+ const pass = defineEvent({ name: "pass", description: "Call this when the commit is correct.", input: z.object({}) });
193
+ const revise = defineEvent({
194
+ name: "revise",
195
+ description: "Call this when the commit is not correct. Say what to change.",
196
+ input: z.object({ notes: z.string() }),
197
+ });
198
+
199
+ // The run input. `branchName` refuses a name that the cut and the push refuse.
200
+ const runInput = z.object({ prompt: z.string(), branch: branchName });
201
+ type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
202
+ type Context = BodyInput & { reviewed?: string };
203
+
204
+ // Your Machine names each folder. So it knows each path before the cut.
205
+ const coderTree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
206
+ const reviewTree = (context: BodyInput) => `${context.workspace.repos.app}/review` as const;
207
+ const cloneTree = (context: BodyInput) => `${context.workspace.repos.app}/default` as const;
208
+
209
+ const body = jr2Setup({
210
+ types: {} as { input: BodyInput; context: Context },
211
+ events: [finished, pass, revise],
212
+ actors: {
213
+ coder: agent({ model: "local/qwen3.6-35b-a3b", instructions: "You fix the bug. You commit the fix." }),
214
+ reviewer: agent({
215
+ model: "local/qwen3.6-35b-a3b",
216
+ workspace: "read",
217
+ instructions: "You review one commit. You change nothing.",
218
+ }),
219
+ // Each run gets a new branch: the cut refuses a branch that exists.
220
+ cut: worktree({ expect: "new" }),
221
+ // No `--force`: git refuses a Worktree with changes, and the output holds its exit code.
222
+ // The state below goes on with either result: a Worktree that stays does no harm here.
223
+ remove: command(["git", "worktree", "remove", arg("path")], { timeout: "1m" }),
224
+ publish: push({ pin: true }),
225
+ fail: fail(),
226
+ },
227
+ }).createMachine({
228
+ id: "fix-a-bug",
229
+ context: ({ input }) => input,
230
+ on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
231
+ initial: "cutting",
232
+ states: {
233
+ cutting: {
234
+ invoke: {
235
+ src: "cut",
236
+ input: ({ context }) => ({ path: coderTree(context), branch: context.branch }),
237
+ // The last arm has no guard: it takes `refused`, `unknown` and each later outcome.
238
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
239
+ },
240
+ },
241
+ coding: {
242
+ invoke: {
243
+ src: "coder",
244
+ input: ({ context }) => ({ prompt: context.prompt, cwd: coderTree(context), continue: true }),
245
+ },
246
+ on: { finished: "reading" },
247
+ },
248
+ // A cut of the same path reads the Worktree. `head` is the tip of the branch, whatever HEAD the coder left.
249
+ reading: {
250
+ invoke: {
251
+ src: "cut",
252
+ input: ({ context }) => ({ path: coderTree(context), branch: context.branch }),
253
+ onDone: [
254
+ {
255
+ guard: ({ event }) => isReady(event.output),
256
+ target: "detaching",
257
+ actions: assign({ reviewed: ({ event }) => readyOf(event.output).head }),
258
+ },
259
+ { target: "notCut" },
260
+ ],
261
+ },
262
+ },
263
+ // Each round forces this folder to the commit, and cleans it.
264
+ detaching: {
265
+ invoke: {
266
+ src: "cut",
267
+ input: ({ context }) => ({ path: reviewTree(context), detach: context.reviewed! }),
268
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "reviewing" }, { target: "notCut" }],
269
+ },
270
+ },
271
+ reviewing: {
272
+ invoke: {
273
+ src: "reviewer",
274
+ input: ({ context }) => ({ prompt: `Review ${context.reviewed}.`, cwd: reviewTree(context) }),
275
+ },
276
+ on: {
277
+ pass: "removing",
278
+ revise: {
279
+ target: "coding",
280
+ actions: assign({ prompt: ({ event }) => `Change the fix as the review asks:\n\n${event.notes}` }),
281
+ },
282
+ },
283
+ },
284
+ // The clone is not the Worktree that goes, so the command runs there.
285
+ removing: {
286
+ invoke: {
287
+ src: "remove",
288
+ input: ({ context }) => ({ path: reviewTree(context), worktree: cloneTree(context) }),
289
+ onDone: "publishing",
290
+ },
291
+ },
292
+ // The input names the Worktree and the commit. jr2 reads the branch from the cut of that path.
293
+ publishing: {
294
+ invoke: {
295
+ src: "publish",
296
+ input: ({ context }) => ({ worktree: coderTree(context), sha: context.reviewed! }),
297
+ onDone: [{ guard: ({ event }) => event.output.outcome === "pushed", target: "done" }, { target: "notPushed" }],
298
+ },
299
+ },
300
+ done: { type: "final" },
301
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
302
+ notPushed: { invoke: { src: "fail", input: { reason: "the push did not succeed" } } },
303
+ failed: { invoke: { src: "fail", input: { reason: "an Agent's Turn could not go on" } } },
304
+ lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
305
+ },
306
+ });
307
+
308
+ export const machine = workspace(body, {
309
+ input: runInput,
310
+ repos: { app: "https://github.com/<you>/app.git" },
311
+ });
312
+ ```
313
+
314
+ Write your GitHub user name in place of `<you>`. The Agents use the model of the tab.
315
+ [Push and sign a branch](push-and-sign-a-branch.md) tells how to give the push a credential.
316
+
317
+ ## Name the path
318
+
319
+ The path of a Worktree is exactly `/work/<slot>/<name>`. `<slot>` is a [Repo Slot](../reference/glossary.md#repo-slot).
320
+ `<name>` is one folder name that you choose. It is not `default`, and it starts with neither `.` nor `-`. It does not
321
+ change with the name of the branch.
322
+
323
+ Make the path from `context.workspace.repos`, and add `as const`. Then the compiler can read the slot, and it refuses a
324
+ slot that the Workspace does not have:
325
+
326
+ ```ts
327
+ // Your Machine names each folder. So it knows each path before the cut.
328
+ const coderTree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
329
+ const reviewTree = (context: BodyInput) => `${context.workspace.repos.app}/review` as const;
330
+ const cloneTree = (context: BodyInput) => `${context.workspace.repos.app}/default` as const;
331
+ ```
332
+
333
+ The check of the compiler is a help. It sees only a literal path under `jr2Setup`. jr2 also checks each path when the
334
+ run gets to it.
335
+
336
+ ## Cut a branch
337
+
338
+ Invoke the Effect with `{ path, branch }`. `branch` is required, unless you give `detach`. The Machine names the branch,
339
+ so jr2 never reads it from the folder or from `HEAD`.
340
+
341
+ ```ts
342
+ cutting: {
343
+ invoke: {
344
+ src: "cut",
345
+ input: ({ context }) => ({ path: coderTree(context), branch: context.branch }),
346
+ // The last arm has no guard: it takes `refused`, `unknown` and each later outcome.
347
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
348
+ },
349
+ },
350
+ ```
351
+
352
+ The cut fetches, then finds the branch in this order:
353
+
354
+ 1. A local branch.
355
+ 2. `origin/<branch>`. The new local branch tracks it.
356
+ 3. A new branch, with no upstream. It starts from `from`, or from the base of the
357
+ [Binding](../reference/glossary.md#binding) when the input has no `from`.
358
+
359
+ The output is `ready`, `refused` or `unknown`. Each Effect outcome is open, so give the last arm of `onDone` no guard.
360
+ [`isReady`](../reference/authoring-surface/isready.md) is the guard for `ready`.
361
+
362
+ | The field of `ready` | What it holds |
363
+ | -------------------- | ---------------------------------------------------------------------------- |
364
+ | `slot`, `path` | The Repo Slot and the path of the Worktree. |
365
+ | `branch` | The branch of the cut, or `null` for a detached cut. |
366
+ | `head` | The tip of the branch, or the commit of a detached cut. It is never `HEAD`. |
367
+ | `found` | How the cut found it: `local`, `remote`, `none`, `held` or `commit`. |
368
+ | `stale` | The warning of git when the fetch failed. The cut used what the clone holds. |
369
+
370
+ `held` means that a cut made this path before, so the Worktree holds earlier work. No fetch happens, and the cut does
371
+ not check `expect` again. Thus a cut of the same path also reads a Worktree:
372
+
373
+ ```ts
374
+ // A cut of the same path reads the Worktree. `head` is the tip of the branch, whatever HEAD the coder left.
375
+ reading: {
376
+ invoke: {
377
+ src: "cut",
378
+ input: ({ context }) => ({ path: coderTree(context), branch: context.branch }),
379
+ onDone: [
380
+ {
381
+ guard: ({ event }) => isReady(event.output),
382
+ target: "detaching",
383
+ actions: assign({ reviewed: ({ event }) => readyOf(event.output).head }),
384
+ },
385
+ { target: "notCut" },
386
+ ],
387
+ },
388
+ },
389
+ ```
390
+
391
+ [`readyOf`](../reference/authoring-surface/readyof.md) gives the `ready` output to an action, because xstate does not
392
+ carry the guard to the action.
393
+
394
+ ## Choose what a cut refuses
395
+
396
+ `expect` says if the branch can exist. It is an option of `worktree()`, so a run cannot change it:
397
+
398
+ - `worktree()`: use a local branch, then a branch of the remote, then make a new branch.
399
+ - `worktree({ expect: "new" })`: refuse a branch that exists, local or on the remote. Use it for a name that a planner
400
+ or a run input chooses for new work. A name that collides is then a refusal, and not the branch of a different person.
401
+ - `worktree({ expect: "existing" })`: refuse a branch that does not exist, and make nothing. Use it when a run must
402
+ continue a branch that exists.
403
+
404
+ The example gives the coder a new branch for each run:
405
+
406
+ ```ts
407
+ // Each run gets a new branch: the cut refuses a branch that exists.
408
+ cut: worktree({ expect: "new" }),
409
+ ```
410
+
411
+ A pick param or a run input that names a branch can use the schema
412
+ [`branchName`](../reference/authoring-surface/branchname.md). It is the rule of the cut and of the push. Thus jr2
413
+ refuses a bad name at the [Menu](../reference/glossary.md#menu) or at the door, before the cut.
414
+
415
+ ## Read a commit with no branch
416
+
417
+ Invoke the Effect with `{ path, detach }` to hold one commit, with no branch. The example gives this Worktree to a
418
+ reviewer. Each cut forces the folder to the commit, and cleans it. Ignored files stay, so that a reviewer can run the
419
+ tests:
420
+
421
+ ```ts
422
+ // Each round forces this folder to the commit, and cleans it.
423
+ detaching: {
424
+ invoke: {
425
+ src: "cut",
426
+ input: ({ context }) => ({ path: reviewTree(context), detach: context.reviewed! }),
427
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "reviewing" }, { target: "notCut" }],
428
+ },
429
+ },
430
+ ```
431
+
432
+ `expect` applies only to a branch. A slot with `expect` can thus also make a detached cut, as `cut` does here. A cut
433
+ that you lend to a [Chart](../reference/glossary.md#chart) must state `expect`, so a Chart uses such a slot too.
434
+
435
+ ## Give the Worktree to each step
436
+
437
+ Each step names its Worktree by its path:
438
+
439
+ | The step | The key of its input |
440
+ | --------------------------------------- | -------------------- |
441
+ | A [Turn](../reference/glossary.md#turn) | `cwd` |
442
+ | A `command` | `worktree` |
443
+ | A `push` | `worktree` |
444
+ | An `http` Effect with a file | `worktree` |
445
+
446
+ Each key is required under Repo Slots. A Turn that wants the folder above the Repo Slots states `cwd: "/work"`. To read
447
+ a slot that has no Worktree, use `/work/<slot>/default`. A Workspace with no Repo Slot, and an Agent with
448
+ `workspace: "none"`, need no `cwd`.
449
+
450
+ A Turn of a Working Agent that names a path where no Worktree exists does not start. The
451
+ [Harness](../reference/glossary.md#harness) refuses it, and the Machine gets `agent.fault` with
452
+ ``the Turn's `cwd` <path> does not exist: cut the Worktree first``.
453
+
454
+ A `push` has no branch in its input. jr2 finds the cut of that path, and reads the branch there. An Agent can move
455
+ `HEAD`, and it cannot change that record:
456
+
457
+ ```ts
458
+ // The input names the Worktree and the commit. jr2 reads the branch from the cut of that path.
459
+ publishing: {
460
+ invoke: {
461
+ src: "publish",
462
+ input: ({ context }) => ({ worktree: coderTree(context), sha: context.reviewed! }),
463
+ onDone: [{ guard: ({ event }) => event.output.outcome === "pushed", target: "done" }, { target: "notPushed" }],
464
+ },
465
+ },
466
+ ```
467
+
468
+ ## Run more than one coder
469
+
470
+ The author chooses how many Agents work in a Workspace. Agents in one Worktree share git, as people in one checkout do.
471
+ Give each coder that needs its own branch a Worktree of its own, with its own path and its own branch. Each Worktree
472
+ uses the one clone. To merge the branches, cut a Worktree for the merge target, and run `git merge` in a `command`
473
+ there. No fetch is necessary, because each branch is in the clone. Then push once.
474
+
475
+ Cuts of one clone wait for each other, so they do not collide.
476
+
477
+ ## Remove a Worktree
478
+
479
+ jr2 has no Effect that removes a Worktree. To remove one, run `git worktree remove` in a `command`:
480
+
481
+ ```ts
482
+ // No `--force`: git refuses a Worktree with changes, and the output holds its exit code.
483
+ // The state below goes on with either result: a Worktree that stays does no harm here.
484
+ remove: command(["git", "worktree", "remove", arg("path")], { timeout: "1m" }),
485
+ ```
486
+
487
+ Invoke the `command` in a different Worktree. The clone is always there, so the example names it:
488
+
489
+ ```ts
490
+ // The clone is not the Worktree that goes, so the command runs there.
491
+ removing: {
492
+ invoke: {
493
+ src: "remove",
494
+ input: ({ context }) => ({ path: reviewTree(context), worktree: cloneTree(context) }),
495
+ onDone: "publishing",
496
+ },
497
+ },
498
+ ```
499
+
500
+ - The branch stays. Only the folder goes.
501
+ - A Worktree with changes or with untracked files stays too, and git exits with a code that is not 0. Route on `exited`
502
+ to see it, or add `--force` to the argv to drop those changes. Ignored files do not stop the removal.
503
+ - jr2 keeps its record of the cut. A cut of the same path and the same branch makes the folder again. Its `found` is
504
+ `local`. A detached cut makes the folder again too.
505
+ - jr2 deletes each Worktree with the [Sandbox](../reference/glossary.md#sandbox). Thus a Machine needs this recipe only
506
+ to free the disk during a run.
507
+
508
+ ## Rules
509
+
510
+ These settle as `refused`, and nothing changes. Route them to your last arm:
511
+
512
+ - a path that is not a Worktree path: `"<path>" is not a Worktree path: /work/<slot>/<name>, with one segment in <name>`
513
+ - the path of the clone: `"<path>" is the clone: it stays as the attach left it; cut a sibling`
514
+ - a name that starts with `.` or `-`: `"<path>": a Worktree's name starts with neither . nor -`
515
+ - a slot that the Workspace does not have:
516
+ `"<path>" names Repo Slot "<slot>", which its Workspace does not carry (<slots>)`
517
+ - no branch and no commit, or both: ``a cut names a branch, or a commit in `detach` ``
518
+ - `from` on a detached cut: ``a detached cut takes no `from` ``
519
+ - `expect: "new"` on a branch that exists: `<branch> exists, and this cut makes only a new branch`
520
+ - `expect: "existing"` on a branch that does not exist: `<branch> does not exist, and this cut makes nothing`
521
+ - a re-cut that does not agree with the first cut: `<path> was cut for <branch>, not <other>`,
522
+ `<path> was cut detached, not for <branch>`, or `<path> was cut from <from>, not <other>`
523
+ - a folder that no cut made: `<path> is a folder and no Worktree: a cut removes nothing it did not make`
524
+ - a detached cut of a Worktree that no cut made:
525
+ `<path> is a Worktree no cut made, and a detached cut forces only its own`
526
+ - a commit that the clone does not hold, also after a fetch: `no commit "<sha>" in this clone`
527
+ - a branch that `default/` or a different Worktree holds: `<path> holds <branch>: read it there, or cut another branch`
528
+ - a name that the clone does not hold, after a fetch that failed:
529
+ `<branch> is not in this clone, and the remote did not answer, so it may exist there: <warning>`
530
+ - a `from` on a branch that exists:
531
+ ``<branch> exists, and it is not at `from` "<from>": `from` starts a new branch and moves no branch``
532
+
533
+ A name that git or the push refuses also settles `refused`. The `reason` says why, for example
534
+ `"<name>" is not a branch name`.
535
+
536
+ These are not `refused`, because no word of a run can cause them:
537
+
538
+ - `createMachine` refuses an Effect's `onDone` with a guard on its last arm:
539
+ `machine "<id>": state "<state>" (Effect "<slot>") has an onDone with no unguarded last arm — … (ADR-0075)`
540
+ - `jr2 up` refuses a `worktree()` in a Workspace with no Repo Slot:
541
+ `workflow "<workflow>": worktree "<slot>" runs in Workspace of workflow "<workflow>", which has no Repo Slot: a cut makes a Worktree of a Repo Slot, and there is none — declare one: repos: { app: "<url>" } (ADR-0075)`
542
+ - when a `worktree()` starts, it refuses the same Workspace:
543
+ `worktree "<slot>" runs under a Workspace with no Repo Slot: a cut makes a Worktree of a Repo Slot, and there is none — declare one: repos: { app: "<url>" } (ADR-0075)`
544
+ - a Repo Slot name that starts with `.`, because `/work/.jr2/` is reserved for jr2. See
545
+ [Bind a shipped Machine's Open parts](bind-open-parts.md).
546
+
547
+ ## Read next
548
+
549
+ - [Workspaces](../concepts/workspaces.md): the clone, the folders, and what names a Worktree.
550
+ - [Effects](../concepts/effects.md): where a cut runs, and what a restart does to it.
551
+ - [Push and sign a branch](push-and-sign-a-branch.md): the `push` Effect.
552
+ - [Set an Agent's access and Dials](set-an-agents-access-and-dials.md): a reviewer in a detached Worktree.
553
+ - [Let an Agent write a Chart](let-an-agent-write-a-chart.md): a cut that you lend to a Chart.
554
+ - Reference: [`worktree`](../reference/authoring-surface/worktree.md),
555
+ [`WorktreeOptions`](../reference/authoring-surface/type-worktreeoptions.md),
556
+ [`WorktreeInput`](../reference/authoring-surface/type-worktreeinput.md),
557
+ [`WorktreeOutput`](../reference/authoring-surface/type-worktreeoutput.md) and
558
+ [`branchName`](../reference/authoring-surface/branchname.md).
559
+ - [ADR-0075](../reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md): a Machine cuts a
560
+ Worktree, and the Workspace only clones.
@@ -308,14 +308,23 @@ refusals of a push and of the [Effector](../reference/glossary.md#effector) imag
308
308
 
309
309
  The check has a limit. The check pod has labels of its own, so a NetworkPolicy that selects the Harness pods by label
310
310
  does not select the check pod. When such a policy closes the egress of the Harness pods, the check can pass while a
311
- Turn fails.
311
+ Turn fails. The egress policy of jr2, which closes the cloud metadata addresses, selects the check pod too.
312
312
 
313
313
  A check can fail when the model works, for example a model that loads for longer than the check waits. When you know
314
314
  that the models work, run `jr2 up --skip-provider-preflight`. No check pod runs, and the converge goes on. `jr2 up`
315
315
  writes one line:
316
- `warning: provider: preflight skipped (--skip-provider-preflight) — these models were not checked: <model>, …`. A
317
- model that does not work then fails in a run, as `agent.fault`, and not at the converge. Remove the flag when the
318
- check works again.
316
+ `warning: provider: preflight skipped (--skip-provider-preflight) — these models were not checked: <model>, …`. When
317
+ an Agent names a remote MCP server, the line ends with
318
+ `; these MCP servers' tool lists were not checked: <server>, …`. A model that does not work then fails in a run, as
319
+ `agent.fault`, and not at the converge. Remove the flag when the check works again.
320
+
321
+ - When an Agent names a remote MCP server, the check pod also asks the server for its tools, through its Custodian. Each
322
+ name in an allowlist must be a tool of the server:
323
+ `error: mcp: workflow "<workflow>": Agent "<slot>" allowlists the tool "<tool>", which "<server>" does not list — it lists: <tools> (ADR-0079)`.
324
+ A server that refuses the token (a 401 or a 403) is an error too:
325
+ `error: mcp: "<server>" at <url> refused the request from a pod on <where> (HTTP <status>) — a wrong or expired value of <NAME>, or a binding of it (hosts, headers, paths) that does not let its Stand-in through to the url; every call of an Agent that names it would fail (ADR-0079)`.
326
+ A server that does not answer is a warning. [Give an Agent MCP tools](give-an-agent-mcp-tools.md#rules) gives each
327
+ text.
319
328
 
320
329
  - Each rollout must complete. The error starts with
321
330
  `error: <part>: rollout did not complete in namespace <namespace> — the pods say:`. See
@@ -330,9 +339,12 @@ refusals of a push and of the [Effector](../reference/glossary.md#effector) imag
330
339
  ``error: <layer>: rollout reported success, but the running pod carries <images> — expected <image>. The cluster is serving code this converge did not deploy; `kubectl -n <namespace> rollout restart deploy` and re-run `jr2 up` to resolve it.``
331
340
  - When the rollout completes but no pod matches, `jr2 up` cannot check the image. It continues:
332
341
  `<layer>: WARNING — rollout succeeded but no pod matched <selector> (nothing verified)`
333
- - Before the publish, the Orchestrator must read the image map that `jr2 up` wrote. When it does not read it in time,
334
- `jr2 up` publishes nothing:
335
- ``refusing: after <seconds>s the Orchestrator still reads an older <maps> from its mount — the kubelet has not refreshed it; nothing was published, and the previous Assembly is still current. Run `jr2 up` again``
342
+ - Before the publish, the Orchestrator must read the maps that `jr2 up` wrote, and the digests of the Caller tokens and
343
+ the Hook secrets. With no publish, `jr2 up` waits for the digests only. When the Orchestrator does not read them in
344
+ time, `jr2 up` stops with exit code 1:
345
+ ``refusing: after <seconds>s the Orchestrator still reads an older <names> from its mount — the kubelet has not refreshed it; <what this means>. Run `jr2 up` again``
346
+ `<what this means>` is `nothing was published, and the previous Assembly is still current`, or
347
+ `a Caller token or Hook secret that this converge wrote does not work yet`, or both.
336
348
  - The Orchestrator checks the Assembly again before it makes it current. It loads each Workflow and `jr2.config.ts`. It
337
349
  refuses an [Open](../reference/glossary.md#open) part that nobody bound, a secret that the config does not declare, a
338
350
  Kit version that is not its own, and a zod `input` that no door reads (a Machine that `jr2Setup` did not make). The