@jr2/orchestrator 0.4.1 → 0.6.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 (361) 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 +478 -0
  10. package/docs/concepts/architecture.md +243 -0
  11. package/docs/concepts/charts.md +146 -0
  12. package/docs/concepts/composition.md +357 -0
  13. package/docs/concepts/converge.md +257 -0
  14. package/docs/concepts/durable-runs.md +189 -0
  15. package/docs/concepts/effects.md +658 -0
  16. package/docs/concepts/gates.md +208 -0
  17. package/docs/concepts/machines-and-workflows.md +298 -0
  18. package/docs/concepts/pools-and-sources.md +230 -0
  19. package/docs/concepts/secrets-and-trust.md +306 -0
  20. package/docs/concepts/the-menu.md +381 -0
  21. package/docs/concepts/workspaces.md +756 -0
  22. package/docs/get-started/a-model-decides.md +563 -0
  23. package/docs/get-started/an-agent-in-a-sandbox.md +383 -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 +993 -0
  27. package/docs/get-started/install.md +130 -0
  28. package/docs/guides/add-tools-to-the-sandbox.md +308 -0
  29. package/docs/guides/answer-a-gate.md +304 -0
  30. package/docs/guides/bind-open-parts.md +224 -0
  31. package/docs/guides/cancel-a-run.md +146 -0
  32. package/docs/guides/clean-up.md +206 -0
  33. package/docs/guides/cut-a-worktree.md +560 -0
  34. package/docs/guides/fix-a-failed-converge.md +361 -0
  35. package/docs/guides/give-the-cluster-git-credentials.md +222 -0
  36. package/docs/guides/iterate-on-a-machine-on-kind.md +190 -0
  37. package/docs/guides/let-an-agent-write-a-chart.md +230 -0
  38. package/docs/guides/look-inside-a-sandbox.md +177 -0
  39. package/docs/guides/mirror-the-kit-images.md +176 -0
  40. package/docs/guides/move-from-kind-to-a-shared-cluster.md +318 -0
  41. package/docs/guides/open-the-console.md +91 -0
  42. package/docs/guides/publish-a-machine-as-an-npm-package.md +350 -0
  43. package/docs/guides/push-and-sign-a-branch.md +532 -0
  44. package/docs/guides/run-a-chart-by-name.md +270 -0
  45. package/docs/guides/run-a-command-or-call-a-url.md +587 -0
  46. package/docs/guides/run-one-worker-per-item.md +322 -0
  47. package/docs/guides/set-an-agents-access-and-dials.md +420 -0
  48. package/docs/guides/size-a-workspace.md +217 -0
  49. package/docs/guides/start-a-run-from-a-run.md +237 -0
  50. package/docs/guides/start-a-run.md +207 -0
  51. package/docs/guides/upgrade-the-kit-version.md +240 -0
  52. package/docs/guides/use-a-hosted-provider.md +214 -0
  53. package/docs/guides/use-a-local-model.md +313 -0
  54. package/docs/guides/watch-a-run.md +349 -0
  55. package/docs/guides/write-a-workflow.md +318 -0
  56. package/docs/index.md +44 -0
  57. package/docs/llms.txt +237 -0
  58. package/docs/reference/authoring-surface/agent.md +151 -0
  59. package/docs/reference/authoring-surface/answer.md +156 -0
  60. package/docs/reference/authoring-surface/arg.md +82 -0
  61. package/docs/reference/authoring-surface/basic.md +62 -0
  62. package/docs/reference/authoring-surface/bearer.md +53 -0
  63. package/docs/reference/authoring-surface/branchname.md +15 -0
  64. package/docs/reference/authoring-surface/chartschema.md +23 -0
  65. package/docs/reference/authoring-surface/chartschemafor.md +48 -0
  66. package/docs/reference/authoring-surface/command.md +206 -0
  67. package/docs/reference/authoring-surface/customize.md +64 -0
  68. package/docs/reference/authoring-surface/defineconfig.md +41 -0
  69. package/docs/reference/authoring-surface/defineevent.md +114 -0
  70. package/docs/reference/authoring-surface/dispatch.md +126 -0
  71. package/docs/reference/authoring-surface/fail.md +96 -0
  72. package/docs/reference/authoring-surface/file.md +142 -0
  73. package/docs/reference/authoring-surface/frompick.md +277 -0
  74. package/docs/reference/authoring-surface/http.md +259 -0
  75. package/docs/reference/authoring-surface/isfailure.md +58 -0
  76. package/docs/reference/authoring-surface/isready.md +14 -0
  77. package/docs/reference/authoring-surface/jr2setup.md +237 -0
  78. package/docs/reference/authoring-surface/open.md +105 -0
  79. package/docs/reference/authoring-surface/openbody.md +86 -0
  80. package/docs/reference/authoring-surface/paramsof.md +143 -0
  81. package/docs/reference/authoring-surface/pool.md +186 -0
  82. package/docs/reference/authoring-surface/push.md +130 -0
  83. package/docs/reference/authoring-surface/readyof.md +21 -0
  84. package/docs/reference/authoring-surface/secret.md +139 -0
  85. package/docs/reference/authoring-surface/sentby.md +83 -0
  86. package/docs/reference/authoring-surface/source.md +51 -0
  87. package/docs/reference/authoring-surface/text.md +62 -0
  88. package/docs/reference/authoring-surface/type-agentdeclaration.md +27 -0
  89. package/docs/reference/authoring-surface/type-agentdefinition.md +80 -0
  90. package/docs/reference/authoring-surface/type-agentlogic.md +15 -0
  91. package/docs/reference/authoring-surface/type-agentslots.md +15 -0
  92. package/docs/reference/authoring-surface/type-answeraction.md +12 -0
  93. package/docs/reference/authoring-surface/type-anyframepath.md +14 -0
  94. package/docs/reference/authoring-surface/type-anyworktreepath.md +15 -0
  95. package/docs/reference/authoring-surface/type-arg.md +19 -0
  96. package/docs/reference/authoring-surface/type-argnames.md +12 -0
  97. package/docs/reference/authoring-surface/type-bindactors.md +14 -0
  98. package/docs/reference/authoring-surface/type-binding.md +61 -0
  99. package/docs/reference/authoring-surface/type-bindingof.md +12 -0
  100. package/docs/reference/authoring-surface/type-bodyacceptsdoor.md +15 -0
  101. package/docs/reference/authoring-surface/type-bodyacceptsslots.md +17 -0
  102. package/docs/reference/authoring-surface/type-ceilings.md +41 -0
  103. package/docs/reference/authoring-surface/type-chainlink.md +19 -0
  104. package/docs/reference/authoring-surface/type-chartaction.md +46 -0
  105. package/docs/reference/authoring-surface/type-chartagent.md +28 -0
  106. package/docs/reference/authoring-surface/type-chartevent.md +20 -0
  107. package/docs/reference/authoring-surface/type-chartguard.md +20 -0
  108. package/docs/reference/authoring-surface/type-chartinvoke.md +28 -0
  109. package/docs/reference/authoring-surface/type-chartjson.md +14 -0
  110. package/docs/reference/authoring-surface/type-chartstate.md +46 -0
  111. package/docs/reference/authoring-surface/type-charttext.md +40 -0
  112. package/docs/reference/authoring-surface/type-charttransition.md +22 -0
  113. package/docs/reference/authoring-surface/type-charttransitions.md +14 -0
  114. package/docs/reference/authoring-surface/type-chartvalue.md +15 -0
  115. package/docs/reference/authoring-surface/type-childat.md +12 -0
  116. package/docs/reference/authoring-surface/type-childslots.md +12 -0
  117. package/docs/reference/authoring-surface/type-commandenv.md +15 -0
  118. package/docs/reference/authoring-surface/type-commandinput.md +20 -0
  119. package/docs/reference/authoring-surface/type-commandoptions.md +56 -0
  120. package/docs/reference/authoring-surface/type-commandoutput.md +122 -0
  121. package/docs/reference/authoring-surface/type-customize.md +111 -0
  122. package/docs/reference/authoring-surface/type-dispatchdefinition.md +39 -0
  123. package/docs/reference/authoring-surface/type-dispatchinput.md +14 -0
  124. package/docs/reference/authoring-surface/type-dispatchopenparts.md +14 -0
  125. package/docs/reference/authoring-surface/type-dispatchoutput.md +72 -0
  126. package/docs/reference/authoring-surface/type-doorlessinput.md +19 -0
  127. package/docs/reference/authoring-surface/type-duration.md +15 -0
  128. package/docs/reference/authoring-surface/type-effectbinding.md +93 -0
  129. package/docs/reference/authoring-surface/type-effectlogic.md +12 -0
  130. package/docs/reference/authoring-surface/type-envopenparts.md +14 -0
  131. package/docs/reference/authoring-surface/type-eventaudience.md +27 -0
  132. package/docs/reference/authoring-surface/type-eventdef.md +45 -0
  133. package/docs/reference/authoring-surface/type-eventfrom.md +16 -0
  134. package/docs/reference/authoring-surface/type-eventsemantics.md +26 -0
  135. package/docs/reference/authoring-surface/type-execoutcome.md +34 -0
  136. package/docs/reference/authoring-surface/type-failslot.md +14 -0
  137. package/docs/reference/authoring-surface/type-failure.md +19 -0
  138. package/docs/reference/authoring-surface/type-failureinput.md +20 -0
  139. package/docs/reference/authoring-surface/type-filebody.md +37 -0
  140. package/docs/reference/authoring-surface/type-framepath.md +14 -0
  141. package/docs/reference/authoring-surface/type-frominput.md +14 -0
  142. package/docs/reference/authoring-surface/type-hostinjectedinput.md +56 -0
  143. package/docs/reference/authoring-surface/type-httpdefinition.md +104 -0
  144. package/docs/reference/authoring-surface/type-httpfileinput.md +20 -0
  145. package/docs/reference/authoring-surface/type-httpinput.md +12 -0
  146. package/docs/reference/authoring-surface/type-httpmethod.md +14 -0
  147. package/docs/reference/authoring-surface/type-httpopenparts.md +12 -0
  148. package/docs/reference/authoring-surface/type-httpoutput.md +95 -0
  149. package/docs/reference/authoring-surface/type-httprequestparts.md +33 -0
  150. package/docs/reference/authoring-surface/type-jr2config.md +126 -0
  151. package/docs/reference/authoring-surface/type-lateroutcome.md +21 -0
  152. package/docs/reference/authoring-surface/type-lends.md +38 -0
  153. package/docs/reference/authoring-surface/type-logicat.md +12 -0
  154. package/docs/reference/authoring-surface/type-markedif.md +12 -0
  155. package/docs/reference/authoring-surface/type-mergedactors.md +12 -0
  156. package/docs/reference/authoring-surface/type-namedsecret.md +25 -0
  157. package/docs/reference/authoring-surface/type-namestart.md +77 -0
  158. package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +27 -0
  159. package/docs/reference/authoring-surface/type-notworktreekeys.md +12 -0
  160. package/docs/reference/authoring-surface/type-openbodydeclaration.md +40 -0
  161. package/docs/reference/authoring-surface/type-openbodylogic.md +14 -0
  162. package/docs/reference/authoring-surface/type-openbodyoutput.md +42 -0
  163. package/docs/reference/authoring-surface/type-openbodyslot.md +18 -0
  164. package/docs/reference/authoring-surface/type-opencommandinput.md +22 -0
  165. package/docs/reference/authoring-surface/type-openeffect.md +12 -0
  166. package/docs/reference/authoring-surface/type-openeffectslots.md +12 -0
  167. package/docs/reference/authoring-surface/type-openof.md +12 -0
  168. package/docs/reference/authoring-surface/type-opensecret.md +23 -0
  169. package/docs/reference/authoring-surface/type-opensecretmark.md +12 -0
  170. package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +26 -0
  171. package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +27 -0
  172. package/docs/reference/authoring-surface/type-poolmachine.md +28 -0
  173. package/docs/reference/authoring-surface/type-poolnextinput.md +22 -0
  174. package/docs/reference/authoring-surface/type-poolspec.md +60 -0
  175. package/docs/reference/authoring-surface/type-pushinput.md +34 -0
  176. package/docs/reference/authoring-surface/type-pushoptions.md +79 -0
  177. package/docs/reference/authoring-surface/type-pushoutput.md +149 -0
  178. package/docs/reference/authoring-surface/type-pushwireoutput.md +12 -0
  179. package/docs/reference/authoring-surface/type-quantity.md +14 -0
  180. package/docs/reference/authoring-surface/type-reached.md +12 -0
  181. package/docs/reference/authoring-surface/type-reposlot.md +70 -0
  182. package/docs/reference/authoring-surface/type-reposlotsof.md +16 -0
  183. package/docs/reference/authoring-surface/type-sandboxoptions.md +84 -0
  184. package/docs/reference/authoring-surface/type-secret.md +25 -0
  185. package/docs/reference/authoring-surface/type-sender.md +19 -0
  186. package/docs/reference/authoring-surface/type-sentbyguards.md +12 -0
  187. package/docs/reference/authoring-surface/type-size.md +85 -0
  188. package/docs/reference/authoring-surface/type-slothandles.md +24 -0
  189. package/docs/reference/authoring-surface/type-sourcenextresult.md +17 -0
  190. package/docs/reference/authoring-surface/type-sourcespec.md +44 -0
  191. package/docs/reference/authoring-surface/type-syncstate.md +12 -0
  192. package/docs/reference/authoring-surface/type-text.md +19 -0
  193. package/docs/reference/authoring-surface/type-textpart.md +24 -0
  194. package/docs/reference/authoring-surface/type-thinkinglevel.md +39 -0
  195. package/docs/reference/authoring-surface/type-toparameterizedobject.md +14 -0
  196. package/docs/reference/authoring-surface/type-toprovidedactor.md +14 -0
  197. package/docs/reference/authoring-surface/type-unknown.md +21 -0
  198. package/docs/reference/authoring-surface/type-usercontainer.md +77 -0
  199. package/docs/reference/authoring-surface/type-withoutemptyindex.md +20 -0
  200. package/docs/reference/authoring-surface/type-workflowevent.md +46 -0
  201. package/docs/reference/authoring-surface/type-workspaceaccess.md +16 -0
  202. package/docs/reference/authoring-surface/type-workspaced.md +115 -0
  203. package/docs/reference/authoring-surface/type-workspacehandles.md +22 -0
  204. package/docs/reference/authoring-surface/type-workspacemachine.md +29 -0
  205. package/docs/reference/authoring-surface/type-workspaceof.md +13 -0
  206. package/docs/reference/authoring-surface/type-workspaceoptions.md +27 -0
  207. package/docs/reference/authoring-surface/type-worktreefound.md +16 -0
  208. package/docs/reference/authoring-surface/type-worktreeinput.md +56 -0
  209. package/docs/reference/authoring-surface/type-worktreekey.md +14 -0
  210. package/docs/reference/authoring-surface/type-worktreeoptions.md +29 -0
  211. package/docs/reference/authoring-surface/type-worktreeoutput.md +45 -0
  212. package/docs/reference/authoring-surface/type-worktreepath.md +16 -0
  213. package/docs/reference/authoring-surface/type-worktreeready.md +37 -0
  214. package/docs/reference/authoring-surface/type-worktreerefused.md +21 -0
  215. package/docs/reference/authoring-surface/workspace.md +287 -0
  216. package/docs/reference/authoring-surface/worktree.md +71 -0
  217. package/docs/reference/authoring-surface.md +217 -0
  218. package/docs/reference/cli.md +433 -0
  219. package/docs/reference/config.md +765 -0
  220. package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +114 -0
  221. package/docs/reference/decisions/0002-duplex-streaming-actor.md +117 -0
  222. package/docs/reference/decisions/0004-worktree-provisioning-model.md +130 -0
  223. package/docs/reference/decisions/0005-sandbox-pod-composition.md +240 -0
  224. package/docs/reference/decisions/0006-agent-control-surface.md +50 -0
  225. package/docs/reference/decisions/0007-durable-machine-state.md +109 -0
  226. package/docs/reference/decisions/0008-orchestrator-as-deployed-app.md +60 -0
  227. package/docs/reference/decisions/0009-cli-and-instance-interface.md +275 -0
  228. package/docs/reference/decisions/0010-bdd-acceptance-tests.md +160 -0
  229. package/docs/reference/decisions/0011-workflow-defined-events.md +141 -0
  230. package/docs/reference/decisions/0012-workspace-wrapper-machine.md +103 -0
  231. package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +175 -0
  232. package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +95 -0
  233. package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +271 -0
  234. package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +126 -0
  235. package/docs/reference/decisions/0017-pool-over-a-source-port.md +71 -0
  236. package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +111 -0
  237. package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +287 -0
  238. package/docs/reference/decisions/0020-private-ca-trust-is-a-named-concept.md +60 -0
  239. package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +101 -0
  240. package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +103 -0
  241. package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +175 -0
  242. package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +436 -0
  243. package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +65 -0
  244. package/docs/reference/decisions/0026-a-turn-that-is-over-is-never-prompted.md +62 -0
  245. package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +245 -0
  246. package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +90 -0
  247. package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +154 -0
  248. package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +100 -0
  249. package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +193 -0
  250. package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +61 -0
  251. package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +126 -0
  252. package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +57 -0
  253. package/docs/reference/decisions/0035-a-runaway-turn-is-ended-rerolled-once-then-a-fault.md +92 -0
  254. package/docs/reference/decisions/0036-a-turn-compacts-its-own-context-mid-flight.md +138 -0
  255. package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +196 -0
  256. package/docs/reference/decisions/0038-jr2-up-builds-every-image-it-deploys.md +170 -0
  257. package/docs/reference/decisions/0039-image-garbage-collects-by-reachability.md +115 -0
  258. package/docs/reference/decisions/0041-a-build-the-host-already-holds-is-not-spent-again.md +64 -0
  259. package/docs/reference/decisions/0042-ready-is-not-routable-an-admission-retries-its-connection.md +142 -0
  260. package/docs/reference/decisions/0043-the-kit-is-tested-as-installed-a-local-registry-stands-in-for-npm.md +170 -0
  261. package/docs/reference/decisions/0044-kit-images-live-at-a-canonical-home-a-self-host-mirrors-it.md +85 -0
  262. package/docs/reference/decisions/0045-the-platform-joins-the-image-address-and-the-cluster-chooses-it.md +82 -0
  263. package/docs/reference/decisions/0046-a-converge-failure-carries-its-diagnosis.md +34 -0
  264. package/docs/reference/decisions/0047-the-git-ssh-key-source-is-the-users-choice.md +47 -0
  265. package/docs/reference/decisions/0048-the-orchestrator-boots-without-its-repos.md +36 -0
  266. package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +126 -0
  267. package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +73 -0
  268. package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +238 -0
  269. package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +86 -0
  270. package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +123 -0
  271. package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +126 -0
  272. package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +107 -0
  273. package/docs/reference/decisions/0056-a-global-jr2-hands-off-to-the-instances-own-and-an-instance-has-one-kit-version.md +62 -0
  274. package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +152 -0
  275. package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +108 -0
  276. package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +427 -0
  277. package/docs/reference/decisions/0060-a-workspace-states-its-size-and-jr2-reserves-all-of-it.md +111 -0
  278. package/docs/reference/decisions/0061-a-memory-kill-ends-the-agents-processes-not-the-harness.md +83 -0
  279. package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +239 -0
  280. package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +82 -0
  281. package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +79 -0
  282. package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +65 -0
  283. package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +552 -0
  284. package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +458 -0
  285. package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +475 -0
  286. package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +180 -0
  287. package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +334 -0
  288. package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +183 -0
  289. package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +144 -0
  290. package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +122 -0
  291. package/docs/reference/decisions/0074-an-unrouted-mechanism-event-is-refused-at-load-and-faults-the-run.md +76 -0
  292. package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +295 -0
  293. package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +320 -0
  294. package/docs/reference/decisions/0077-jr2-requires-landlock-on-every-sandbox-node.md +79 -0
  295. package/docs/reference/decisions.md +86 -0
  296. package/docs/reference/glossary.md +687 -0
  297. package/docs/reference/http-api.md +1386 -0
  298. package/docs/reference/machines.md +189 -0
  299. package/docs/reference/mechanism-events.md +72 -0
  300. package/docs/why.md +207 -0
  301. package/package.json +5 -3
  302. package/src/actor.ts +694 -106
  303. package/src/agent.ts +114 -38
  304. package/src/ambient.ts +3 -4
  305. package/src/assembly-checks.ts +189 -7
  306. package/src/cause.ts +234 -0
  307. package/src/chart.ts +345 -46
  308. package/src/charts.ts +43 -8
  309. package/src/config.ts +440 -178
  310. package/src/custodian.lua +17 -5
  311. package/src/custodian.ts +325 -99
  312. package/src/customize.ts +199 -49
  313. package/src/dispatch-effect.ts +945 -0
  314. package/src/door-compat.ts +217 -0
  315. package/src/durability.ts +11 -4
  316. package/src/effect-checks.ts +50 -3
  317. package/src/effect.ts +641 -128
  318. package/src/effector-wire.ts +165 -13
  319. package/src/fail.ts +222 -0
  320. package/src/harness-client.ts +587 -50
  321. package/src/harness-env.ts +33 -0
  322. package/src/held-secrets.ts +125 -16
  323. package/src/holds.ts +3 -0
  324. package/src/http-effect.ts +556 -58
  325. package/src/http.ts +480 -30
  326. package/src/index.ts +74 -82
  327. package/src/instance.ts +68 -8
  328. package/src/internal.ts +85 -0
  329. package/src/kube-client.ts +6 -3
  330. package/src/machine-doc.ts +24 -7
  331. package/src/mechanism-routes.ts +168 -0
  332. package/src/model-keys.generated.ts +53 -0
  333. package/src/model-keys.ts +42 -58
  334. package/src/names.ts +19 -6
  335. package/src/notices.ts +483 -41
  336. package/src/open-body.ts +242 -40
  337. package/src/open-effect.ts +81 -8
  338. package/src/open.ts +90 -6
  339. package/src/parts.ts +213 -30
  340. package/src/party.ts +101 -2
  341. package/src/pick.ts +497 -11
  342. package/src/pool.ts +282 -50
  343. package/src/registration.ts +133 -12
  344. package/src/repo-identity.ts +7 -3
  345. package/src/repos.ts +22 -3
  346. package/src/run-host.ts +665 -45
  347. package/src/run-output.ts +38 -0
  348. package/src/sandbox-effect.ts +457 -71
  349. package/src/sandbox-kube.ts +66 -17
  350. package/src/secret-placement.ts +59 -17
  351. package/src/server.ts +3 -0
  352. package/src/setup.ts +325 -62
  353. package/src/size.ts +121 -9
  354. package/src/snapshot-store.ts +54 -10
  355. package/src/stub-harness.ts +44 -16
  356. package/src/timers.ts +14 -1
  357. package/src/tokens.ts +107 -32
  358. package/src/vocabulary.ts +88 -14
  359. package/src/wire.ts +100 -26
  360. package/src/workspace.ts +771 -238
  361. package/src/worktree.ts +249 -0
