@jr2/orchestrator 0.4.1 → 0.5.1

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 (327) hide show
  1. package/README.md +20 -2
  2. package/console/components/app.ts +2 -0
  3. package/console/components/fleet.ts +14 -1
  4. package/console/components/machine-pane.ts +41 -2
  5. package/console/main.ts +13 -1
  6. package/console/store.ts +102 -6
  7. package/console/style.css +21 -0
  8. package/docs/agents-block.md +5 -0
  9. package/docs/concepts/agents-and-turns.md +442 -0
  10. package/docs/concepts/architecture.md +230 -0
  11. package/docs/concepts/charts.md +143 -0
  12. package/docs/concepts/composition.md +357 -0
  13. package/docs/concepts/converge.md +254 -0
  14. package/docs/concepts/durable-runs.md +189 -0
  15. package/docs/concepts/effects.md +603 -0
  16. package/docs/concepts/gates.md +208 -0
  17. package/docs/concepts/machines-and-workflows.md +289 -0
  18. package/docs/concepts/pools-and-sources.md +230 -0
  19. package/docs/concepts/secrets-and-trust.md +222 -0
  20. package/docs/concepts/the-menu.md +378 -0
  21. package/docs/concepts/workspaces.md +678 -0
  22. package/docs/get-started/a-model-decides.md +563 -0
  23. package/docs/get-started/an-agent-in-a-sandbox.md +381 -0
  24. package/docs/get-started/connect-a-model.md +248 -0
  25. package/docs/get-started/create-an-instance.md +194 -0
  26. package/docs/get-started/have-your-assistant-write-a-machine.md +922 -0
  27. package/docs/get-started/install.md +126 -0
  28. package/docs/guides/add-tools-to-the-sandbox.md +295 -0
  29. package/docs/guides/answer-a-gate.md +304 -0
  30. package/docs/guides/bind-open-parts.md +223 -0
  31. package/docs/guides/cancel-a-run.md +146 -0
  32. package/docs/guides/clean-up.md +206 -0
  33. package/docs/guides/fix-a-failed-converge.md +361 -0
  34. package/docs/guides/give-the-cluster-git-credentials.md +222 -0
  35. package/docs/guides/iterate-on-a-machine-on-kind.md +190 -0
  36. package/docs/guides/let-an-agent-write-a-chart.md +226 -0
  37. package/docs/guides/look-inside-a-sandbox.md +174 -0
  38. package/docs/guides/mirror-the-kit-images.md +176 -0
  39. package/docs/guides/move-from-kind-to-a-shared-cluster.md +302 -0
  40. package/docs/guides/open-the-console.md +91 -0
  41. package/docs/guides/publish-a-machine-as-an-npm-package.md +350 -0
  42. package/docs/guides/push-and-sign-a-branch.md +486 -0
  43. package/docs/guides/run-a-chart-by-name.md +270 -0
  44. package/docs/guides/run-a-command-or-call-a-url.md +544 -0
  45. package/docs/guides/run-one-worker-per-item.md +321 -0
  46. package/docs/guides/set-an-agents-access-and-dials.md +375 -0
  47. package/docs/guides/size-a-workspace.md +204 -0
  48. package/docs/guides/start-a-run-from-a-run.md +237 -0
  49. package/docs/guides/start-a-run.md +207 -0
  50. package/docs/guides/upgrade-the-kit-version.md +240 -0
  51. package/docs/guides/use-a-hosted-provider.md +208 -0
  52. package/docs/guides/use-a-local-model.md +313 -0
  53. package/docs/guides/watch-a-run.md +326 -0
  54. package/docs/guides/write-a-workflow.md +318 -0
  55. package/docs/index.md +44 -0
  56. package/docs/llms.txt +216 -0
  57. package/docs/reference/authoring-surface/agent.md +128 -0
  58. package/docs/reference/authoring-surface/answer.md +140 -0
  59. package/docs/reference/authoring-surface/arg.md +60 -0
  60. package/docs/reference/authoring-surface/basic.md +62 -0
  61. package/docs/reference/authoring-surface/bearer.md +53 -0
  62. package/docs/reference/authoring-surface/chartschema.md +23 -0
  63. package/docs/reference/authoring-surface/chartschemafor.md +48 -0
  64. package/docs/reference/authoring-surface/command.md +191 -0
  65. package/docs/reference/authoring-surface/customize.md +64 -0
  66. package/docs/reference/authoring-surface/defineconfig.md +41 -0
  67. package/docs/reference/authoring-surface/defineevent.md +114 -0
  68. package/docs/reference/authoring-surface/dispatch.md +126 -0
  69. package/docs/reference/authoring-surface/fail.md +83 -0
  70. package/docs/reference/authoring-surface/file.md +122 -0
  71. package/docs/reference/authoring-surface/frompick.md +277 -0
  72. package/docs/reference/authoring-surface/http.md +159 -0
  73. package/docs/reference/authoring-surface/isfailure.md +58 -0
  74. package/docs/reference/authoring-surface/jr2setup.md +237 -0
  75. package/docs/reference/authoring-surface/open.md +74 -0
  76. package/docs/reference/authoring-surface/openbody.md +86 -0
  77. package/docs/reference/authoring-surface/paramsof.md +125 -0
  78. package/docs/reference/authoring-surface/pool.md +186 -0
  79. package/docs/reference/authoring-surface/push.md +112 -0
  80. package/docs/reference/authoring-surface/secret.md +118 -0
  81. package/docs/reference/authoring-surface/sentby.md +83 -0
  82. package/docs/reference/authoring-surface/source.md +51 -0
  83. package/docs/reference/authoring-surface/text.md +62 -0
  84. package/docs/reference/authoring-surface/type-agentdeclaration.md +27 -0
  85. package/docs/reference/authoring-surface/type-agentdefinition.md +80 -0
  86. package/docs/reference/authoring-surface/type-agentlogic.md +15 -0
  87. package/docs/reference/authoring-surface/type-agentslots.md +12 -0
  88. package/docs/reference/authoring-surface/type-answeraction.md +12 -0
  89. package/docs/reference/authoring-surface/type-arg.md +19 -0
  90. package/docs/reference/authoring-surface/type-argnames.md +12 -0
  91. package/docs/reference/authoring-surface/type-binding.md +62 -0
  92. package/docs/reference/authoring-surface/type-bindingof.md +12 -0
  93. package/docs/reference/authoring-surface/type-bodyacceptsdoor.md +15 -0
  94. package/docs/reference/authoring-surface/type-bodyacceptsslots.md +17 -0
  95. package/docs/reference/authoring-surface/type-ceilings.md +41 -0
  96. package/docs/reference/authoring-surface/type-chainlink.md +19 -0
  97. package/docs/reference/authoring-surface/type-chartaction.md +46 -0
  98. package/docs/reference/authoring-surface/type-chartagent.md +28 -0
  99. package/docs/reference/authoring-surface/type-chartevent.md +20 -0
  100. package/docs/reference/authoring-surface/type-chartguard.md +20 -0
  101. package/docs/reference/authoring-surface/type-chartinvoke.md +28 -0
  102. package/docs/reference/authoring-surface/type-chartjson.md +14 -0
  103. package/docs/reference/authoring-surface/type-chartstate.md +46 -0
  104. package/docs/reference/authoring-surface/type-charttext.md +40 -0
  105. package/docs/reference/authoring-surface/type-charttransition.md +22 -0
  106. package/docs/reference/authoring-surface/type-charttransitions.md +14 -0
  107. package/docs/reference/authoring-surface/type-chartvalue.md +15 -0
  108. package/docs/reference/authoring-surface/type-childat.md +12 -0
  109. package/docs/reference/authoring-surface/type-childslots.md +12 -0
  110. package/docs/reference/authoring-surface/type-commandenv.md +15 -0
  111. package/docs/reference/authoring-surface/type-commandinput.md +19 -0
  112. package/docs/reference/authoring-surface/type-commandoptions.md +78 -0
  113. package/docs/reference/authoring-surface/type-commandoutput.md +104 -0
  114. package/docs/reference/authoring-surface/type-customize.md +109 -0
  115. package/docs/reference/authoring-surface/type-dispatchdefinition.md +39 -0
  116. package/docs/reference/authoring-surface/type-dispatchinput.md +14 -0
  117. package/docs/reference/authoring-surface/type-dispatchopenparts.md +14 -0
  118. package/docs/reference/authoring-surface/type-dispatchoutput.md +65 -0
  119. package/docs/reference/authoring-surface/type-duration.md +15 -0
  120. package/docs/reference/authoring-surface/type-effectbinding.md +93 -0
  121. package/docs/reference/authoring-surface/type-effectlogic.md +12 -0
  122. package/docs/reference/authoring-surface/type-envopenparts.md +14 -0
  123. package/docs/reference/authoring-surface/type-eventaudience.md +27 -0
  124. package/docs/reference/authoring-surface/type-eventdef.md +45 -0
  125. package/docs/reference/authoring-surface/type-eventfrom.md +16 -0
  126. package/docs/reference/authoring-surface/type-eventsemantics.md +26 -0
  127. package/docs/reference/authoring-surface/type-execoutcome.md +34 -0
  128. package/docs/reference/authoring-surface/type-failslot.md +14 -0
  129. package/docs/reference/authoring-surface/type-failure.md +19 -0
  130. package/docs/reference/authoring-surface/type-failureinput.md +20 -0
  131. package/docs/reference/authoring-surface/type-filebody.md +41 -0
  132. package/docs/reference/authoring-surface/type-frominput.md +14 -0
  133. package/docs/reference/authoring-surface/type-hostinjectedinput.md +58 -0
  134. package/docs/reference/authoring-surface/type-httpdefinition.md +101 -0
  135. package/docs/reference/authoring-surface/type-httpinput.md +12 -0
  136. package/docs/reference/authoring-surface/type-httpmethod.md +14 -0
  137. package/docs/reference/authoring-surface/type-httpopenparts.md +12 -0
  138. package/docs/reference/authoring-surface/type-httpoutput.md +89 -0
  139. package/docs/reference/authoring-surface/type-httprequestparts.md +33 -0
  140. package/docs/reference/authoring-surface/type-jr2config.md +126 -0
  141. package/docs/reference/authoring-surface/type-lends.md +38 -0
  142. package/docs/reference/authoring-surface/type-logicat.md +12 -0
  143. package/docs/reference/authoring-surface/type-markedif.md +12 -0
  144. package/docs/reference/authoring-surface/type-mergedactors.md +12 -0
  145. package/docs/reference/authoring-surface/type-namedsecret.md +25 -0
  146. package/docs/reference/authoring-surface/type-noslotspec.md +26 -0
  147. package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +32 -0
  148. package/docs/reference/authoring-surface/type-openbodydeclaration.md +40 -0
  149. package/docs/reference/authoring-surface/type-openbodylogic.md +14 -0
  150. package/docs/reference/authoring-surface/type-openbodyoutput.md +42 -0
  151. package/docs/reference/authoring-surface/type-openbodyslot.md +18 -0
  152. package/docs/reference/authoring-surface/type-opencommandinput.md +17 -0
  153. package/docs/reference/authoring-surface/type-openeffect.md +12 -0
  154. package/docs/reference/authoring-surface/type-openeffectslots.md +12 -0
  155. package/docs/reference/authoring-surface/type-openof.md +12 -0
  156. package/docs/reference/authoring-surface/type-opensecret.md +23 -0
  157. package/docs/reference/authoring-surface/type-opensecretmark.md +12 -0
  158. package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +31 -0
  159. package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +32 -0
  160. package/docs/reference/authoring-surface/type-poolmachine.md +28 -0
  161. package/docs/reference/authoring-surface/type-poolspec.md +60 -0
  162. package/docs/reference/authoring-surface/type-pushinput.md +15 -0
  163. package/docs/reference/authoring-surface/type-pushoptions.md +79 -0
  164. package/docs/reference/authoring-surface/type-pushoutput.md +124 -0
  165. package/docs/reference/authoring-surface/type-pushwireoutput.md +12 -0
  166. package/docs/reference/authoring-surface/type-quantity.md +14 -0
  167. package/docs/reference/authoring-surface/type-reached.md +12 -0
  168. package/docs/reference/authoring-surface/type-reposlot.md +70 -0
  169. package/docs/reference/authoring-surface/type-reposlotsof.md +16 -0
  170. package/docs/reference/authoring-surface/type-sandboxoptions.md +77 -0
  171. package/docs/reference/authoring-surface/type-secret.md +25 -0
  172. package/docs/reference/authoring-surface/type-sender.md +19 -0
  173. package/docs/reference/authoring-surface/type-sentbyguards.md +12 -0
  174. package/docs/reference/authoring-surface/type-size.md +85 -0
  175. package/docs/reference/authoring-surface/type-slothandles.md +32 -0
  176. package/docs/reference/authoring-surface/type-sourcenextresult.md +17 -0
  177. package/docs/reference/authoring-surface/type-sourcespec.md +44 -0
  178. package/docs/reference/authoring-surface/type-syncstate.md +12 -0
  179. package/docs/reference/authoring-surface/type-text.md +19 -0
  180. package/docs/reference/authoring-surface/type-textpart.md +24 -0
  181. package/docs/reference/authoring-surface/type-thinkinglevel.md +39 -0
  182. package/docs/reference/authoring-surface/type-toparameterizedobject.md +14 -0
  183. package/docs/reference/authoring-surface/type-toprovidedactor.md +14 -0
  184. package/docs/reference/authoring-surface/type-unknown.md +21 -0
  185. package/docs/reference/authoring-surface/type-usercontainer.md +77 -0
  186. package/docs/reference/authoring-surface/type-withoutemptyindex.md +20 -0
  187. package/docs/reference/authoring-surface/type-workflowevent.md +46 -0
  188. package/docs/reference/authoring-surface/type-workspaceaccess.md +16 -0
  189. package/docs/reference/authoring-surface/type-workspaced.md +94 -0
  190. package/docs/reference/authoring-surface/type-workspacehandles.md +23 -0
  191. package/docs/reference/authoring-surface/type-workspacemachine.md +29 -0
  192. package/docs/reference/authoring-surface/type-workspaceof.md +13 -0
  193. package/docs/reference/authoring-surface/type-workspaceoptions.md +39 -0
  194. package/docs/reference/authoring-surface/type-workspacespec.md +37 -0
  195. package/docs/reference/authoring-surface/workspace.md +259 -0
  196. package/docs/reference/authoring-surface.md +197 -0
  197. package/docs/reference/cli.md +433 -0
  198. package/docs/reference/config.md +756 -0
  199. package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +113 -0
  200. package/docs/reference/decisions/0002-duplex-streaming-actor.md +110 -0
  201. package/docs/reference/decisions/0004-worktree-provisioning-model.md +124 -0
  202. package/docs/reference/decisions/0005-sandbox-pod-composition.md +230 -0
  203. package/docs/reference/decisions/0006-agent-control-surface.md +47 -0
  204. package/docs/reference/decisions/0007-durable-machine-state.md +109 -0
  205. package/docs/reference/decisions/0008-orchestrator-as-deployed-app.md +60 -0
  206. package/docs/reference/decisions/0009-cli-and-instance-interface.md +275 -0
  207. package/docs/reference/decisions/0010-bdd-acceptance-tests.md +160 -0
  208. package/docs/reference/decisions/0011-workflow-defined-events.md +141 -0
  209. package/docs/reference/decisions/0012-workspace-wrapper-machine.md +103 -0
  210. package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +157 -0
  211. package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +95 -0
  212. package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +265 -0
  213. package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +124 -0
  214. package/docs/reference/decisions/0017-pool-over-a-source-port.md +69 -0
  215. package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +111 -0
  216. package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +275 -0
  217. package/docs/reference/decisions/0020-private-ca-trust-is-a-named-concept.md +60 -0
  218. package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +100 -0
  219. package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +103 -0
  220. package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +176 -0
  221. package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +439 -0
  222. package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +65 -0
  223. package/docs/reference/decisions/0026-a-turn-that-is-over-is-never-prompted.md +62 -0
  224. package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +237 -0
  225. package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +89 -0
  226. package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +154 -0
  227. package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +100 -0
  228. package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +190 -0
  229. package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +61 -0
  230. package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +127 -0
  231. package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +57 -0
  232. package/docs/reference/decisions/0035-a-runaway-turn-is-ended-rerolled-once-then-a-fault.md +92 -0
  233. package/docs/reference/decisions/0036-a-turn-compacts-its-own-context-mid-flight.md +138 -0
  234. package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +196 -0
  235. package/docs/reference/decisions/0038-jr2-up-builds-every-image-it-deploys.md +170 -0
  236. package/docs/reference/decisions/0039-image-garbage-collects-by-reachability.md +115 -0
  237. package/docs/reference/decisions/0041-a-build-the-host-already-holds-is-not-spent-again.md +64 -0
  238. package/docs/reference/decisions/0042-ready-is-not-routable-an-admission-retries-its-connection.md +142 -0
  239. package/docs/reference/decisions/0043-the-kit-is-tested-as-installed-a-local-registry-stands-in-for-npm.md +170 -0
  240. package/docs/reference/decisions/0044-kit-images-live-at-a-canonical-home-a-self-host-mirrors-it.md +85 -0
  241. package/docs/reference/decisions/0045-the-platform-joins-the-image-address-and-the-cluster-chooses-it.md +82 -0
  242. package/docs/reference/decisions/0046-a-converge-failure-carries-its-diagnosis.md +34 -0
  243. package/docs/reference/decisions/0047-the-git-ssh-key-source-is-the-users-choice.md +47 -0
  244. package/docs/reference/decisions/0048-the-orchestrator-boots-without-its-repos.md +36 -0
  245. package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +126 -0
  246. package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +73 -0
  247. package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +227 -0
  248. package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +81 -0
  249. package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +111 -0
  250. package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +126 -0
  251. package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +107 -0
  252. package/docs/reference/decisions/0056-a-global-jr2-hands-off-to-the-instances-own-and-an-instance-has-one-kit-version.md +62 -0
  253. package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +152 -0
  254. package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +106 -0
  255. package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +384 -0
  256. package/docs/reference/decisions/0060-a-workspace-states-its-size-and-jr2-reserves-all-of-it.md +111 -0
  257. package/docs/reference/decisions/0061-a-memory-kill-ends-the-agents-processes-not-the-harness.md +83 -0
  258. package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +212 -0
  259. package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +83 -0
  260. package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +79 -0
  261. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +65 -0
  262. package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +550 -0
  263. package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +430 -0
  264. package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +464 -0
  265. package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +180 -0
  266. package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +323 -0
  267. package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +183 -0
  268. package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +144 -0
  269. package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +122 -0
  270. package/docs/reference/decisions/0074-an-unrouted-mechanism-event-is-refused-at-load-and-faults-the-run.md +76 -0
  271. package/docs/reference/decisions.md +83 -0
  272. package/docs/reference/glossary.md +648 -0
  273. package/docs/reference/http-api.md +1348 -0
  274. package/docs/reference/machines.md +190 -0
  275. package/docs/reference/mechanism-events.md +72 -0
  276. package/docs/why.md +206 -0
  277. package/package.json +5 -3
  278. package/src/actor.ts +541 -79
  279. package/src/agent.ts +114 -38
  280. package/src/ambient.ts +2 -1
  281. package/src/assembly-checks.ts +189 -7
  282. package/src/cause.ts +234 -0
  283. package/src/chart.ts +169 -37
  284. package/src/charts.ts +34 -6
  285. package/src/config.ts +430 -178
  286. package/src/custodian.ts +74 -22
  287. package/src/customize.ts +188 -46
  288. package/src/dispatch-effect.ts +945 -0
  289. package/src/door-compat.ts +217 -0
  290. package/src/durability.ts +11 -4
  291. package/src/effect.ts +341 -44
  292. package/src/effector-wire.ts +160 -11
  293. package/src/fail.ts +209 -0
  294. package/src/harness-client.ts +541 -47
  295. package/src/http-effect.ts +495 -53
  296. package/src/http.ts +427 -16
  297. package/src/index.ts +60 -82
  298. package/src/instance.ts +68 -8
  299. package/src/internal.ts +84 -0
  300. package/src/machine-doc.ts +21 -3
  301. package/src/mechanism-routes.ts +168 -0
  302. package/src/model-keys.generated.ts +53 -0
  303. package/src/model-keys.ts +18 -58
  304. package/src/notices.ts +66 -13
  305. package/src/open-body.ts +159 -23
  306. package/src/open-effect.ts +81 -8
  307. package/src/open.ts +59 -6
  308. package/src/parts.ts +184 -13
  309. package/src/party.ts +68 -2
  310. package/src/pick.ts +463 -11
  311. package/src/pool.ts +247 -36
  312. package/src/registration.ts +83 -4
  313. package/src/repos.ts +2 -1
  314. package/src/run-host.ts +565 -31
  315. package/src/run-output.ts +38 -0
  316. package/src/sandbox-effect.ts +273 -38
  317. package/src/sandbox-kube.ts +3 -1
  318. package/src/secret-placement.ts +52 -17
  319. package/src/server.ts +3 -0
  320. package/src/setup.ts +239 -56
  321. package/src/size.ts +121 -9
  322. package/src/snapshot-store.ts +54 -10
  323. package/src/stub-harness.ts +44 -16
  324. package/src/timers.ts +14 -1
  325. package/src/vocabulary.ts +69 -14
  326. package/src/wire.ts +90 -16
  327. package/src/workspace.ts +697 -175
