@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
package/console/style.css CHANGED
@@ -91,9 +91,25 @@ button:hover {
91
91
  color: var(--phosphor);
92
92
  }
93
93
 
94
+ /* The page under the nav: the work row above, the bottom drawer across the full width below. */
94
95
  main {
95
96
  flex: 1;
96
97
  display: flex;
98
+ flex-direction: column;
99
+ min-height: 0;
100
+ }
101
+
102
+ /* The work row: the rail, then the Machine and the right drawer. */
103
+ #work {
104
+ flex: 1;
105
+ display: flex;
106
+ min-width: 0;
107
+ min-height: 0;
108
+ }
109
+ #upper {
110
+ flex: 1;
111
+ display: flex;
112
+ min-width: 0;
97
113
  min-height: 0;
98
114
  }
99
115
 
@@ -270,6 +286,199 @@ main {
270
286
  font-family: var(--mono);
271
287
  }
272
288
 
289
+ /* A run on an older Assembly (ADR-0069): the graph is the run's own Machine. */
290
+ .notice-line {
291
+ color: var(--amber);
292
+ font-family: var(--mono);
293
+ }
294
+ .older-assembly {
295
+ font-size: 11px;
296
+ margin-right: 6px;
297
+ }
298
+ .run-reason {
299
+ flex-basis: 100%;
300
+ font-size: 11px;
301
+ white-space: normal;
302
+ }
303
+ .runs-head {
304
+ font-size: 10px;
305
+ letter-spacing: 0.14em;
306
+ text-transform: uppercase;
307
+ cursor: default;
308
+ }
309
+
310
+ /* ---- The bottom drawer: the selected run's conversations (ADR-0023, ADR-0032) ---- */
311
+
312
+ #bottom-drawer {
313
+ position: relative;
314
+ display: flex;
315
+ flex-direction: column;
316
+ flex-shrink: 0;
317
+ min-height: 0;
318
+ background: var(--ink-2);
319
+ border-top: 1px solid var(--line);
320
+ }
321
+ /* A window made shorter after the height was set: the Machine keeps at least 160px. */
322
+ #bottom-drawer.bottom--open {
323
+ max-height: max(120px, calc(100vh - 160px));
324
+ }
325
+ .bottom-resize {
326
+ touch-action: none; /* a drag on a touch screen moves the edge, not the page */
327
+ position: absolute;
328
+ top: -3px;
329
+ left: 0;
330
+ right: 0;
331
+ height: 6px;
332
+ cursor: ns-resize;
333
+ z-index: 1;
334
+ }
335
+ .bottom-tabs {
336
+ display: flex;
337
+ align-items: center;
338
+ gap: 4px;
339
+ padding: 6px 12px;
340
+ overflow-x: auto;
341
+ flex-shrink: 0;
342
+ }
343
+ .bottom-title {
344
+ font-size: 11px;
345
+ letter-spacing: 0.14em;
346
+ text-transform: uppercase;
347
+ color: var(--text-dim);
348
+ margin: 0 8px 0 4px;
349
+ }
350
+ .slot-tab {
351
+ font-size: 12px;
352
+ color: var(--text-dim);
353
+ border-color: transparent;
354
+ white-space: nowrap;
355
+ }
356
+ .slot-tab.tab--active {
357
+ color: var(--text);
358
+ border-color: var(--line);
359
+ }
360
+ .live-dot {
361
+ display: inline-block;
362
+ width: 7px;
363
+ height: 7px;
364
+ border-radius: 50%;
365
+ background: var(--phosphor);
366
+ margin-right: 6px;
367
+ vertical-align: middle;
368
+ }
369
+ .bottom-body {
370
+ flex: 1;
371
+ display: flex;
372
+ min-height: 0;
373
+ border-top: 1px solid var(--line-soft);
374
+ }
375
+ .conversation-pane {
376
+ flex: 1;
377
+ min-width: 0;
378
+ /* In a column (a narrow screen), the pane's own minimum would be the whole conversation: it
379
+ would spill out of the drawer, and push the Steering box off the screen. */
380
+ min-height: 0;
381
+ display: flex;
382
+ flex-direction: column;
383
+ }
384
+ #conversation {
385
+ flex: 1;
386
+ overflow-y: auto;
387
+ padding: 8px 16px 16px;
388
+ }
389
+ .conversation-block + .conversation-block {
390
+ margin-top: 16px;
391
+ border-top: 1px dashed var(--line);
392
+ padding-top: 8px;
393
+ }
394
+ .conversation-head {
395
+ font-size: 11px;
396
+ margin-bottom: 6px;
397
+ }
398
+ .conv-text,
399
+ .conv-body {
400
+ white-space: pre-wrap;
401
+ word-break: break-word;
402
+ }
403
+ .conv-text {
404
+ margin: 6px 0;
405
+ }
406
+ #conversation details {
407
+ margin: 4px 0;
408
+ }
409
+ #conversation summary {
410
+ cursor: pointer;
411
+ white-space: nowrap;
412
+ overflow: hidden;
413
+ text-overflow: ellipsis;
414
+ }
415
+ .conv-body {
416
+ margin: 4px 0 4px 16px;
417
+ padding: 6px 10px;
418
+ border-left: 2px solid var(--line);
419
+ }
420
+ .conv-label {
421
+ font-size: 10px;
422
+ letter-spacing: 0.1em;
423
+ text-transform: uppercase;
424
+ color: var(--text-dim);
425
+ }
426
+ .conv-thinking {
427
+ color: var(--text-dim);
428
+ }
429
+ .conv-steering .conv-label,
430
+ .conv-steering .conv-body {
431
+ color: var(--blue);
432
+ }
433
+ .conv-notice .conv-label,
434
+ .conv-notice .conv-body {
435
+ color: var(--amber);
436
+ }
437
+ .conv-call .conv-label {
438
+ color: var(--phosphor);
439
+ }
440
+ .conv-answer {
441
+ border-left-color: var(--phosphor);
442
+ }
443
+ .conv-refused .conv-label,
444
+ .conv-refused .conv-answer {
445
+ color: var(--red);
446
+ border-left-color: var(--red);
447
+ }
448
+ .conv-mark {
449
+ margin: 6px 0;
450
+ font-size: 11px;
451
+ color: var(--text-dim);
452
+ }
453
+ .conv-cut,
454
+ .conv-swept {
455
+ color: var(--orange);
456
+ }
457
+ .steering-box {
458
+ width: 300px;
459
+ flex-shrink: 0;
460
+ padding: 8px 12px;
461
+ border-left: 1px solid var(--line-soft);
462
+ display: flex;
463
+ flex-direction: column;
464
+ gap: 6px;
465
+ }
466
+ .steering-box textarea {
467
+ flex: 1;
468
+ min-height: 60px;
469
+ }
470
+ /* A narrow screen: the Steering box goes under the conversation, not beside it. */
471
+ @media (max-width: 720px) {
472
+ .bottom-body {
473
+ flex-direction: column;
474
+ }
475
+ .steering-box {
476
+ width: auto;
477
+ border-left: 0;
478
+ border-top: 1px solid var(--line-soft);
479
+ }
480
+ }
481
+
273
482
  /* ---- Machine (SVG) ---- */