package/README.md CHANGED
@@ -1,8 +1,26 @@
1
1
  # @jr2/orchestrator
2
2
 
3
3
  The jr2 Orchestrator: the runtime that executes Machines — xstate actors driving Agents in Kubernetes Sandboxes — plus
4
- the HTTP API, the Console it serves, and the kit pieces a Workflow imports (`agent()`, `workspace()`, `gate()`,
5
- `customize()`, …).
4
+ the HTTP API, the Console it serves, and the Authoring surface.
5
+
6
+ The Authoring surface is what this package exports from its root: the names that an author writes in a workflow module
7
+ or in `jr2.config.ts`, and no other names.
8
+
9
+ - **Machine and events:** `jr2Setup()`, `defineEvent()`, `sentBy()`, and the type `HostInjectedInput`.
10
+ - **Agents:** `agent()`, and the types `AgentDefinition` and `ThinkingLevel`.
11
+ - **Workspaces and Repos:** `workspace()`, and the types `Workspaced`, `RepoSlot` and `Binding`.
12
+ - **Effects:** `command()`, `arg()`, `http()`, `secret()`, `bearer()`, `basic()`, `text()`, `file()`, `push()`,
13
+ `dispatch()`, `fromPick()`, `paramsOf()`, `answer()`, and the types `CommandOutput`, `HttpOutput`, `PushOutput` and
14
+ `DispatchOutput`.
15
+ - **Composition:** `open`, `customize()`, `pool()`, `source()`, and the types `Customize`, `EffectBinding`, `Size` and
16
+ `UserContainer`.
17
+ - **Charts:** `openBody()`, `chartSchema`, `chartSchemaFor()`, and the types `OpenBodyDeclaration` and `OpenBodyOutput`.
18
+ - **Config:** `defineConfig()`, and the type `JR2Config`.
19
+
20
+ A state that needs outside input invokes the Gate as `src: "gate"`. You do not import it: `jr2Setup()` registers it.
21
+
22
+ The kit's own packages import `@jr2/orchestrator/internal`. It is not for workflow authors. It has no stability promise,
23
+ and any name in it can change in any release.
6
24
 
