@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
@@ -43,8 +43,10 @@
43
43
  // containers:
44
44
  //
45
45
  // volume runtime the kit's Harness image, as an `image` volume → /opt/jr2
46
- // volume conversations an emptyDir → /conversations, the Harness container's alone
46
+ // volume conversations an emptyDir → /run/jr2/conversations, the Harness container's alone
47
47
  // (ADR-0031: a Harness restart inside the pod keeps its conversations)
48
+ // volume shell an emptyDir → /run/jr2/shell, the Harness container's alone: the
49
+ // socket of a person's shell (`jr2 workspace shell`, ADR-0076)
48
50
  // initContainer preflight the USER'S image + that volume → ADR-0037's probe, the thing that
49
51
  // proves a registry ref, whose first appearance is this provision
50
52
  // container harness the Sandbox Image, command overridden, /work + /opt/jr2 mounted
@@ -83,11 +85,14 @@ import {
83
85
  custodianBootstrap,
84
86
  custodianComposition,
85
87
  custodianScript,
88
+ CREDENTIAL_KEYS,
89
+ heldStandInKey,
86
90
  CUSTODIAN_BOOTSTRAP_KEY,
87
91
  CUSTODIAN_SCRIPT_KEY,
88
92
  type CustodianComposition,
89
93
  } from "./custodian.ts";