274
483
 
275
484
  /* Every box is click-to-select (outline only — the click is reserved beyond that). */
@@ -490,6 +699,27 @@ marker.arrow--error path {
490
699
  outline: none;
491
700
  border-color: var(--phosphor);
492
701
  }
702
+ #caller {
703
+ font-family: var(--mono);
704
+ color: var(--text);
705
+ max-width: 260px;
706
+ overflow: hidden;
707
+ text-overflow: ellipsis;
708
+ white-space: nowrap;
709
+ }
710
+ #login-note {
711
+ color: var(--red);
712
+ max-width: 260px;
713
+ overflow: hidden;
714
+ text-overflow: ellipsis;
715
+ white-space: nowrap;
716
+ }
717
+ #caller[hidden],
718
+ #sign-out[hidden],
719
+ #token[hidden],
720
+ #login-note[hidden] {
721
+ display: none;
722
+ }
493
723
  .token-state {
494
724
  font-size: 11px;
495
725
  letter-spacing: 0.04em;
@@ -611,6 +841,7 @@ ul {
611
841
  display: flex;
612
842
  gap: 8px;
613
843
  align-items: baseline;
844
+ flex-wrap: wrap;
614
845
  }
615
846
  .wf-runs li:hover {
616
847
  border-color: var(--line);
@@ -1,5 +1,5 @@
1
- jr2 is newer than your training data. Before you write a Machine or change jr2.config.ts, read the bundled docs in node_modules/@jr2/orchestrator/docs/. They are the docs of this Instance's Kit version, 0.5.1. Start with guides/write-a-workflow.md and with reference/authoring-surface.md, the contents page of the Authoring surface. Read one page with each call of your file tool, because a file tool cuts off a long output. Before you give a change to the user, run `npx --no jr2 check` in the Instance folder. It does the typecheck and the load of each Workflow that `jr2 up` does first, with no cluster, and it gives the same refusals.
1
+ jr2 is newer than your training data. Before you write a Machine or change jr2.config.ts, read the bundled docs in node_modules/@jr2/orchestrator/docs/. They are the docs of this Instance's Kit version, 0.7.0. Start with guides/write-a-workflow.md and with reference/authoring-surface.md, the contents page of the Authoring surface. Read one page with each call of your file tool, because a file tool cuts off a long output. Before you give a change to the user, run `npx --no jr2 check` in the Instance folder. It does the typecheck and the load of each Workflow that `jr2 up` does first, with no cluster, and it gives the same refusals.
2
2
 
3
3
  A final state means that the work succeeded: the run ends `done`. When the work did not succeed, invoke `fail()` from a state (reference/authoring-surface/fail.md), and the run ends `failed`. Do not throw to fail: a throw is a defect, and the run ends `error`.
4
4
 
5
- [jr2 docs index]|root: ./node_modules/@jr2/orchestrator/docs|reference:{authoring-surface.md,machines.md,config.md,cli.md,http-api.md,mechanism-events.md,glossary.md,decisions.md}|reference/authoring-surface:{one file per export and type; reference/authoring-surface.md lists them}|guides:{iterate-on-a-machine-on-kind.md,write-a-workflow.md,bind-open-parts.md,set-an-agents-access-and-dials.md,run-a-command-or-call-a-url.md,push-and-sign-a-branch.md,start-a-run-from-a-run.md,add-tools-to-the-sandbox.md,size-a-workspace.md,run-one-worker-per-item.md,publish-a-machine-as-an-npm-package.md,let-an-agent-write-a-chart.md,run-a-chart-by-name.md,start-a-run.md,answer-a-gate.md,watch-a-run.md,look-inside-a-sandbox.md,cancel-a-run.md,open-the-console.md,use-a-local-model.md,use-a-hosted-provider.md,give-the-cluster-git-credentials.md,move-from-kind-to-a-shared-cluster.md,mirror-the-kit-images.md,upgrade-the-kit-version.md,clean-up.md,fix-a-failed-converge.md}|concepts:{machines-and-workflows.md,agents-and-turns.md,the-menu.md,gates.md,effects.md,workspaces.md,composition.md,charts.md,pools-and-sources.md,architecture.md,secrets-and-trust.md,converge.md,durable-runs.md}|.:{index.md,why.md}|get-started:{install.md,create-an-instance.md,connect-a-model.md,a-model-decides.md,an-agent-in-a-sandbox.md,have-your-assistant-write-a-machine.md}|reference/decisions:{one file per ADR; reference/decisions.md lists them}
5
+ [jr2 docs index]|root: ./node_modules/@jr2/orchestrator/docs|reference:{authoring-surface.md,machines.md,hooks.md,config.md,cli.md,http-api.md,mechanism-events.md,glossary.md,decisions.md}|reference/authoring-surface:{one file per group, export and type; reference/authoring-surface.md lists them}|guides:{iterate-on-a-machine-on-kind.md,write-a-workflow.md,bind-open-parts.md,set-an-agents-access-and-dials.md,give-an-agent-mcp-tools.md,cut-a-worktree.md,run-a-command-or-call-a-url.md,call-an-mcp-tool-from-a-machine.md,push-and-sign-a-branch.md,start-a-run-from-a-run.md,add-tools-to-the-sandbox.md,write-a-tool-as-an-mcp-server.md,size-a-workspace.md,run-one-worker-per-item.md,start-a-run-for-each-alert.md,write-a-hook-kind.md,publish-a-machine-as-an-npm-package.md,let-an-agent-write-a-chart.md,run-a-chart-by-name.md,start-a-run.md,answer-a-gate.md,answer-a-gate-from-a-forge.md,steer-an-agent.md,watch-a-run.md,read-a-conversation.md,look-inside-a-sandbox.md,cancel-a-run.md,open-the-console.md,use-a-local-model.md,use-a-hosted-provider.md,give-the-cluster-git-credentials.md,give-a-caller-a-scope.md,move-from-kind-to-a-shared-cluster.md,mirror-the-kit-images.md,upgrade-the-kit-version.md,clean-up.md,fix-a-failed-converge.md}|concepts:{machines-and-workflows.md,agents-and-turns.md,the-menu.md,gates.md,effects.md,workspaces.md,composition.md,charts.md,pools-and-sources.md,architecture.md,secrets-and-trust.md,callers-and-hooks.md,converge.md,durable-runs.md}|.:{index.md,why.md}|get-started:{install.md,create-an-instance.md,connect-a-model.md,a-model-decides.md,an-agent-in-a-sandbox.md,have-your-assistant-write-a-machine.md}|reference/decisions:{one file per ADR; reference/decisions.md lists them}
@@ -14,10 +14,10 @@ what a state sets for one Turn, and how a Turn ends.
14
14
 
15
15
  ## Why the work is in Turns
16
16
 
17
- A long conversation in which a model decides all the work is difficult to review and difficult to control. In jr2, each
18
- state of the Machine asks the Agent for one thing. The Agent does that thing, then picks an event. The Machine decides
19
- where the run goes next. Thus the Agent does one thing at a time, and the [Console](../reference/glossary.md#console)
20
- shows the state of each Turn.
17
+ A long [Conversation](../reference/glossary.md#conversation) in which a model decides all the work is difficult to
18
+ review and difficult to control. In jr2, each state of the Machine asks the Agent for one thing. The Agent does that
19
+ thing, then picks an event. The Machine decides where the run goes next. Thus the Agent does one thing at a time, and
20
+ the [Console](../reference/glossary.md#console) shows the state of each Turn.
21
21
 
22
22
  A model cannot correctly control some parts of a Turn, so jr2 controls them. jr2 sets where the Agent works and how its
23
23
  Turn ends. It also decides what to do when a Turn does not end. You do not write that code, so you cannot forget it.
@@ -35,6 +35,8 @@ Agent. A state invokes it with `src: "coder"`. The definition is plain data, and
35
35
  | `workspace` | What the Agent can do to the Workspace: `"write"` (the default), `"read"` or `"none"`. |
36
36
  | `thinkingLevel` | How hard the model thinks, when the state sets no other level. The default is `"off"`. |
37
37
  | `description` | A short text for the people who read the Machine. The model does not read it. |
38
+ | `steerable` | `false` refuses a Steering message from a Caller. The default is `true`. |
39
+ | `mcp` | The MCP servers whose tools the Agent can call, each with its allowlist. |
38
40
 
39
41
  [`AgentDefinition`](../reference/authoring-surface/type-agentdefinition.md) gives each field.
40
42
 
@@ -49,8 +51,10 @@ for one Turn, because then the name of the Agent would not tell what it is.
49
51
  ## The Working tools
50
52
 
51
53
  The [Working tools](../reference/glossary.md#working-tools) are the file and shell tools of an Agent: read, write, edit,
52
- bash, grep and glob. The [Harness](../reference/glossary.md#harness) runs them in its own container. The `workspace`
53
- field selects them:
54
+ bash, grep and glob. The [Harness](../reference/glossary.md#harness) runs them in its own container. Each program that
55
+ they start, and the file I/O of read, write and edit, runs confined with Landlock. It can do all that the user of the
56
+ container can do, but it cannot read what the Harness holds. [Secrets and trust](secrets-and-trust.md) tells why. The
57
+ `workspace` field selects the Working tools:
54
58
 
55
59
  - `"write"` gives all the Working tools.
56
60
  - `"read"` gives no write tool and no edit tool. The Agent keeps bash, so a command can still write a file. A review
@@ -64,14 +68,39 @@ The field also tells where the Turn runs. An Agent with `"write"` or `"read"` wo
64
68
  [Instance Harness](../reference/glossary.md#instance-harness), also when a `workspace()` holds it.
65
69
  [Architecture](architecture.md) shows where each Harness runs.
66
70
 
71
+ ## The MCP tools
72
+
73
+ The [MCP tools](../reference/glossary.md#mcp-tools) of an Agent are the tools of the MCP servers that its definition
74
+ names. They let the Agent act on a service, such as a chat or a ticket tracker, with a credential that it never reads.
75
+ The `mcp` block of `jr2.config.ts` declares each server by a name of yours, and the `mcp` field of the definition names
76
+ the servers and the tools:
77
+
78
+ - A remote server needs an allowlist: a list of tool names, or `"*"`. The Harness gives the model only those tools. The
79
+ token of the server is a [Held secret](../reference/glossary.md#held-secret), so the model and the code of the
80
+ Workspace never read it. Thus the list is a guarantee, except where Workspace code can also spend the token. There,
81
+ `jr2 up` takes only `"*"`.
82
+ - A stdio server is a program of the [Sandbox Image](../reference/glossary.md#sandbox-image). It runs as Workspace code,
83
+ inside the confinement of the Sandbox, so it takes no list. A Menu-only Agent cannot name one.
84
+
85
+ A call of an MCP tool is not a pick. It changes nothing in the Machine, and the Turn goes on after it. The model reads
86
+ the text of the result. The Harness reads the tools of each server at the first Turn of a conversation, and keeps the
87
+ same tools until the conversation ends. The tools block has the Working tools first, then the MCP tools, then the Menu.
88
+ A server that does not answer at the first Turn fails the Turn.
89
+
90
+ An MCP tool runs when the model calls it, with no approval. A call that needs the approval of a person is the work of
91
+ the Machine: the Agent picks, a [Gate](../reference/glossary.md#gate) waits for the approval, and an `mcp`
92
+ [Effect](../reference/glossary.md#effect) makes the call (see [Effects](effects.md#mcp)).
93
+ [Give an Agent MCP tools](../guides/give-an-agent-mcp-tools.md) gives the fields and the refusals.
94
+
67
95
  ## What a state sets for one Turn
68
96
 
69
97
  The `input` of the invoke is the Turn. It has five keys, and no other:
70
98
 
71
99
  - **The [Frame](../reference/glossary.md#frame): `prompt` and `cwd`.** The prompt tells what this Turn is about. `cwd`
72
- is the directory where the Working tools work. A definition cannot hold a `cwd`, because the Worktree of a run exists
73
- only when the run starts. Under a Workspace with one [Repo Slot](../reference/glossary.md#repo-slot), the default
74
- `cwd` is the Worktree of that slot.
100
+ is the directory where the Working tools work. A definition cannot hold a `cwd`, because a Worktree exists only after
101
+ a run cuts it. Under a Workspace with [Repo Slots](../reference/glossary.md#repo-slot), a Turn of an Agent with
102
+ Working tools states its `cwd`. A Turn that wants `/work` states it too. There is no default, because a search in
103
+ `/work` hits `default/`, and a relative write lands outside each Worktree.
75
104
  - **The [Dials](../reference/glossary.md#dials): `model` and `thinkingLevel`.** They tell how hard the Agent works on
76
105
  this Turn, and they replace the values of the definition for this Turn only. The Agent stays the same Agent.
77
106
  - **`continue`.** It tells if the Turn continues the conversation of the Agent. See
@@ -90,7 +119,7 @@ changes, the coder continues its conversation and thinks harder on that Turn:
90
119
  ```ts
91
120
  import { z } from "zod";
92
121
  import { assign } from "xstate";
93
- import { agent, defineEvent, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";
122
+ import { agent, defineEvent, fail, isReady, jr2Setup, workspace, worktree, type Workspaced } from "@jr2/orchestrator";
94
123
 
95
124
  const finish = defineEvent({
96
125
  name: "finish",
@@ -112,6 +141,9 @@ const runInput = z.object({ branch: z.string() });
112
141
  type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
113
142
  type Context = BodyInput & { summary: string; notes: string };
114
143
 
144
+ // The Worktree of each Turn of the coder.
145
+ const fixTree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
146
+
115
147
  const body = jr2Setup({
116
148
  types: {} as { input: BodyInput; context: Context },
117
149
  events: [finish, approve, requestChanges],
@@ -128,21 +160,30 @@ const body = jr2Setup({
128
160
  workspace: "none",
129
161
  thinkingLevel: "low",
130
162
  }),
163
+ cut: worktree(),
131
164
  fail: fail(),
132
165
  },
133
166
  }).createMachine({
134
167
  id: "fix",
135
168
  context: ({ input }) => ({ ...input, summary: "", notes: "" }),
136
169
  on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
137
- initial: "coding",
170
+ initial: "cutting",
138
171
  states: {
172
+ // The Workspace only clones. The Machine cuts the Worktree that the Agent works in.
173
+ cutting: {
174
+ invoke: {
175
+ src: "cut",
176
+ input: ({ context }) => ({ path: fixTree(context), branch: context.branch }),
177
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
178
+ },
179
+ },
139
180
  coding: {
140
181
  invoke: {
141
182
  src: "coder",
142
183
  // The Frame (prompt and cwd) and continue. This Turn starts the coder's conversation.
143
184
  input: ({ context }) => ({
144
185
  prompt: "Make `node --test` pass, then commit.",
145
- cwd: context.workspace.repos.app,
186
+ cwd: fixTree(context),
146
187
  continue: true,
147
188
  }),
148
189
  },
@@ -161,7 +202,7 @@ const body = jr2Setup({
161
202
  // The same conversation as in coding, with a Dial: the coder thinks harder on this Turn.
162
203
  input: ({ context }) => ({
163
204
  prompt: `The fix is not complete: ${context.notes}\nFix it, then commit.`,
164
- cwd: context.workspace.repos.app,
205
+ cwd: fixTree(context),
165
206
  continue: true,
166
207
  thinkingLevel: "high",
167
208
  }),
@@ -169,6 +210,7 @@ const body = jr2Setup({
169
210
  on: { finish: { target: "checking", actions: assign({ summary: ({ event }) => event.summary }) } },
170
211
  },
171
212
  done: { type: "final" },
213
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
172
214
  failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
173
215
  lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
174
216
  },
@@ -177,7 +219,6 @@ const body = jr2Setup({
177
219
  export const machine = workspace(body, {
178
220
  input: runInput,
179
221
  repos: { app: "https://github.com/you/app.git" },
180
- spec: ({ input }) => ({ branch: input.branch }),
181
222
  });
182
223
  ```
183
224
 
@@ -186,7 +227,7 @@ export const machine = workspace(body, {
186
227
  ```ts
187
228
  import { z } from "zod";
188
229
  import { assign } from "xstate";
189
- import { agent, defineEvent, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";
230
+ import { agent, defineEvent, fail, isReady, jr2Setup, workspace, worktree, type Workspaced } from "@jr2/orchestrator";
190
231
 
191
232
  const finish = defineEvent({
192
233
  name: "finish",
@@ -208,6 +249,9 @@ const runInput = z.object({ branch: z.string() });
208
249
  type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
209
250
  type Context = BodyInput & { summary: string; notes: string };
210
251
 
252
+ // The Worktree of each Turn of the coder.
253
+ const fixTree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
254
+
211
255
  const body = jr2Setup({
212
256
  types: {} as { input: BodyInput; context: Context },
213
257
  events: [finish, approve, requestChanges],
@@ -224,21 +268,30 @@ const body = jr2Setup({
224
268
  workspace: "none",
225
269
  thinkingLevel: "low",
226
270
  }),
271
+ cut: worktree(),
227
272
  fail: fail(),
228
273
  },
229
274
  }).createMachine({
230
275
  id: "fix",
231
276
  context: ({ input }) => ({ ...input, summary: "", notes: "" }),
232
277
  on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
233
- initial: "coding",
278
+ initial: "cutting",
234
279
  states: {
280
+ // The Workspace only clones. The Machine cuts the Worktree that the Agent works in.
281
+ cutting: {
282
+ invoke: {
283
+ src: "cut",
284
+ input: ({ context }) => ({ path: fixTree(context), branch: context.branch }),
285
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
286
+ },
287
+ },
235
288
  coding: {
236
289
  invoke: {
237
290
  src: "coder",
238
291
  // The Frame (prompt and cwd) and continue. This Turn starts the coder's conversation.
239
292
  input: ({ context }) => ({
240
293
  prompt: "Make `node --test` pass, then commit.",
241
- cwd: context.workspace.repos.app,
294
+ cwd: fixTree(context),
242
295
  continue: true,
243
296
  }),
244
297
  },
@@ -257,7 +310,7 @@ const body = jr2Setup({
257
310
  // The same conversation as in coding, with a Dial: the coder thinks harder on this Turn.
258
311
  input: ({ context }) => ({
259
312
  prompt: `The fix is not complete: ${context.notes}\nFix it, then commit.`,
260
- cwd: context.workspace.repos.app,
313
+ cwd: fixTree(context),
261
314
  continue: true,
262
315
  thinkingLevel: "high",
263
316
  }),
@@ -265,6 +318,7 @@ const body = jr2Setup({
265
318
  on: { finish: { target: "checking", actions: assign({ summary: ({ event }) => event.summary }) } },
266
319
  },
267
320
  done: { type: "final" },
321
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
268
322
  failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
269
323
  lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
270
324
  },
@@ -273,7 +327,6 @@ const body = jr2Setup({
273
327
  export const machine = workspace(body, {
274
328
  input: runInput,
275
329
  repos: { app: "https://github.com/you/app.git" },
276
- spec: ({ input }) => ({ branch: input.branch }),
277
330
  });
278
331
  ```
279
332
 
@@ -341,6 +394,16 @@ continue that conversation again. The next Turn with `continue: true` starts a n
341
394
  full task again, because jr2 cannot write that prompt for you. A Harness restart is the only exception: the restarted
342
395
  Harness keeps the conversation, so the next Turn continues it.
343
396
 
397
+ ### The record of a conversation
398
+
399
+ The Harness prints each conversation to its pod log. It also sends each entry to the
400
+ [Orchestrator](../reference/glossary.md#orchestrator) during the Turn: each prompt, the text and the thinking of the
401
+ model, each call and the answer of each pick. The Orchestrator keeps these entries for as long as it keeps the run, so
402
+ you can read the conversation after the Sandbox is gone. The record holds no result of a Working tool or of an MCP tool,
403
+ because such a result is the text that the Agent read, which can hold a secret. The record is for a person to read. The
404
+ model never reads it, and a Turn never continues from it. `jr2 logs` and the bottom drawer of the Console show it. See
405
+ [Read a conversation](../guides/read-a-conversation.md).
406
+
344
407
  ## The Briefing
345
408
 
346
409
  The Briefing is the text that jr2 itself gives the model. It tells facts that a correct Agent needs and cannot find for
@@ -348,20 +411,58 @@ itself. It tells nothing about the task: the prompt tells the task. It has two p
348
411
 
349
412
  - **The standing part** comes after the instructions, and it is the same on each Turn. It tells how the Agent acts on
350
413
  the run: with a pick from its Menu. It also tells the CPUs and the [Size](../reference/glossary.md#size) of the
351
- Sandbox, or that a Menu-only Agent has no Working tools.
414
+ Sandbox, or that a Menu-only Agent has no Working tools. To an Agent with MCP tools, it tells that a call of an MCP
415
+ tool acts on a service outside the workflow, is not a pick, and does not end the Turn.
352
416
  - **The Turn part** comes after the prompt. It tells the directory of the Turn, its
353
- [Allowed picks](../reference/glossary.md#allowed-picks), and the notices. [The Menu](the-menu.md) tells what the
354
- Allowed picks are. When they change during the Turn, the Harness tells them to the model again. When an Allowed pick
355
- carries a [Chart](../reference/glossary.md#chart), the Turn part also tells how a Chart runs (see
356
- [Charts](charts.md)).
417
+ [Allowed picks](../reference/glossary.md#allowed-picks), the notices, and the [Steering messages](#steering-messages).
418
+ [The Menu](the-menu.md) tells what the Allowed picks are. When they change during the Turn, the Harness tells them to
419
+ the model again. When an Allowed pick carries a [Chart](../reference/glossary.md#chart), the Turn part also tells how
420
+ a Chart runs (see [Charts](charts.md)).
357
421
 
358
- A notice tells the next Turn what happened before it. For example: the conversation is new and the earlier context is
359
- gone, or the processes of the Sandbox stopped at its memory limit. jr2 gives each notice one time, to the next Turn that
360
- it is for.
422
+ A notice tells a Turn what happened before it. For example: the conversation is new and the earlier context is gone, or
423
+ the processes of the Sandbox stopped at its memory limit. A notice about a conversation goes to the next Turn of that
424
+ conversation. A notice about the Workspace goes to each conversation that was in the Workspace when the processes
425
+ stopped:
426
+
427
+ - A Turn that is open hears it before its next model request.
428
+ - A continued conversation hears it at its next Turn.
429
+ - The next Turn of the Agent whose Turn the stop cut hears it, also when that Turn is fresh.
430
+
431
+ A conversation hears each notice one time. A conversation whose own bash call already told it about the stop does not
432
+ hear the notice. A conversation that starts after the stop does not hear it, except the next Turn of the Agent whose
433
+ Turn the stop cut.
361
434
 
362
435
  You cannot turn the Briefing off. It contains only facts that make the Agent work better. An `instructions` that tells
363
436
  the same fact again does no harm.
364
437
 
438
+ ## Steering messages
439
+
440
+ A [Steering message](../reference/glossary.md#steering-message) is free text to one Agent of a run. The Agent hears it
441
+ one time, and nothing interrupts the Agent. A [Caller](../reference/glossary.md#caller) sends one with `jr2 steer`, and
442
+ the Machine sends one with the [`steer`](../reference/authoring-surface/steer.md) action. A message is not a pick and
443
+ not an event: no guard reads it, and no Gate takes it. The Agent decides what to do with it, and it acts on the run only
444
+ with its picks.
445
+
446
+ A message goes to an Agent slot: the path of the Machine and the name of the Agent, such as `root/coder`. The slot of an
447
+ Agent in a child Machine starts with the path of that Machine, such as `review/reviewer`. `jr2 steer <run id>` lists the
448
+ slots of a run.
449
+
450
+ - When a Turn of the slot is open, the Harness adds the message to the Turn before the next model request.
451
+ - When the Turn ends with a pick before its next model request, the message waits for the next Turn of the slot.
452
+ - When no Turn of the slot is open, the message waits for the next Turn of the slot in the same Machine instance.
453
+ - When that Machine instance ends first, the message is not delivered. The run records it as `not-delivered`.
454
+
455
+ The Harness puts the message in the Turn part, after the notices and before the Allowed picks. It tells the model who
456
+ wrote the message:
457
+
458
+ - A Caller's message is an instruction from outside the run, with the name of the Caller.
459
+ - A message that the Machine relays from another Agent is information from a peer. The workflow did not write it. A line
460
+ after the text says that it is not an instruction, and that the Agent does what the workflow asked.
461
+ - A message that the Machine relays from a Gate is what the Gate received, not an order. The workflow did not write it.
462
+ - A message from the Machine that relays no one is the text of the workflow.
463
+
464
+ [Steer an Agent](../guides/steer-an-agent.md) tells how to send one.
465
+
365
466
  ## When a Turn fails
366
467
 
367
468
  jr2 tries to recover a Turn before it tells the Machine. When it cannot recover the Turn, it sends one event,
@@ -409,19 +510,26 @@ the model in `models`. A model with no context window gets no Compaction.
409
510
  different key.
410
511
  - A Turn cannot set `instructions` or `workspace`.
411
512
  - `cwd` is an absolute path. The Harness refuses a Turn with a relative `cwd`.
412
- - Under a Workspace with more than one Repo Slot, each Turn of an Agent with Working tools sets `cwd`. jr2 refuses the
413
- Turn without it.
513
+ - Under a Workspace with Repo Slots, each Turn of an Agent with Working tools sets `cwd`. jr2 refuses the Turn without
514
+ it.
414
515
  - An Agent with `"write"` or `"read"` runs in the body of a `workspace()`. jr2 refuses its Turn outside one.
415
516
  - `jr2 up` sees only the models of the definitions. It cannot see a model that a Turn sets as a Dial. The Harness
416
517
  refuses a model that it cannot find when the Turn starts.
417
518
  - A Turn ends when the state that invoked the Agent exits.
418
519
  - After `agent.fault` for a conversation, jr2 does not continue it, except after a Harness restart.
520
+ - `jr2 up` refuses an MCP server that the `mcp` block does not declare, a remote server with no allowlist, and a stdio
521
+ server on a Menu-only Agent.
522
+ - A Steering message is at most 16 KiB. `steerable: false` refuses a Caller's message, and the Machine can still send
523
+ one.
419
524
 
420
525
  [Set an Agent's access and Dials](../guides/set-an-agents-access-and-dials.md) gives the exact text of each refusal.
421
526
 
422
527
  ## Read next
423
528
 
424
529
  - [Set an Agent's access and Dials](../guides/set-an-agents-access-and-dials.md)
530
+ - [Read a conversation](../guides/read-a-conversation.md)
531
+ - [Give an Agent MCP tools](../guides/give-an-agent-mcp-tools.md) and
532
+ [Write a tool as an MCP server](../guides/write-a-tool-as-an-mcp-server.md)
425
533
  - [The Menu](the-menu.md), [Workspaces](workspaces.md) and [Architecture](architecture.md)
426
534
  - Reference: [`agent`](../reference/authoring-surface/agent.md),
427
535
  [`AgentDefinition`](../reference/authoring-surface/type-agentdefinition.md),
@@ -430,6 +538,8 @@ the model in `models`. A model with no context window gets no Compaction.
430
538
  [`harness.provider`](../reference/config.md#harness-provider)
431
539
  - [ADR-0018](../reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md): an Agent is a
432
540
  definition, and a Turn can set its Dials
541
+ - [ADR-0023](../reference/decisions/0023-the-harness-prints-the-conversation.md): the Harness prints the conversation,
542
+ and the Orchestrator keeps it
433
543
  - [ADR-0028](../reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md): what an
434
544
  Agent can do to the Workspace is a part of its definition
435
545
  - [ADR-0057](../reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md): a Turn is its
@@ -438,5 +548,8 @@ the model in `models`. A model with no context window gets no Compaction.
438
548
  state that asked for it
439
549
  - [ADR-0016](../reference/decisions/0016-agent-turn-mechanics-are-internal.md): jr2 owns the mechanics of a Turn
440
550
  - [ADR-0062](../reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md): the Briefing
551
+ - [ADR-0002](../reference/decisions/0002-duplex-streaming-actor.md): Steering messages
552
+ - [ADR-0079](../reference/decisions/0079-an-agent-holds-mcp-tools-a-machine-calls-them-as-an-effect-and-the-machine-is-the-approval.md):
553
+ the MCP tools of an Agent
441
554
  - [ADR-0035](../reference/decisions/0035-a-runaway-turn-is-ended-rerolled-once-then-a-fault.md): a Runaway
442
555
  - [ADR-0036](../reference/decisions/0036-a-turn-compacts-its-own-context-mid-flight.md): Compaction