@jr2/orchestrator 0.6.0 → 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 (301) 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 +86 -9
  14. package/docs/concepts/architecture.md +41 -28
  15. package/docs/concepts/callers-and-hooks.md +205 -0
  16. package/docs/concepts/charts.md +7 -5
  17. package/docs/concepts/composition.md +10 -1
  18. package/docs/concepts/converge.md +4 -2
  19. package/docs/concepts/durable-runs.md +43 -16
  20. package/docs/concepts/effects.md +50 -22
  21. package/docs/concepts/gates.md +95 -25
  22. package/docs/concepts/machines-and-workflows.md +5 -4
  23. package/docs/concepts/pools-and-sources.md +187 -11
  24. package/docs/concepts/secrets-and-trust.md +73 -33
  25. package/docs/concepts/the-menu.md +11 -0
  26. package/docs/concepts/workspaces.md +6 -5
  27. package/docs/get-started/a-model-decides.md +14 -13
  28. package/docs/get-started/an-agent-in-a-sandbox.md +43 -34
  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/guides/add-tools-to-the-sandbox.md +55 -11
  32. package/docs/guides/answer-a-gate-from-a-forge.md +304 -0
  33. package/docs/guides/answer-a-gate.md +74 -37
  34. package/docs/guides/bind-open-parts.md +24 -8
  35. package/docs/guides/call-an-mcp-tool-from-a-machine.md +572 -0
  36. package/docs/guides/cancel-a-run.md +26 -16
  37. package/docs/guides/fix-a-failed-converge.md +18 -6
  38. package/docs/guides/give-a-caller-a-scope.md +203 -0
  39. package/docs/guides/give-an-agent-mcp-tools.md +422 -0
  40. package/docs/guides/iterate-on-a-machine-on-kind.md +10 -9
  41. package/docs/guides/let-an-agent-write-a-chart.md +9 -6
  42. package/docs/guides/look-inside-a-sandbox.md +101 -31
  43. package/docs/guides/open-the-console.md +63 -14
  44. package/docs/guides/read-a-conversation.md +225 -0
  45. package/docs/guides/run-a-chart-by-name.md +17 -16
  46. package/docs/guides/run-one-worker-per-item.md +15 -9
  47. package/docs/guides/set-an-agents-access-and-dials.md +2 -0
  48. package/docs/guides/start-a-run-for-each-alert.md +290 -0
  49. package/docs/guides/start-a-run-from-a-run.md +18 -16
  50. package/docs/guides/start-a-run.md +24 -18
  51. package/docs/guides/steer-an-agent.md +332 -0
  52. package/docs/guides/use-a-hosted-provider.md +1 -1
  53. package/docs/guides/watch-a-run.md +127 -121
  54. package/docs/guides/write-a-hook-kind.md +238 -0
  55. package/docs/guides/write-a-tool-as-an-mcp-server.md +351 -0
  56. package/docs/guides/write-a-workflow.md +17 -7
  57. package/docs/llms.txt +81 -15
  58. package/docs/reference/authoring-surface/agent.md +1 -1
  59. package/docs/reference/authoring-surface/answer.md +1 -1
  60. package/docs/reference/authoring-surface/arg.md +1 -1
  61. package/docs/reference/authoring-surface/basic.md +1 -1
  62. package/docs/reference/authoring-surface/bearer.md +1 -1
  63. package/docs/reference/authoring-surface/branchname.md +1 -1
  64. package/docs/reference/authoring-surface/carry.md +23 -0
  65. package/docs/reference/authoring-surface/chartschema.md +1 -1
  66. package/docs/reference/authoring-surface/chartschemafor.md +1 -1
  67. package/docs/reference/authoring-surface/command.md +1 -1
  68. package/docs/reference/authoring-surface/customize.md +4 -1
  69. package/docs/reference/authoring-surface/defineconfig.md +1 -1
  70. package/docs/reference/authoring-surface/defineevent.md +1 -1
  71. package/docs/reference/authoring-surface/dispatch.md +5 -4
  72. package/docs/reference/authoring-surface/fail.md +1 -1
  73. package/docs/reference/authoring-surface/file.md +1 -1
  74. package/docs/reference/authoring-surface/frompick.md +1 -1
  75. package/docs/reference/authoring-surface/gate.md +118 -0
  76. package/docs/reference/authoring-surface/group-agents.md +15 -0
  77. package/docs/reference/authoring-surface/group-charts.md +16 -0
  78. package/docs/reference/authoring-surface/group-composition.md +25 -0
  79. package/docs/reference/authoring-surface/group-config.md +17 -0
  80. package/docs/reference/authoring-surface/group-effects.md +48 -0
  81. package/docs/reference/authoring-surface/group-failure.md +13 -0
  82. package/docs/reference/authoring-surface/group-gates.md +16 -0
  83. package/docs/reference/authoring-surface/group-machine-and-events.md +15 -0
  84. package/docs/reference/authoring-surface/group-steering.md +12 -0
  85. package/docs/reference/authoring-surface/group-types-these-signatures-name.md +137 -0
  86. package/docs/reference/authoring-surface/group-workspaces-and-repos.md +15 -0
  87. package/docs/reference/authoring-surface/http.md +1 -1
  88. package/docs/reference/authoring-surface/isfailure.md +1 -1
  89. package/docs/reference/authoring-surface/isready.md +1 -1
  90. package/docs/reference/authoring-surface/jr2setup.md +13 -3
  91. package/docs/reference/authoring-surface/mcp.md +107 -0
  92. package/docs/reference/authoring-surface/open.md +5 -3
  93. package/docs/reference/authoring-surface/openbody.md +1 -1
  94. package/docs/reference/authoring-surface/paramsof.md +1 -1
  95. package/docs/reference/authoring-surface/pool.md +77 -9
  96. package/docs/reference/authoring-surface/push.md +1 -1
  97. package/docs/reference/authoring-surface/readyof.md +1 -1
  98. package/docs/reference/authoring-surface/reread.md +19 -0
  99. package/docs/reference/authoring-surface/secret.md +1 -1
  100. package/docs/reference/authoring-surface/sentby.md +1 -1
  101. package/docs/reference/authoring-surface/skip.md +22 -0
  102. package/docs/reference/authoring-surface/source.md +56 -1
  103. package/docs/reference/authoring-surface/steer.md +93 -0
  104. package/docs/reference/authoring-surface/text.md +1 -1
  105. package/docs/reference/authoring-surface/type-agentdefinition.md +14 -1
  106. package/docs/reference/authoring-surface/type-agentmcpserver.md +54 -0
  107. package/docs/reference/authoring-surface/type-anyframepath.md +1 -1
  108. package/docs/reference/authoring-surface/type-anyworktreepath.md +1 -1
  109. package/docs/reference/authoring-surface/type-binding.md +1 -1
  110. package/docs/reference/authoring-surface/type-caller.md +40 -0
  111. package/docs/reference/authoring-surface/type-callerrecord.md +32 -0
  112. package/docs/reference/authoring-surface/type-carry.md +19 -0
  113. package/docs/reference/authoring-surface/type-chainlink.md +3 -3
  114. package/docs/reference/authoring-surface/type-commandoutput.md +1 -1
  115. package/docs/reference/authoring-surface/type-customize.md +16 -1
  116. package/docs/reference/authoring-surface/type-delivered.md +17 -0
  117. package/docs/reference/authoring-surface/type-deliveredevent.md +18 -0
  118. package/docs/reference/authoring-surface/type-dispatchdefinition.md +4 -3
  119. package/docs/reference/authoring-surface/type-dispatchoutput.md +1 -1
  120. package/docs/reference/authoring-surface/type-effectbinding.md +12 -2
  121. package/docs/reference/authoring-surface/type-framepath.md +1 -1
  122. package/docs/reference/authoring-surface/type-gatebinding.md +15 -0
  123. package/docs/reference/authoring-surface/type-gatehooks.md +12 -0
  124. package/docs/reference/authoring-surface/type-gatelook.md +37 -0
  125. package/docs/reference/authoring-surface/type-gateoutcome.md +32 -0
  126. package/docs/reference/authoring-surface/type-gatereply.md +19 -0
  127. package/docs/reference/authoring-surface/type-gateslot.md +21 -0
  128. package/docs/reference/authoring-surface/type-gateslotinput.md +13 -0
  129. package/docs/reference/authoring-surface/type-gateslotparts.md +18 -0
  130. package/docs/reference/authoring-surface/type-gateslots.md +12 -0
  131. package/docs/reference/authoring-surface/type-gatetypesat.md +13 -0
  132. package/docs/reference/authoring-surface/type-hostinjectedinput.md +1 -1
  133. package/docs/reference/authoring-surface/type-httpoutput.md +1 -1
  134. package/docs/reference/authoring-surface/type-jr2config.md +37 -2
  135. package/docs/reference/authoring-surface/type-lateroutcome.md +1 -1
  136. package/docs/reference/authoring-surface/type-lends.md +5 -1
  137. package/docs/reference/authoring-surface/type-lookoutput.md +14 -0
  138. package/docs/reference/authoring-surface/type-mcpcalloutput.md +78 -0
  139. package/docs/reference/authoring-surface/type-mcpnotreturned.md +42 -0
  140. package/docs/reference/authoring-surface/type-mcpoptions.md +47 -0
  141. package/docs/reference/authoring-surface/type-mcpoutput.md +50 -0
  142. package/docs/reference/authoring-surface/type-mcpreadoutput.md +53 -0
  143. package/docs/reference/authoring-surface/type-mcpremoteserver.md +50 -0
  144. package/docs/reference/authoring-surface/type-mcpserver.md +41 -0
  145. package/docs/reference/authoring-surface/type-mcpstdioserver.md +42 -0
  146. package/docs/reference/authoring-surface/type-namedsecret.md +4 -4
  147. package/docs/reference/authoring-surface/type-openbodydeclaration.md +1 -1
  148. package/docs/reference/authoring-surface/type-openbodyoutput.md +1 -1
  149. package/docs/reference/authoring-surface/type-poolnextinput.md +1 -1
  150. package/docs/reference/authoring-surface/type-poolspec.md +11 -6
  151. package/docs/reference/authoring-surface/type-pushoutput.md +1 -1
  152. package/docs/reference/authoring-surface/type-pushsourcespec.md +38 -0
  153. package/docs/reference/authoring-surface/type-readsourcespec.md +47 -0
  154. package/docs/reference/authoring-surface/type-reposlot.md +1 -1
  155. package/docs/reference/authoring-surface/type-reread.md +18 -0
  156. package/docs/reference/authoring-surface/type-runsconfig.md +41 -0
  157. package/docs/reference/authoring-surface/type-sender.md +26 -1
  158. package/docs/reference/authoring-surface/type-sendercallerfield.md +14 -0
  159. package/docs/reference/authoring-surface/type-size.md +1 -1
  160. package/docs/reference/authoring-surface/type-skip.md +19 -0
  161. package/docs/reference/authoring-surface/type-sourcehooks.md +23 -0
  162. package/docs/reference/authoring-surface/type-sourcein.md +25 -0
  163. package/docs/reference/authoring-surface/type-sourcereply.md +18 -0
  164. package/docs/reference/authoring-surface/type-sourcespec.md +16 -7
  165. package/docs/reference/authoring-surface/type-sourceverdict.md +49 -0
  166. package/docs/reference/authoring-surface/type-standingpoolmachine.md +12 -0
  167. package/docs/reference/authoring-surface/type-standingpoolspec.md +51 -0
  168. package/docs/reference/authoring-surface/type-steerargs.md +20 -0
  169. package/docs/reference/authoring-surface/type-thinkinglevel.md +1 -1
  170. package/docs/reference/authoring-surface/type-usercontainer.md +1 -1
  171. package/docs/reference/authoring-surface/type-workspaced.md +1 -1
  172. package/docs/reference/authoring-surface/type-worktreefound.md +3 -3
  173. package/docs/reference/authoring-surface/type-worktreeinput.md +1 -1
  174. package/docs/reference/authoring-surface/type-worktreeoptions.md +1 -1
  175. package/docs/reference/authoring-surface/type-worktreeoutput.md +1 -1
  176. package/docs/reference/authoring-surface/type-worktreepath.md +1 -1
  177. package/docs/reference/authoring-surface/type-worktreeready.md +1 -1
  178. package/docs/reference/authoring-surface/type-worktreerefused.md +4 -4
  179. package/docs/reference/authoring-surface/workspace.md +1 -1
  180. package/docs/reference/authoring-surface/worktree.md +1 -1
  181. package/docs/reference/authoring-surface.md +88 -167
  182. package/docs/reference/cli.md +413 -74
  183. package/docs/reference/config.md +235 -2
  184. package/docs/reference/decisions/0002-duplex-streaming-actor.md +71 -11
  185. package/docs/reference/decisions/0005-sandbox-pod-composition.md +14 -10
  186. package/docs/reference/decisions/0006-agent-control-surface.md +4 -4
  187. package/docs/reference/decisions/0007-durable-machine-state.md +1 -1
  188. package/docs/reference/decisions/0009-cli-and-instance-interface.md +150 -49
  189. package/docs/reference/decisions/0010-bdd-acceptance-tests.md +5 -3
  190. package/docs/reference/decisions/0011-workflow-defined-events.md +256 -12
  191. package/docs/reference/decisions/0012-workspace-wrapper-machine.md +9 -2
  192. package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +20 -14
  193. package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +53 -27
  194. package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +18 -14
  195. package/docs/reference/decisions/0017-pool-over-a-source-port.md +226 -12
  196. package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +15 -7
  197. package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +32 -18
  198. package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +14 -1
  199. package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +4 -4
  200. package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +116 -34
  201. package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +38 -37
  202. package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +10 -5
  203. package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +7 -6
  204. package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +23 -7
  205. package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +18 -10
  206. package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +3 -2
  207. package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +23 -18
  208. package/docs/reference/decisions/0032-the-console-unlocks-with-a-callers-credential.md +101 -0
  209. package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +4 -3
  210. package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +6 -6
  211. package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +5 -4
  212. package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +19 -19
  213. package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +6 -1
  214. package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +55 -40
  215. package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +14 -13
  216. package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +7 -0
  217. package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +13 -7
  218. package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +38 -30
  219. package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +64 -17
  220. package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +2 -1
  221. package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +2 -2
  222. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-kept-for-a-set-time.md +109 -0
  223. package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +51 -23
  224. package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +94 -54
  225. package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +101 -47
  226. package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +32 -9
  227. package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +17 -13
  228. package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +56 -30
  229. package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +35 -25
  230. package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +4 -3
  231. package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +37 -10
  232. package/docs/reference/decisions/0078-a-caller-comes-from-one-authenticator-seam-and-acts-within-its-scopes.md +285 -0
  233. 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
  234. package/docs/reference/decisions.md +6 -4
  235. package/docs/reference/glossary.md +96 -42
  236. package/docs/reference/hooks.md +1077 -0
  237. package/docs/reference/http-api.md +976 -149
  238. package/docs/why.md +2 -1
  239. package/package.json +10 -3
  240. package/src/actor.ts +36 -10
  241. package/src/agent.ts +50 -0
  242. package/src/assembly-checks.ts +530 -4
  243. package/src/callers.ts +245 -0
  244. package/src/chart.ts +52 -7
  245. package/src/config.ts +550 -1
  246. package/src/conversations.ts +453 -0
  247. package/src/custodian.ts +8 -2
  248. package/src/customize.ts +143 -4
  249. package/src/dispatch-effect.ts +142 -26
  250. package/src/durability.ts +2 -0
  251. package/src/duration.ts +20 -0
  252. package/src/effect-checks.ts +2 -1
  253. package/src/effect.ts +60 -7
  254. package/src/effector-wire.ts +272 -27
  255. package/src/gate-brand.ts +16 -0
  256. package/src/gate.ts +634 -48
  257. package/src/harness-client.ts +10 -4
  258. package/src/held-secrets.ts +72 -23
  259. package/src/holds.ts +2 -2
  260. package/src/hook-kinds/discord.ts +92 -0
  261. package/src/hook-kinds/door.ts +107 -0
  262. package/src/hook-kinds/github.ts +89 -0
  263. package/src/hook-kinds/gitlab.ts +72 -0
  264. package/src/hook-kinds/hook.ts +7 -0
  265. package/src/hook-kinds/index.ts +465 -0
  266. package/src/hook-kinds/slack.ts +151 -0
  267. package/src/hook-kinds/webhook.ts +113 -0
  268. package/src/hooks.ts +506 -0
  269. package/src/http-effect.ts +76 -38
  270. package/src/http.ts +889 -94
  271. package/src/index.ts +16 -5
  272. package/src/instance.ts +196 -26
  273. package/src/internal.ts +22 -3
  274. package/src/machine-doc.ts +26 -1
  275. package/src/mcp-effect.ts +424 -0
  276. package/src/mount-digest.ts +41 -7
  277. package/src/names.ts +64 -2
  278. package/src/notices.ts +138 -10
  279. package/src/open-body.ts +25 -11
  280. package/src/open-effect.ts +17 -4
  281. package/src/open.ts +4 -2
  282. package/src/parts.ts +87 -9
  283. package/src/party.ts +2 -1
  284. package/src/pick.ts +2 -2
  285. package/src/pool.ts +1142 -163
  286. package/src/registration.ts +203 -13
  287. package/src/run-host.ts +1509 -171
  288. package/src/run-list.ts +191 -0
  289. package/src/sandbox-kube.ts +53 -5
  290. package/src/secret-placement.ts +239 -33
  291. package/src/server.ts +53 -4
  292. package/src/setup.ts +72 -32
  293. package/src/snapshot-store.ts +565 -48
  294. package/src/steer.ts +111 -0
  295. package/src/stub-harness.ts +6 -2
  296. package/src/tokens.ts +263 -22
  297. package/src/wire.ts +17 -0
  298. package/src/workspace.ts +50 -6
  299. package/src/worktree.ts +3 -3
  300. package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +0 -61
  301. 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.6.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.
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,cut-a-worktree.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
 