90
- import { readHeldManifest, workspaceHeldPod, type HeldManifest } from "./held-secrets.ts";
94
+ import { heldStandIn, readHeldManifest, workspaceHeldPod, type HeldManifest } from "./held-secrets.ts";
95
+ import { markHarnessEnv } from "./harness-env.ts";
91
96
  import {
92
97
  effectorManifestKey,
93
98
  readSandboxEffectorManifest,
@@ -102,6 +107,8 @@ import {
102
107
  CONVERSATIONS_DIR,
103
108
  CONVERSATIONS_DIR_ENV,
104
109
  CONVERSATIONS_VOLUME,
110
+ SHELL_DIR,
111
+ SHELL_VOLUME,
105
112
  HELD_MOUNT,
106
113
  CA_CONFIGMAP,
107
114
  heldManifestKey,
@@ -112,6 +119,15 @@ import {
112
119
  PRIORITY_CLASS_SANDBOX,
113
120
  REPOS_MOUNT,
114
121
  sandboxCustodianConfigMap,
122
+ ANNOTATION_HOLD,
123
+ ANNOTATION_KEEPALIVE,
124
+ ANNOTATION_WORKSPACE_PATH,
125
+ HOLD_HELD,
126
+ HOLD_RELEASED,
127
+ LABEL_SANDBOX_RUN,
128
+ LABEL_SANDBOX_WORKFLOW,
129
+ LABEL_SANDBOX_WORKSPACE,
130
+ workspaceLabel,
115
131
  } from "./names.ts";
116
132
  import {
117
133
  CONFIGMAPS,
@@ -133,10 +149,14 @@ import {
133
149
  type SandboxObject,
134
150
  type SandboxWatch,
135
151
  } from "./sandbox-watch.ts";
136
- import { effectorKey, harnessToken, harnessTokenDigest, sandboxToken } from "./tokens.ts";
152
+ import { controlStandIn, controlToken, effectorKey, harnessToken, harnessTokenDigest, sandboxToken } from "./tokens.ts";
137
153
  import type { AttachError, AttachRequest, AttachResponse } from "./wire.ts";
138
154
  import type { Continuity, MemoryKill, PlacingWait, ProvisionedRepo, SandboxLoss, SandboxPort } from "./workspace.ts";
139
155
 
156
+ /** A Secret's `data`: each value base64'd. */
157
+ const base64Values = (values: Record<string, string>): Record<string, string> =>
158
+ Object.fromEntries(Object.entries(values).map(([k, v]) => [k, Buffer.from(v).toString("base64")]));
159
+
140
160
  /** Where jr2's runtime lands in every container that gets it (ADR-0037). `/opt/jr2` and not `/app`
141
161
  * because a stranger's base may already use `/app`, and one layout must serve both the stock
142
162
  * Harness image and an arbitrary Sandbox Image. It is a PUBLISHED surface: `bin/` beside `lib/`
@@ -156,11 +176,21 @@ const RUNTIME_VOLUME_MOUNT = { name: RUNTIME_VOLUME, mountPath: RUNTIME_MOUNT, s
156
176
  /** The primary container's command (ADR-0037). Absolute, so it never depends on the image's
157
177
  * `WORKDIR`, and identical to the stock Harness image's own `CMD` — one runtime, two placements.
158
178
  * `tini` is PID 1 (ADR-0061): the Agent's processes are the Harness's children, and a tree the
159
- * memory guard kills must leave no zombies behind. */
179
+ * memory guard kills must leave no zombies behind. The Harness holds the Stand-ins in its memory,
180
+ * and below Landlock ABI 6 a confined child can still signal it (ADR-0076): `effector nocore`
181
+ * starts it with no core file, so a dumping signal writes nothing a child reads, and
182
+ * `--disable-sigusr1` keeps SIGUSR1 from opening Node's inspector, which would run a child's code
183
+ * in the Harness. `--harness-env` gives the Harness process only the names jr2 composed, less each
184
+ * name that loads code from a path, and the domain the whole start env (`harness-env.ts`). */
160
185
  const HARNESS_COMMAND = [
161
186
  `${RUNTIME_MOUNT}/bin/tini`,
162
187
  "--",
188
+ `${RUNTIME_MOUNT}/bin/effector`,
189
+ "nocore",
190
+ "--harness-env",
191
+ "--",
163
192
  `${RUNTIME_MOUNT}/bin/node`,
193
+ "--disable-sigusr1",
164
194
  `${RUNTIME_MOUNT}/src/main.ts`,
165
195
  ];
166
196
 
@@ -753,6 +783,7 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
753
783
  name: string;
754
784
  runId: string;
755
785
  workflow: string;
786
+ path: string;
756
787
  image?: string;
757
788
  user?: string;
758
789
  workGroup?: number;
@@ -785,8 +816,16 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
785
816
  metadata: {
786
817
  name: req.name,
787
818
  namespace: ns,
788
- // The run↔workspace link `jr2 ls` groups by (ADR-0009/0012) — readable without the host.
789
- labels: { "jr2.dev/run": req.runId, "jr2.dev/workflow": req.workflow },
819
+ // The run↔workspace link the `jr2 workspace` verbs read (ADR-0009/0012), without the host:
820
+ // the run, the Workflow and a selector form of the path as labels, the exact path as an
821
+ // annotation. The hold mark is `held` from this first write (ADR-0021); the Lease writes it
822
+ // again with each renewal, and `released` when it stops for good.
823
+ labels: {
824
+ [LABEL_SANDBOX_RUN]: req.runId,
825
+ [LABEL_SANDBOX_WORKFLOW]: req.workflow,
826
+ ...(req.path ? { [LABEL_SANDBOX_WORKSPACE]: workspaceLabel(req.path) } : {}),
827
+ },
828
+ annotations: { ...(req.path ? { [ANNOTATION_WORKSPACE_PATH]: req.path } : {}), [ANNOTATION_HOLD]: HOLD_HELD },
790
829
  },
791
830
  spec: {
792
831
  // The Sandbox Image, unmodified (ADR-0037) — the user's tools, its own USER and HOME, and
@@ -834,8 +873,14 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
834
873
  // Never empty: the Custodian's address is unconditional. The seat's own vars (the fallback
835
874
  // `HOME`) come FIRST, so the instance's `harness.env` can still override them the way it
836
875
  // overrides anything the image set.
837
- env: [...seat.env, ...harnessEnv(req.name, custodian, cpuHintEnv())],
838
- ...(cfg().envFrom?.length ? { envFrom: cfg().envFrom } : {}),
876
+ // Marked (`harness-env.ts`, ADR-0076): the Harness's start tells jr2's names from the image's.
877
+ ...(() => {
878
+ const marked = markHarnessEnv(
879
+ [...seat.env, ...harnessEnv(req.name, custodian, cpuHintEnv())],
880
+ cfg().envFrom ?? [],
881
+ );
882
+ return { env: marked.env, ...(marked.envFrom.length ? { envFrom: marked.envFrom } : {}) };
883
+ })(),
839
884
  // What the AGENT gets: an address on its own loopback and a Stand-in for every credential,
840
885
  // and no credential anywhere. The Custodian beside it holds them (ADR-0013, ADR-0059).
841
886
  sidecars,
@@ -865,6 +910,9 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
865
910
  // that Workspace is `Lost` (ADR-0021) — and mounted below into the Harness container
866
911
  // ALONE: the User Container must not read an Agent's history.
867
912
  { name: CONVERSATIONS_VOLUME, emptyDir: {} },
913
+ // The shell socket's folder (ADR-0076): the Harness listens there for `jr2 workspace
914
+ // shell`, in the Harness container ALONE, where no process that it confines makes a file.
915
+ { name: SHELL_VOLUME, emptyDir: {} },
868
916
  // Only for ADR-0037's fallback seat: uid 1000 on a stranger's base has no home at all.
869
917
  ...seat.homeVolume,
870
918
  // The Custodian's (its values, leaves and config), and the trust ConfigMap (ADR-0020).
@@ -879,6 +927,7 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
879
927
  { name: "work", mountPath: WORK_ROOT },
880
928
  RUNTIME_VOLUME_MOUNT,
881
929
  { name: CONVERSATIONS_VOLUME, mountPath: CONVERSATIONS_DIR },
930
+ { name: SHELL_VOLUME, mountPath: SHELL_DIR },
882
931
  ...seat.homeMount,
883
932
  ...custodian.harnessMounts,
884
933
  ],
@@ -902,7 +951,7 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
902
951
  * `data`, not `stringData`: a server-side apply owns the fields it names, and `stringData` is
903
952
  * write-only — it never reads back as the field applied.
904
953
  */
905
- const applyTokenSecret = async (name: string, owner: KubeObject): Promise<void> => {
954
+ const applyTokenSecret = async (name: string, owner: KubeObject, manifest: HeldManifest): Promise<void> => {
906
955
  if (!opts.signingKey) throw new Error("kubeSandbox: a Custodian needs a signingKey to mint its Sandbox token");
907
956
  const uid = owner.metadata?.uid;
908
957
  if (!uid) throw new Error(`Sandbox "${name}": the CR's apply answered with no uid to own its token Secret`);
@@ -925,7 +974,19 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
925
974
  ],
926
975
  },
927
976
  type: "Opaque",
928
- data: { JR2_SANDBOX_TOKEN: Buffer.from(sandboxToken(opts.signingKey, name)).toString("base64") },
977
+ // The pod's credentials (ADR-0076, C1, C1b): its fetch token and its control token, which the
978
+ // Custodian alone mounts; its secret control Stand-in; and one secret Stand-in per held secret
979
+ // the pod's manifest names, which the Custodian (for its swap) and the Harness container (as
980
+ // files under `/run/jr2/`) mount. Every one a signed name, so a re-provision re-applies the
981
+ // same values. Never a ConfigMap, the CR, an env, an event or a log line.
982
+ data: base64Values({
983
+ [CREDENTIAL_KEYS.fetchToken]: sandboxToken(opts.signingKey, name),
984
+ [CREDENTIAL_KEYS.controlToken]: controlToken(opts.signingKey, name),
985
+ [CREDENTIAL_KEYS.controlStandIn]: controlStandIn(opts.signingKey, name),
986
+ ...Object.fromEntries(
987
+ manifest.secrets.map((s) => [heldStandInKey(s.name), heldStandIn(opts.signingKey!, name, s.name)]),
988
+ ),
989
+ }),
929
990
  });
930
991
  };
