@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
@@ -0,0 +1,332 @@
1
+ ---
2
+ title: Steer an Agent
3
+ description: Send free text to one Agent of a live run, from the CLI, from HTTP, or from the Machine itself.
4
+ ---
5
+
6
+ # Steer an Agent
7
+
8
+ Send free text to one [Agent](../reference/glossary.md#agent) of a live run, from the CLI, from HTTP, or from the
9
+ [Machine](../reference/glossary.md#machine) itself.
10
+
11
+ A [Steering message](../reference/glossary.md#steering-message) is not a pick and not an event. No guard reads it, and
12
+ no [Gate](../reference/glossary.md#gate) takes it. The Agent hears it one time, and nothing interrupts the Agent. Then
13
+ the Agent decides what to do, and it acts on the run only with its picks. To move the run, answer a Gate:
14
+ [Answer a Gate](answer-a-gate.md).
15
+
16
+ The examples on this page use the [Workflow](../reference/glossary.md#workflow) `notes`. A writer writes release notes,
17
+ and a reviewer reads them. When the reviewer sends a note, the Machine relays it to the writer as a Steering message.
18
+ Save the file as `workflows/notes.ts` in your [Instance](../reference/glossary.md#instance). Then run `jr2 up`:
19
+
20
+ **Anthropic**
21
+
22
+ ```ts
23
+ import { assign } from "xstate";
24
+ import { z } from "zod";
25
+ import { agent, defineEvent, fail, jr2Setup, steer } from "@jr2/orchestrator";
26
+
27
+ // The writer's pick: the draft is ready for review.
28
+ const done = defineEvent({
29
+ name: "done",
30
+ description: "The draft is ready. Give the whole draft.",
31
+ input: z.object({ draft: z.string().min(1) }),
32
+ });
33
+ // The reviewer's two picks.
34
+ const note = defineEvent({
35
+ name: "note",
36
+ description: "Send the draft back to the writer, with what to change.",
37
+ input: z.object({ text: z.string().min(1) }),
38
+ });
39
+ const approve = defineEvent({
40
+ name: "approve",
41
+ description: "The draft is good.",
42
+ input: z.object({}),
43
+ });
44
+
45
+ type Context = { version: string; draft?: string; fault?: string };
46
+
47
+ export const machine = jr2Setup({
48
+ types: {} as { input: { version: string }; context: Context },
49
+ events: [done, note, approve],
50
+ actors: {
51
+ writer: agent({
52
+ model: "anthropic/claude-haiku-5-5",
53
+ instructions: "You write short release notes.",
54
+ workspace: "none",
55
+ }),
56
+ // A Caller cannot steer the reviewer. The Machine can.
57
+ reviewer: agent({
58
+ model: "anthropic/claude-haiku-5-5",
59
+ instructions: "You review release notes for clear and correct words.",
60
+ workspace: "none",
61
+ steerable: false,
62
+ }),
63
+ fail: fail(),
64
+ },
65
+ }).createMachine({
66
+ id: "notes",
67
+ input: z.object({ version: z.string() }),
68
+ context: ({ input }) => ({ version: input.version }),
69
+ initial: "writing",
70
+ // A Turn that fails in either state ends the run `failed`, with the reason of the Turn.
71
+ on: { "agent.fault": { target: ".failed", actions: assign({ fault: ({ event }) => event.reason }) } },
72
+ states: {
73
+ writing: {
74
+ invoke: {
75
+ src: "writer",
76
+ // The writer continues its conversation, so it keeps its draft from Turn to Turn.
77
+ input: ({ context }) => ({ prompt: `Write the release notes for ${context.version}.`, continue: true }),
78
+ },
79
+ on: { done: { target: "reviewing", actions: assign({ draft: ({ event }) => event.draft }) } },
80
+ },
81
+ reviewing: {
82
+ invoke: {
83
+ src: "reviewer",
84
+ input: ({ context }) => ({ prompt: `Review these release notes:\n\n${context.draft ?? ""}` }),
85
+ },
86
+ on: {
87
+ // The reviewer's note goes to the writer's next Turn as a Steering message. `from` names the
88
+ // reviewer, so the writer reads it as information from a peer, not as an instruction.
89
+ note: {
90
+ target: "writing",
91
+ actions: steer("writer", ({ event }) => event.text, { from: ({ event }) => event.sender }),
92
+ },
93
+ approve: "published",
94
+ },
95
+ },
96
+ published: { type: "final" },
97
+ failed: { invoke: { src: "fail", input: ({ context }) => ({ reason: context.fault ?? "the Turn failed" }) } },
98
+ },
99
+ });
100
+ ```
101
+
102
+ **Local**
103
+
104
+ ```ts
105
+ import { assign } from "xstate";
106
+ import { z } from "zod";
107
+ import { agent, defineEvent, fail, jr2Setup, steer } from "@jr2/orchestrator";
108
+
109
+ // The writer's pick: the draft is ready for review.
110
+ const done = defineEvent({
111
+ name: "done",
112
+ description: "The draft is ready. Give the whole draft.",
113
+ input: z.object({ draft: z.string().min(1) }),
114
+ });
115
+ // The reviewer's two picks.
116
+ const note = defineEvent({
117
+ name: "note",
118
+ description: "Send the draft back to the writer, with what to change.",
119
+ input: z.object({ text: z.string().min(1) }),
120
+ });
121
+ const approve = defineEvent({
122
+ name: "approve",
123
+ description: "The draft is good.",
124
+ input: z.object({}),
125
+ });
126
+
127
+ type Context = { version: string; draft?: string; fault?: string };
128
+
129
+ export const machine = jr2Setup({
130
+ types: {} as { input: { version: string }; context: Context },
131
+ events: [done, note, approve],
132
+ actors: {
133
+ writer: agent({
134
+ model: "local/qwen3.6-35b-a3b",
135
+ instructions: "You write short release notes.",
136
+ workspace: "none",
137
+ }),
138
+ // A Caller cannot steer the reviewer. The Machine can.
139
+ reviewer: agent({
140
+ model: "local/qwen3.6-35b-a3b",
141
+ instructions: "You review release notes for clear and correct words.",
142
+ workspace: "none",
143
+ steerable: false,
144
+ }),
145
+ fail: fail(),
146
+ },
147
+ }).createMachine({
148
+ id: "notes",
149
+ input: z.object({ version: z.string() }),
150
+ context: ({ input }) => ({ version: input.version }),
151
+ initial: "writing",
152
+ // A Turn that fails in either state ends the run `failed`, with the reason of the Turn.
153
+ on: { "agent.fault": { target: ".failed", actions: assign({ fault: ({ event }) => event.reason }) } },
154
+ states: {
155
+ writing: {
156
+ invoke: {
157
+ src: "writer",
158
+ // The writer continues its conversation, so it keeps its draft from Turn to Turn.
159
+ input: ({ context }) => ({ prompt: `Write the release notes for ${context.version}.`, continue: true }),
160
+ },
161
+ on: { done: { target: "reviewing", actions: assign({ draft: ({ event }) => event.draft }) } },
162
+ },
163
+ reviewing: {
164
+ invoke: {
165
+ src: "reviewer",
166
+ input: ({ context }) => ({ prompt: `Review these release notes:\n\n${context.draft ?? ""}` }),
167
+ },
168
+ on: {
169
+ // The reviewer's note goes to the writer's next Turn as a Steering message. `from` names the
170
+ // reviewer, so the writer reads it as information from a peer, not as an instruction.
171
+ note: {
172
+ target: "writing",
173
+ actions: steer("writer", ({ event }) => event.text, { from: ({ event }) => event.sender }),
174
+ },
175
+ approve: "published",
176
+ },
177
+ },
178
+ published: { type: "final" },
179
+ failed: { invoke: { src: "fail", input: ({ context }) => ({ reason: context.fault ?? "the Turn failed" }) } },
180
+ },
181
+ });
182
+ ```
183
+
184
+ The Agents use the model of the tab.
185
+
186
+ In the commands, replace these values:
187
+
188
+ - `<namespace>`: the namespace of your Instance. It is the [`name`](../reference/config.md#name) in `jr2.config.ts`.
189
+ When `jr2.config.ts` sets no `name`, it is the name of the Instance folder.
190
+ - `<run id>`: the run id, or its first 4 characters or more. `jr2 run` prints the run id in the line
191
+ `run <run id> (<workflow>) — attached`.
192
+
193
+ Give each `jr2` command in the Instance folder.
194
+
195
+ ## Start a run
196
+
197
+ ```sh
198
+ jr2 run notes --input '{"version":"1.4.0"}'
199
+ ```
200
+
201
+ ```text
202
+ → context <context> / namespace <namespace>
203
+ run 7058fde8-4c32-4513-82f0-e6c095d8707b (notes) — attached
204
+ → active "writing"
205
+ → active "writing"
206
+ ```
207
+
208
+ Your run id is different. Give the commands in the next steps in a second terminal.
209
+
210
+ ## Find the Agent slot
211
+
212
+ A message goes to an Agent slot: the path of the Machine and the name of the Agent. The Agents of the root Machine have
213
+ the path `root`. An Agent in a child Machine has the path of that Machine, such as `review/reviewer`. Give
214
+ [`jr2 steer`](../reference/cli.md#steer) the run id alone to list the slots:
215
+
216
+ ```sh
217
+ jr2 steer 7058
218
+ ```
219
+
220
+ ```text
221
+ → context <context> / namespace <namespace>
222
+ [{"agent":"root/writer","open":true,"steerable":true},{"agent":"root/reviewer","open":false,"steerable":false}]
223
+ ```
224
+
225
+ - `open` is `true` when a [Turn](../reference/glossary.md#turn) of the slot is open now.
226
+ - `steerable` is `false` when the definition of the Agent says `steerable: false`. A Caller cannot steer it.
227
+
228
+ The list has each Agent of each Machine instance that is live now, also an Agent with no open Turn.
229
+
230
+ ## Send the message
231
+
232
+ ```sh
233
+ jr2 steer 7058 root/writer "Put the breaking change first."
234
+ ```
235
+
236
+ ```text
237
+ → context <context> / namespace <namespace>
238
+ sent a Steering message to root/writer on 7058fde8-4c32-4513-82f0-e6c095d8707b: its open Turn hears it at its next step boundary, or its next Turn hears it if this Turn ends first
239
+ ```
240
+
241
+ Then one of these things occurs:
242
+
243
+ - When a Turn of the slot is open, the Harness adds the message to the Turn before the next model request.
244
+ - When the Turn ends with a pick before its next model request, the message waits for the next Turn of the slot.
245
+ - When no Turn of the slot is open, the message waits. The next Turn of the slot in the same Machine instance hears it,
246
+ and `jr2 steer` prints `its next Turn hears it`.
247
+ - When that Machine instance ends first, the message is not delivered.
248
+
249
+ ## Read what became of the message
250
+
251
+ [`jr2 status`](../reference/cli.md#status) prints the record of the messages of the run in its `steering` field. Each
252
+ entry has the slot, the author, the text, the time, and the `outcome`: `held` while it waits, `heard` when a Turn heard
253
+ it, or `not-delivered` when its Machine instance ended first.
254
+
255
+ ```sh
256
+ jr2 status 7058
257
+ ```
258
+
259
+ ```text
260
+ → context <context> / namespace <namespace>
261
+ {"runId":"7058fde8-4c32-4513-82f0-e6c095d8707b","workflow":"notes",…,"steering":[{"id":"c46a31f0-db82-4d80-b7f1-8908c2d9b121","agent":"root/writer","author":{"kind":"caller","via":"token","name":"instance","onBehalfOf":"kubernetes-admin"},"text":"Put the breaking change first.","at":"2026-11-06T20:56:33.005Z","outcome":"heard"},{"id":"f788b1f6-2b93-44be-a54e-e91f83685493","agent":"root/writer","author":{"kind":"machine","from":{"party":"agent","id":"reviewer"}},"text":"The release notes are well-structured, but I suggest a change for clarity in the **Notifications** section:\n\n\"Real-time notifications are now **persisted** across device logins.\"\n\n\"Persisted\" is technical jargon referring to data storage. If the intended meaning is that notifications appear on different devices, \"**synchronized**\" (or \"synced\") is the standard and clearer term for users.\n\nSuggested edit: \"Real-time notifications are now **synchronized** across devices.\"","at":"2026-11-06T20:57:35.442Z","outcome":"heard"}],…}
262
+ started by: token/instance on behalf of kubernetes-admin
263
+ ```
264
+
265
+ The model reads the message after the notices of the Turn and before its Allowed picks. The Harness tells the model that
266
+ the message is an instruction from outside the run, and gives your name as a [Caller](../reference/glossary.md#caller).
267
+
268
+ ## Send the message from the Console
269
+
270
+ With a credential that has the `steer` scope for the Workflow, the [Console](../reference/glossary.md#console) shows a
271
+ box beside the conversation in the bottom drawer. Select the run, and click the tab of the Agent slot. Type the message
272
+ in the box under `steer <slot>`, and click `send`. The box shows `<slot> cannot be steered now` when the definition of
273
+ the Agent says `steerable: false`, or when the Machine instance of the slot ended. The conversation shows the message
274
+ where the model read it. [Open the Console](open-the-console.md#read-a-conversation) tells how to open the drawer.
275
+
276
+ ## Send the message from HTTP
277
+
278
+ A client that is not the CLI sends the message to
279
+ [`POST /runs/:runId/steering`](../reference/http-api.md#post-runs-runid-steering), with the credential of a Caller that
280
+ has the `steer` scope for the Workflow of the run. [Give a Caller a scope](give-a-caller-a-scope.md) makes such a token.
281
+ The path takes the full run id, not a prefix.
282
+ [`GET /runs/:runId/agents`](../reference/http-api.md#get-runs-runid-agents) lists the slots. This example reaches the
283
+ Orchestrator through the port forward in [Open the Console](open-the-console.md):
284
+
285
+ ```sh
286
+ curl -X POST http://localhost:4000/runs/<run id>/steering \
287
+ -H "authorization: Bearer <token>" \
288
+ -d '{"agent":"root/writer","text":"Put the breaking change first."}'
289
+ ```
290
+
291
+ ```text
292
+ {"id":"29e54d63-e858-4249-a789-f7e5506f433a","agent":"root/writer","open":true}
293
+ ```
294
+
295
+ The status is 202.
296
+
297
+ ## Steer from the Machine
298
+
299
+ The Machine sends a Steering message with the [`steer`](../reference/authoring-surface/steer.md) action, in a
300
+ transition. In `notes.ts`, the `note` pick of the reviewer sends the writer back to `writing`, and `steer` gives the
301
+ reviewer's text to the writer's next Turn.
302
+
303
+ `from` names the [Sender](../reference/glossary.md#sender) of the event: here, the reviewer. Then the writer reads the
304
+ text as information from a peer, not as an instruction. When `from` is a Gate, the writer reads the text as what the
305
+ Gate received, not as an order: the workflow did not write it. A `steer` with no `from` is the text of the workflow
306
+ itself. Agents tell each other things only in this way: jr2 gives an Agent no tool to message another Agent.
307
+
308
+ The Machine can steer an Agent whose definition says `steerable: false`. That refuses Callers only.
309
+
310
+ ## Rules
311
+
312
+ - A message is at most 16 KiB of UTF-8. `POST /runs/:runId/steering` refuses a longer text with the status 413:
313
+ `the text is longer than 16384 bytes (16 KiB)`. The `steer` action cuts a longer text and adds
314
+ `[jr2 cut this message at 16 KiB]`.
315
+ - A body with no `agent`, or no `text`, gets the status 400.
316
+ - A slot that no live Machine instance of the run holds gets the status 409, with the slots of the run in `agents`:
317
+ `no live Machine instance of run "<run id>" holds the Agent slot "<agent>" (its slots: <slots>)`. A run that has ended
318
+ gets 409 too: `run "<run id>" is not live: no Agent of it can hear a message`.
319
+ - A slot whose Agent says `steerable: false` gets the status 403:
320
+ `the Agent slot "<agent>" is not steerable: its definition says steerable: false`.
321
+ - A Caller with no `steer` scope for the Workflow of the run gets the status 403:
322
+ `the Caller <via>/<name> needs the "steer" scope for Workflow "<workflow>" (ADR-0078)`.
323
+ - An unknown run gets the status 404: `no run "<run id>"`.
324
+ - The record keeps the newest 100 messages of a run, and each message that waits.
325
+
326
+ ## Read next
327
+
328
+ - [Agents and Turns](../concepts/agents-and-turns.md#steering-messages)
329
+ - [`jr2 steer`](../reference/cli.md#steer) and [`steer`](../reference/authoring-surface/steer.md)
330
+ - [ADR-0002](../reference/decisions/0002-duplex-streaming-actor.md#steering-messages): Steering messages
331
+ - [ADR-0062](../reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md): one ledger for notices
332
+ and Steering messages
@@ -186,7 +186,7 @@ custom provider, with `harness.provider` and `apiKey`. The guide
186
186
  - `jr2 up` refuses a gateway address that is not `https://`:
187
187
  `harness.catalog.<id>.baseUrl must be an https:// URL — the Custodian carries TLS only (ADR-0059). Read it from .env: catalog: { anthropic: { baseUrl: process.env.LITELLM_URL ?? "" } }`.
188
188
  - `jr2 up` warns about a key that no pod gets:
189
- `warning: secrets[<i>] (<NAME>) is named by nothing; goes nowhere — no workspace() lists it, no Agent's provider reads it, and no Effect names it (ADR-0059, ADR-0068)`.
189
+ `warning: secrets[<i>] (<NAME>) is named by nothing; goes nowhere — no workspace() lists it, no Agent's provider reads it, and no Effect or Hook names it (ADR-0059, ADR-0068)`.
190
190
  - A credential that signs each request, such as `AWS_ACCESS_KEY_ID`, cannot be a Held secret. `jr2 up` warns when
191
191
  `harness.env` sets one. Send the calls through a gateway that holds the credential, and hold the key of the gateway:
192
192
  `warning: harness.env sets <NAME>: a signing credential cannot be held (a Stand-in cannot be swapped into a signature), so the Agent can read it — route the provider through a gateway that holds it, and hold the gateway's key instead (ADR-0059)`.