@jr2/orchestrator 0.5.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 (185) hide show
  1. package/docs/agents-block.md +2 -2
  2. package/docs/concepts/agents-and-turns.md +56 -20
  3. package/docs/concepts/architecture.md +30 -17
  4. package/docs/concepts/charts.md +6 -3
  5. package/docs/concepts/converge.md +3 -0
  6. package/docs/concepts/effects.md +86 -31
  7. package/docs/concepts/machines-and-workflows.md +9 -0
  8. package/docs/concepts/pools-and-sources.md +6 -6
  9. package/docs/concepts/secrets-and-trust.md +126 -42
  10. package/docs/concepts/the-menu.md +3 -0
  11. package/docs/concepts/workspaces.md +129 -51
  12. package/docs/get-started/an-agent-in-a-sandbox.md +21 -19
  13. package/docs/get-started/have-your-assistant-write-a-machine.md +111 -40
  14. package/docs/get-started/install.md +4 -0
  15. package/docs/guides/add-tools-to-the-sandbox.md +17 -4
  16. package/docs/guides/bind-open-parts.md +5 -4
  17. package/docs/guides/cut-a-worktree.md +560 -0
  18. package/docs/guides/fix-a-failed-converge.md +1 -1
  19. package/docs/guides/let-an-agent-write-a-chart.md +5 -1
  20. package/docs/guides/look-inside-a-sandbox.md +18 -15
  21. package/docs/guides/move-from-kind-to-a-shared-cluster.md +16 -0
  22. package/docs/guides/push-and-sign-a-branch.md +67 -21
  23. package/docs/guides/run-a-command-or-call-a-url.md +84 -41
  24. package/docs/guides/run-one-worker-per-item.md +19 -18
  25. package/docs/guides/set-an-agents-access-and-dials.md +67 -22
  26. package/docs/guides/size-a-workspace.md +19 -6
  27. package/docs/guides/use-a-hosted-provider.md +6 -0
  28. package/docs/guides/watch-a-run.md +47 -24
  29. package/docs/guides/write-a-workflow.md +1 -1
  30. package/docs/llms.txt +33 -12
  31. package/docs/reference/authoring-surface/agent.md +34 -11
  32. package/docs/reference/authoring-surface/answer.md +19 -3
  33. package/docs/reference/authoring-surface/arg.md +27 -5
  34. package/docs/reference/authoring-surface/branchname.md +15 -0
  35. package/docs/reference/authoring-surface/command.md +36 -21
  36. package/docs/reference/authoring-surface/fail.md +17 -4
  37. package/docs/reference/authoring-surface/file.md +36 -16
  38. package/docs/reference/authoring-surface/http.md +108 -8
  39. package/docs/reference/authoring-surface/isready.md +14 -0
  40. package/docs/reference/authoring-surface/jr2setup.md +1 -1
  41. package/docs/reference/authoring-surface/open.md +36 -5
  42. package/docs/reference/authoring-surface/paramsof.md +22 -4
  43. package/docs/reference/authoring-surface/pool.md +4 -4
  44. package/docs/reference/authoring-surface/push.md +30 -12
  45. package/docs/reference/authoring-surface/readyof.md +21 -0
  46. package/docs/reference/authoring-surface/secret.md +25 -4
  47. package/docs/reference/authoring-surface/source.md +3 -3
  48. package/docs/reference/authoring-surface/type-agentdefinition.md +2 -2
  49. package/docs/reference/authoring-surface/type-agentslots.md +4 -1
  50. package/docs/reference/authoring-surface/type-anyframepath.md +14 -0
  51. package/docs/reference/authoring-surface/type-anyworktreepath.md +15 -0
  52. package/docs/reference/authoring-surface/type-bindactors.md +14 -0
  53. package/docs/reference/authoring-surface/type-binding.md +5 -6
  54. package/docs/reference/authoring-surface/type-commandinput.md +4 -3
  55. package/docs/reference/authoring-surface/type-commandoptions.md +0 -22
  56. package/docs/reference/authoring-surface/type-commandoutput.md +22 -4
  57. package/docs/reference/authoring-surface/type-customize.md +4 -2
  58. package/docs/reference/authoring-surface/type-dispatchoutput.md +8 -1
  59. package/docs/reference/authoring-surface/type-doorlessinput.md +19 -0
  60. package/docs/reference/authoring-surface/type-filebody.md +4 -8
  61. package/docs/reference/authoring-surface/type-framepath.md +14 -0
  62. package/docs/reference/authoring-surface/type-hostinjectedinput.md +2 -4
  63. package/docs/reference/authoring-surface/type-httpdefinition.md +6 -3
  64. package/docs/reference/authoring-surface/type-httpfileinput.md +20 -0
  65. package/docs/reference/authoring-surface/type-httpoutput.md +7 -1
  66. package/docs/reference/authoring-surface/type-lateroutcome.md +21 -0
  67. package/docs/reference/authoring-surface/type-namestart.md +77 -0
  68. package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +1 -6
  69. package/docs/reference/authoring-surface/type-notworktreekeys.md +12 -0
  70. package/docs/reference/authoring-surface/type-opencommandinput.md +7 -2
  71. package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +1 -6
  72. package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +5 -10
  73. package/docs/reference/authoring-surface/type-poolnextinput.md +22 -0
  74. package/docs/reference/authoring-surface/type-poolspec.md +2 -2
  75. package/docs/reference/authoring-surface/type-pushinput.md +22 -3
  76. package/docs/reference/authoring-surface/type-pushoutput.md +32 -7
  77. package/docs/reference/authoring-surface/type-reposlot.md +5 -5
  78. package/docs/reference/authoring-surface/type-sandboxoptions.md +11 -4
  79. package/docs/reference/authoring-surface/type-slothandles.md +5 -13
  80. package/docs/reference/authoring-surface/type-sourcespec.md +10 -10
  81. package/docs/reference/authoring-surface/type-workspaced.md +29 -8
  82. package/docs/reference/authoring-surface/type-workspacehandles.md +5 -6
  83. package/docs/reference/authoring-surface/type-workspaceoptions.md +1 -13
  84. package/docs/reference/authoring-surface/type-worktreefound.md +16 -0
  85. package/docs/reference/authoring-surface/type-worktreeinput.md +56 -0
  86. package/docs/reference/authoring-surface/type-worktreekey.md +14 -0
  87. package/docs/reference/authoring-surface/type-worktreeoptions.md +29 -0
  88. package/docs/reference/authoring-surface/type-worktreeoutput.md +45 -0
  89. package/docs/reference/authoring-surface/type-worktreepath.md +16 -0
  90. package/docs/reference/authoring-surface/type-worktreeready.md +37 -0
  91. package/docs/reference/authoring-surface/type-worktreerefused.md +21 -0
  92. package/docs/reference/authoring-surface/workspace.md +65 -37
  93. package/docs/reference/authoring-surface/worktree.md +71 -0
  94. package/docs/reference/authoring-surface.md +30 -10
  95. package/docs/reference/cli.md +1 -1
  96. package/docs/reference/config.md +13 -4
  97. package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +10 -9
  98. package/docs/reference/decisions/0002-duplex-streaming-actor.md +17 -10
  99. package/docs/reference/decisions/0004-worktree-provisioning-model.md +27 -21
  100. package/docs/reference/decisions/0005-sandbox-pod-composition.md +29 -19
  101. package/docs/reference/decisions/0006-agent-control-surface.md +6 -3
  102. package/docs/reference/decisions/0012-workspace-wrapper-machine.md +30 -30
  103. package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +35 -17
  104. package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +8 -2
  105. package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +9 -7
  106. package/docs/reference/decisions/0017-pool-over-a-source-port.md +6 -4
  107. package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +21 -9
  108. package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +2 -1
  109. package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +8 -9
  110. package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +62 -65
  111. package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +9 -1
  112. package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +13 -12
  113. package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +4 -1
  114. package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +18 -19
  115. package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +8 -8
  116. package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +4 -4
  117. package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +57 -46
  118. package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +5 -0
  119. package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +20 -8
  120. package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +24 -24
  121. package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +5 -3
  122. package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +110 -67
  123. package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +101 -74
  124. package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +5 -6
  125. package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +2 -0
  126. package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +181 -153
  127. package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +74 -63
  128. package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +31 -20
  129. package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +1 -1
  130. package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +295 -0
  131. package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +320 -0
  132. package/docs/reference/decisions/0077-jr2-requires-landlock-on-every-sandbox-node.md +79 -0
  133. package/docs/reference/decisions.md +3 -0
  134. package/docs/reference/glossary.md +51 -12
  135. package/docs/reference/http-api.md +45 -7
  136. package/docs/reference/machines.md +0 -1
  137. package/docs/why.md +5 -4
  138. package/package.json +3 -3
  139. package/src/actor.ts +161 -35
  140. package/src/agent.ts +6 -6
  141. package/src/ambient.ts +3 -5
  142. package/src/chart.ts +186 -19
  143. package/src/charts.ts +9 -2
  144. package/src/config.ts +16 -6
  145. package/src/custodian.lua +17 -5
  146. package/src/custodian.ts +251 -77
  147. package/src/customize.ts +11 -3
  148. package/src/effect-checks.ts +50 -3
  149. package/src/effect.ts +343 -127
  150. package/src/effector-wire.ts +6 -3
  151. package/src/fail.ts +17 -4
  152. package/src/harness-client.ts +74 -31
  153. package/src/harness-env.ts +33 -0
  154. package/src/held-secrets.ts +125 -16
  155. package/src/holds.ts +3 -0
  156. package/src/http-effect.ts +88 -32
  157. package/src/http.ts +56 -17
  158. package/src/index.ts +15 -1
  159. package/src/internal.ts +1 -0
  160. package/src/kube-client.ts +6 -3
  161. package/src/machine-doc.ts +3 -4
  162. package/src/model-keys.ts +24 -0
  163. package/src/names.ts +19 -6
  164. package/src/notices.ts +443 -54
  165. package/src/open-body.ts +85 -19
  166. package/src/open.ts +36 -5
  167. package/src/parts.ts +40 -28
  168. package/src/party.ts +33 -0
  169. package/src/pick.ts +41 -7
  170. package/src/pool.ts +44 -23
  171. package/src/registration.ts +53 -11
  172. package/src/repo-identity.ts +7 -3
  173. package/src/repos.ts +20 -2
  174. package/src/run-host.ts +106 -20
  175. package/src/sandbox-effect.ts +217 -66
  176. package/src/sandbox-kube.ts +63 -16
  177. package/src/secret-placement.ts +9 -2
  178. package/src/setup.ts +86 -6
  179. package/src/tokens.ts +107 -32
  180. package/src/vocabulary.ts +23 -4
  181. package/src/wire.ts +10 -10
  182. package/src/workspace.ts +264 -253
  183. package/src/worktree.ts +249 -0
  184. package/docs/reference/authoring-surface/type-noslotspec.md +0 -26
  185. package/docs/reference/authoring-surface/type-workspacespec.md +0 -37