@@ -66,6 +68,30 @@ The field also tells where the Turn runs. An Agent with `"write"` or `"read"` wo
66
68
  [Instance Harness](../reference/glossary.md#instance-harness), also when a `workspace()` holds it.
67
69
  [Architecture](architecture.md) shows where each Harness runs.
68
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
+
69
95
  ## What a state sets for one Turn
70
96
 
71
97
  The `input` of the invoke is the Turn. It has five keys, and no other:
@@ -368,6 +394,16 @@ continue that conversation again. The next Turn with `continue: true` starts a n
368
394
  full task again, because jr2 cannot write that prompt for you. A Harness restart is the only exception: the restarted
369
395
  Harness keeps the conversation, so the next Turn continues it.
370
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
+
371
407
  ## The Briefing
372
408
 
373
409
  The Briefing is the text that jr2 itself gives the model. It tells facts that a correct Agent needs and cannot find for
@@ -375,12 +411,13 @@ itself. It tells nothing about the task: the prompt tells the task. It has two p
375
411
 
376
412
  - **The standing part** comes after the instructions, and it is the same on each Turn. It tells how the Agent acts on
377
413
  the run: with a pick from its Menu. It also tells the CPUs and the [Size](../reference/glossary.md#size) of the
378
- 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.
379
416
  - **The Turn part** comes after the prompt. It tells the directory of the Turn, its
380
- [Allowed picks](../reference/glossary.md#allowed-picks), and the notices. [The Menu](the-menu.md) tells what the
381
- Allowed picks are. When they change during the Turn, the Harness tells them to the model again. When an Allowed pick
382
- carries a [Chart](../reference/glossary.md#chart), the Turn part also tells how a Chart runs (see
383
- [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)).
384
421
 
385
422
  A notice tells a Turn what happened before it. For example: the conversation is new and the earlier context is gone, or
386
423
  the processes of the Sandbox stopped at its memory limit. A notice about a conversation goes to the next Turn of that
@@ -398,6 +435,34 @@ Turn the stop cut.
398
435
  You cannot turn the Briefing off. It contains only facts that make the Agent work better. An `instructions` that tells
399
436
  the same fact again does no harm.
400
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
+
401
466
  ## When a Turn fails
402
467
 
403
468
  jr2 tries to recover a Turn before it tells the Machine. When it cannot recover the Turn, it sends one event,
@@ -452,12 +517,19 @@ the model in `models`. A model with no context window gets no Compaction.
452
517
  refuses a model that it cannot find when the Turn starts.
453
518
  - A Turn ends when the state that invoked the Agent exits.
454
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.
455
524
 
456
525
  [Set an Agent's access and Dials](../guides/set-an-agents-access-and-dials.md) gives the exact text of each refusal.
457
526
 
458
527
  ## Read next
459
528
 
460
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)
461
533
  - [The Menu](the-menu.md), [Workspaces](workspaces.md) and [Architecture](architecture.md)
462
534
  - Reference: [`agent`](../reference/authoring-surface/agent.md),
463
535
  [`AgentDefinition`](../reference/authoring-surface/type-agentdefinition.md),
@@ -466,6 +538,8 @@ the model in `models`. A model with no context window gets no Compaction.
466
538
  [`harness.provider`](../reference/config.md#harness-provider)
467
539
  - [ADR-0018](../reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md): an Agent is a
468
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
469
543
  - [ADR-0028](../reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md): what an
470
544
  Agent can do to the Workspace is a part of its definition
471
545
  - [ADR-0057](../reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md): a Turn is its
@@ -474,5 +548,8 @@ the model in `models`. A model with no context window gets no Compaction.
474
548
  state that asked for it
475
549
  - [ADR-0016](../reference/decisions/0016-agent-turn-mechanics-are-internal.md): jr2 owns the mechanics of a Turn
476
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
477
554
  - [ADR-0035](../reference/decisions/0035-a-runaway-turn-is-ended-rerolled-once-then-a-fault.md): a Runaway
478
555
  - [ADR-0036](../reference/decisions/0036-a-turn-compacts-its-own-context-mid-flight.md): Compaction
@@ -46,7 +46,7 @@ its pod can reach. Thus jr2 puts each thing that the Agent must not touch in a d
46
46
  - **Instance Harness**: runs the Turns of the Menu-only Agents
47
47
  - Harness
48
48
  - Custodian
49
- - **Instance Effector**: runs the Effects that read no Worktree file
49
+ - **Instance Effector**: runs the Effects that read no Worktree file, and checks a Hook's signature
50
50
  - **Repo cache**: one pod on each Sandbox node
51
51
  - ↓ a Turn, an Effect · ↑ a pick, through the Custodian · ↓ the Repo cache gives each Repo
52
52
  - **Sandbox**: one pod for each Workspace, in the same namespace
@@ -84,23 +84,30 @@ to the Orchestrator's Service, for the life of the command. The [global options]
84
84
  tell how to give a URL and a token instead. The CLI keeps no local state about the cluster.
85
85
 
86
86
  The [Console](../reference/glossary.md#console) is a page that the Orchestrator serves. You open it in a browser,
87
- through a port forward that you start. [Open the Console](../guides/open-the-console.md) gives the commands.
87
+ through a port forward that you start. It draws the Machine of each live run, and marks a run that started on an older
88
+ [Assembly](../reference/glossary.md#assembly). With the credential of a [Caller](../reference/glossary.md#caller), it
89
+ shows the open [Gates](../reference/glossary.md#gate) that you can answer. With the credential of a Caller that has
90
+ `read`, it also lists the ended runs, and shows the [Conversations](../reference/glossary.md#conversation) of the Agents
91
+ in a drawer at the bottom. [Open the Console](../guides/open-the-console.md) gives the commands.
92
+
93
+ The `jr2 workspace` commands do not talk to the Orchestrator. They read the Sandbox resources with your kubectl
94
+ credentials, and open a shell or a port forward into a Sandbox pod. Thus they work when the Orchestrator is down.
88
95
 
89
96
  ## The Orchestrator
90
97
 
91
98
  The Orchestrator is one pod for each Instance (`replicas: 1`), with the Service `jr2-orchestrator` on port 4000. It
92
99
  hosts all the [Workflows](../reference/glossary.md#workflow) of the Instance and many runs of each Workflow. It keeps
93
- the snapshot of each run on its own volume, so a run continues after a restart. [Durable runs](durable-runs.md) tells
94
- how.
100
+ the snapshot of each run on its own volume, so a run continues after a restart. It also keeps there the conversation of
101
+ each Agent, which each Harness sends during the Turn. [Durable runs](durable-runs.md) tells how, and for how long.
95
102
 
96
103
  The pod runs the `jr2-orchestrator` [Kit image](../reference/glossary.md#kit-image), which holds no code of yours. The
97
- Orchestrator loads your Workflows and your config from the [Assembly](../reference/glossary.md#assembly) that `jr2 up`
98
- publishes to it, and it keeps each Assembly on its volume. [Converge](converge.md#the-assembly) tells how.
104
+ Orchestrator loads your Workflows and your config from the Assembly that `jr2 up` publishes to it, and it keeps each
105
+ Assembly on its volume. [Converge](converge.md#the-assembly) tells how.
99
106
 
100
107
  The Orchestrator does these things:
101
108
 
102
109
  - It runs each Machine as an [xstate](https://xstate.js.org) actor, and holds the state of each run.
103
- - It serves the HTTP API that the CLI, the Console, a webhook and the Custodians call. See the
110
+ - It serves the HTTP API that the CLI, the Console, the other Callers, the Hooks and the Custodians call. See the
104
111
  [HTTP API](../reference/http-api.md).
105
112
  - It sends each Turn to a Harness, and judges each pick that comes back.
106
113
  - It writes a Sandbox resource when a run enters a Workspace. Then it watches the Sandbox resource until the Workspace
@@ -116,9 +123,11 @@ To isolate two sets of Workflows, use two Instances. Each Instance has its own n
116
123
  ## The Harness
117
124
 
118
125
  The Harness is jr2's own server for the Turns of Agents. It speaks to the model provider. It gives the model the Agent's
119
- Menu and its Working tools. It executes each Working tool that the model calls, and sends each pick through the
120
- Custodian. Each program that a Working tool starts runs confined with Landlock. The Harness holds no Agents of its own.
121
- Each Turn brings the Agent's definition with it. [Agents and Turns](agents-and-turns.md) tells what happens in a Turn.
126
+ Working tools, its [MCP tools](../reference/glossary.md#mcp-tools) and its Menu. It executes each Working tool that the
127
+ model calls, and sends each pick through the Custodian. It is the MCP client of the Agent: it calls each MCP tool on its
128
+ server, a remote one through the Custodian, or a stdio one that it starts. Each program that a Working tool starts runs
129
+ confined with Landlock, and so does each stdio MCP server. The Harness holds no Agents of its own. Each Turn brings the
130
+ Agent's definition with it. [Agents and Turns](agents-and-turns.md) tells what happens in a Turn.
122
131
 
123
132
  The Harness has two placements:
124
133
 
@@ -128,8 +137,8 @@ The Harness has two placements:
128
137
  Harness serves all the Agents of the Sandbox.
129
138
  - **As the Instance Harness.** The Instance Harness is one StatefulSet for each Instance, `jr2-instance-harness`. Each
130
139
  Turn of a Menu-only Agent (`workspace: "none"`) runs here. Its pod has a Harness and a Custodian, and no Worktree. It
131
- keeps each conversation on its volume while a run can continue it. `jr2 up` converges it when a Machine of the
132
- Instance has a Menu-only Agent.
140
+ runs no program of an Agent, so its Agents can use only remote MCP servers. It keeps each conversation on its volume
141
+ while a run can continue it. `jr2 up` converges it when a Machine of the Instance has a Menu-only Agent.
133
142
 
134
143
  A Harness answers only the Orchestrator. The Orchestrator sends a bearer token on each call, and the Harness accepts no
135
144
  call without it, except its health check. `jr2 up` also converges NetworkPolicies that let only the Orchestrator's pods
@@ -141,14 +150,14 @@ connect to a Harness pod, and that stop each Harness pod at the cloud metadata a
141
150
  Each Harness pod has a Custodian: each Sandbox, and the Instance Harness. The Custodian is a container beside the
142
151
  Harness. The Agent executes no code in it. It does two things:
143
152
 
144
- - It carries five kinds of call from the pod to the Orchestrator: the Menu reads, the picks, the polls for the answer to
145
- a pick, the reports that a step boundary gave its notices to the model, and the fetch asks. It sends the first four
146
- with the control token of the Sandbox, and the fetch asks with its fetch token. These five routes are all that it
147
- forwards. It refuses all other routes. The Harness sends the first four on a Unix socket in `/run/jr2`. A confined
148
- program cannot make a socket there, and the Custodian refuses a request on it that does not have the control Stand-in.
149
- The fetch asks go to port `8081` on loopback.
150
- - It holds the [Held secrets](../reference/glossary.md#held-secret) of its pod, such as a model API key. It puts the
151
- value into the requests that go to the hosts of each Held secret.
153
+ - It carries six kinds of call from the pod to the Orchestrator: the Menu reads, the picks, the polls for the answer to
154
+ a pick, the reports that a step boundary gave its notices to the model, the batches of the conversation's entries, and
155
+ the fetch asks. It sends the first five with the control token of the Sandbox, and the fetch asks with its fetch
156
+ token. These six routes are all that it forwards. It refuses all other routes. The Harness sends the first five on a
157
+ Unix socket in `/run/jr2`. A confined program cannot make a socket there, and the Custodian refuses a request on it
158
+ that does not have the control Stand-in. The fetch asks go to port `8081` on loopback.
159
+ - It holds the [Held secrets](../reference/glossary.md#held-secret) of its pod, such as a model API key or the token of
160
+ an MCP server. It puts the value into the requests that go to the hosts of each Held secret.
152
161
 
153
162
  The Custodian runs Envoy, from a [Pinned image](../reference/glossary.md#pinned-image). The Orchestrator writes its
154
163
  config for a Sandbox, and `jr2 up` writes it for the Instance Harness. [Secrets and trust](secrets-and-trust.md) tells
@@ -156,8 +165,8 @@ how the Custodian holds a credential.
156
165
 
157
166
  ## The Effector
158
167
 
159
- The Effector runs each `http` and `push` Effect, each `command` that names an Effect secret, and each `dispatch` that
160
- names a target. Thus a credential that an Effect uses stays out of the Harness container. The Effector is jr2's own
168
+ The Effector runs each `http`, `mcp` and `push` Effect, each `command` that names an Effect secret, and each `dispatch`
169
+ that names a target. Thus a credential that an Effect uses stays out of the Harness container. The Effector is jr2's own
161
170
  program, and it runs in a container in which the Agent executes nothing. [Effects](effects.md) tells which Effect runs
162
171
  where. It has two placements:
163
172
 
@@ -165,12 +174,16 @@ where. It has two placements:
165
174
  `push`, an `http` Effect whose body is a Worktree file, and a `command` that names an Effect secret. Its image is the
166
175
  Sandbox Image, unless the `workspace()` names a different image.
167
176
  - **The Instance Effector** is one pod for each Instance, `jr2-instance-effector`. It runs each `http` Effect that reads
168
- no Worktree file, and each `dispatch` that starts a run on a different Orchestrator. It holds the Instance token of
169
- that Orchestrator as an Effect secret. It runs in the `jr2-harness` Kit image.
170
-
171
- Each placement exists only when a Machine of the Instance puts an Effect there. A `command` that names no Effect secret
172
- does not use an Effector. It runs in the Harness container of its Sandbox, with the same tools and access as the Agent,
173
- and confined in the same way.
177
+ no Worktree file, each `mcp` Effect, and each `dispatch` that starts a run on a different Orchestrator. It holds the
178
+ token of each MCP server that an `mcp` Effect calls, and the Caller token for that Orchestrator, as Effect secrets. It
179
+ also serves the [Hooks](../reference/glossary.md#hook): it holds the secret of each Hook that checks a signature with
180
+ a shared secret (`mac`) and checks the signature, and it sends the follow-up of a kind that posts one, such as the
181
+ reply to a Slack click. It runs in the `jr2-harness` Kit image.
182
+
183
+ A Sandbox Effector exists only when a Machine of the Instance puts an Effect there. The Instance Effector exists only
184
+ when a Machine puts an Effect there or a Hook needs it. A `command` that names no Effect secret does not use an
185
+ Effector. It runs in the Harness container of its Sandbox, with the same tools and access as the Agent, and confined in
186
+ the same way.
174
187
 
175
188
  The Orchestrator signs each request that it sends to an Effector, and the Effector signs each answer. The Orchestrator
176
189
  only asks, and the Effector holds the credentials.