931
992
 
@@ -1030,7 +1091,7 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
1030
1091
  },
1031
1092
  data: {
1032
1093
  [CUSTODIAN_BOOTSTRAP_KEY]: JSON.stringify(custodianBootstrap(manifest, orchestrator)),
1033
- [CUSTODIAN_SCRIPT_KEY]: custodianScript(manifest),
1094
+ [CUSTODIAN_SCRIPT_KEY]: custodianScript(manifest, { fetch: true }),
1034
1095
  },
1035
1096
  });
1036
1097
  };
@@ -1257,8 +1318,9 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
1257
1318
  image: refs.custodian,
1258
1319
  pod,
1259
1320
  config: sandboxCustodianConfigMap(req.name),
1260
- token: { secret: secretName(req.name), key: "JR2_SANDBOX_TOKEN" },
1321
+ credentials: { secret: secretName(req.name) },
1261
1322
  sandbox: req.name,
1323
+ ...(req.secrets?.length ? { granted: req.secrets } : {}),
1262
1324
  caBundle: cfg().caBundle === true,
1263
1325
  resources: split.custodian,
1264
1326
  });
@@ -1287,7 +1349,7 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
1287
1349
  sandboxes();
1288
1350
  const applied = await kube().apply(SANDBOXES, ns, cr).catch(noOperator(req.name, "Sandbox"));
1289
1351
  // After the CR: its uid owns both, so they go when it goes.
1290
- await applyTokenSecret(req.name, applied);
1352
+ await applyTokenSecret(req.name, applied, manifest);
1291
1353
  await applyCustodianConfig(req.name, applied, manifest);
