@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
@@ -83,6 +83,7 @@ import {
83
83
  MAX_KILLS_BODY,
84
84
  MAX_TOLD,
85
85
  type Notice,
86
+ type SteeringMessage,
86
87
  type Settlement,
87
88
  type StreamEvent,
88
89
  type SubmissionSettledEvent,
@@ -107,10 +108,15 @@ export type HarnessClient = {
107
108
  * `/work` — the stub-Harness run with no Workspace. */
108
109
  cwd?: string;
109
110
  definition: AgentDefinition;
111
+ /** The Agent's slot (ADR-0076), which the Harness states on each control request for this
112
+ * conversation. Omitted only by a caller that drives no Machine (a test of the wire). */
113
+ slot?: string;
110
114
  model?: string;
111
115
  thinkingLevel?: ThinkingLevel;
112
116
  /** The pending notices in this admission's scope (ADR-0062). Omitted when there are none. */
113
117
  notices?: Notice[];
118
+ /** The Steering messages held for this Agent slot (ADR-0002). Omitted when there are none. */
119
+ steering?: SteeringMessage[];
114
120
  /** The admission is for a conversation this process was told the Harness keeps (ADR-0062).
115
121
  * The Harness that keeps none answers 404 and seats none: this verb throws
116
122
  * {@link ConversationNotKept}. */
@@ -382,12 +388,15 @@ export function createHarnessClient(options: HarnessClientOptions): HarnessClien
382
388
  // `machine-doc.ts` and the surface read it — and the Harness neither validates nor
383
389
  // uses it, so it has no business on the Turn's wire.
384
390
  definition: admittedDefinition(sendOptions.definition),
391
+ // Who the conversation is (ADR-0076): the Harness states it on each control request.
392
+ ...(sendOptions.slot === undefined ? {} : { slot: sendOptions.slot }),
385
393
  // Omitted when unset, so an admission with no dials is byte-identical to before.
386
394
  ...(sendOptions.model ? { model: sendOptions.model } : {}),
387
395
  ...(sendOptions.thinkingLevel ? { thinkingLevel: sendOptions.thinkingLevel } : {}),
388
396
  // The Briefing's news (ADR-0062): typed data, the Harness writes the words. Omitted
389
397
  // when there is none, so an admission without notices is byte-identical to before.
390
398
  ...(sendOptions.notices?.length ? { notices: sendOptions.notices } : {}),
399
+ ...(sendOptions.steering?.length ? { steering: sendOptions.steering } : {}),
391
400
  // Omitted when unset, so an admission that is not for a kept conversation is
392
401
  // byte-identical to before.
393
402
  ...(sendOptions.kept ? { kept: true } : {}),
@@ -608,10 +617,11 @@ export function createHarnessClient(options: HarnessClientOptions): HarnessClien
608
617
 
609
618
  /** The definition as the ADMISSION carries it (ADR-0057): identity alone. `description` is
610
619
  * Console material the Orchestrator strips before admission — the Harness has no use for it and
611
- * no longer validates it. Every other field travels, so a field added to the definition reaches
612
- * the Harness without a change here. */
613
- function admittedDefinition(definition: AgentDefinition): Omit<AgentDefinition, "description"> {
614
- const { description: _description, ...identity } = definition;
620
+ * no longer validates it. `steerable` is the Orchestrator's own (ADR-0002): it refuses Callers,
621
+ * and the model never reads it. Every other field travels, so a field added to the definition
622
+ * reaches the Harness without a change here. */
623
+ function admittedDefinition(definition: AgentDefinition): Omit<AgentDefinition, "description" | "steerable"> {
624
+ const { description: _description, steerable: _steerable, ...identity } = definition;
615
625
  return identity;
616
626
  }
617
627
 
@@ -629,9 +639,11 @@ export function harnessAgentRunPort(client: HarnessClient): AgentRunPort {
629
639
  // to the Harness's refusal if it is not a path.
630
640
  ...(input.cwd === undefined ? {} : { cwd: input.cwd }),
631
641
  definition: opts.definition,
642
+ slot: opts.slot,
632
643
  model: input.model,
633
644
  thinkingLevel: input.thinkingLevel,
634
645
  ...(opts.notices?.length ? { notices: opts.notices } : {}),
646
+ ...(opts.steering?.length ? { steering: opts.steering } : {}),
635
647
  ...(opts.kept ? { kept: true } : {}),
636
648
  signal: opts.signal,
637
649
  });
@@ -751,8 +763,9 @@ export function createLiveSetPush(options: {
751
763
  * `invoke: { src: "coder", input: { prompt } }`. The key is the Agent's name.
752
764
  *
753
765
  * The invoke's `input` is the Turn: `prompt` (required), `cwd`, `model`, `thinkingLevel` and
754
- * `continue`. `cwd` is the absolute directory where the Working tools work. Absent, it is the
755
- * Worktree of the Workspace's one Repo Slot. `continue: true` continues the Agent's conversation
766
+ * `continue`. `cwd` is the absolute directory where the Working tools work. Under Repo Slots it
767
+ * is required: a Worktree that a cut made, `<slot>/default` to read, or `/work`. An Agent with
768
+ * `workspace: "none"`, and a Workspace with no Repo Slot, need no `cwd`. `continue: true` continues the Agent's conversation
756
769
  * in this Machine. Absent, each Turn starts a new conversation. `continue` is the literal `true`,
757
770
  * not a `boolean`. A Turn can join only a conversation that an earlier Turn started with
758
771
  * `continue: true`. Thus in a retry loop, put `continue: true` on each Turn, also on the first, so
@@ -778,10 +791,9 @@ export function createLiveSetPush(options: {
778
791
  * - a key in `input` that a Turn does not have: ``agent "<slot>": the Turn's input carries
779
792
  * `<key>`, which a Turn has no use for — its input is its Frame (`prompt`, `cwd`), its Dials
780
793
  * (`model`, `thinkingLevel`), and `continue` (ADR-0057)``
781
- * - no `cwd` under a Workspace with more than one Repo Slot: ``turn <id>: agent "<slot>" works
782
- * under a Workspace carrying more than one Repo Slot (<slots>) and its Turn framed no `cwd` —
783
- * say which Worktree it works in (`cwd: context.workspace.repos.<slot>`, one of those), because
784
- * the kit gives no slot a meaning (ADR-0051) and a Turn's Frame is where it works (ADR-0057)``
794
+ * - no `cwd` under Repo Slots: ``turn <id>: agent "<slot>" works under a Workspace with Repo Slots
795
+ * (<slots>) and its Turn framed no `cwd`: say where it works, a Worktree, or `cwd: "/work"` above
796
+ * them (ADR-0057)``
785
797
  * - a `cwd` that is not an absolute path: ``agent "<slot>": the Turn's Frame carries a `cwd` that
786
798
  * is not an absolute path — the Frame says WHERE this Turn works (ADR-0057), and a Turn rooted
787
799
  * anywhere else would work in the wrong directory silently``. The Harness makes this refusal
@@ -801,7 +813,16 @@ export function createLiveSetPush(options: {
801
813
  * @example
802
814
  * ```ts
803
815
  * import { z } from "zod";
804
- * import { agent, defineEvent, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";
816
+ * import {
817
+ * agent,
818
+ * defineEvent,
819
+ * fail,
820
+ * isReady,
821
+ * jr2Setup,
822
+ * workspace,
823
+ * worktree,
824
+ * type Workspaced,
825
+ * } from "@jr2/orchestrator";
805
826
  *
806
827
  * const finish = defineEvent({
807
828
  * name: "finish",
@@ -811,6 +832,8 @@ export function createLiveSetPush(options: {
811
832
  * const runInput = z.object({ branch: z.string() });
812
833
  * type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
813
834
  *
835
+ * const fixTree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
836
+ *
814
837
  * const body = jr2Setup({
815
838
  * types: {} as { input: BodyInput; context: BodyInput },
816
839
  * events: [finish],
@@ -819,26 +842,35 @@ export function createLiveSetPush(options: {
819
842
  * model: "anthropic/claude-haiku-5-5",
820
843
  * instructions: "You fix failing tests. You change no test.",
821
844
  * }),
845
+ * cut: worktree(),
822
846
  * fail: fail(),
823
847
  * },
824
848
  * }).createMachine({
825
849
  * id: "fix",
826
850
  * context: ({ input }) => input,
827
851
  * on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
828
- * initial: "coding",
852
+ * initial: "cutting",
829
853
  * states: {
854
+ * cutting: {
855
+ * invoke: {
856
+ * src: "cut",
857
+ * input: ({ context }) => ({ path: fixTree(context), branch: context.branch }),
858
+ * onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
859
+ * },
860
+ * },
830
861
  * coding: {
831
862
  * invoke: {
832
863
  * src: "coder",
833
864
  * input: ({ context }) => ({
834
865
  * prompt: "Make `node --test` pass, then commit.",
835
- * cwd: context.workspace.repos.app,
866
+ * cwd: fixTree(context),
836
867
  * thinkingLevel: "high",
837
868
  * }),
838
869
  * },
839
870
  * on: { finish: "done" },
840
871
  * },
841
872
  * done: { type: "final" },
873
+ * notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
842
874
  * failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
843
875
  * lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
844
876
  * },
@@ -847,7 +879,6 @@ export function createLiveSetPush(options: {
847
879
  * export const machine = workspace(body, {
848
880
  * input: runInput,
849
881
  * repos: { app: "https://github.com/you/app.git" },
850
- * spec: ({ input }) => ({ branch: input.branch }),
851
882
  * });
852
883
  * ```
853
884
  *
@@ -856,6 +887,9 @@ export function createLiveSetPush(options: {
856
887
  * @see docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md
857
888
  * @see docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md
858
889
  */
890
+ export function agent<const D extends AgentDeclaration>(
891
+ declaration: D,
892
+ ): AgentLogic & (D extends { workspace: "none" } ? { readonly definition: { readonly workspace: "none" } } : unknown);
859
893
  export function agent(declaration: AgentDeclaration): AgentLogic {
860
894
  // THE authoring surface for an Agent (ADR-0049): one definition in, one actor slot out. The
861
895
  // slot key is the Agent's name (the Harness route, the minted iid, the markers), so a name the
@@ -956,8 +990,8 @@ export function createExecPort(options: {
956
990
  *
957
991
  * Where it runs:
958
992
  * - With no Effect secret in `env`, in the Harness container of the enclosing Workspace's Sandbox.
959
- * It runs in the Worktree of a Repo Slot, or in `/work` in a Workspace with no Repo Slot. The
960
- * Agent's Working tools also run in this container.
993
+ * It runs in the Worktree that `worktree` of the invoke's input names, or in `/work` in a
994
+ * Workspace with no Repo Slot. The Agent's Working tools also run in this container.
961
995
  * - With an Effect secret in `env`, in the Sandbox Effector, against a commit of the branch. This
962
996
  * is the branch tip when it starts, or with `pin: true` the commit that the invoke's `input.sha`
963
997
  * names. The output then says `dirty: true` when the Worktree held edits that the command did
@@ -994,11 +1028,9 @@ export function createExecPort(options: {
994
1028
  * And when it starts, with no Effect secret in `env`:
995
1029
  * - outside a `workspace()`: `command "<slot>" runs in the Harness container of a Workspace, and
996
1030
  * its state is not inside a workspace() — invoke it from a Workspace's body (ADR-0067)`
997
- * - no `slot` under a Workspace with more than one Repo Slot: `command "<slot>" runs under a
998
- * Workspace carrying more than one Repo Slot (<slots>) and names none — say which Worktree it
999
- * runs in: command(argv, { slot: "<slot>" }) (ADR-0051)`
1000
- * - a `slot` that the Workspace does not have: `command "<slot>" names Repo Slot "<name>", which
1001
- * its Workspace does not carry (<slots>)`
1031
+ * - no `worktree` under Repo Slots: `` command "<slot>" runs under a Workspace with Repo Slots
1032
+ * (<slots>) and its input names no `worktree`: say which, a Worktree that a cut gave or
1033
+ * `<slot>/default` ``
1002
1034
  * - an `arg()` with no string in `input`: `command "<slot>": argv slot <<name>> has no string
1003
1035
  * value in its input (got <type>) — map it in the invoke's input`. The angle brackets around the
1004
1036
  * arg's name are in the text: `argv slot <file>`. `<type>` is `nothing` when `input` has no such
@@ -1007,15 +1039,13 @@ export function createExecPort(options: {
1007
1039
  * And when it starts, with an Effect secret in `env`:
1008
1040
  * - outside a `workspace()`: `command "<slot>" runs in the Sandbox Effector of a Workspace, and its
1009
1041
  * state is not inside a workspace() — invoke it from a Workspace's body (ADR-0067)`
1010
- * - no `slot` under a Workspace with more than one Repo Slot: `command "<slot>" runs under a
1011
- * Workspace carrying more than one Repo Slot (<slots>) — say which: { slot: "<slot>" }
1012
- * (ADR-0051)`
1013
1042
  * - a Workspace with no Repo Slot: `command "<slot>" runs under a Workspace with no Repo Slot: a
1014
1043
  * command with an Effect secret runs against one commit of a Repo Slot's branch, and there is
1015
1044
  * none — declare a Repo Slot, or name no secret in its env, and it runs in /work beside the Agent
1016
1045
  * (ADR-0051)`. `jr2 up` refuses it first, with the same reason
1017
- * - a `slot` that the Workspace does not have: `command "<slot>" names Repo Slot "<name>", which
1018
- * its Workspace does not carry (<slots>)`
1046
+ * - a `worktree` that no cut made in this Sandbox: the output is `exited` 127, with `no cut made
1047
+ * <path> in this Sandbox: cut it with worktree()` in its tail. A detached Worktree gets the same
1048
+ * form
1019
1049
  * - `pin: true` and an `input.sha` that is not a full commit id: `command "<slot>" (pin): its
1020
1050
  * input's sha is not a full commit id`
1021
1051
  * - an `arg()` with no string in `input`: the same text as above.
@@ -1023,8 +1053,7 @@ export function createExecPort(options: {
1023
1053
  * @param argv - The program and its arguments: strings and `arg("name")` entries. Or `open`, in a
1024
1054
  * Machine that you publish as a package, for the Instance that registers it to bind with
1025
1055
  * `customize()`.
1026
- * @param options - Optional. `slot`: the Repo Slot whose Worktree the command runs in; needed only
1027
- * where the Workspace has more than one. `timeout`: `"90s"`, `"10m"` or `"1h"`, default
1056
+ * @param options - Optional. `timeout`: `"90s"`, `"10m"` or `"1h"`, default
1028
1057
  * `"10m"`; when it expires, the output is `timeout`. `tail`: how many characters of the end of
1029
1058
  * the output stream to keep, default 4096. `env`: environment variables. Each value is
1030
1059
  * `secret("name")` for the value of an Effect secret, or `secret("name").path` for the path of a
@@ -1035,26 +1064,46 @@ export function createExecPort(options: {
1035
1064
  * @example
1036
1065
  * ```ts
1037
1066
  * import { z } from "zod";
1038
- * import { arg, command, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";
1067
+ * import {
1068
+ * arg,
1069
+ * command,
1070
+ * fail,
1071
+ * isReady,
1072
+ * jr2Setup,
1073
+ * workspace,
1074
+ * worktree,
1075
+ * type Workspaced,
1076
+ * } from "@jr2/orchestrator";
1039
1077
  *
1040
1078
  * const runInput = z.object({ branch: z.string() });
1041
1079
  * type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
1042
1080
  *
1081
+ * const testTree = (context: BodyInput) => `${context.workspace.repos.app}/test` as const;
1082
+ *
1043
1083
  * const body = jr2Setup({
1044
- * types: {} as { input: BodyInput },
1084
+ * types: {} as { input: BodyInput; context: BodyInput },
1045
1085
  * actors: {
1086
+ * cut: worktree(),
1046
1087
  * tests: command(["node", "--test", arg("file")], { timeout: "5m" }),
1047
1088
  * fail: fail(),
1048
1089
  * },
1049
1090
  * }).createMachine({
1050
1091
  * id: "check",
1092
+ * context: ({ input }) => input,
1051
1093
  * on: { "workspace.lost": ".lost" },
1052
- * initial: "testing",
1094
+ * initial: "cutting",
1053
1095
  * states: {
1096
+ * cutting: {
1097
+ * invoke: {
1098
+ * src: "cut",
1099
+ * input: ({ context }) => ({ path: testTree(context), branch: context.branch }),
1100
+ * onDone: [{ guard: ({ event }) => isReady(event.output), target: "testing" }, { target: "notCut" }],
1101
+ * },
1102
+ * },
1054
1103
  * testing: {
1055
1104
  * invoke: {
1056
1105
  * src: "tests",
1057
- * input: { file: "test/greet.test.js" },
1106
+ * input: ({ context }) => ({ file: "test/greet.test.js", worktree: testTree(context) }),
1058
1107
  * onDone: [
1059
1108
  * {
1060
1109
  * guard: ({ event }) => event.output.outcome === "exited" && event.output.code === 0,
@@ -1067,6 +1116,7 @@ export function createExecPort(options: {
1067
1116
  * passed: { type: "final" },
1068
1117
  * // Not final states: each one fails the run, and the run ends `failed`.
1069
1118
  * failed: { invoke: { src: "fail", input: { reason: "the test did not pass" } } },
1119
+ * notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
1070
1120
  * lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
1071
1121
  * },
1072
1122
  * });
@@ -1074,7 +1124,6 @@ export function createExecPort(options: {
1074
1124
  * export const machine = workspace(body, {
1075
1125
  * input: runInput,
1076
1126
  * repos: { app: "https://github.com/you/app.git" },
1077
- * spec: ({ input }) => ({ branch: input.branch }),
1078
1127
  * });
1079
1128
  * ```
1080
1129
  *
@@ -1086,7 +1135,7 @@ export function createExecPort(options: {
1086
1135
  export function command<const A extends readonly (string | Arg)[], const Opt extends CommandOptions = CommandOptions>(
1087
1136
  argv: A,
1088
1137
  options?: Opt,
1089
- ): EffectLogic<CommandInput<A, Opt["pin"]>, CommandOutput> & OpenOf<EnvOpenParts<Opt>>;
1138
+ ): EffectLogic<CommandInput<A, Opt["pin"], Opt>, CommandOutput> & OpenOf<EnvOpenParts<Opt>>;
1090
1139
  /**
1091
1140
  * Make a `command` Effect whose argv is Open: `command(open, options)`, in a Machine that you
1092
1141
  * publish as a package. The Instance that registers the Machine binds the argv one time:
@@ -1103,7 +1152,7 @@ export function command<const A extends readonly (string | Arg)[], const Opt ext
1103
1152
  export function command<const Opt extends CommandOptions = CommandOptions>(
1104
1153
  argv: typeof open,
1105
1154
  options?: Opt,
1106
- ): EffectLogic<OpenCommandInput<Opt["pin"]>, CommandOutput> & OpenEffect<"argv" | EnvOpenParts<Opt>>;
1155
+ ): EffectLogic<OpenCommandInput<Opt["pin"], Opt>, CommandOutput> & OpenEffect<"argv" | EnvOpenParts<Opt>>;
1107
1156
  export function command(
1108
1157
  argv: readonly (string | Arg)[] | typeof open,
1109
1158
  options: CommandOptions = {},
@@ -0,0 +1,33 @@
1
+ // What a Harness container's env tells its start (ADR-0076): which names jr2 composed. The Harness
2
+ // starts as `effector nocore --harness-env -- node …`, and that gives the Harness PROCESS only the
3
+ // names jr2 composed, less each name that loads code from a path (`NODE_OPTIONS`, `LD_*`,
4
+ // `OPENSSL_CONF` …), because the image's `ENV` can name a file that Workspace code writes. The
5
+ // domain, where the Agent's programs run, still gets the container's whole start env.
6
+ //
7
+ // Two marks make the names jr2 composed visible inside the container:
8
+ // - `JR2_HARNESS_ENV_NAMES`: the names of the container's `env`, comma-separated.
9
+ // - The prefix `JR2_ENVFROM_` before each `envFrom` key (with a source's own prefix after it):
10
+ // its keys are not known here, a user's Secret or ConfigMap among them. The start puts each key
11
+ // back under its own name, below a name of `env`, as Kubernetes orders them.
12
+
13
+ /** The env name that lists the names of the Harness container's `env`. */
14
+ export const HARNESS_ENV_NAMES_ENV = "JR2_HARNESS_ENV_NAMES";
15
+
16
+ /** The prefix before each `envFrom` key of a Harness container. */
17
+ export const HARNESS_ENVFROM_PREFIX = "JR2_ENVFROM_";
18
+
19
+ /** The Harness container's `env` with `JR2_HARNESS_ENV_NAMES` last, and its `envFrom` with the
20
+ * prefix `JR2_ENVFROM_`. Both Harness placements use it: a Sandbox's and the Instance Harness. */
21
+ export function markHarnessEnv<E extends { name: string }, F extends { prefix?: string }>(
22
+ env: readonly E[],
23
+ envFrom: readonly F[],
24
+ ): { env: (E | { name: string; value: string })[]; envFrom: F[] } {
25
+ const names = [...new Set(env.map((v) => v.name))].filter((n) => n !== HARNESS_ENV_NAMES_ENV);
26
+ return {
27
+ env: [
28
+ ...env.filter((v) => v.name !== HARNESS_ENV_NAMES_ENV),
29
+ { name: HARNESS_ENV_NAMES_ENV, value: names.join(",") },
30
+ ],
31
+ envFrom: envFrom.map((f) => ({ ...f, prefix: `${HARNESS_ENVFROM_PREFIX}${f.prefix ?? ""}` })),
32
+ };
33
+ }