@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,296 @@
1
+ # A Machine cuts a Worktree, and the Workspace only clones
2
+
3
+ `workspace()` made one branch Worktree for each Repo Slot from `spec.branch`, and one detached Worktree from
4
+ `spec.reviewSha`. So `spec` collected kinds of Worktree, a slot that is only read got a Worktree that no Agent used, and
5
+ a Machine could not run two coders in one clone, retry a review in a clean folder, or name a branch after its plan. Now
6
+ the Workspace only clones. A Worktree is a folder that a Machine names and makes with a kit Effect, `worktree()`.
7
+
8
+ The layout and the branch order follow the conventions that [gwtmux](https://github.com/snapwich/gwtmux) defined: jr2
9
+ does not call gwtmux and does not depend on it. Three designs were built on real files, attacked, and judged: a design
10
+ with the path as the reference (this one), a design with the branch as the reference, and a design with no step that
11
+ makes a Worktree. A prototype of the chosen design passed 62 of 62 `@kind` scenarios in real pods.
12
+
13
+ ## Decision
14
+
15
+ ### The Workspace
16
+
17
+ - **The Workspace clones.** `spec`, `workspace.branch` and `workspace.review` go. `workGroup` is an option of
18
+ `workspace()`: `workspace(body, { workGroup: 2000 })`.
19
+ - **A handle is the slot's folder, and not a Worktree.** `context.workspace.repos.app` is `/work/app`.
20
+ - **`default/` stays on the Binding's base.** A branch is attached, and a tag or a commit is detached. With no base, it
21
+ is the Repo's default branch. A slot that is only read needs nothing more: an Agent reads `/work/<slot>/default`. No
22
+ work happens in `default/`, and a cut of the branch that it holds is `refused`, and the reason names
23
+ `/work/<slot>/default`.
24
+ - **The author chooses how many Agents work in a Workspace.** The rule "one Agent at a time" goes. Agents in one
25
+ Worktree share git as people in one checkout do. Each coder that needs its own branch gets its own Worktree of the one
26
+ clone.
27
+ - **`/work/.jr2/` is reserved for jr2.** A Repo Slot name cannot start with `.`. An Agent can write under `/work`, so
28
+ nothing there is a record that jr2 trusts.
29
+
30
+ ### `worktree()`
31
+
32
+ ```ts
33
+ worktree(); // a local branch, then origin (tracked), then new
34
+ worktree({ expect: "new" }); // refuse a branch that exists
35
+ worktree({ expect: "existing" }); // refuse a branch that does not exist, and make nothing
36
+
37
+ { path: "/work/app/fix", branch: "docs/123", from?: "v3" } // a branch Worktree
38
+ { path: "/work/app/review", detach: sha } // forced and cleaned on each cut
39
+
40
+ { outcome: "ready", slot, path, branch: string | null, head, found, stale? }
41
+ { outcome: "refused", reason } // nothing changed
42
+ { outcome: "unknown", reason }
43
+ ```
44
+
45
+ - **The path is the reference, and the Machine knows it before the cut.** It is exactly `/work/<slot>/<name>`, with one
46
+ segment that is not `default` and starts with neither `.` nor `-`. So a door word or a planner's word does not become
47
+ a folder tree, and a `run` branch and a `run/a` branch never need nested folders.
48
+ - **`branch` is required unless `detach` is given.** The branch is read from the cut's record, never from the folder or
49
+ from HEAD. A Machine can use one word for both. The rule can relax after v1, and the reverse is a break.
50
+ - **A cut resolves a branch in one order, after a fetch:** a local branch, then `origin/<branch>` with tracking, then a
51
+ new branch from `from` or the Binding's base with no upstream. `found` says which: `local`, `remote` or `none`. A path
52
+ that a cut already made needs no fetch, and `found` is `held`. A detached cut says `commit`.
53
+ - **A failed fetch degrades.** `stale` carries ADR-0053's warning, and the cut uses what the clone holds. A name that
54
+ the clone does not hold is `refused`, because the remote cannot confirm that it is new.
55
+ - **`expect` is static**, so a Chart cannot change it. The string can grow. A boolean cannot, and its absent value and
56
+ its `false` would mean different things.
57
+ - **A cut runs on the `command` machinery**: a kit program in the Harness container, no new wire kind, marked
58
+ idempotent. Each thing that an Agent's word can cause settles as `refused`, and never as `onError` (ADR-0067). A cut
59
+ writes a record before it changes git, so `refused` changes nothing and the next cut in the clone repairs a killed
60
+ cut. It never removes a folder that its record does not name. A re-cut that disagrees with the first cut is `refused`.
61
+ Cuts of one clone are serialized by a lock.
62
+ - **A detached cut is forced from its own record** and cleaned with `-ffd`. Ignored files stay, because a reviewer runs
63
+ the tests (ADR-0028).
64
+ - **A cut needs a Repo Slot.** `jr2 up` and the invoke refuse `worktree()` under a Workspace with no Repo Slot, as they
65
+ refuse a `push` (ADR-0051).
66
+ - **v1 has no kit removal.** The docs give a `command` that runs `git worktree remove`.
67
+
68
+ ### What names a Worktree
69
+
70
+ ```ts
71
+ coder: { prompt, cwd: "/work/app/fix" } // required under Repo Slots
72
+ publish: { worktree: "/work/app/fix", sha } // push
73
+ test: { worktree: "/work/app/fix" } // command
74
+ send: { name: "r.md", worktree: "/work/app/fix" } // http with a file body
75
+ ```
76
+
77
+ - **`cwd` and `worktree` are required under Repo Slots.** A Workspace that only clones has no Worktree for a default to
78
+ name, and `/work` is the wrong default: an Agent's search hits `default/`, and a relative write lands outside each
79
+ Worktree. That is the incident in ADR-0057. A Turn that wants `/work` states it. A Workspace with no Repo Slot, and an
80
+ Agent with `workspace: "none"`, need no `cwd`.
81
+ - **`push` has no `to` and no `branch` in its input.** It keeps its static `slot`. The Orchestrator finds the cut's
82
+ settled row in the run's ledger, by the path and this Sandbox, and tells the Effector which branch to publish. An
83
+ Agent can change all of git in the pod, and it cannot change that row. With a read of HEAD, `git switch main` would
84
+ publish `main`. With an input key, a Chart could aim at any remote branch. A push with no row, a row of another slot,
85
+ or a detached Worktree is `rejected` at stage start. The ledger key is (slot, branch). The local name equals the
86
+ remote name, so an Agent, a Gate and a person in the pod all see the real branch.
87
+ - **A `command` that names a secret and an `http` file body need the same row.** A path alone does not name the target
88
+ of a credential.
89
+ - **A bad Worktree does not add an outcome.** A `command` settles `exited` 127 with the reason in its tail, and an
90
+ `http` file body settles `refused`.
91
+ - **A compile error catches a wrong slot.** `Workspaced` types a handle as the literal `/work/<slot>`, and `jr2Setup`
92
+ maps the body's slots to each Worktree input. The compile check is a help and the guarantee is at run time. It sees
93
+ the slot and the first character of the name, under `jr2Setup`, on a literal path. It does not see a path held as
94
+ `string`, a plain `setup()`, a `repos: open` Machine, or a body that is generic in its slots. A helper must return
95
+ `as const`.
96
+
97
+ ### A Chart
98
+
99
+ - A cut lent to a Chart must state `expect`, and a Chart reads it with the kit guard `jr2.ready`.
100
+ - The door refuses `expect: "existing"` beside a lent force push, because together they let a Chart force-push any
101
+ existing branch that `default/` does not hold.
102
+ - The door refuses a `cwd` that is a slot's folder.
103
+ - A Chart's payload has no `pattern`, so a Chart cannot state the branch rule, and the cut refuses a bad name. A
104
+ hand-written Machine's pick param uses the kit schema `branchName`, so a bad name is refused at the Menu. The cut and
105
+ the push share that rule. Names with `@`, `#` or `+` are refused, as the Effector refuses them.
106
+
107
+ ### Output and the walk
108
+
109
+ - **Every Effect outcome is open.** `worktree()`, `push`, `command`, `http` and `mcp` each hold a stand-in member in
110
+ their union, so that no author can write an exhaustive check. A later outcome is then no break.
111
+ - **The load-time walk refuses an Effect's `onDone` with no unguarded last arm.** A type cannot see a missing arm, and
112
+ with no match a run stays in that state and shows no fault.
113
+
114
+ ### Fetches in one clone
115
+
116
+ All Worktrees of a clone share `refs/remotes/origin/*`. A `git fetch` updates a ref only if it still holds the value
117
+ that the fetch read, so two fetches that overlap on a moved remote can fail with
118
+ `cannot lock ref … is at <sha> but expected <sha>`. The failure does no harm: the ref is already newer, and a second
119
+ fetch works. But it costs a Turn, so `jr2-upload-pack` takes a per-clone lock and keeps it until the fetch ends. It
120
+ takes the lock after it asks the node cache, so a dead remote does not make coders wait in line. The program execs
121
+ `git upload-pack`. That process can end before the fetch writes its refs: that happens when a pack moves. In a shared
122
+ clone, git often keeps the connection open to the end. The lock must last to the end of the fetch in both cases, so a
123
+ small child process that watches the fetch holds it, and ends when the fetch ends. The child watches the `git fetch`
124
+ process and not its parent, because `git remote-ext` ends with the connection.
125
+
126
+ A cut keeps its own lock, and fetches under it. A fetch waits only for a fetch: a cut can wait for the fetch lock, and
127
+ nothing that holds the fetch lock waits for a cut, so the two cannot deadlock. A fetch waits at most 30 s in line, then
128
+ runs with no lock, because the lock only helps and must not fail a fetch.
129
+
130
+ | Measured | 4 coders | 8 coders |
131
+ | ---------------------------------------------------------------------- | --------------------- | -------- |
132
+ | Real pod, `ext::` path, 90 s, moving remote, no lock | 29% of fetches failed | 39% |
133
+ | Local, no lock | 8% | 11% |
134
+ | Local, `core.filesRefLockTimeout=5000` | 8% | 11% |
135
+ | Local, lock for the connection only | 3% | 4% |
136
+ | Local, lock held to the end of the fetch | 0% | 0% |
137
+ | Real pod, same load, lock held to the end of the fetch: failed fetches | 0 of 349 | 0 of 725 |
138
+ | Real pod, same load, with the lock: fetch p95 | 1066 ms | 1078 ms |
139
+ | Real pod, same load, with the lock: cut p95 | 4289 ms | 8256 ms |
140
+
141
+ Git's lock timeout does not help, because no lock is busy: the compare fails. If the wait under the lock is too long in
142
+ a pod, jr2 drops this lock and adds a `@model` claim that an Agent runs the fetch again.
143
+
144
+ ### Smaller rules
145
+
146
+ - **A Pool's `next` reads `{ active, settled, input }`.** `input` is the Pool's input and `settled` holds the ids of the
147
+ finished and failed items, so a Source can fan out over a plan with no state of its own.
148
+ - **A wrapper's door is parsed under a parent too**, so a parent that passes less than a `workspace()` or a `pool()`
149
+ requires fails (ADR-0033).
150
+ - **A Sandbox delete waits for its pod**, because a retry can take the name of a pod that is still going away
151
+ (ADR-0021).
152
+ - **An Agent's commits on a side branch are not published**, and `found` says `held`. A warning field can follow after
153
+ v1.
154
+ - **`jr2 status <run>` shows each path and branch.** `jr2 workspace ls` shows only Sandboxes, because it reads cluster
155
+ labels.
156
+
157
+ ## Example
158
+
159
+ A coder, a detached reviewer, and a signed push of the commit that the reviewer read. The reviewer has its own folder,
160
+ which each round forces to the commit and cleans.
161
+
162
+ ```ts
163
+ type BodyInput = Workspaced<{ prompt: string; branch: string }, "app">;
164
+ const coderTree = (c: BodyInput) => `${c.workspace.repos.app}/work` as const;
165
+ const reviewTree = (c: BodyInput) => `${c.workspace.repos.app}/review` as const;
166
+
167
+ const body = jr2Setup({
168
+ types: {} as { input: BodyInput; context: BodyInput & { reviewed?: string } },
169
+ actors: {
170
+ coder: agent({ model, instructions: "You fix the bug. You commit the fix." }),
171
+ reviewer: agent({ model, workspace: "read", instructions: "You review one commit. You change nothing." }),
172
+ cut: worktree(),
173
+ publish: push({ sign: true, pin: true }),
174
+ },
175
+ }).createMachine({
176
+ initial: "cutting",
177
+ states: {
178
+ cutting: {
179
+ invoke: {
180
+ src: "cut",
181
+ input: ({ context }) => ({ path: coderTree(context), branch: context.branch }),
182
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
183
+ },
184
+ },
185
+ coding: {
186
+ invoke: {
187
+ src: "coder",
188
+ input: ({ context }) => ({ prompt: context.prompt, cwd: coderTree(context), continue: true }),
189
+ },
190
+ on: { finished: "reading" },
191
+ },
192
+ // A cut is idempotent, so it also reads a Worktree. `head` is the tip of the branch, whatever HEAD the coder left.
193
+ reading: {
194
+ invoke: {
195
+ src: "cut",
196
+ input: ({ context }) => ({ path: coderTree(context), branch: context.branch }),
197
+ onDone: [
198
+ {
199
+ guard: ({ event }) => isReady(event.output),
200
+ target: "detaching",
201
+ actions: assign({ reviewed: ({ event }) => readyOf(event.output).head }),
202
+ },
203
+ { target: "notCut" },
204
+ ],
205
+ },
206
+ },
207
+ detaching: {
208
+ invoke: {
209
+ src: "cut",
210
+ input: ({ context }) => ({ path: reviewTree(context), detach: context.reviewed! }),
211
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "reviewing" }, { target: "notCut" }],
212
+ },
213
+ },
214
+ reviewing: {
215
+ invoke: {
216
+ src: "reviewer",
217
+ input: ({ context }) => ({ prompt: `Review ${context.reviewed}.`, cwd: reviewTree(context) }),
218
+ },
219
+ on: { pass: "publishing", revise: "coding" },
220
+ },
221
+ publishing: {
222
+ invoke: {
223
+ src: "publish",
224
+ input: ({ context }) => ({ worktree: coderTree(context), sha: context.reviewed! }),
225
+ onDone: [{ guard: ({ event }) => event.output.outcome === "pushed", target: "done" }, { target: "coding" }],
226
+ },
227
+ },
228
+ done: { type: "final" },
229
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
230
+ },
231
+ });
232
+ ```
233
+
234
+ Concurrent coders in one clone. A Pool in the body runs one worker for each task, and each worker cuts its own Worktree.
235
+ The body cuts its merge target first, so a name conflict is refused before a coder works. Then it merges each branch, in
236
+ one clone with no fetch, and pushes once.
237
+
238
+ ```ts
239
+ const taskTree = (c: WorkerInput) => `${c.workspace.repos.app}/task-${c.id}` as const;
240
+ const mergeTree = (c: BodyInput) => `${c.workspace.repos.app}/merge` as const;
241
+
242
+ // In the worker:
243
+ cutting: { invoke: { src: "cut", input: ({ context }) => ({ path: taskTree(context), branch: `task/${context.id}` }) } },
244
+ coding: { invoke: { src: "coder", input: ({ context }) => ({ prompt: context.title, cwd: taskTree(context) }) } },
245
+
246
+ // In the body:
247
+ cutting: { invoke: { src: "cut", input: ({ context }) => ({ path: mergeTree(context), branch: context.branch }) } },
248
+ working: { invoke: { src: "coders", input: ({ context }) => ({ tasks: context.tasks, workspace: context.workspace }) } },
249
+ merging: {
250
+ invoke: {
251
+ src: "merge", // command(["git", "merge", "--no-edit", arg("branch")])
252
+ input: ({ context }) => ({ branch: `task/${context.left[0]!}`, worktree: mergeTree(context) }),
253
+ },
254
+ },
255
+ publishing: { invoke: { src: "publish", input: ({ context }) => ({ worktree: mergeTree(context) }) } },
256
+ ```
257
+
258
+ ## Considered options
259
+
260
+ - **The branch as the reference: `worktree({ slot, branch })`, with the path as output.** Rejected. The path is known
261
+ only after the cut, so each later state reads it from context, and a Chart needs an output read. `/` in a branch must
262
+ map to a folder. S1 cost 29 more lines against 8 for this design, and its attack found three fatal faults.
263
+ - **No step: a Worktree named as data, made on first use.** Rejected. A Turn has no route for a refused cut, and that is
264
+ the fault of its central idea. A planner's typo becomes a Turn that cannot start. It saves lines in the hard
265
+ scenarios, and it saves nothing in the common one.
266
+ - **The name is the local branch.** Rejected. A door word then reaches a path, a slash needs a mapping, and `run` beside
267
+ `run/a` collides.
268
+ - **`to` on `push`.** Rejected for v1: no scenario needs it, and it can be added with no break. A name chosen after the
269
+ work needs a cut first.
270
+ - **`push` reads HEAD.** Rejected. An Agent can move HEAD.
271
+ - **`default/` always on the Repo's default branch.** Rejected. An Agent would read the wrong version of a pinned
272
+ handbook with no sign, and a read-only slot is a reason for this design.
273
+ - **`cwd` defaults to `/work`.** Rejected, as ADR-0057 rejected it.
274
+ - **A bad path goes to `onError`.** Rejected by ADR-0067: an Agent's param can cause it.
275
+
276
+ ## Consequences
277
+
278
+ - After v1, these are additive: a removal Effect, a sparse checkout, a new Worktree source, `to`, a relaxed `branch` or
279
+ `cwd`, a later outcome, and durable output under `/work/.jr2/` or on its own mount.
280
+ - Park and restore can only restore all of `/work`. A restore from the remote alone cannot work: settled cuts do not run
281
+ again, and unpushed work is gone. v1 does not promise that form.
282
+ - A packaged Machine with two slots still needs a static `slot` on its `push`.
283
+ - A kill of the cut's node process alone can leave `git worktree add` running after the cut's lock frees, because git
284
+ does not inherit the lock.
285
+ - The fetch lock's holder ends as an orphan, so PID 1 must reap it. A User Container whose PID 1 does not reap keeps one
286
+ more zombie for each fetch there: 50 fetches left 50, beside the 52 that git leaves by itself with no jr2 program.
287
+ - A kill in the short `update-ref` step leaves a stale ref lock, and no cut removes it. So that name stays `refused`.
288
+ - Several Agents now share one Sandbox (concurrent coders, or a reviewer beside a coder), and so do the workers of a
289
+ Pool in one clone. They share the one Harness and `/work`. Only the Harness process holds the control credential, and
290
+ each process it starts in `/work` runs confined, so no Agent's code can act as another Agent
291
+ ([ADR-0076](0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md)).
292
+ - This change alters the Frame, the Chart briefing and the door's refusal text. The full `@model` run read 18 of 19
293
+ scenarios. `chart-refusal/off` read 6 of 10, below its floor of 7, and each miss failed at the Menu's validation,
294
+ before the door, on the JSON-string Chart that ADR-0070 records. Run alone, two runs on each side at one time, `main`
295
+ read 8 and 8 of 10, and this change read 9 and 7 of 10. So this change does not lower the cell. The floor stays, and a
296
+ full run can miss it.