1292
1354
  if (effectorManifest) {
1293
1355
  await applyEffectorKey(req.name, applied);
@@ -1403,24 +1465,44 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
1403
1465
  const { identity, key } = repoIdentity(r.url);
1404
1466
  return { slot: r.slot, url: r.url, identity, key, ...(r.ref !== undefined ? { ref: r.ref } : {}) };
1405
1467
  }),
1406
- branch: req.spec.branch,
1407
- ...(req.spec.reviewSha ? { reviewSha: req.spec.reviewSha } : {}),
1408
1468
  };
1409
- const { repos, review } = await postAttach(req.name, endpoint, body);
1469
+ const { repos, bases } = await postAttach(req.name, endpoint, body);
1410
1470
  const stale = staleSlots(req.repos, staleByName.get(req.name));
1411
- return { repos, ...(review ? { review } : {}), ...(stale ? { stale } : {}) };
1471
+ return { repos, bases, ...(stale ? { stale } : {}) };
1412
1472
  },
1413
1473
 
1414
1474
  leaseIntervalMs,
1415
1475
 
1416
1476
  async renew(name) {
1417
- // A write, and only that (ADR-0021): the stamp the operator's idle GC reads. What the
1418
- // workspace IS comes from the watch, never from this answer.
1477
+ // A write, and only that (ADR-0021): the stamp the operator's idle GC reads, and the hold
1478
+ // mark, written again so a restored run's Lease marks the Sandbox `held`. What the workspace
1479
+ // IS comes from the watch, never from this answer.
1419
1480
  await kube().patch(SANDBOXES, ns, name, {
1420
- metadata: { annotations: { "jr2.dev/keepalive": new Date().toISOString() } },
1481
+ metadata: { annotations: { [ANNOTATION_KEEPALIVE]: new Date().toISOString(), [ANNOTATION_HOLD]: HOLD_HELD } },
1421
1482
  });
1422
1483
  },
1423
1484
 
1485
+ async releaseHold(name) {
1486
+ // The Lease stopped for good (ADR-0021): no run holds this Sandbox now, and `jr2 workspace rm`
1487
+ // may remove it. A write, and only that.
1488
+ await kube().patch(SANDBOXES, ns, name, { metadata: { annotations: { [ANNOTATION_HOLD]: HOLD_RELEASED } } });
1489
+ },
1490
+
1491
+ async releaseRun(runId) {
1492
+ // A restore ended this run without hosting it (ADR-0021): no Lease runs, so each of its
1493
+ // Sandboxes gets the mark here. The list is the cluster's, not the watch's cache, which may
1494
+ // not have listed yet at boot.
1495
+ const list = await kube().list<SandboxObject>(SANDBOXES, ns, { labelSelector: `${LABEL_SANDBOX_RUN}=${runId}` });
1496
+ await Promise.all(
1497
+ list.items.flatMap((sb) => {
1498
+ const name = sb.metadata?.name;
1499
+ return name
1500
+ ? [kube().patch(SANDBOXES, ns, name, { metadata: { annotations: { [ANNOTATION_HOLD]: HOLD_RELEASED } } })]
1501
+ : [];
1502
+ }),
1503
+ );
1504
+ },
1505
+
1424
1506
  continuity(name, listener) {
1425
1507
  // The watch's word on this name (ADR-0063): the first list, then every event. A dropped
1426
1508
  // watch says nothing, so this says nothing either — unknown is never loss.
@@ -1458,7 +1540,20 @@ export function kubeSandbox(opts: KubeSandboxOptions = {}): SandboxPort {
1458
1540
  async destroy(name) {
1459
1541
  staleByName.delete(name);
1460
1542
  // The token Secret is the CR's child from birth, so deleting the CR reaps it (ADR-0001).
1461
- await kube().delete(SANDBOXES, ns, name);
1543
+ await kube().delete(SANDBOXES, ns, name, { foreground: true });
1544
+ // A retry of the same invoke id takes the same name, and the pod takes it too: a new Sandbox
1545
+ // must not find the old pod on its way out, and read `Lost` (ADR-0075). So the wait is
1546
+ // for the pod as well: foreground keeps the CR until the pod is gone. Bounded: a stuck finalizer
1547
+ // is the operator's to report, and the run does not wait on it for ever.
1548
+ for (let i = 0; i < 120; i++) {
1549
+ if (
1550
+ (await kube()
1551
+ .get<SandboxObject>(SANDBOXES, ns, name)
1552
+ .catch(() => undefined)) === undefined
1553
+ )
1554
+ return;
1555
+ await new Promise((resolve) => setTimeout(resolve, 500));
1556
+ }
1462
1557
  },
1463
1558
  };
1464
1559
  }