package/docs/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # jr2
2
2
 
3
- > A kit for agentic workflows as xstate Machines, run on Kubernetes. These are the docs of Kit version 0.5.1, as plain Markdown.
3
+ > A kit for agentic workflows as xstate Machines, run on Kubernetes. These are the docs of Kit version 0.6.0, as plain Markdown.
4
4
 
5
5
  ## Home
6
6
 
@@ -55,8 +55,9 @@
55
55
  - [Write a Workflow](guides/write-a-workflow.md): Write a module in workflows/ that exports a Machine, with the input that starts a run and its Vocabulary.
56
56
  - [Bind a shipped Machine's Open parts](guides/bind-open-parts.md): Register a Machine from a package as a Workflow, and bind the parts that it leaves Open with customize().
57
57
  - [Set an Agent's access and Dials](guides/set-an-agents-access-and-dials.md): Choose what an Agent can do to the Workspace, and set the Dials and continue of one Turn.
58
+ - [Cut a Worktree](guides/cut-a-worktree.md): Make a Worktree with worktree(), choose what a cut refuses, and remove a Worktree.
58
59
  - [Run a command or call a URL with an Effect](guides/run-a-command-or-call-a-url.md): Run a program or call a URL as an Effect, give it input from a pick, and route on its output.
59
- - [Push and sign a branch](guides/push-and-sign-a-branch.md): Push the branch of a Workspace, and sign its commits with a key that the Agent never reads.
60
+ - [Push and sign a branch](guides/push-and-sign-a-branch.md): Push the branch of a Worktree, and sign its commits with a key that the Agent never reads.
60
61
  - [Start a run from a run](guides/start-a-run-from-a-run.md): Use a dispatch Effect to start a run of a Workflow from a Machine, in this Instance or in a different one.
61
62
  - [Add tools to the Sandbox](guides/add-tools-to-the-sandbox.md): Put the programs that your Agents use into the Sandbox Image, or run a service in a User Container.
62
63
  - [Size a Workspace](guides/size-a-workspace.md): Give a Workspace the memory and cpu that its Sandbox needs, and see how jr2 divides them in the pod.
@@ -77,12 +78,13 @@
77
78
  - [`agent`](reference/authoring-surface/agent.md): Make an Agent: an actor slot that runs one Turn of a model each time a state invokes it.
78
79
  - [`AgentDefinition`](reference/authoring-surface/type-agentdefinition.md): An Agent's definition: which model it runs, its instructions, and what it may do to the Workspace.
79
80
  - [`ThinkingLevel`](reference/authoring-surface/type-thinkinglevel.md): How hard the model thinks before it answers: `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"` or `"xhigh"`.
80
- - [`workspace`](reference/authoring-surface/workspace.md): Run a body Machine in a Sandbox: a pod of its own, with a Worktree of each Repo Slot on one branch.
81
- - [`Workspaced`](reference/authoring-surface/type-workspaced.md): The input of a `workspace()` body: the run input, plus `workspace`, the handles that the Workspace adds (`workspace.repos`, `workspace.branch`, `workspace.review`).
81
+ - [`workspace`](reference/authoring-surface/workspace.md): Run a body Machine in a Sandbox: a pod of its own, with a clone of each Repo Slot.
82
+ - [`Workspaced`](reference/authoring-surface/type-workspaced.md): The input of a `workspace()` body: the run input, plus `workspace`, the handles that the Workspace adds (`workspace.repos`, the folder of each Repo Slot).
82
83
  - [`Binding`](reference/authoring-surface/type-binding.md): The repository of a Repo Slot: `{ url, ref }`.
83
84
  - [`RepoSlot`](reference/authoring-surface/type-reposlot.md): The value of one Repo Slot in `workspace({ repos })`.
84
85
  - [`arg`](reference/authoring-surface/arg.md): Mark one argv entry of a `command` that the input of the Effect fills.
85
86
  - [`CommandOutput`](reference/authoring-surface/type-commandoutput.md): The output of a `command` Effect: what the `onDone` of its state gets as `event.output`.
87
+ - [`LaterOutcome`](reference/authoring-surface/type-lateroutcome.md): A value of `outcome` that this kit does not give.
86
88
  - [`command`](reference/authoring-surface/command.md): Make a `command` Effect: an actor slot that runs one program in the Workspace's Sandbox when a state invokes it.
87
89
  - [`basic`](reference/authoring-surface/basic.md): Make the `auth` of an `http` Effect that sends `Authorization: Basic <value>`, where the value is the base64 of `user:password`.
88
90
  - [`bearer`](reference/authoring-surface/bearer.md): Make the `auth` of an `http` Effect that sends `Authorization: Bearer <value>`, with the value of an Effect secret.
@@ -91,8 +93,22 @@
91
93
  - [`secret`](reference/authoring-surface/secret.md): Name an Effect secret: `secret("jira")`.
92
94
  - [`text`](reference/authoring-surface/text.md): Make a string from literal text and Effect secrets, as a tagged template: `` text`Token ${secret("x")}` ``.
93
95
  - [`HttpOutput`](reference/authoring-surface/type-httpoutput.md): The output of an `http` Effect: what the `onDone` of its state gets as `event.output`.
94
- - [`push`](reference/authoring-surface/push.md): Make a `push` Effect: it pushes the branch of the Workspace to the Binding of its Repo Slot.
96
+ - [`push`](reference/authoring-surface/push.md): Make a `push` Effect: it pushes the branch of a Worktree to the Binding of its Repo Slot.
95
97
  - [`PushOutput`](reference/authoring-surface/type-pushoutput.md): The output of a `push` Effect: what the `onDone` of its state gets as `event.output`.
98
+ - [`branchName`](reference/authoring-surface/branchname.md): A kit schema for a pick param that names a branch.
99
+ - [`isReady`](reference/authoring-surface/isready.md): Is it `ready`?
100
+ - [`readyOf`](reference/authoring-surface/readyof.md): The `ready` output of an `onDone` arm that `isReady` guards.
101
+ - [`worktree`](reference/authoring-surface/worktree.md): Make a `worktree` Effect: it cuts a Worktree of a Repo Slot, or reads the one that is there.
102
+ - [`AnyFramePath`](reference/authoring-surface/type-anyframepath.md): A Turn's Frame: a Worktree, or `/work`, stated.
103
+ - [`AnyWorktreePath`](reference/authoring-surface/type-anyworktreepath.md): A Worktree of any Repo Slot: what a kit factory states, before `jr2Setup` narrows it to the slots of the body.
104
+ - [`FramePath`](reference/authoring-surface/type-framepath.md): A Turn's Frame in a Workspace with the Repo Slots `S`.
105
+ - [`WorktreeFound`](reference/authoring-surface/type-worktreefound.md): What a cut found: `held`, a cut made this Worktree earlier, so what is in it is earlier work; `local`, a local branch; `remote`, `origin/<branch>`, now tracked; `none`, a new branch with no upstream; `commit`, a detached cut.
106
+ - [`WorktreeInput`](reference/authoring-surface/type-worktreeinput.md): The input of a `worktree()`: a branch Worktree, or a detached one.
107
+ - [`WorktreeOptions`](reference/authoring-surface/type-worktreeoptions.md): The options of `worktree()`.
108
+ - [`WorktreeOutput`](reference/authoring-surface/type-worktreeoutput.md): The output of a `worktree()`.
109
+ - [`WorktreePath`](reference/authoring-surface/type-worktreepath.md): A Worktree of the Repo Slots `S`.
110
+ - [`WorktreeReady`](reference/authoring-surface/type-worktreeready.md): Type, an export of @jr2/orchestrator.
111
+ - [`WorktreeRefused`](reference/authoring-surface/type-worktreerefused.md): No Worktree, and nothing changed: a bad path, a name git or the push refuses, a re-cut that does not agree with the first, a branch that another Worktree holds, an `expect` that does not hold, or a name that the remote cannot confirm.
96
112
  - [`dispatch`](reference/authoring-surface/dispatch.md): Make a `dispatch` Effect: it starts a run of a Workflow.
97
113
  - [`DispatchOutput`](reference/authoring-surface/type-dispatchoutput.md): The output of a `dispatch` Effect.
98
114
  - [`answer`](reference/authoring-surface/answer.md): Set what the Agent reads when jr2 answers its pick.
@@ -106,6 +122,7 @@
106
122
  - [`UserContainer`](reference/authoring-surface/type-usercontainer.md): The User Container in its object form: its image, and its part of the Workspace's Size.
107
123
  - [`pool`](reference/authoring-surface/pool.md): Make a Pool: a Machine that runs one worker Machine for each item that a Source gives, with at most `cap` workers at once.
108
124
  - [`source`](reference/authoring-surface/source.md): Declare a Source: where a `pool()` gets its work items, one at a time.
125
+ - [`PoolNextInput`](reference/authoring-surface/type-poolnextinput.md): The input of a Source's `next`: the ids of the items that workers have now, the ids of the items that settled, and the Pool's input.
109
126
  - [`openBody`](reference/authoring-surface/openbody.md): Make an Open body: the actor slot that a Chart binds.
110
127
  - [`OpenBodyDeclaration`](reference/authoring-surface/type-openbodydeclaration.md): What an Open body declares: the parts that it lends a Chart, what the Agents of a Chart can have, and the limits of a Chart.
111
128
  - [`OpenBodyOutput`](reference/authoring-surface/type-openbodyoutput.md): The output of an Open body.
@@ -126,7 +143,7 @@
126
143
  - [`WithoutEmptyIndex`](reference/authoring-surface/type-withoutemptyindex.md): The fields of the run input `T`.
127
144
  - [`PermissiveWorkspaceOptions`](reference/authoring-surface/type-permissiveworkspaceoptions.md): The options of a `workspace()` with no `input`: it starts with any input.
128
145
  - [`PermissiveNoSlotWorkspaceOptions`](reference/authoring-surface/type-permissivenoslotworkspaceoptions.md): The options of a `workspace()` with no Repo Slot and no `input`: it starts with any input.
129
- - [`WorkspaceHandles`](reference/authoring-surface/type-workspacehandles.md): What the body of a `workspace()` gets as `input.workspace`: the path of each Worktree, and the branch.
146
+ - [`WorkspaceHandles`](reference/authoring-surface/type-workspacehandles.md): What the body of a `workspace()` gets as `input.workspace`: the folder of each Repo Slot.
130
147
  - [`ExecOutcome`](reference/authoring-surface/type-execoutcome.md): How an exec ended.
131
148
  - [`Unknown`](reference/authoring-surface/type-unknown.md): The output `{ outcome: "unknown", reason }`: the Effect may have acted, and jr2 cannot tell.
132
149
  - [`Arg`](reference/authoring-surface/type-arg.md): One entry of a command's argv that the input of the Effect fills, as `arg("name")` makes it.
@@ -136,11 +153,14 @@
136
153
  - [`Secret`](reference/authoring-surface/type-secret.md): What `secret("name")` gives: an Effect secret, by its name in the `secrets` list of `jr2.config.ts`.
137
154
  - [`Text`](reference/authoring-surface/type-text.md): What the `text` template gives: a string of literal text and Effect secrets, in order.
138
155
  - [`FromInput`](reference/authoring-surface/type-frominput.md): A value of a file body's part: as written, or from the Effect's input.
139
- - [`FileBody`](reference/authoring-surface/type-filebody.md): `file(path, { slot?, segments?, contentType? })`: a Worktree file as an `http` body.
156
+ - [`FileBody`](reference/authoring-surface/type-filebody.md): `file(path, { segments?, contentType? })`: a Worktree file as an `http` body.
140
157
  - [`HttpDefinition`](reference/authoring-surface/type-httpdefinition.md): An `http` Effect's definition.
158
+ - [`HttpFileInput`](reference/authoring-surface/type-httpfileinput.md): The input of an `http` Effect with a Worktree file as its body.
141
159
  - [`OpenSecret`](reference/authoring-surface/type-opensecret.md): `secret(open)`: a secret a packaged Machine names in its auth, a header or a command's env, and leaves for its composer to name (ADR-0054).
142
160
  - [`PushOptions`](reference/authoring-surface/type-pushoptions.md): The options of `push()`.
143
- - [`PushInput`](reference/authoring-surface/type-pushinput.md): The input of a `push` Effect: `{ sha }` with `pin`, and `{ message }` with `squash`.
161
+ - [`PushInput`](reference/authoring-surface/type-pushinput.md): The input of a `push` Effect: the Worktree that a cut made, `{ sha }` with `pin`, and `{ message }` with `squash`.
162
+ - [`Duration`](reference/authoring-surface/type-duration.md): A length of time: a positive number and a unit, `s`, `m` or `h`.
163
+ - [`NameStart`](reference/authoring-surface/type-namestart.md): What a Worktree's name may start with: neither `.` nor `-`, and not the end of the path.
144
164
  - [`DispatchDefinition`](reference/authoring-surface/type-dispatchdefinition.md): The definition of a `dispatch` Effect (ADR-0071).
145
165
  - [`DispatchInput`](reference/authoring-surface/type-dispatchinput.md): A dispatch's input: the run's body — the slot's schema's type, or any JSON object.
146
166
  - [`DispatchOpenParts`](reference/authoring-surface/type-dispatchopenparts.md): The Open part a dispatch definition states: its target, when it is `open`.
@@ -155,10 +175,7 @@
155
175
  - [`Sender`](reference/authoring-surface/type-sender.md): Who delivered an event: an Agent by its slot, or a Gate by its invoke id (ADR-0015).
156
176
  - [`FailureInput`](reference/authoring-surface/type-failureinput.md): What a Failure carries: `reason`, text for a person, and `detail`, optional JSON for a machine reader.
157
177
  - [`SandboxOptions`](reference/authoring-surface/type-sandboxoptions.md): The options of a `workspace()` that say what its Sandbox is made of and which Repos it clones.
158
- - [`WorkspaceSpec`](reference/authoring-surface/type-workspacespec.md): What the `spec` of a `workspace()` returns: the branch that the Workspace works on, and two optional fields.
159
- - [`NoSlotSpec`](reference/authoring-surface/type-noslotspec.md): What the `spec` of a `workspace()` with no Repo Slot returns: only `workGroup`.
160
178
  - [`SlotHandles`](reference/authoring-surface/type-slothandles.md): The handles of a Workspace that declares Repo Slots.
161
- - [`Duration`](reference/authoring-surface/type-duration.md): A length of time: a positive number and a unit, `s`, `m` or `h`.
162
179
  - [`CommandEnv`](reference/authoring-surface/type-commandenv.md): The `env` of a `command`: for each variable, `secret("name")` for the value of an Effect secret, or `secret("name").path` for the path of a file that holds it.
163
180
  - [`TextPart`](reference/authoring-surface/type-textpart.md): One part of a `Text`: `{ text }`, literal text, or `{ secret }`, the name of an Effect secret.
164
181
  - [`HttpMethod`](reference/authoring-surface/type-httpmethod.md): The method of an `http` Effect: `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE` or `OPTIONS`.
@@ -179,18 +196,20 @@
179
196
  - [`ToProvidedActor`](reference/authoring-surface/type-toprovidedactor.md): A type that the Authoring surface names.
180
197
  - [`MergedActors`](reference/authoring-surface/type-mergedactors.md): A type that the Authoring surface names.
181
198
  - [`ToParameterizedObject`](reference/authoring-surface/type-toparameterizedobject.md): A type that the Authoring surface names.
199
+ - [`BindActors`](reference/authoring-surface/type-bindactors.md): A type that the Authoring surface names.
182
200
  - [`SentByGuards`](reference/authoring-surface/type-sentbyguards.md): A type that the Authoring surface names.
183
201
  - [`AgentLogic`](reference/authoring-surface/type-agentlogic.md): A type that the Authoring surface names.
184
202
  - [`BodyAcceptsDoor`](reference/authoring-surface/type-bodyacceptsdoor.md): A type that the Authoring surface names.
185
203
  - [`WorkspaceMachine`](reference/authoring-surface/type-workspacemachine.md): A type that the Authoring surface names.
204
+ - [`DoorlessInput`](reference/authoring-surface/type-doorlessinput.md): A type that the Authoring surface names.
186
205
  - [`BodyAcceptsSlots`](reference/authoring-surface/type-bodyacceptsslots.md): A type that the Authoring surface names.
187
206
  - [`EffectLogic`](reference/authoring-surface/type-effectlogic.md): A type that the Authoring surface names.
188
207
  - [`OpenOf`](reference/authoring-surface/type-openof.md): A type that the Authoring surface names.
189
208
  - [`EnvOpenParts`](reference/authoring-surface/type-envopenparts.md): A type that the Authoring surface names.
190
209
  - [`OpenEffect`](reference/authoring-surface/type-openeffect.md): A type that the Authoring surface names.
191
210
  - [`MarkedIf`](reference/authoring-surface/type-markedif.md): A type that the Authoring surface names.
192
- - [`HttpInput`](reference/authoring-surface/type-httpinput.md): A type that the Authoring surface names.
193
211
  - [`HttpOpenParts`](reference/authoring-surface/type-httpopenparts.md): A type that the Authoring surface names.
212
+ - [`HttpInput`](reference/authoring-surface/type-httpinput.md): A type that the Authoring surface names.
194
213
  - [`PushWireOutput`](reference/authoring-surface/type-pushwireoutput.md): A type that the Authoring surface names.
195
214
  - [`SyncState`](reference/authoring-surface/type-syncstate.md): A type that the Authoring surface names.
196
215
  - [`AnswerAction`](reference/authoring-surface/type-answeraction.md): A type that the Authoring surface names.
@@ -206,6 +225,8 @@
206
225
  - [`PoolMachine`](reference/authoring-surface/type-poolmachine.md): A type that the Authoring surface names.
207
226
  - [`EventFrom`](reference/authoring-surface/type-eventfrom.md): A type that the Authoring surface names.
208
227
  - [`ArgNames`](reference/authoring-surface/type-argnames.md): A type that the Authoring surface names.
228
+ - [`WorktreeKey`](reference/authoring-surface/type-worktreekey.md): A type that the Authoring surface names.
229
+ - [`NotWorktreeKeys`](reference/authoring-surface/type-notworktreekeys.md): A type that the Authoring surface names.
209
230
  - [`OpenSecretMark`](reference/authoring-surface/type-opensecretmark.md): A type that the Authoring surface names.
210
231
  - [@jr2/machines](reference/machines.md): The Machines that @jr2/machines ships: their input, their output, and their Open parts.
211
232
  - [jr2.config.ts](reference/config.md): Every field of jr2.config.ts: its type, whether it is required, its default, and what it does.
@@ -8,7 +8,11 @@ description: "Make an Agent: an actor slot that runs one Turn of a model each ti
8
8
  Function, in `@jr2/orchestrator/src/harness-client.ts`. It is an export of `@jr2/orchestrator`, on the [Authoring surface](../authoring-surface.md) page, in Agents.
9
9
 
10
10
  ```ts
11
- function agent(declaration: AgentDeclaration): AgentLogic
11
+ function agent<
12
+ const D extends AgentDeclaration,
13
+ >(
14
+ declaration: D,
15
+ ): AgentLogic & (D extends { workspace: "none" } ? { readonly definition: { readonly workspace: "none" } } : unknown)
12
16
  ```
13
17
 
14
18
  Make an Agent: an actor slot that runs one Turn of a model each time a state invokes it. Put it
@@ -16,8 +20,9 @@ under `actors` in `jr2Setup`, and invoke it by its key: `actors: { coder: agent(
16
20
  `invoke: { src: "coder", input: { prompt } }`. The key is the Agent's name.
17
21
 
18
22
  The invoke's `input` is the Turn: `prompt` (required), `cwd`, `model`, `thinkingLevel` and
19
- `continue`. `cwd` is the absolute directory where the Working tools work. Absent, it is the
20
- Worktree of the Workspace's one Repo Slot. `continue: true` continues the Agent's conversation
23
+ `continue`. `cwd` is the absolute directory where the Working tools work. Under Repo Slots it
24
+ is required: a Worktree that a cut made, `<slot>/default` to read, or `/work`. An Agent with
25
+ `workspace: "none"`, and a Workspace with no Repo Slot, need no `cwd`. `continue: true` continues the Agent's conversation
21
26
  in this Machine. Absent, each Turn starts a new conversation. `continue` is the literal `true`,
22
27
  not a `boolean`. A Turn can join only a conversation that an earlier Turn started with
23
28
  `continue: true`. Thus in a retry loop, put `continue: true` on each Turn, also on the first, so
@@ -43,10 +48,9 @@ When a Turn starts, it refuses:
43
48
  - a key in `input` that a Turn does not have: ``agent "<slot>": the Turn's input carries
44
49
  `<key>`, which a Turn has no use for — its input is its Frame (`prompt`, `cwd`), its Dials
45
50
  (`model`, `thinkingLevel`), and `continue` (ADR-0057)``
46
- - no `cwd` under a Workspace with more than one Repo Slot: ``turn <id>: agent "<slot>" works
47
- under a Workspace carrying more than one Repo Slot (<slots>) and its Turn framed no `cwd` —
48
- say which Worktree it works in (`cwd: context.workspace.repos.<slot>`, one of those), because
49
- the kit gives no slot a meaning (ADR-0051) and a Turn's Frame is where it works (ADR-0057)``
51
+ - no `cwd` under Repo Slots: ``turn <id>: agent "<slot>" works under a Workspace with Repo Slots
52
+ (<slots>) and its Turn framed no `cwd`: say where it works, a Worktree, or `cwd: "/work"` above
53
+ them (ADR-0057)``
50
54
  - a `cwd` that is not an absolute path: ``agent "<slot>": the Turn's Frame carries a `cwd` that
51
55
  is not an absolute path — the Frame says WHERE this Turn works (ADR-0057), and a Turn rooted
52
56
  anywhere else would work in the wrong directory silently``. The Harness makes this refusal
@@ -70,7 +74,16 @@ When a Turn starts, it refuses:
70
74
 
71
75
  ```ts
72
76
  import { z } from "zod";
73
- import { agent, defineEvent, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";
77
+ import {
78
+ agent,
79
+ defineEvent,
80
+ fail,
81
+ isReady,
82
+ jr2Setup,
83
+ workspace,
84
+ worktree,
85
+ type Workspaced,
86
+ } from "@jr2/orchestrator";
74
87
 
75
88
  const finish = defineEvent({
76
89
  name: "finish",
@@ -80,6 +93,8 @@ const finish = defineEvent({
80
93
  const runInput = z.object({ branch: z.string() });
81
94
  type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
82
95
 
96
+ const fixTree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
97
+
83
98
  const body = jr2Setup({
84
99
  types: {} as { input: BodyInput; context: BodyInput },
85
100
  events: [finish],
@@ -88,26 +103,35 @@ const body = jr2Setup({
88
103
  model: "anthropic/claude-haiku-5-5",
89
104
  instructions: "You fix failing tests. You change no test.",
90
105
  }),
106
+ cut: worktree(),
91
107
  fail: fail(),
92
108
  },
93
109
  }).createMachine({
94
110
  id: "fix",
95
111
  context: ({ input }) => input,
96
112
  on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
97
- initial: "coding",
113
+ initial: "cutting",
98
114
  states: {
115
+ cutting: {
116
+ invoke: {
117
+ src: "cut",
118
+ input: ({ context }) => ({ path: fixTree(context), branch: context.branch }),
119
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
120
+ },
121
+ },
99
122
  coding: {
100
123
  invoke: {
101
124
  src: "coder",
102
125
  input: ({ context }) => ({
103
126
  prompt: "Make `node --test` pass, then commit.",
104
- cwd: context.workspace.repos.app,
127
+ cwd: fixTree(context),
105
128
  thinkingLevel: "high",
106
129
  }),
107
130
  },
108
131
  on: { finish: "done" },
109
132
  },
110
133
  done: { type: "final" },
134
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
111
135
  failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
112
136
  lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
113
137
  },
@@ -116,7 +140,6 @@ const body = jr2Setup({
116
140
  export const machine = workspace(body, {
117
141
  input: runInput,
118
142
  repos: { app: "https://github.com/you/app.git" },
119
- spec: ({ input }) => ({ branch: input.branch }),
120
143
  });
121
144
  ```
122
145
 
@@ -61,8 +61,10 @@ import {
61
61
  command,
62
62
  defineEvent,
63
63
  fail,
64
+ isReady,
64
65
  jr2Setup,
65
66
  workspace,
67
+ worktree,
66
68
  type Workspaced,
67
69
  } from "@jr2/orchestrator";
68
70
 
@@ -80,6 +82,8 @@ const finished = defineEvent({
80
82
 
81
83
  type Input = Workspaced<{}, "app">;
82
84
 
85
+ const fixTree = (context: Input) => `${context.workspace.repos.app}/fix` as const;
86
+
83
87
  const body = jr2Setup({
84
88
  types: {} as { context: Input; input: Input },
85
89
  events: [runTests, finished],
@@ -88,6 +92,7 @@ const body = jr2Setup({
88
92
  model: "anthropic/claude-haiku-5-5",
89
93
  instructions: "You are a careful engineer.",
90
94
  }),
95
+ cut: worktree(),
91
96
  tests: command(["npm", "test"]),
92
97
  fail: fail(),
93
98
  },
@@ -95,10 +100,20 @@ const body = jr2Setup({
95
100
  id: "fix-tests",
96
101
  context: ({ input }) => input,
97
102
  on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
98
- initial: "coding",
103
+ initial: "cutting",
99
104
  states: {
105
+ cutting: {
106
+ invoke: {
107
+ src: "cut",
108
+ input: ({ context }) => ({ path: fixTree(context), branch: "fix-tests" }),
109
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
110
+ },
111
+ },
100
112
  coding: {
101
- invoke: { src: "coder", input: { prompt: "Make the tests pass." } },
113
+ invoke: {
114
+ src: "coder",
115
+ input: ({ context }) => ({ prompt: "Make the tests pass.", cwd: fixTree(context) }),
116
+ },
102
117
  on: { finished: "done" },
103
118
  initial: "ready",
104
119
  states: {
@@ -106,6 +121,7 @@ const body = jr2Setup({
106
121
  testing: {
107
122
  invoke: {
108
123
  src: "tests",
124
+ input: ({ context }) => ({ worktree: fixTree(context) }),
109
125
  onDone: {
110
126
  target: "ready",
111
127
  // The Agent reads this string, not the whole output of the command.
@@ -120,6 +136,7 @@ const body = jr2Setup({
120
136
  },
121
137
  },
122
138
  done: { type: "final" },
139
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
123
140
  failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
124
141
  lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
125
142
  },
@@ -127,7 +144,6 @@ const body = jr2Setup({
127
144
 
128
145
  export const machine = workspace(body, {
129
146
  repos: { app: { url: "https://github.com/you/app.git" } },
130
- spec: () => ({ branch: "fix-tests" }),
131
147
  });
132
148
  ```
133
149
 
@@ -26,30 +26,52 @@ map it in the invoke's input`. The angle brackets around the name are in the tex
26
26
  **Example**
27
27
 
28
28
  ```ts
29
- import { arg, command, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";
29
+ import {
30
+ arg,
31
+ command,
32
+ fail,
33
+ isReady,
34
+ jr2Setup,
35
+ workspace,
36
+ worktree,
37
+ type Workspaced,
38
+ } from "@jr2/orchestrator";
30
39
 
31
40
  type Input = Workspaced<{ file: string }, "app">;
32
41
 
42
+ const lintTree = (context: Input) => `${context.workspace.repos.app}/lint` as const;
43
+
33
44
  const body = jr2Setup({
34
45
  types: {} as { context: Input; input: Input },
35
- actors: { lint: command(["npx", "eslint", arg("file")]), fail: fail() },
46
+ actors: { cut: worktree(), lint: command(["npx", "eslint", arg("file")]), fail: fail() },
36
47
  }).createMachine({
37
48
  id: "lint",
38
49
  context: ({ input }) => input,
39
50
  on: { "workspace.lost": ".lost" },
40
- initial: "lint",
51
+ initial: "cutting",
41
52
  states: {
53
+ cutting: {
54
+ invoke: {
55
+ src: "cut",
56
+ input: ({ context }) => ({ path: lintTree(context), branch: "lint" }),
57
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "lint" }, { target: "notCut" }],
58
+ },
59
+ },
42
60
  lint: {
43
- invoke: { src: "lint", input: ({ context }) => ({ file: context.file }), onDone: "done" },
61
+ invoke: {
62
+ src: "lint",
63
+ input: ({ context }) => ({ file: context.file, worktree: lintTree(context) }),
64
+ onDone: "done",
65
+ },
44
66
  },
45
67
  done: { type: "final" },
68
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
46
69
  lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
47
70
  },
48
71
  });
49
72
 
50
73
  export const machine = workspace(body, {
51
74
  repos: { app: { url: "https://github.com/you/app.git" } },
52
- spec: () => ({ branch: "lint" }),
53
75
  });
54
76
  ```
55
77
 
@@ -0,0 +1,15 @@
1
+ ---
2
+ title: branchName
3
+ description: A kit schema for a pick param that names a branch.
4
+ ---
5
+
6
+ # `branchName`
7
+
8
+ Constant, in `@jr2/orchestrator/src/worktree.ts`. It is an export of `@jr2/orchestrator`, on the [Authoring surface](../authoring-surface.md) page, in Effects.
9
+
10
+ ```ts
11
+ const branchName: ZodString
12
+ ```
13
+
14
+ A kit schema for a pick param that names a branch. For example:
15
+ `input: z.object({ branch: branchName })`.
@@ -16,7 +16,7 @@ function command<
16
16
  >(
17
17
  argv: A,
18
18
  options?: Opt,
19
- ): EffectLogic<CommandInput<A, Opt["pin"]>, CommandOutput> & OpenOf<EnvOpenParts<Opt>>
19
+ ): EffectLogic<CommandInput<A, Opt["pin"], Opt>, CommandOutput> & OpenOf<EnvOpenParts<Opt>>
20
20
  ```
21
21
 
22
22
  Make a `command` Effect: an actor slot that runs one program in the Workspace's Sandbox when a
@@ -29,8 +29,8 @@ shell, write it: `["sh", "-c", "…"]`.
29
29
 
30
30
  Where it runs:
31
31
  - With no Effect secret in `env`, in the Harness container of the enclosing Workspace's Sandbox.
32
- It runs in the Worktree of a Repo Slot, or in `/work` in a Workspace with no Repo Slot. The
33
- Agent's Working tools also run in this container.
32
+ It runs in the Worktree that `worktree` of the invoke's input names, or in `/work` in a
33
+ Workspace with no Repo Slot. The Agent's Working tools also run in this container.
34
34
  - With an Effect secret in `env`, in the Sandbox Effector, against a commit of the branch. This
35
35
  is the branch tip when it starts, or with `pin: true` the commit that the invoke's `input.sha`
36
36
  names. The output then says `dirty: true` when the Worktree held edits that the command did
@@ -67,11 +67,9 @@ It refuses, when you call it:
67
67
  And when it starts, with no Effect secret in `env`:
68
68
  - outside a `workspace()`: `command "<slot>" runs in the Harness container of a Workspace, and
69
69
  its state is not inside a workspace() — invoke it from a Workspace's body (ADR-0067)`
70
- - no `slot` under a Workspace with more than one Repo Slot: `command "<slot>" runs under a
71
- Workspace carrying more than one Repo Slot (<slots>) and names none — say which Worktree it
72
- runs in: command(argv, { slot: "<slot>" }) (ADR-0051)`
73
- - a `slot` that the Workspace does not have: `command "<slot>" names Repo Slot "<name>", which
74
- its Workspace does not carry (<slots>)`
70
+ - no `worktree` under Repo Slots: `` command "<slot>" runs under a Workspace with Repo Slots
71
+ (<slots>) and its input names no `worktree`: say which, a Worktree that a cut gave or
72
+ `<slot>/default` ``
75
73
  - an `arg()` with no string in `input`: `command "<slot>": argv slot <<name>> has no string
76
74
  value in its input (got <type>) — map it in the invoke's input`. The angle brackets around the
77
75
  arg's name are in the text: `argv slot <file>`. `<type>` is `nothing` when `input` has no such
@@ -80,15 +78,13 @@ And when it starts, with no Effect secret in `env`:
80
78
  And when it starts, with an Effect secret in `env`:
81
79
  - outside a `workspace()`: `command "<slot>" runs in the Sandbox Effector of a Workspace, and its
82
80
  state is not inside a workspace() — invoke it from a Workspace's body (ADR-0067)`
83
- - no `slot` under a Workspace with more than one Repo Slot: `command "<slot>" runs under a
84
- Workspace carrying more than one Repo Slot (<slots>) — say which: { slot: "<slot>" }
85
- (ADR-0051)`
86
81
  - a Workspace with no Repo Slot: `command "<slot>" runs under a Workspace with no Repo Slot: a
87
82
  command with an Effect secret runs against one commit of a Repo Slot's branch, and there is
88
83
  none — declare a Repo Slot, or name no secret in its env, and it runs in /work beside the Agent
89
84
  (ADR-0051)`. `jr2 up` refuses it first, with the same reason
90
- - a `slot` that the Workspace does not have: `command "<slot>" names Repo Slot "<name>", which
91
- its Workspace does not carry (<slots>)`
85
+ - a `worktree` that no cut made in this Sandbox: the output is `exited` 127, with `no cut made
86
+ <path> in this Sandbox: cut it with worktree()` in its tail. A detached Worktree gets the same
87
+ form
92
88
  - `pin: true` and an `input.sha` that is not a full commit id: `command "<slot>" (pin): its
93
89
  input's sha is not a full commit id`
94
90
  - an `arg()` with no string in `input`: the same text as above.
@@ -98,8 +94,7 @@ And when it starts, with an Effect secret in `env`:
98
94
  - `argv`: The program and its arguments: strings and `arg("name")` entries. Or `open`, in a
99
95
  Machine that you publish as a package, for the Instance that registers it to bind with
100
96
  `customize()`.
101
- - `options` ([`CommandOptions`](type-commandoptions.md)): Optional. `slot`: the Repo Slot whose Worktree the command runs in; needed only
102
- where the Workspace has more than one. `timeout`: `"90s"`, `"10m"` or `"1h"`, default
97
+ - `options` ([`CommandOptions`](type-commandoptions.md)): Optional. `timeout`: `"90s"`, `"10m"` or `"1h"`, default
103
98
  `"10m"`; when it expires, the output is `timeout`. `tail`: how many characters of the end of
104
99
  the output stream to keep, default 4096. `env`: environment variables. Each value is
105
100
  `secret("name")` for the value of an Effect secret, or `secret("name").path` for the path of a
@@ -112,26 +107,46 @@ And when it starts, with an Effect secret in `env`:
112
107
 
113
108
  ```ts
114
109
  import { z } from "zod";
115
- import { arg, command, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";
110
+ import {
111
+ arg,
112
+ command,
113
+ fail,
114
+ isReady,
115
+ jr2Setup,
116
+ workspace,
117
+ worktree,
118
+ type Workspaced,
119
+ } from "@jr2/orchestrator";
116
120
 
117
121
  const runInput = z.object({ branch: z.string() });
118
122
  type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
119
123
 
124
+ const testTree = (context: BodyInput) => `${context.workspace.repos.app}/test` as const;
125
+
120
126
  const body = jr2Setup({
121
- types: {} as { input: BodyInput },
127
+ types: {} as { input: BodyInput; context: BodyInput },
122
128
  actors: {
129
+ cut: worktree(),
123
130
  tests: command(["node", "--test", arg("file")], { timeout: "5m" }),
124
131
  fail: fail(),
125
132
  },
126
133
  }).createMachine({
127
134
  id: "check",
135
+ context: ({ input }) => input,
128
136
  on: { "workspace.lost": ".lost" },
129
- initial: "testing",
137
+ initial: "cutting",
130
138
  states: {
139
+ cutting: {
140
+ invoke: {
141
+ src: "cut",
142
+ input: ({ context }) => ({ path: testTree(context), branch: context.branch }),
143
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "testing" }, { target: "notCut" }],
144
+ },
145
+ },
131
146
  testing: {
132
147
  invoke: {
133
148
  src: "tests",
134
- input: { file: "test/greet.test.js" },
149
+ input: ({ context }) => ({ file: "test/greet.test.js", worktree: testTree(context) }),
135
150
  onDone: [
136
151
  {
137
152
  guard: ({ event }) => event.output.outcome === "exited" && event.output.code === 0,
@@ -144,6 +159,7 @@ const body = jr2Setup({
144
159
  passed: { type: "final" },
145
160
  // Not final states: each one fails the run, and the run ends `failed`.
146
161
  failed: { invoke: { src: "fail", input: { reason: "the test did not pass" } } },
162
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
147
163
  lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
148
164
  },
149
165
  });
@@ -151,7 +167,6 @@ const body = jr2Setup({
151
167
  export const machine = workspace(body, {
152
168
  input: runInput,
153
169
  repos: { app: "https://github.com/you/app.git" },
154
- spec: ({ input }) => ({ branch: input.branch }),
155
170
  });
156
171
  ```
157
172
 
@@ -170,7 +185,7 @@ function command<
170
185
  >(
171
186
  argv: typeof open,
172
187
  options?: Opt,
173
- ): EffectLogic<OpenCommandInput<Opt["pin"]>, CommandOutput> & OpenEffect<"argv" | EnvOpenParts<Opt>>
188
+ ): EffectLogic<OpenCommandInput<Opt["pin"], Opt>, CommandOutput> & OpenEffect<"argv" | EnvOpenParts<Opt>>
174
189
  ```
175
190
 
176
191
  Make a `command` Effect whose argv is Open: `command(open, options)`, in a Machine that you
@@ -37,24 +37,37 @@ It refuses an input that is not a Failure's, and the run ends `error`: ``fail: t
37
37
 
38
38
  ```ts
39
39
  import { z } from "zod";
40
- import { command, fail, jr2Setup, workspace, type Workspaced } from "@jr2/orchestrator";
40
+ import { command, fail, isReady, jr2Setup, workspace, worktree, type Workspaced } from "@jr2/orchestrator";
41
41
 
42
42
  const runInput = z.object({ branch: z.string() });
43
+ type BodyInput = Workspaced<z.infer<typeof runInput>, "app">;
44
+
45
+ const testTree = (context: BodyInput) => `${context.workspace.repos.app}/test` as const;
43
46
 
44
47
  const body = jr2Setup({
45
- types: {} as { input: Workspaced<z.infer<typeof runInput>, "app"> },
48
+ types: {} as { input: BodyInput; context: BodyInput },
46
49
  actors: {
50
+ cut: worktree(),
47
51
  tests: command(["npm", "test"], { timeout: "15m" }),
48
52
  fail: fail(),
49
53
  },
50
54
  }).createMachine({
51
55
  id: "check",
56
+ context: ({ input }) => input,
52
57
  on: { "workspace.lost": ".lost" },
53
- initial: "testing",
58
+ initial: "cutting",
54
59
  states: {
60
+ cutting: {
61
+ invoke: {
62
+ src: "cut",
63
+ input: ({ context }) => ({ path: testTree(context), branch: context.branch }),
64
+ onDone: [{ guard: ({ event }) => isReady(event.output), target: "testing" }, { target: "notCut" }],
65
+ },
66
+ },
55
67
  testing: {
56
68
  invoke: {
57
69
  src: "tests",
70
+ input: ({ context }) => ({ worktree: testTree(context) }),
58
71
  onDone: [
59
72
  {
60
73
  guard: ({ event }) => event.output.outcome === "exited" && event.output.code === 0,
@@ -67,6 +80,7 @@ const body = jr2Setup({
67
80
  // Not a final state: the run ends `failed`, and the Workspace deletes the Sandbox.
68
81
  failing: { invoke: { src: "fail", input: { reason: "npm test did not pass" } } },
69
82
  passed: { type: "final" },
83
+ notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
70
84
  lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
71
85
  },
72
86
  });
@@ -74,7 +88,6 @@ const body = jr2Setup({
74
88
  export const machine = workspace(body, {
75
89
  input: runInput,
76
90
  repos: { app: "https://github.com/you/app.git" },
77
- spec: ({ input }) => ({ branch: input.branch }),
78
91
  });
79
92
  ```
80
93