@@ -0,0 +1,563 @@
1
+ ---
2
+ title: A model decides
3
+ description: Write a Workflow in which a model chooses the next state, and answer its question at a Gate.
4
+ ---
5
+
6
+ # A model decides
7
+
8
+ At the end of this page, you have a [Workflow](../reference/glossary.md#workflow), `triage`, in which a model makes a
9
+ decision. An [Agent](../reference/glossary.md#agent) reads a feature request and picks one of three events. When it asks
10
+ a question, the run waits at a [Gate](../reference/glossary.md#gate) until you answer. You answer one run from the CLI
11
+ and one run from the [Console](../reference/glossary.md#console).
12
+
13
+ ## Before you start
14
+
15
+ Do [Connect a model](connect-a-model.md) first. The [Instance](../reference/glossary.md#instance) `my-instance` must
16
+ have the model of your tab.
17
+
18
+ You need the port forward of [Create an Instance](create-an-instance.md). Keep it open in its terminal. Then open a new
19
+ terminal in `my-instance` for `jr2 send`. This page calls it the send terminal. Give the other commands in your first
20
+ terminal, in `my-instance`.
21
+
22
+ ## Write the Workflow
23
+
24
+ Make the file `workflows/triage.ts` in `my-instance`. The name of the file is the name of the Workflow, so the Workflow
25
+ is `triage`. Copy this code into the file:
26
+
27
+ **Anthropic**
28
+
29
+ ```ts
30
+ import { assign } from "xstate";
31
+ import { z } from "zod";
32
+ import { agent, defineEvent, jr2Setup } from "@jr2/orchestrator";
33
+
34
+ // The run input: what you give `jr2 run triage --input`. The Console makes its start form from it.
35
+ const door = z.object({
36
+ request: z.string().describe("A feature request, in the requester's own words."),
37
+ });
38
+
39
+ // The Agent's three picks. Each one is a tool that the model can call.
40
+ const accept = defineEvent({
41
+ name: "accept",
42
+ description: "The request is clear enough to build: it names what to change, where, and how to tell it is done.",
43
+ input: z.object({ summary: z.string().describe("The request restated as one actionable sentence.") }),
44
+ });
45
+ const needsInfo = defineEvent({
46
+ name: "needs_info",
47
+ description: "The request could be built more than one way, or its outcome cannot be checked. Ask one question.",
48
+ input: z.object({ question: z.string().describe("The one question whose answer would make it buildable.") }),
49
+ });
50
+ const reject = defineEvent({
51
+ name: "reject",
52
+ description: "The request is not a change to software, or it asks for something harmful.",
53
+ input: z.object({ reason: z.string().describe("Why, in one sentence.") }),
54
+ });
55
+ // Your one reply. Only a Gate takes it, so the Agent can never send it.
56
+ const answer = defineEvent({
57
+ name: "answer",
58
+ description: "Answer the triager's question. It triages the request again with the answer in hand.",
59
+ input: z.object({ info: z.string().describe("The answer, in prose.") }),
60
+ });
61
+
62
+ type Ctx = z.infer<typeof door> & {
63
+ // Each question that the Agent asked, and the answer that it got.
64
+ exchange: { question: string; info?: string }[];
65
+ // Why the last Turn ended with no pick, when it did.
66
+ fault?: string;
67
+ summary?: string;
68
+ reason?: string;
69
+ };
70
+ // The output of the run: the decision. The job of a triage is the decision itself, so "rejected" is a
71
+ // correct answer: a final state, with the reason in the output, and not a Failure.
72
+ type Output = { outcome: "accepted"; summary: string } | { outcome: "rejected"; reason: string };
73
+
74
+ export const machine = jr2Setup({
75
+ types: {} as { context: Ctx; input: z.infer<typeof door>; output: Output },
76
+ events: [accept, needsInfo, reject, answer],
77
+ actors: {
78
+ triager: agent({
79
+ // The provider, then the model. jr2.config.ts holds the key for the provider.
80
+ model: "anthropic/claude-haiku-5-5",
81
+ description: "Reads one feature request and decides whether it can be built as written.",
82
+ // No Sandbox and no Working tools: the Agent can only read its prompt and pick.
83
+ workspace: "none",
84
+ thinkingLevel: "off",
85
+ instructions: `You triage feature requests for a small software team. You read one request and
86
+ decide, by calling exactly one tool:
87
+
88
+ - accept — it names WHAT to change, WHERE (which command, screen, or file), and how to tell it
89
+ is done.
90
+ - needs_info — any of those is missing. Ask the ONE question that would settle it. Never guess
91
+ what the requester meant: if you would have to assume, ask.
92
+ - reject — it is not a change to software, or it asks for something harmful.
93
+
94
+ You have no tools but these three, and you MUST end your turn by calling one of them.`,
95
+ }),
96
+ },
97
+ }).createMachine({
98
+ id: "triage",
99
+ input: door,
100
+ context: ({ input }) => ({ request: input.request, exchange: [] }),
101
+ initial: "triaging",
102
+ states: {
103
+ // The Agent's Menu is the events that this state takes: accept, needs_info and reject.
104
+ triaging: {
105
+ invoke: { src: "triager", input: ({ context }) => ({ prompt: prompt(context) }) },
106
+ on: {
107
+ accept: { target: "accepted", actions: assign({ summary: ({ event }) => event.summary }) },
108
+ reject: { target: "rejected", actions: assign({ reason: ({ event }) => event.reason }) },
109
+ needs_info: {
110
+ target: "clarify",
111
+ actions: assign({
112
+ exchange: ({ context, event }) => [...context.exchange, { question: event.question }],
113
+ fault: undefined,
114
+ }),
115
+ },
116
+ // The Turn failed, with no pick. Wait at the Gate, so that your answer starts a new Turn.
117
+ "agent.fault": { target: "clarify", actions: assign({ fault: ({ event }) => event.reason }) },
118
+ },
119
+ },
120
+ // The Gate. Its name is the name of this state, and it takes the events of this state: answer.
121
+ clarify: {
122
+ invoke: {
123
+ src: "gate",
124
+ input: ({ context }) => ({
125
+ meta:
126
+ context.fault !== undefined ? { fault: context.fault } : { question: context.exchange.at(-1)!.question },
127
+ }),
128
+ },
129
+ on: {
130
+ answer: {
131
+ target: "triaging",
132
+ actions: assign({
133
+ exchange: ({ context, event }) =>
134
+ context.fault !== undefined
135
+ ? context.exchange
136
+ : [...context.exchange.slice(0, -1), { ...context.exchange.at(-1)!, info: event.info }],
137
+ fault: undefined,
138
+ }),
139
+ },
140
+ },
141
+ },
142
+ accepted: { type: "final", output: ({ context }): Output => ({ outcome: "accepted", summary: context.summary! }) },
143
+ rejected: { type: "final", output: ({ context }): Output => ({ outcome: "rejected", reason: context.reason! }) },
144
+ },
145
+ // xstate reads only this root `output`. It gets the output of the final state as `event.output`.
146
+ output: ({ event }) => event.output as Output,
147
+ });
148
+
149
+ // The prompt of each Turn: the request, then each question and its answer.
150
+ function prompt(context: Ctx): string {
151
+ const answered = context.exchange
152
+ .filter((e) => e.info !== undefined)
153
+ .map((e) => `\n\nYou asked: ${e.question}\nThe requester answered: ${e.info}`)
154
+ .join("");
155
+ return `Feature request:\n${context.request}${answered}`;
156
+ }
157
+ ```
158
+
159
+ **Local**
160
+
161
+ ```ts
162
+ import { assign } from "xstate";
163
+ import { z } from "zod";
164
+ import { agent, defineEvent, jr2Setup } from "@jr2/orchestrator";
165
+
166
+ // The run input: what you give `jr2 run triage --input`. The Console makes its start form from it.
167
+ const door = z.object({
168
+ request: z.string().describe("A feature request, in the requester's own words."),
169
+ });
170
+
171
+ // The Agent's three picks. Each one is a tool that the model can call.
172
+ const accept = defineEvent({
173
+ name: "accept",
174
+ description: "The request is clear enough to build: it names what to change, where, and how to tell it is done.",
175
+ input: z.object({ summary: z.string().describe("The request restated as one actionable sentence.") }),
176
+ });
177
+ const needsInfo = defineEvent({
178
+ name: "needs_info",
179
+ description: "The request could be built more than one way, or its outcome cannot be checked. Ask one question.",
180
+ input: z.object({ question: z.string().describe("The one question whose answer would make it buildable.") }),
181
+ });
182
+ const reject = defineEvent({
183
+ name: "reject",
184
+ description: "The request is not a change to software, or it asks for something harmful.",
185
+ input: z.object({ reason: z.string().describe("Why, in one sentence.") }),
186
+ });
187
+ // Your one reply. Only a Gate takes it, so the Agent can never send it.
188
+ const answer = defineEvent({
189
+ name: "answer",
190
+ description: "Answer the triager's question. It triages the request again with the answer in hand.",
191
+ input: z.object({ info: z.string().describe("The answer, in prose.") }),
192
+ });
193
+
194
+ type Ctx = z.infer<typeof door> & {
195
+ // Each question that the Agent asked, and the answer that it got.
196
+ exchange: { question: string; info?: string }[];
197
+ // Why the last Turn ended with no pick, when it did.
198
+ fault?: string;
199
+ summary?: string;
200
+ reason?: string;
201
+ };
202
+ // The output of the run: the decision. The job of a triage is the decision itself, so "rejected" is a
203
+ // correct answer: a final state, with the reason in the output, and not a Failure.
204
+ type Output = { outcome: "accepted"; summary: string } | { outcome: "rejected"; reason: string };
205
+
206
+ export const machine = jr2Setup({
207
+ types: {} as { context: Ctx; input: z.infer<typeof door>; output: Output },
208
+ events: [accept, needsInfo, reject, answer],
209
+ actors: {
210
+ triager: agent({
211
+ // `local` is the provider id in jr2.config.ts. The rest is the name that the endpoint serves.
212
+ model: "local/qwen3.6-35b-a3b",
213
+ description: "Reads one feature request and decides whether it can be built as written.",
214
+ // No Sandbox and no Working tools: the Agent can only read its prompt and pick.
215
+ workspace: "none",
216
+ thinkingLevel: "off",
217
+ instructions: `You triage feature requests for a small software team. You read one request and
218
+ decide, by calling exactly one tool:
219
+
220
+ - accept — it names WHAT to change, WHERE (which command, screen, or file), and how to tell it
221
+ is done.
222
+ - needs_info — any of those is missing. Ask the ONE question that would settle it. Never guess
223
+ what the requester meant: if you would have to assume, ask.
224
+ - reject — it is not a change to software, or it asks for something harmful.
225
+
226
+ You have no tools but these three, and you MUST end your turn by calling one of them.`,
227
+ }),
228
+ },
229
+ }).createMachine({
230
+ id: "triage",
231
+ input: door,
232
+ context: ({ input }) => ({ request: input.request, exchange: [] }),
233
+ initial: "triaging",
234
+ states: {
235
+ // The Agent's Menu is the events that this state takes: accept, needs_info and reject.
236
+ triaging: {
237
+ invoke: { src: "triager", input: ({ context }) => ({ prompt: prompt(context) }) },
238
+ on: {
239
+ accept: { target: "accepted", actions: assign({ summary: ({ event }) => event.summary }) },
240
+ reject: { target: "rejected", actions: assign({ reason: ({ event }) => event.reason }) },
241
+ needs_info: {
242
+ target: "clarify",
243
+ actions: assign({
244
+ exchange: ({ context, event }) => [...context.exchange, { question: event.question }],
245
+ fault: undefined,
246
+ }),
247
+ },
248
+ // The Turn failed, with no pick. Wait at the Gate, so that your answer starts a new Turn.
249
+ "agent.fault": { target: "clarify", actions: assign({ fault: ({ event }) => event.reason }) },
250
+ },
251
+ },
252
+ // The Gate. Its name is the name of this state, and it takes the events of this state: answer.
253
+ clarify: {
254
+ invoke: {
255
+ src: "gate",
256
+ input: ({ context }) => ({
257
+ meta:
258
+ context.fault !== undefined ? { fault: context.fault } : { question: context.exchange.at(-1)!.question },
259
+ }),
260
+ },
261
+ on: {
262
+ answer: {
263
+ target: "triaging",
264
+ actions: assign({
265
+ exchange: ({ context, event }) =>
266
+ context.fault !== undefined
267
+ ? context.exchange
268
+ : [...context.exchange.slice(0, -1), { ...context.exchange.at(-1)!, info: event.info }],
269
+ fault: undefined,
270
+ }),
271
+ },
272
+ },
273
+ },
274
+ accepted: { type: "final", output: ({ context }): Output => ({ outcome: "accepted", summary: context.summary! }) },
275
+ rejected: { type: "final", output: ({ context }): Output => ({ outcome: "rejected", reason: context.reason! }) },
276
+ },
277
+ // xstate reads only this root `output`. It gets the output of the final state as `event.output`.
278
+ output: ({ event }) => event.output as Output,
279
+ });
280
+
281
+ // The prompt of each Turn: the request, then each question and its answer.
282
+ function prompt(context: Ctx): string {
283
+ const answered = context.exchange
284
+ .filter((e) => e.info !== undefined)
285
+ .map((e) => `\n\nYou asked: ${e.question}\nThe requester answered: ${e.info}`)
286
+ .join("");
287
+ return `Feature request:\n${context.request}${answered}`;
288
+ }
289
+ ```
290
+
291
+ The two tabs are different only in the `model` line and its comment. The file has five parts:
292
+
293
+ - **The run input.** `door` is a zod schema. A run of `triage` starts with one `request`.
294
+ - **The Vocabulary.** Each [`defineEvent()`](../reference/authoring-surface/defineevent.md) makes one event of the
295
+ [Vocabulary](../reference/glossary.md#vocabulary). Each transition belongs to the party that its state invokes.
296
+ `triaging` invokes the Agent, so only the Agent can send `accept`, `needs_info` and `reject`. `clarify` invokes a
297
+ Gate, so only the Gate can take `answer`.
298
+ - **The Agent.** [`agent()`](../reference/authoring-surface/agent.md) makes the Agent `triager`, with its model and its
299
+ instructions. `workspace: "none"` gives it no [Sandbox](../reference/glossary.md#sandbox) and no
300
+ [Working tools](../reference/glossary.md#working-tools). It can only read its prompt and pick an event.
301
+ `thinkingLevel: "off"` makes the model pick with no thinking step. [Agents and Turns](../concepts/agents-and-turns.md)
302
+ explains the other fields.
303
+ - **The Machine.** [`jr2Setup()`](../reference/authoring-surface/jr2setup.md) takes the Vocabulary and the Agent. Then
304
+ `createMachine` gives the states of the [Machine](../reference/glossary.md#machine).
305
+ - **The prompt.** `prompt()` makes the text of each [Turn](../reference/glossary.md#turn) from the request and each
306
+ question and answer.
307
+
308
+ The state `triaging` invokes `triager`. Its transitions take `accept`, `needs_info` and `reject`, so these three events
309
+ are the [Menu](../reference/glossary.md#menu) of the Agent. The model sees each event as a tool, with its `description`
310
+ and its input schema. The Agent ends its Turn when it calls one of them. The fourth transition,
311
+ [`agent.fault`](../reference/mechanism-events.md#agent-fault), is not on the Menu. jr2 sends it when a Turn fails with
312
+ no pick. Then the run waits at the Gate, and the Gate shows a `fault` in place of a question.
313
+
314
+ The state `clarify` invokes [`gate`](../reference/authoring-surface/jr2setup.md), which jr2 supplies. Its `meta` holds
315
+ the question of the Agent, and its one transition takes `answer`. The Gate has the name of its state: `clarify`. When
316
+ you send `answer`, the run goes back to `triaging`. The next Turn gets the request, the question, and your answer in its
317
+ prompt.
318
+
319
+ ## Converge the Instance
320
+
321
+ [`jr2 up`](../reference/cli.md#up) publishes the Workflows to the [Orchestrator](../reference/glossary.md#orchestrator).
322
+ Thus you run it each time that you change a Workflow. In the first terminal, run:
323
+
324
+ ```sh
325
+ jr2 up
326
+ ```
327
+
328
+ `jr2 up` prints who can send each event, in each state of `triage`. Then it converges the cluster.
329
+
330
+ **Anthropic**
331
+
332
+ The output shows where the model key goes. Then `jr2 up` asks your model for one tool call, from inside the cluster:
333
+
334
+ ```text
335
+ → .env: ANTHROPIC_API_KEY
336
+ jr2 up — instance "my-instance" → context kind-jr2 / namespace my-instance
337
+ typecheck: tsc --noEmit (the instance's own compiler)
338
+ seats: workflow "triage" — who may send what, per state (ADR-0015)
339
+ triage.triaging agent:triager: [accept, needs_info, reject]
340
+ triage.clarify gate: [answer]
341
+ agents: triager (carried by 2 workflow machine(s))
342
+ …
343
+ secret ANTHROPIC_API_KEY: Held in the Instance Harness
344
+ the Instance Harness: Custodian holds ANTHROPIC_API_KEY (provider)
345
+ held secret ANTHROPIC_API_KEY → api.anthropic.com (literal)
346
+ held secrets: minted the Instance's CA into jr2-held-ca
347
+ provider: checking anthropic/claude-haiku-5-5 on the Instance Harness, through a Custodian that holds ANTHROPIC_API_KEY for api.anthropic.com
348
+ provider: the check pod has up to 5 min to start, then up to 6 min for its model
349
+ …
350
+ provider: anthropic/claude-haiku-5-5 reachable, and it completed a tool call
351
+ …
352
+ instance harness: converging (triager declares workspace: "none")
353
+ instance harness: verified — 1 pod(s) running ghcr.io/snapwich/jr2-harness:<version>
354
+ …
355
+ converged — `jr2 run <workflow>` when ready
356
+ ```
357
+
358
+ The warning of Connect a model, `secrets[0] (ANTHROPIC_API_KEY) is named by nothing; goes nowhere`, is gone. `triager`
359
+ names an Anthropic model, so `jr2 up` gives the key to the [Custodian](../reference/glossary.md#custodian) of the pod
360
+ that runs its Turns. Then it checks the model through a Custodian that holds the key. If the check fails, `jr2 up` stops
361
+ and prints what to examine.
362
+
363
+ **Local**
364
+
365
+ `jr2 up` asks your model for one tool call, from inside the cluster:
366
+
367
+ ```text
368
+ → .env: LOCAL_MODEL_URL
369
+ jr2 up — instance "my-instance" → context kind-jr2 / namespace my-instance
370
+ typecheck: tsc --noEmit (the instance's own compiler)
371
+ seats: workflow "triage" — who may send what, per state (ADR-0015)
372
+ triage.triaging agent:triager: [accept, needs_info, reject]
373
+ triage.clarify gate: [answer]
374
+ agents: triager (carried by 2 workflow machine(s))
375
+ …
376
+ the Instance Harness: Custodian holds nothing
377
+ provider: checking local/qwen3.6-35b-a3b on the Instance Harness, with no held key (harness.provider has no apiKey), direct, as a pod that holds no secret calls it
378
+ provider: the check pod has up to 5 min to start, then up to 6 min for its model
379
+ …
380
+ provider: local/qwen3.6-35b-a3b reachable, and it completed a tool call
381
+ …
382
+ instance harness: converging (triager declares workspace: "none")
383
+ instance harness: verified — 1 pod(s) running ghcr.io/snapwich/jr2-harness:<version>
384
+ …
385
+ converged — `jr2 run <workflow>` when ready
386
+ ```
387
+
388
+ The line of Connect a model, `provider: <url> configured, but no carried Agent names a "local/…" model — skipped`, is
389
+ gone. `triager` names a `local/…` model, so `jr2 up` checks that the endpoint completes a tool call. If the check fails,
390
+ `jr2 up` stops and prints what to examine.
391
+
392
+ The Orchestrator loads the new Workflows with no restart, so the port forward stays open.
393
+
394
+ ## Start the first run
395
+
396
+ In the first terminal, run:
397
+
398
+ ```sh
399
+ jr2 run triage --input '{"request":"People keep asking what version they are running."}'
400
+ ```
401
+
402
+ [`jr2 run`](../reference/cli.md#run) starts the run and stays attached to it. The Agent reads the request. The request
403
+ does not say where to show the version, so the Agent normally asks a question. The run goes to `clarify` and waits
404
+ there:
405
+
406
+ ```text
407
+ …
408
+ → context kind-jr2 / namespace my-instance
409
+ run 8fecb896-2100-4ee6-88d6-788eaf0d7244 (triage) — attached
410
+ → active "triaging"
411
+ → active "triaging"
412
+ → active "clarify"
413
+ ```
414
+
415
+ The output of each `jr2` command starts with the line `→ .env:`, with the keys that the CLI took from `.env`. From this
416
+ step on, the output on this page shows `…` in place of that line. Your run id is different. The line
417
+ `→ active "triaging"` can show more than one time. `jr2 run` prints a line for each status that the run sends. Two lines
418
+ can show the same state. `jr2 run` does not return while the run waits. Keep it open.
419
+
420
+ > **Note**
421
+ >
422
+ > The model decides, so your run can be different. If the Agent picks `accept` or `reject`, the run ends with no Gate. A
423
+ > request that says what to change and how to tell that it is done is clear, and the Agent accepts it immediately. For
424
+ > example, this run started with the request
425
+ > `Add a --version flag to the CLI. It prints the installed version and exits.`:
426
+ >
427
+ > ```text
428
+ > …
429
+ > → context kind-jr2 / namespace my-instance
430
+ > run 89cc6ea5-9e2d-4f8a-8d02-18a6e47f2a5c (triage) — attached
431
+ > → active "triaging"
432
+ > → done "accepted"
433
+ > {"runId":"89cc6ea5-9e2d-4f8a-8d02-18a6e47f2a5c","workflow":"triage","instanceId":"fac049b9-9dd2-4ba5-aca8-0b3ebe619701","status":"done","value":"accepted","context":{"request":"Add a --version flag to the CLI. It prints the installed version and exits.","exchange":[],"summary":"Add a --version flag to the CLI that prints the installed version and exits."},"children":[],"waiting":[],"held":[],"assembly":"3eb6cd4d61bf","output":{"outcome":"accepted","summary":"Add a --version flag to the CLI that prints the installed version and exits."}}
434
+ > ```
435
+ >
436
+ > Your run id and your [Instance ID](../reference/glossary.md#instance-id) are different, and so is the `summary`, the
437
+ > text of the model. If your run with the first request ends with no Gate, start it again until it waits at `clarify`.
438
+
439
+ ## Read the question
440
+
441
+ The Gate holds the question of the Agent in its `meta`. In the send terminal, run:
442
+
443
+ ```sh
444
+ jr2 status <run id>
445
+ ```
446
+
447
+ `<run id>` is the run id that `jr2 run` printed. You can give its first 4 characters or more, such as `8fecb896`.
448
+ [`jr2 status`](../reference/cli.md#status) prints the status of the run as one line of JSON. The Gate is in `gates`, at
449
+ the end:
450
+
451
+ ```text
452
+ …
453
+ → context kind-jr2 / namespace my-instance
454
+ {"runId":"8fecb896-2100-4ee6-88d6-788eaf0d7244","workflow":"triage","instanceId":"a814d943-9b27-410c-a790-2c4225aa05ba","status":"active","value":"clarify","context":{"request":"People keep asking what version they are running.","exchange":[{"question":"Where specifically should the version number be displayed (e.g., CLI flag, About screen, or help output), and what exact user action should trigger it?"}]},"children":[],"waiting":[],"held":[],"assembly":"3eb6cd4d61bf","gates":[{"gate":"clarify","path":["clarify"],"accepts":[{"name":"answer","description":"Answer the triager's question. It triages the request again with the answer in hand.","input":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"info":{"type":"string","description":"The answer, in prose."}},"required":["info"],"additionalProperties":false}}],"acceptsNow":["answer"],"meta":{"question":"Where specifically should the version number be displayed (e.g., CLI flag, About screen, or help output), and what exact user action should trigger it?"}}]}
455
+ ```
456
+
457
+ The `question` is in the words of the model, so your question is different. Your instance id is different too. The Gate
458
+ `clarify` takes `answer`, with an `info` string.
459
+
460
+ ## Answer from the CLI
461
+
462
+ In the send terminal, run:
463
+
464
+ ```sh
465
+ jr2 send <run id> --gate clarify --event answer --input '{"info":"Add a --version flag to the CLI. It prints the installed version and exits."}'
466
+ ```
467
+
468
+ [`jr2 send`](../reference/cli.md#send) gives the event to the Gate:
469
+
470
+ ```text
471
+ …
472
+ → context kind-jr2 / namespace my-instance
473
+ delivered answer to gate "clarify" on 8fecb896-2100-4ee6-88d6-788eaf0d7244
474
+ ```
475
+
476
+ The run goes back to `triaging`, and the Agent reads your answer. Look at the first terminal. When the Agent picks
477
+ `accept`, the run ends, and `jr2 run` prints the last status:
478
+
479
+ ```text
480
+ …
481
+ → active "triaging"
482
+ → active "triaging"
483
+ → done "accepted"
484
+ {"runId":"8fecb896-2100-4ee6-88d6-788eaf0d7244","workflow":"triage","instanceId":"a814d943-9b27-410c-a790-2c4225aa05ba","status":"done","value":"accepted","context":{"request":"People keep asking what version they are running.","exchange":[{"question":"Where specifically should the version number be displayed (e.g., CLI flag, About screen, or help output), and what exact user action should trigger it?","info":"Add a --version flag to the CLI. It prints the installed version and exits."}],"summary":"Add a --version flag to the CLI that prints the installed version and exits."},"children":[],"waiting":[],"held":[],"assembly":"3eb6cd4d61bf","output":{"outcome":"accepted","summary":"Add a --version flag to the CLI that prints the installed version and exits."}}
485
+ ```
486
+
487
+ `summary` is the request as the model wrote it again, in one sentence. Your summary is different. The `output` of the
488
+ run holds the decision. The job of a triage is the decision, so a `reject` is a correct answer too: the run ends `done`,
489
+ with `"outcome":"rejected"` and the reason in its output. If the Agent asks a second question, the run goes to `clarify`
490
+ again. Read the question, and answer it in the same way.
491
+
492
+ ## Start the second run
493
+
494
+ In the first terminal, run:
495
+
496
+ ```sh
497
+ jr2 run triage --input '{"request":"The greeting looks wrong sometimes."}'
498
+ ```
499
+
500
+ This request does not say what is wrong. The run goes to `clarify` and waits, as the first run did:
501
+
502
+ ```text
503
+ …
504
+ → context kind-jr2 / namespace my-instance
505
+ run 84079cb2-3cdd-4b9a-ae39-51ab873c5f3c (triage) — attached
506
+ → active "triaging"
507
+ → active "clarify"
508
+ ```
509
+
510
+ `84079cb2-3cdd-4b9a-ae39-51ab873c5f3c` is the id of the second run. Your run id is different. If the Agent picks
511
+ `accept` or `reject`, start the run again.
512
+
513
+ ## Answer from the Console
514
+
515
+ Open `http://localhost:4000` in your browser. If the badge after the `instance token` box shows `live`, go to the next
516
+ step. If the box is empty, get the token. In the send terminal, run:
517
+
518
+ ```sh
519
+ kubectl -n my-instance get secret jr2-instance -o jsonpath='{.data.JR2_INSTANCE_TOKEN}' | base64 -d
520
+ ```
521
+
522
+ Type the token in the `instance token` box. Push Enter. The badge after the box shows `live`.
523
+
524
+ Click `triage` in the Fleet rail on the left. The center shows the Machine of `triage`, with its states and transitions.
525
+ Click the run in the rail. The Console lights the state of the run, `clarify`.
526
+
527
+ Click the `Attention` tab in the drawer on the right. It has one card for the Gate:
528
+
529
+ - The card starts with `⚑ clarify`, then `triage` and the first 8 characters of the run id.
530
+ - Under `question`, it shows the question of the Agent.
531
+ - Under `answer`, it has a form with the field `info *`. The `*` shows that the field is necessary.
532
+
533
+ Type this text in the `info` field:
534
+
535
+ ```text
536
+ Spaces around the name show in the greeting. Trim the name.
537
+ ```
538
+
539
+ Click `send`. The card disappears, and the run goes back to `triaging`. If the Agent asks one more question, a new card
540
+ shows it. Answer it in your own words, in the same way. When the Agent picks `accept`, the run ends. The `jr2 run` in
541
+ the first terminal prints the last status.
542
+
543
+ ## What happened
544
+
545
+ You wrote a Machine with two waiting states. In `triaging`, a model chose the next state. In `clarify`, a person sent
546
+ the event that moved it. The Machine gave all of the transitions. The model chose only among the events of its state.
547
+ [Agents and Turns](../concepts/agents-and-turns.md) explains the Agent and its Turn.
548
+
549
+ The Menu of `triager` came from the transitions of `triaging`. You did not give the Agent a list of picks. A pick that
550
+ the state does not take moves nothing. [The Menu](../concepts/the-menu.md) explains what the Agent can pick, and
551
+ [ADR-0015](../reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md) gives the reasons.
552
+
553
+ The Gate `clarify` was open only while the run was in its state. It took only `answer`. `jr2 send` and the Console sent
554
+ the same event to a Gate with the same name, through the same route. [Gates](../concepts/gates.md) explains who can
555
+ answer a Gate. [Answer a Gate](../guides/answer-a-gate.md) gives the other ways to answer one.
556
+
557
+ `triager` has `workspace: "none"`, so its Turns ran on the
558
+ [Instance Harness](../reference/glossary.md#instance-harness). No Sandbox started for the run.
559
+ [Architecture](../concepts/architecture.md) shows what runs where.
560
+
561
+ ## Next
562
+
563
+ [An Agent in a Sandbox](an-agent-in-a-sandbox.md).