7
25
  An Instance depends on it and its `workflows/` import from it; `jr2 up` bakes the engine and those workflows into one
8
26
  image, so this package is run in-cluster, never on the host. Its version is the kit's version: the Kit images an
@@ -8,6 +8,7 @@ import { Fragment, h, type JSX } from "preact";
8
8
  import { useState } from "preact/hooks";
9
9
  import {
10
10
  selectedRun,
11
+ selectedRunFailure,
11
12
  selectedRunGates,
12
13
  selectedRunHeld,
13
14
  selectedRunWaiting,
@@ -80,6 +81,7 @@ export function App(props: {
80
81
  gates: selectedRunGates(store),
81
82
  waiting: selectedRunWaiting(store),
82
83
  held: selectedRunHeld(store),
84
+ failure: selectedRunFailure(store),
83
85
  api,
84
86
  }),
85
87
  h(Drawer, { store, chosenTab, onChooseTab: setChosenTab, api }),
@@ -7,7 +7,7 @@
7
7
  // (`chart file` or `chart`) and, when a publish no longer admits it, `unrunnable` with the reason.
8
8
 
9
9
  import { h, type JSX } from "preact";
10
- import { fleetEntries, fleetRuns, type FleetEntry, type ObservedRun, type Store } from "../store.ts";
10
+ import { dispatchBadge, fleetEntries, fleetRuns, type FleetEntry, type ObservedRun, type Store } from "../store.ts";
11
11
  import { SchemaForm } from "./schema-form.ts";
12
12
  import type { AppApi } from "./app.ts";
13
13
 
@@ -131,6 +131,8 @@ function runRows(
131
131
  function runRow(name: string, run: ObservedRun, settled: boolean, store: Store, api: AppApi): JSX.Element {
132
132
  const gates = store.gates.get(run.runId)?.gates.length ?? 0;
133
133
  const selected = name === store.workflow && run.runId === store.selectedRunId;
134
+ // A dispatched run names its caller on the row (ADR-0071), off the open observation.
135
+ const badge = dispatchBadge(run);
134
136
  return h(
135
137
  "li",
136
138
  {
@@ -142,6 +144,17 @@ function runRow(name: string, run: ObservedRun, settled: boolean, store: Store,
142
144
  },
143
145
  },
144
146
  h("span", { class: "run-id" }, run.runId.slice(0, 8)),
147
+ badge && run.dispatchedBy
148
+ ? h(
149
+ "span",
150
+ {
151
+ class: "dispatch-badge dim",
152
+ title: `dispatched by ${run.dispatchedBy.run} (${run.dispatchedBy.slot}), depth ${run.dispatchedBy.depth}`,
153
+ style: { fontSize: "11px", marginRight: "6px" },
154
+ },
155
+ badge,
156
+ )
157
+ : null,
145
158
  gates
146
159
  ? h("span", { class: "gate-badge", title: `${gates} open gate${gates === 1 ? "" : "s"}` }, `⚑${gates}`)
147
160
  : null,
@@ -5,7 +5,15 @@
5
5
 
6
6
  import { h, type JSX } from "preact";
7
7
  import { useEffect, useRef } from "preact/hooks";
8
- import { docSeats, type GateCard, type HeldLine, type ObservedRun, type WaitingLine } from "../store.ts";
8
+ import {
9
+ dispatchStrip,
10
+ dispatchedStrip as dispatchedStripText,
11
+ docSeats,
12
+ type GateCard,
13
+ type HeldLine,
14
+ type ObservedRun,
15
+ type WaitingLine,
16
+ } from "../store.ts";
9
17
  import {
10
18
  clearCanvas,
11
19
  initCanvas,
@@ -23,9 +31,10 @@ export function MachinePane(props: {
23
31
  gates: GateCard[];
24
32
  waiting: WaitingLine[];
25
33
  held: HeldLine[];
34
+ failure: string | null;
26
35
  api: AppApi;
27
36
  }): JSX.Element {
28
- const { view, run, selectedNodeId, gates, waiting, held, api } = props;
37
+ const { view, run, selectedNodeId, gates, waiting, held, failure, api } = props;
29
38
  const canvasRef = useRef<HTMLElement>(null);
30
39
  const svgRef = useRef<SVGSVGElement>(null);
31
40
 
@@ -58,14 +67,37 @@ export function MachinePane(props: {
58
67
  { id: "canvas", ref: canvasRef },
59
68
  h("div", { id: "placeholder", hidden: !view.placeholder }, view.placeholder ?? ""),
60
69
  h("div", { id: "error", hidden: !view.note, class: view.note?.notice ? "notice" : "" }, view.note?.text ?? ""),
70
+ dispatchedStrip(run),
71
+ startedStrip(run),
61
72
  rootTransitionStrip(view.doc),
62
73
  seatsPanel(view.doc),
74
+ failureStrip(failure),
63
75
  waitingStrip(waiting),
64
76
  heldStrip(held),
65
77
  h("svg", { id: "machine-svg", ref: svgRef }),
66
78
  );
67
79
  }
68
80
 
81
+ /** Who dispatched the selected run (ADR-0071): its caller's run, slot and the chain's depth. Read
82
+ * off the open observation the pane already holds, so it shows for every viewer, with no fetch. */
83
+ function dispatchedStrip(run: ObservedRun | null): JSX.Element | null {
84
+ const text = dispatchStrip(run);
85
+ if (!text) return null;
86
+ return h(
87
+ "div",
88
+ { id: "dispatched-by", class: "dim", style: { margin: "28px 28px 0", fontFamily: "var(--mono)" } },
89
+ text,
90
+ );
91
+ }
92
+
93
+ /** The runs the selected run dispatched (ADR-0071): the chain's other direction, off the same
94
+ * open observation, with no fetch. */
95
+ function startedStrip(run: ObservedRun | null): JSX.Element | null {
96
+ const text = dispatchedStripText(run);
97
+ if (!text) return null;
98
+ return h("div", { id: "dispatched", class: "dim", style: { margin: "8px 28px 0", fontFamily: "var(--mono)" } }, text);
99
+ }
100
+
69
101
  /** Machine-level transitions ("from any state") as the strip above the Machine — an edge from the
70
102
  * root would lie, because the root has no box (it renders as the page). */
71
103
  function rootTransitionStrip(doc: MachineDoc | null): JSX.Element {
@@ -130,6 +162,13 @@ function seatsPanel(doc: MachineDoc | null): JSX.Element | null {
130
162
  );
131
163
  }
132
164
 
165
+ /** Why the selected run failed (ADR-0073): the reason that the Machine gave to `fail`, as `jr2 status`
166
+ * prints it. The rail colors a `failed` run for every viewer; the reason is in the run's output,
167
+ * which is guarded, so it is here only with a live token. */
168
+ function failureStrip(failure: string | null): JSX.Element {
169
+ return h("div", { id: "failure", hidden: failure === null }, failure === null ? "" : `failed: ${failure}`);
170
+ }
171
+
133
172
  /** Why the selected run's Workspaces in `placing` wait (ADR-0064), one line each, in the
134
173
  * scheduler's or the quota's own words. The diagram lights `placing` for every viewer; this reason
135
174
  * is guarded, so it is here only with a live token. */
package/console/main.ts CHANGED
@@ -37,6 +37,7 @@ import { h, render } from "preact";
37
37
  import {
38
38
  applyFrame,
39
39
  emptyStore,
40
+ failureReason,
40
41
  machineDocSource,
41
42
  selectedRun,
42
43
  type Frame,
@@ -158,10 +159,21 @@ async function refreshRun(runId: string, workflow: string): Promise<void> {
158
159
  const res = await gfetch(`/runs/${encodeURIComponent(runId)}`);
159
160
  if (!res) return; // 401 already dropped the page to observer
160
161
  // !ok: settled + evicted — no gates, and nothing waits.
161
- const body = res.ok ? ((await res.json()) as { gates?: GateCard[]; waiting?: WaitingLine[]; held?: HeldLine[] }) : {};
162
+ const body = res.ok
163
+ ? ((await res.json()) as {
164
+ status?: string;
165
+ output?: unknown;
166
+ gates?: GateCard[];
167
+ waiting?: WaitingLine[];
168
+ held?: HeldLine[];
169
+ })
170
+ : {};
162
171
  if (runFetchSerial.get(runId) !== serial) return; // superseded — a newer re-fetch owns the answer
163
172
  dispatch({ kind: "gates", runId, workflow, gates: body.gates ?? [] });
164
173
  dispatch({ kind: "waiting", runId, workflow, waiting: body.waiting ?? [], held: body.held ?? [] });
174
+ // The reason of a run that ended `failed` (ADR-0073). A 404 says nothing about it, so a reason
175
+ // the page has stays.
176
+ if (res.ok) dispatch({ kind: "failure", runId, reason: failureReason(body) });
165
177
  }
166
178
 
167
179
  // ---- The two writes (start-run + gate delivery — ADR-0033) --------------------------------------
package/console/store.ts CHANGED
@@ -30,8 +30,20 @@ export type ObservedRun = {
30
30
  /** The hashes of the Charts the run binds now, distinct and sorted. A run can bind a second Chart
31
31
  * in its life, so these, with the run id, key its doc. Absent from an older Orchestrator. */
32
32
  chartHashes?: string[];
33
+ /** The run that dispatched this one, the caller's slot, and this run's depth in the chain
34
+ * (ADR-0071). Routing, on the open band (ADR-0014): the page reads it off the observation it
35
+ * already holds, with no fetch and no token. `instance` is set for a foreign caller, opaque text.
36
+ * Absent for a run nobody dispatched, and from an Orchestrator older than ADR-0071. */
37
+ dispatchedBy?: DispatchedByView;
38
+ /** The runs this run's `dispatch` Effects started, oldest first, by slot (ADR-0071): the chain's
39
+ * other direction, the same routing on the same band. Absent when it started none. */
40
+ dispatched?: Array<{ slot: string; run: string }>;
33
41
  };
34
42
 
43
+ /** {@link ObservedRun.dispatchedBy} — mirrors `RunObservation.dispatchedBy` in run-host.ts. The
44
+ * idempotency key is not on the open band: it names the caller's ledger. */
45
+ export type DispatchedByView = { run: string; slot: string; depth: number; instance?: string };
46
+
35
47
  /** Where a Workflow came from (ADR-0070): a Machine or a Chart file in the Assembly, or a runtime
36
48
  * Chart put on the Instance. */
37
49
  export type WorkflowOrigin = "machine" | "file" | "runtime";
@@ -100,6 +112,7 @@ export type Frame =
100
112
  | { kind: "token"; state: TokenState }
101
113
  | { kind: "gates"; runId: string; workflow: string; gates: GateCard[] }
102
114
  | { kind: "waiting"; runId: string; workflow: string; waiting: WaitingLine[]; held?: HeldLine[] }
115
+ | { kind: "failure"; runId: string; reason: string | null }
103
116
  | { kind: "inboxScope"; all: boolean }
104
117
  | { kind: "startForm"; workflow: string | null };
105
118
 
@@ -129,6 +142,11 @@ export type Frame =
129
142
  * `waiting` why each run's Workspaces in `placing` wait (ADR-0064): runId -> { workflow, waiting },
130
143
  * off the SAME `GET /runs/:id` re-fetch as `gates`, under the same rules — guarded, whole
131
144
  * per run, gone with the credential. The open band sees `placing` lit and nothing more.
145
+ * `failures` the reason of each run this page knows that ended `failed` (ADR-0073): runId -> reason,
146
+ * off the SAME `GET /runs/:id` re-fetch, under the same rules — guarded (the open band
147
+ * sees the `failed` status and its color, never the output), gone with the credential.
148
+ * A failed run is a settled run, so `gone` keeps it; it goes with the run when the run
149
+ * leaves both `runs` and `settled`.
132
150
  * `inboxAll` the widen control: false = the inbox follows the selection, true = every workflow.
133
151
  * `startFormFor` which workflow's start-run form is open, if any.
134
152
  * `selectedNodeId` the diagram node the reader clicked — an elk node id (scope + state id), one at
@@ -152,6 +170,7 @@ export type Store = {
152
170
  token: TokenState;
153
171
  gates: Map<string, { workflow: string; gates: GateCard[] }>;
154
172
  waiting: Map<string, { workflow: string; waiting: WaitingLine[]; held: HeldLine[] }>;
173
+ failures: Map<string, string>;
155
174
  inboxAll: boolean;
156
175
  startFormFor: string | null;
157
176
  };
@@ -180,6 +199,7 @@ export function emptyStore(): Store {
180
199
  token: "none",
181
200
  gates: new Map(),
182
201
  waiting: new Map(),
202
+ failures: new Map(),
183
203
  inboxAll: false,
184
204
  startFormFor: null,
185
205
  };
@@ -189,17 +209,24 @@ export function emptyStore(): Store {
189
209
  * that learns a new frame type does not break a page still running yesterday's script. */
190
210
  export function applyFrame(store: Store, frame: Frame): Store {
191
211
  switch (frame.kind) {
192
- case "runs":
212
+ case "runs": {
193
213
  // The server's whole truth about what is live. Runs that ended during a disconnect are simply
194
214
  // ABSENT — no `gone` was delivered for them and none is needed; they were never ours to settle.
195
215
  // The same wholeness settles the inbox: a selected-workflow run the frame does not mention can
196
- // never be re-fetched again, so its card leaves with it.
216
+ // never be re-fetched again, so its card leaves with it. A failure stays while its run is live
217
+ // or settled here.
218
+ const runs = new Map(frame.runs.map((r): [string, ObservedRun] => [r.runId, r]));
219
+ const orphans = [...store.failures.keys()].filter((id) => !runs.has(id) && !store.settled.has(id));
220
+ let failures = store.failures;
221
+ for (const id of orphans) failures = mapWithout(failures, id);
197
222
  return select({
198
223
  ...store,
199
- runs: new Map(frame.runs.map((r): [string, ObservedRun] => [r.runId, r])),
224
+ runs,
200
225
  gates: dropAbsent(store.gates, store.workflow, new Set(frame.runs.map((r) => r.runId))),
201
226
  waiting: dropAbsent(store.waiting, store.workflow, new Set(frame.runs.map((r) => r.runId))),
227
+ failures,
202
228
  });
229
+ }
203
230
 
204
231
  case "status":
205
232
  return select({ ...store, runs: new Map(store.runs).set(frame.status.runId, frame.status) });
@@ -216,8 +243,13 @@ export function applyFrame(store: Store, frame: Frame): Store {
216
243
  const runs = new Map(store.runs);
217
244
  runs.delete(frame.runId);
218
245
  const settled = new Map(store.settled).set(frame.runId, departing);
219
- while (settled.size > SETTLED_CAP) settled.delete(settled.keys().next().value!);
220
- return select({ ...store, runs, settled, gates, waiting });
246
+ let failures = store.failures;
247
+ while (settled.size > SETTLED_CAP) {
248
+ const evicted = settled.keys().next().value!;
249
+ settled.delete(evicted);
250
+ failures = mapWithout(failures, evicted);
251
+ }
252
+ return select({ ...store, runs, settled, gates, waiting, failures });
221
253
  }
222
254
 
223
255
  case "emit":
@@ -253,6 +285,8 @@ export function applyFrame(store: Store, frame: Frame): Store {
253
285
  selectedRunId: null,
254
286
  selectedNodeId: null,
255
287
  connection: "connecting",
288
+ // Each failure belongs to a run of the old selection's `runs` or `settled`, which go.
289
+ failures: new Map(),
256
290
  };
257
291
  }
258
292
 
@@ -287,7 +321,7 @@ export function applyFrame(store: Store, frame: Frame): Store {
287
321
  // "invalid" (the any-later-401 drop of ADR-0032) empties the inbox. "checking" keeps it — a
288
322
  // re-validation of a token that turns out fine should not flash the inbox empty.
289
323
  if (frame.state === "none" || frame.state === "invalid") {
290
- return { ...store, token: frame.state, gates: new Map(), waiting: new Map() };
324
+ return { ...store, token: frame.state, gates: new Map(), waiting: new Map(), failures: new Map() };
291
325
  }
292
326
  return { ...store, token: frame.state };
293
327
 
@@ -322,6 +356,20 @@ export function applyFrame(store: Store, frame: Frame): Store {
322
356
  return { ...store, waiting };
323
357
  }
324
358
 
359
+ case "failure": {
360
+ // The same guarded re-fetch's third half (ADR-0073): the reason of a run that ended `failed`.
361
+ // Nothing folded without the credential, and nothing for a run that the page does not hold:
362
+ // the re-fetch can come back after a `select` moved on. `null` says the run did not fail.
363
+ if (store.token !== "live") return store;
364
+ if (frame.reason === null) {
365
+ const failures = mapWithout(store.failures, frame.runId);
366
+ return failures === store.failures ? store : { ...store, failures };
367
+ }
368
+ if (!store.runs.has(frame.runId) && !store.settled.has(frame.runId)) return store;
369
+ if (store.failures.get(frame.runId) === frame.reason) return store;
370
+ return { ...store, failures: new Map(store.failures).set(frame.runId, frame.reason) };
371
+ }
372
+
325
373
  case "inboxScope":
326
374
  return { ...store, inboxAll: frame.all };
327
375
 
@@ -464,6 +512,38 @@ export function machineDocSource(
464
512
  return { key: `workflow:${workflow}`, path: `${base}/machine` };
465
513
  }
466
514
 
515
+ /** The fleet row's badge for a dispatched run (ADR-0071): `↳ <run8>`, the caller's run id cut as
516
+ * the row cuts its own. Null for a run nobody dispatched. */
517
+ export function dispatchBadge(run: ObservedRun): string | null {
518
+ const by = run.dispatchedBy;
519
+ return by ? `↳ ${by.run.slice(0, 8)}` : null;
520
+ }
521
+
522
+ /** The Machine pane's strip for a dispatched run (ADR-0071): `dispatched by <run8> · <slot> ·
523
+ * depth n`, and `· from Orchestrator <name>` when the caller is on another Orchestrator (its
524
+ * name as it sent it, never an Instance ID). Null for a run
525
+ * nobody dispatched. */
526
+ export function dispatchStrip(run: ObservedRun | null): string | null {
527
+ const by = run?.dispatchedBy;
528
+ if (!by) return null;
529
+ const from = by.instance ? ` · from Orchestrator ${by.instance}` : "";
530
+ return `dispatched by ${by.run.slice(0, 8)} · ${by.slot} · depth ${by.depth}${from}`;
531
+ }
532
+
533
+ /** The most runs the pane's `dispatched` strip names: a watcher dispatches on every pass. */
534
+ const DISPATCHED_SHOWN = 5;
535
+
536
+ /** The Machine pane's strip for a run that dispatched (ADR-0071): `dispatched <run8> (<slot>) · …`,
537
+ * newest last, the older ones counted. Null for a run that started none. */
538
+ export function dispatchedStrip(run: ObservedRun | null): string | null {
539
+ const all = run?.dispatched ?? [];
540
+ if (all.length === 0) return null;
541
+ const shown = all.slice(-DISPATCHED_SHOWN);
542
+ const older = all.length - shown.length;
543
+ const named = shown.map((d) => `${d.run.slice(0, 8)} (${d.slot})`).join(" · ");
544
+ return `dispatched ${older > 0 ? `${older} more · ` : ""}${named}`;
545
+ }
546
+
467
547
  /** The inbox as the Attention tab draws it: every card, or the selection's slice. The inbox itself
468
548
  * is GLOBAL (every workflow the fleet knows) — the filter is presentation, which is why it lives
469
549
  * in a selector and not in `applyFrame`. */
@@ -488,6 +568,22 @@ export function selectedRunWaiting(store: Store): WaitingLine[] {
488
568
  return store.waiting.get(store.selectedRunId)?.waiting ?? [];
489
569
  }
490
570
 
571
+ /** The reason of a run that ended `failed`, off a `GET /runs/:id` answer (ADR-0073): the Failure's
572
+ * `reason` in the run's output. Null for every other status, and for an output with no reason
573
+ * text — the same reading as `jr2 status`'s `failed:` line. */
574
+ export function failureReason(body: { status?: string; output?: unknown }): string | null {
575
+ if (body.status !== "failed") return null;
576
+ const reason = (body.output as { reason?: unknown } | null | undefined)?.reason;
577
+ return typeof reason === "string" ? reason : null;
578
+ }
579
+
580
+ /** Why the SELECTED run failed (ADR-0073): the reason of its Failure, or null when it did not fail
581
+ * or the page has no live token to read it with. */
582
+ export function selectedRunFailure(store: Store): string | null {
583
+ if (store.selectedRunId === null) return null;
584
+ return store.failures.get(store.selectedRunId) ?? null;
585
+ }
586
+
491
587
  /** The SELECTED run's outstanding picks, each with since when it is held (ADR-0024) — empty in
492
588
  * observer mode. */
493
589
  export function selectedRunHeld(store: Store): HeldLine[] {
package/console/style.css CHANGED
@@ -12,6 +12,8 @@
12
12
  --phosphor-soft: rgba(78, 240, 167, 0.12);
13
13
  --amber: #f0c04e;
14
14
  --red: #f06a5f;
15
+ /* A Failure (ADR-0073): an end the Machine chose, so not the red of a fault. */
16
+ --orange: #f0954e;
15
17
  --blue: #6aa7f0;
16
18
  --mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;
17
19
  }
@@ -229,6 +231,22 @@ main {
229
231
  color: var(--text-dim);
230
232
  }
231
233
 
234
+ /* A failed run (ADR-0073): the reason of its Failure. Orange like the rail's `failed` status — the
235
+ Machine chose this end, so it is not the red of an `error`. */
236
+ #failure {
237
+ margin: 0 28px 16px;
238
+ max-width: 720px;
239
+ border: 1px solid var(--orange);
240
+ border-radius: 4px;
241
+ padding: 8px 12px;
242
+ color: var(--orange);
243
+ font-family: var(--mono);
244
+ }
245
+
246
+ #failure[hidden] {
247
+ display: none;
248
+ }
249
+
232
250
  /* An outstanding pick (ADR-0024): an Agent's Turn held while the workflow runs its pick. */
233
251
  #held {
234
252
  list-style: none;
@@ -615,6 +633,9 @@ ul {
615
633
  .wf-runs .run-status.status--error {
616
634
  color: var(--red);
617
635
  }
636
+ .wf-runs .run-status.status--failed {
637
+ color: var(--orange);
638
+ }
618
639
  .wf-runs .run-status.status--done {
619
640
  color: var(--phosphor);
620
641
  }
@@ -0,0 +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.
2
+
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
+
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}