@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.
- package/docs/agents-block.md +2 -2
- package/docs/concepts/agents-and-turns.md +56 -20
- package/docs/concepts/architecture.md +30 -17
- package/docs/concepts/charts.md +6 -3
- package/docs/concepts/converge.md +3 -0
- package/docs/concepts/effects.md +86 -31
- package/docs/concepts/machines-and-workflows.md +9 -0
- package/docs/concepts/pools-and-sources.md +6 -6
- package/docs/concepts/secrets-and-trust.md +126 -42
- package/docs/concepts/the-menu.md +3 -0
- package/docs/concepts/workspaces.md +129 -51
- package/docs/get-started/an-agent-in-a-sandbox.md +21 -19
- package/docs/get-started/have-your-assistant-write-a-machine.md +111 -40
- package/docs/get-started/install.md +4 -0
- package/docs/guides/add-tools-to-the-sandbox.md +17 -4
- package/docs/guides/bind-open-parts.md +5 -4
- package/docs/guides/cut-a-worktree.md +560 -0
- package/docs/guides/fix-a-failed-converge.md +1 -1
- package/docs/guides/let-an-agent-write-a-chart.md +5 -1
- package/docs/guides/look-inside-a-sandbox.md +18 -15
- package/docs/guides/move-from-kind-to-a-shared-cluster.md +16 -0
- package/docs/guides/push-and-sign-a-branch.md +67 -21
- package/docs/guides/run-a-command-or-call-a-url.md +84 -41
- package/docs/guides/run-one-worker-per-item.md +19 -18
- package/docs/guides/set-an-agents-access-and-dials.md +67 -22
- package/docs/guides/size-a-workspace.md +19 -6
- package/docs/guides/use-a-hosted-provider.md +6 -0
- package/docs/guides/watch-a-run.md +47 -24
- package/docs/guides/write-a-workflow.md +1 -1
- package/docs/llms.txt +33 -12
- package/docs/reference/authoring-surface/agent.md +34 -11
- package/docs/reference/authoring-surface/answer.md +19 -3
- package/docs/reference/authoring-surface/arg.md +27 -5
- package/docs/reference/authoring-surface/branchname.md +15 -0
- package/docs/reference/authoring-surface/command.md +36 -21
- package/docs/reference/authoring-surface/fail.md +17 -4
- package/docs/reference/authoring-surface/file.md +36 -16
- package/docs/reference/authoring-surface/http.md +108 -8
- package/docs/reference/authoring-surface/isready.md +14 -0
- package/docs/reference/authoring-surface/jr2setup.md +1 -1
- package/docs/reference/authoring-surface/open.md +36 -5
- package/docs/reference/authoring-surface/paramsof.md +22 -4
- package/docs/reference/authoring-surface/pool.md +4 -4
- package/docs/reference/authoring-surface/push.md +30 -12
- package/docs/reference/authoring-surface/readyof.md +21 -0
- package/docs/reference/authoring-surface/secret.md +25 -4
- package/docs/reference/authoring-surface/source.md +3 -3
- package/docs/reference/authoring-surface/type-agentdefinition.md +2 -2
- package/docs/reference/authoring-surface/type-agentslots.md +4 -1
- package/docs/reference/authoring-surface/type-anyframepath.md +14 -0
- package/docs/reference/authoring-surface/type-anyworktreepath.md +15 -0
- package/docs/reference/authoring-surface/type-bindactors.md +14 -0
- package/docs/reference/authoring-surface/type-binding.md +5 -6
- package/docs/reference/authoring-surface/type-commandinput.md +4 -3
- package/docs/reference/authoring-surface/type-commandoptions.md +0 -22
- package/docs/reference/authoring-surface/type-commandoutput.md +22 -4
- package/docs/reference/authoring-surface/type-customize.md +4 -2
- package/docs/reference/authoring-surface/type-dispatchoutput.md +8 -1
- package/docs/reference/authoring-surface/type-doorlessinput.md +19 -0
- package/docs/reference/authoring-surface/type-filebody.md +4 -8
- package/docs/reference/authoring-surface/type-framepath.md +14 -0
- package/docs/reference/authoring-surface/type-hostinjectedinput.md +2 -4
- package/docs/reference/authoring-surface/type-httpdefinition.md +6 -3
- package/docs/reference/authoring-surface/type-httpfileinput.md +20 -0
- package/docs/reference/authoring-surface/type-httpoutput.md +7 -1
- package/docs/reference/authoring-surface/type-lateroutcome.md +21 -0
- package/docs/reference/authoring-surface/type-namestart.md +77 -0
- package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +1 -6
- package/docs/reference/authoring-surface/type-notworktreekeys.md +12 -0
- package/docs/reference/authoring-surface/type-opencommandinput.md +7 -2
- package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +1 -6
- package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +5 -10
- package/docs/reference/authoring-surface/type-poolnextinput.md +22 -0
- package/docs/reference/authoring-surface/type-poolspec.md +2 -2
- package/docs/reference/authoring-surface/type-pushinput.md +22 -3
- package/docs/reference/authoring-surface/type-pushoutput.md +32 -7
- package/docs/reference/authoring-surface/type-reposlot.md +5 -5
- package/docs/reference/authoring-surface/type-sandboxoptions.md +11 -4
- package/docs/reference/authoring-surface/type-slothandles.md +5 -13
- package/docs/reference/authoring-surface/type-sourcespec.md +10 -10
- package/docs/reference/authoring-surface/type-workspaced.md +29 -8
- package/docs/reference/authoring-surface/type-workspacehandles.md +5 -6
- package/docs/reference/authoring-surface/type-workspaceoptions.md +1 -13
- package/docs/reference/authoring-surface/type-worktreefound.md +16 -0
- package/docs/reference/authoring-surface/type-worktreeinput.md +56 -0
- package/docs/reference/authoring-surface/type-worktreekey.md +14 -0
- package/docs/reference/authoring-surface/type-worktreeoptions.md +29 -0
- package/docs/reference/authoring-surface/type-worktreeoutput.md +45 -0
- package/docs/reference/authoring-surface/type-worktreepath.md +16 -0
- package/docs/reference/authoring-surface/type-worktreeready.md +37 -0
- package/docs/reference/authoring-surface/type-worktreerefused.md +21 -0
- package/docs/reference/authoring-surface/workspace.md +65 -37
- package/docs/reference/authoring-surface/worktree.md +71 -0
- package/docs/reference/authoring-surface.md +30 -10
- package/docs/reference/cli.md +1 -1
- package/docs/reference/config.md +13 -4
- package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +10 -9
- package/docs/reference/decisions/0002-duplex-streaming-actor.md +17 -10
- package/docs/reference/decisions/0004-worktree-provisioning-model.md +27 -21
- package/docs/reference/decisions/0005-sandbox-pod-composition.md +29 -19
- package/docs/reference/decisions/0006-agent-control-surface.md +6 -3
- package/docs/reference/decisions/0012-workspace-wrapper-machine.md +30 -30
- package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +35 -17
- package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +8 -2
- package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +9 -7
- package/docs/reference/decisions/0017-pool-over-a-source-port.md +6 -4
- package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +21 -9
- package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +2 -1
- package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +8 -9
- package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +62 -65
- package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +9 -1
- package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +13 -12
- package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +4 -1
- package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +18 -19
- package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +8 -8
- package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +4 -4
- package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +57 -46
- package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +5 -0
- package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +20 -8
- package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +24 -24
- package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +5 -3
- package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +110 -67
- package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +101 -74
- package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +5 -6
- 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
- package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +181 -153
- package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +74 -63
- package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +31 -20
- package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +1 -1
- package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +295 -0
- package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +320 -0
- package/docs/reference/decisions/0077-jr2-requires-landlock-on-every-sandbox-node.md +79 -0
- package/docs/reference/decisions.md +3 -0
- package/docs/reference/glossary.md +51 -12
- package/docs/reference/http-api.md +45 -7
- package/docs/reference/machines.md +0 -1
- package/docs/why.md +5 -4
- package/package.json +3 -3
- package/src/actor.ts +161 -35
- package/src/agent.ts +6 -6
- package/src/ambient.ts +3 -5
- package/src/chart.ts +186 -19
- package/src/charts.ts +9 -2
- package/src/config.ts +16 -6
- package/src/custodian.lua +17 -5
- package/src/custodian.ts +251 -77
- package/src/customize.ts +11 -3
- package/src/effect-checks.ts +50 -3
- package/src/effect.ts +343 -127
- package/src/effector-wire.ts +6 -3
- package/src/fail.ts +17 -4
- package/src/harness-client.ts +74 -31
- package/src/harness-env.ts +33 -0
- package/src/held-secrets.ts +125 -16
- package/src/holds.ts +3 -0
- package/src/http-effect.ts +88 -32
- package/src/http.ts +56 -17
- package/src/index.ts +15 -1
- package/src/internal.ts +1 -0
- package/src/kube-client.ts +6 -3
- package/src/machine-doc.ts +3 -4
- package/src/model-keys.ts +24 -0
- package/src/names.ts +19 -6
- package/src/notices.ts +443 -54
- package/src/open-body.ts +85 -19
- package/src/open.ts +36 -5
- package/src/parts.ts +40 -28
- package/src/party.ts +33 -0
- package/src/pick.ts +41 -7
- package/src/pool.ts +44 -23
- package/src/registration.ts +53 -11
- package/src/repo-identity.ts +7 -3
- package/src/repos.ts +20 -2
- package/src/run-host.ts +106 -20
- package/src/sandbox-effect.ts +217 -66
- package/src/sandbox-kube.ts +63 -16
- package/src/secret-placement.ts +9 -2
- package/src/setup.ts +86 -6
- package/src/tokens.ts +107 -32
- package/src/vocabulary.ts +23 -4
- package/src/wire.ts +10 -10
- package/src/workspace.ts +264 -253
- package/src/worktree.ts +249 -0
- package/docs/reference/authoring-surface/type-noslotspec.md +0 -26
- package/docs/reference/authoring-surface/type-workspacespec.md +0 -37
|
@@ -8,10 +8,10 @@ description: How a Workflow gets a Sandbox with a git Worktree or a shared folde
|
|
|
8
8
|
A [Workspace](../reference/glossary.md#workspace) is a [Machine](../reference/glossary.md#machine) that runs a body
|
|
9
9
|
Machine in a [Sandbox](../reference/glossary.md#sandbox). The Sandbox is a pod of its own, with a folder, `/work`, that
|
|
10
10
|
the Agents and Effects of the body share. When the Workspace names [Repos](../reference/glossary.md#repo), `/work` holds
|
|
11
|
-
a git [Worktree](../reference/glossary.md#worktree)
|
|
12
|
-
the folder (see [A Workspace with no Repo](#a-workspace-with-no-repo)). You make a Workspace
|
|
13
|
-
[`workspace()`](../reference/authoring-surface/workspace.md). The Workspace makes the Sandbox when the run enters
|
|
14
|
-
and deletes the Sandbox when the body reaches a final state.
|
|
11
|
+
a clone of each Repo. The body cuts each git [Worktree](../reference/glossary.md#worktree) that it needs. A Workspace
|
|
12
|
+
that names no Repo has only the folder (see [A Workspace with no Repo](#a-workspace-with-no-repo)). You make a Workspace
|
|
13
|
+
with [`workspace()`](../reference/authoring-surface/workspace.md). The Workspace makes the Sandbox when the run enters
|
|
14
|
+
it, and deletes the Sandbox when the body reaches a final state.
|
|
15
15
|
|
|
16
16
|
## Why Workspaces exist
|
|
17
17
|
|
|
@@ -27,14 +27,24 @@ Agent.
|
|
|
27
27
|
## A Workspace and its body
|
|
28
28
|
|
|
29
29
|
This example is a [Workflow](../reference/glossary.md#workflow). A coder changes the `app` Repo, and reads the
|
|
30
|
-
`handbook` Repo beside it. Then a person approves the change at a
|
|
31
|
-
pushes the branch:
|
|
30
|
+
`handbook` Repo beside it. The Machine first cuts the coder's Worktree. Then a person approves the change at a
|
|
31
|
+
[Gate](../reference/glossary.md#gate), and the Machine pushes the branch:
|
|
32
32
|
|
|
33
33
|
**Anthropic**
|
|
34
34
|
|
|
35
35
|
```ts
|
|
36
36
|
import { z } from "zod";
|
|
37
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
agent,
|
|
39
|
+
defineEvent,
|
|
40
|
+
fail,
|
|
41
|
+
isReady,
|
|
42
|
+
jr2Setup,
|
|
43
|
+
push,
|
|
44
|
+
workspace,
|
|
45
|
+
worktree,
|
|
46
|
+
type Workspaced,
|
|
47
|
+
} from "@jr2/orchestrator";
|
|
38
48
|
|
|
39
49
|
const finished = defineEvent({
|
|
40
50
|
name: "finished",
|
|
@@ -51,6 +61,10 @@ const approve = defineEvent({
|
|
|
51
61
|
const runInput = z.object({ ticket: z.string(), prompt: z.string() });
|
|
52
62
|
type BodyInput = Workspaced<z.infer<typeof runInput>, "app" | "handbook">;
|
|
53
63
|
|
|
64
|
+
// The folder of the Worktree, and its branch. The Machine knows both before the cut.
|
|
65
|
+
const fixTree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
|
|
66
|
+
const branchOf = (context: BodyInput) => `docs/${context.ticket}`;
|
|
67
|
+
|
|
54
68
|
const body = jr2Setup({
|
|
55
69
|
types: {} as { context: BodyInput; input: BodyInput },
|
|
56
70
|
events: [finished, approve],
|
|
@@ -59,6 +73,7 @@ const body = jr2Setup({
|
|
|
59
73
|
model: "anthropic/claude-haiku-5-5",
|
|
60
74
|
instructions: "You are a careful engineer. You commit your work on the branch.",
|
|
61
75
|
}),
|
|
76
|
+
cut: worktree(),
|
|
62
77
|
// Two Repo Slots, so the push names the slot that it pushes.
|
|
63
78
|
publish: push({ slot: "app" }),
|
|
64
79
|
fail: fail(),
|
|
@@ -66,17 +81,25 @@ const body = jr2Setup({
|
|
|
66
81
|
}).createMachine({
|
|
67
82
|
id: "docs-fix",
|
|
68
83
|
context: ({ input }) => input,
|
|
69
|
-
initial: "
|
|
84
|
+
initial: "cutting",
|
|
70
85
|
// The Sandbox is gone, and its unpushed commits with it. This body fails the run.
|
|
71
86
|
on: { "agent.fault": ".failed", "workspace.lost": ".lost" },
|
|
72
87
|
states: {
|
|
88
|
+
// The Workspace only clones. The Machine cuts the Worktree that the Agent works in.
|
|
89
|
+
cutting: {
|
|
90
|
+
invoke: {
|
|
91
|
+
src: "cut",
|
|
92
|
+
input: ({ context }) => ({ path: fixTree(context), branch: branchOf(context) }),
|
|
93
|
+
onDone: [{ guard: ({ event }) => isReady(event.output), target: "working" }, { target: "notCut" }],
|
|
94
|
+
},
|
|
95
|
+
},
|
|
73
96
|
working: {
|
|
74
97
|
invoke: {
|
|
75
98
|
src: "coder",
|
|
76
99
|
input: ({ context }) => ({
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
cwd: context
|
|
100
|
+
// A slot that is only read needs no cut: its `default` folder is on the Binding's base.
|
|
101
|
+
prompt: `${context.prompt}\nRead the style rules in ${context.workspace.repos.handbook}/default.`,
|
|
102
|
+
cwd: fixTree(context),
|
|
80
103
|
}),
|
|
81
104
|
},
|
|
82
105
|
on: { finished: "review" },
|
|
@@ -86,7 +109,7 @@ const body = jr2Setup({
|
|
|
86
109
|
invoke: {
|
|
87
110
|
src: "gate",
|
|
88
111
|
input: ({ context }) => ({
|
|
89
|
-
meta: { branch: context
|
|
112
|
+
meta: { branch: branchOf(context), worktree: fixTree(context) },
|
|
90
113
|
}),
|
|
91
114
|
},
|
|
92
115
|
on: { approve: "publishing" },
|
|
@@ -96,11 +119,14 @@ const body = jr2Setup({
|
|
|
96
119
|
publishing: {
|
|
97
120
|
invoke: {
|
|
98
121
|
src: "publish",
|
|
122
|
+
// The Worktree names what to push: jr2 reads its branch from the cut.
|
|
123
|
+
input: ({ context }) => ({ worktree: fixTree(context) }),
|
|
99
124
|
onDone: [{ guard: ({ event }) => event.output.outcome === "pushed", target: "done" }, { target: "review" }],
|
|
100
125
|
},
|
|
101
126
|
},
|
|
102
127
|
done: { type: "final" },
|
|
103
128
|
// Not final states: a final state means `done`. Each one fails the run, and the run ends `failed`.
|
|
129
|
+
notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
|
|
104
130
|
lost: { invoke: { src: "fail", input: { reason: "the Sandbox was lost" } } },
|
|
105
131
|
failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
|
|
106
132
|
},
|
|
@@ -115,7 +141,6 @@ export const machine = workspace(body, {
|
|
|
115
141
|
app: { url: "https://github.com/you/app.git", ref: "main" },
|
|
116
142
|
handbook: "https://github.com/you/handbook.git",
|
|
117
143
|
},
|
|
118
|
-
spec: ({ input }) => ({ branch: `docs/${input.ticket}` }),
|
|
119
144
|
});
|
|
120
145
|
```
|
|
121
146
|
|
|
@@ -123,7 +148,17 @@ export const machine = workspace(body, {
|
|
|
123
148
|
|
|
124
149
|
```ts
|
|
125
150
|
import { z } from "zod";
|
|
126
|
-
import {
|
|
151
|
+
import {
|
|
152
|
+
agent,
|
|
153
|
+
defineEvent,
|
|
154
|
+
fail,
|
|
155
|
+
isReady,
|
|
156
|
+
jr2Setup,
|
|
157
|
+
push,
|
|
158
|
+
workspace,
|
|
159
|
+
worktree,
|
|
160
|
+
type Workspaced,
|
|
161
|
+
} from "@jr2/orchestrator";
|
|
127
162
|
|
|
128
163
|
const finished = defineEvent({
|
|
129
164
|
name: "finished",
|
|
@@ -140,6 +175,10 @@ const approve = defineEvent({
|
|
|
140
175
|
const runInput = z.object({ ticket: z.string(), prompt: z.string() });
|
|
141
176
|
type BodyInput = Workspaced<z.infer<typeof runInput>, "app" | "handbook">;
|
|
142
177
|
|
|
178
|
+
// The folder of the Worktree, and its branch. The Machine knows both before the cut.
|
|
179
|
+
const fixTree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
|
|
180
|
+
const branchOf = (context: BodyInput) => `docs/${context.ticket}`;
|
|
181
|
+
|
|
143
182
|
const body = jr2Setup({
|
|
144
183
|
types: {} as { context: BodyInput; input: BodyInput },
|
|
145
184
|
events: [finished, approve],
|
|
@@ -148,6 +187,7 @@ const body = jr2Setup({
|
|
|
148
187
|
model: "local/qwen3.6-35b-a3b",
|
|
149
188
|
instructions: "You are a careful engineer. You commit your work on the branch.",
|
|
150
189
|
}),
|
|
190
|
+
cut: worktree(),
|
|
151
191
|
// Two Repo Slots, so the push names the slot that it pushes.
|
|
152
192
|
publish: push({ slot: "app" }),
|
|
153
193
|
fail: fail(),
|
|
@@ -155,17 +195,25 @@ const body = jr2Setup({
|
|
|
155
195
|
}).createMachine({
|
|
156
196
|
id: "docs-fix",
|
|
157
197
|
context: ({ input }) => input,
|
|
158
|
-
initial: "
|
|
198
|
+
initial: "cutting",
|
|
159
199
|
// The Sandbox is gone, and its unpushed commits with it. This body fails the run.
|
|
160
200
|
on: { "agent.fault": ".failed", "workspace.lost": ".lost" },
|
|
161
201
|
states: {
|
|
202
|
+
// The Workspace only clones. The Machine cuts the Worktree that the Agent works in.
|
|
203
|
+
cutting: {
|
|
204
|
+
invoke: {
|
|
205
|
+
src: "cut",
|
|
206
|
+
input: ({ context }) => ({ path: fixTree(context), branch: branchOf(context) }),
|
|
207
|
+
onDone: [{ guard: ({ event }) => isReady(event.output), target: "working" }, { target: "notCut" }],
|
|
208
|
+
},
|
|
209
|
+
},
|
|
162
210
|
working: {
|
|
163
211
|
invoke: {
|
|
164
212
|
src: "coder",
|
|
165
213
|
input: ({ context }) => ({
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
cwd: context
|
|
214
|
+
// A slot that is only read needs no cut: its `default` folder is on the Binding's base.
|
|
215
|
+
prompt: `${context.prompt}\nRead the style rules in ${context.workspace.repos.handbook}/default.`,
|
|
216
|
+
cwd: fixTree(context),
|
|
169
217
|
}),
|
|
170
218
|
},
|
|
171
219
|
on: { finished: "review" },
|
|
@@ -175,7 +223,7 @@ const body = jr2Setup({
|
|
|
175
223
|
invoke: {
|
|
176
224
|
src: "gate",
|
|
177
225
|
input: ({ context }) => ({
|
|
178
|
-
meta: { branch: context
|
|
226
|
+
meta: { branch: branchOf(context), worktree: fixTree(context) },
|
|
179
227
|
}),
|
|
180
228
|
},
|
|
181
229
|
on: { approve: "publishing" },
|
|
@@ -185,11 +233,14 @@ const body = jr2Setup({
|
|
|
185
233
|
publishing: {
|
|
186
234
|
invoke: {
|
|
187
235
|
src: "publish",
|
|
236
|
+
// The Worktree names what to push: jr2 reads its branch from the cut.
|
|
237
|
+
input: ({ context }) => ({ worktree: fixTree(context) }),
|
|
188
238
|
onDone: [{ guard: ({ event }) => event.output.outcome === "pushed", target: "done" }, { target: "review" }],
|
|
189
239
|
},
|
|
190
240
|
},
|
|
191
241
|
done: { type: "final" },
|
|
192
242
|
// Not final states: a final state means `done`. Each one fails the run, and the run ends `failed`.
|
|
243
|
+
notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
|
|
193
244
|
lost: { invoke: { src: "fail", input: { reason: "the Sandbox was lost" } } },
|
|
194
245
|
failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
|
|
195
246
|
},
|
|
@@ -204,28 +255,26 @@ export const machine = workspace(body, {
|
|
|
204
255
|
app: { url: "https://github.com/you/app.git", ref: "main" },
|
|
205
256
|
handbook: "https://github.com/you/handbook.git",
|
|
206
257
|
},
|
|
207
|
-
spec: ({ input }) => ({ branch: `docs/${input.ticket}` }),
|
|
208
258
|
});
|
|
209
259
|
```
|
|
210
260
|
|
|
211
261
|
[Agents and Turns](agents-and-turns.md) tells how to define an Agent.
|
|
212
262
|
|
|
213
263
|
The options of `workspace()` say what the Sandbox is. [`jr2 up`](../reference/cli.md#up) reads them before a run starts.
|
|
214
|
-
Only
|
|
264
|
+
Only a per-run [Repo Slot](../reference/glossary.md#repo-slot) reads the run input:
|
|
215
265
|
|
|
216
266
|
- `input` is the schema of the run input: what [`jr2 run`](../reference/cli.md#run) gives with `--input`. Put it on the
|
|
217
267
|
`workspace()`, not on the body.
|
|
218
268
|
- `repos` gives the Repo Slots that the Sandbox clones. Leave it out for a Workspace with no Repo.
|
|
219
|
-
- `spec` is a function from the run input to the branch. Its input also holds `instanceId` (see
|
|
220
|
-
[`HostInjectedInput`](../reference/authoring-surface/type-hostinjectedinput.md)).
|
|
221
269
|
- `resources` is the [Size](../reference/glossary.md#size). `image`, `user` and `effector` name the images of the pod's
|
|
222
270
|
containers.
|
|
223
271
|
- `secrets` names the [Held secrets](../reference/glossary.md#held-secret) that the Sandbox can use (see
|
|
224
272
|
[Secrets and trust](secrets-and-trust.md)).
|
|
273
|
+
- `workGroup` is the group id that owns the files in `/work`. The default is 2000.
|
|
225
274
|
|
|
226
275
|
The body gets the run input, plus `workspace`: the handles of the Workspace (see
|
|
227
|
-
[`WorkspaceHandles`](../reference/authoring-surface/type-workspacehandles.md)). `workspace.repos` gives the
|
|
228
|
-
|
|
276
|
+
[`WorkspaceHandles`](../reference/authoring-surface/type-workspacehandles.md)). `workspace.repos` gives the folder of
|
|
277
|
+
each Repo Slot, `/work/<slot>`. This folder is not a Worktree. Give the path of a Worktree to an Agent's
|
|
229
278
|
[Turn](../reference/glossary.md#turn) as its `cwd`, as the example does. Type the body's input with
|
|
230
279
|
[`Workspaced`](../reference/authoring-surface/type-workspaced.md), also when the run input is `z.object({})`.
|
|
231
280
|
|
|
@@ -243,7 +292,8 @@ A Repo Slot is a key of the `repos` option. The key is your Machine's name for t
|
|
|
243
292
|
Repo under `/work`. Each slot is one of three kinds:
|
|
244
293
|
|
|
245
294
|
- **Bound**: the Machine gives the url, or a [Binding](../reference/glossary.md#binding) `{ url, ref }`. `ref` is the
|
|
246
|
-
branch or the commit that the
|
|
295
|
+
branch, the tag or the commit that the clone stays on, and a new branch starts from it. Without `ref`, it is the
|
|
296
|
+
Repo's default branch.
|
|
247
297
|
- **[Open](../reference/glossary.md#open)**: the Machine gives [`open`](../reference/authoring-surface/open.md). The
|
|
248
298
|
[Instance](../reference/glossary.md#instance) that registers the Machine binds the slot with
|
|
249
299
|
[`customize()`](../reference/authoring-surface/customize.md) (see [Composition](composition.md)).
|
|
@@ -251,7 +301,7 @@ Repo under `/work`. Each slot is one of three kinds:
|
|
|
251
301
|
|
|
252
302
|
A Machine that names no slot writes `repos: open` for the whole map. Then the composer names each slot.
|
|
253
303
|
`workspace.repos` keeps the slots in the order that `repos` declares them. jr2 gives no slot a special meaning. Your
|
|
254
|
-
Machine says
|
|
304
|
+
Machine says where each Agent works.
|
|
255
305
|
|
|
256
306
|
The cluster keeps one read-only cache of each Repo on each node. A Sandbox clones from that cache, and a fetch in the
|
|
257
307
|
pod goes through it. [Architecture](architecture.md) tells about the Repo cache. Run
|
|
@@ -259,23 +309,44 @@ pod goes through it. [Architecture](architecture.md) tells about the Repo cache.
|
|
|
259
309
|
|
|
260
310
|
## The folders in the Sandbox
|
|
261
311
|
|
|
262
|
-
Each Repo Slot gets a folder under `/work`. The clone of the Repo is `/work/<slot>/default/`.
|
|
263
|
-
is
|
|
264
|
-
|
|
265
|
-
[Project layout](../reference/glossary.md#project-layout).
|
|
312
|
+
Each Repo Slot gets a folder under `/work`. The clone of the Repo is `/work/<slot>/default/`. It stays on the base of
|
|
313
|
+
the Binding: a branch is attached, and a tag or a commit is detached. No work happens in `default/`. A slot that an
|
|
314
|
+
Agent only reads needs nothing more: the Agent reads `/work/<slot>/default`. This is the
|
|
315
|
+
[Project layout](../reference/glossary.md#project-layout). `/work/.jr2/` is reserved for jr2.
|
|
316
|
+
|
|
317
|
+
The Workspace only clones. Your Machine cuts each Worktree with the
|
|
318
|
+
[`worktree()`](../reference/authoring-surface/worktree.md) Effect, in a state of the body. You give the path, and the
|
|
319
|
+
branch or the commit:
|
|
320
|
+
|
|
321
|
+
- `{ path: "/work/app/fix", branch: "docs/123" }` cuts a branch Worktree. The cut finds a local branch, then
|
|
322
|
+
`origin/<branch>`, tracked, after a fetch. With neither, it makes a new branch from `from` or the base of the Binding.
|
|
323
|
+
- `{ path: "/work/app/review", detach: sha }` cuts a detached Worktree for a reviewer. Each cut forces it to the commit
|
|
324
|
+
and cleans it. Ignored files stay, so that the reviewer can run the tests.
|
|
325
|
+
|
|
326
|
+
The path is exactly `/work/<slot>/<name>`. The name is one segment that is not `default` and starts with neither `.` nor
|
|
327
|
+
`-`. So your Machine knows the path before the cut, and the folder name does not change with the branch name.
|
|
328
|
+
|
|
329
|
+
The output of a cut is `ready`, `refused` or `unknown`. A later outcome can come, so route the last arm of `onDone` with
|
|
330
|
+
no guard. A bad path or a bad branch name is `refused`, and nothing changes. A cut is idempotent: the same cut again
|
|
331
|
+
reads the same Worktree, and its `head` is the tip of the branch.
|
|
332
|
+
|
|
333
|
+
`worktree({ expect: "new" })` refuses a branch that exists. `worktree({ expect: "existing" })` refuses a branch that
|
|
334
|
+
does not exist, and makes nothing.
|
|
335
|
+
|
|
336
|
+
The author chooses how many Agents work in a Workspace. Agents in one Worktree share git, as people in one checkout do.
|
|
337
|
+
Each coder that needs its own branch gets its own Worktree of the one clone.
|
|
266
338
|
|
|
267
|
-
|
|
268
|
-
|
|
339
|
+
Your Machine chooses the branch name. Give each run a different branch, so that two runs do not push to one branch. Make
|
|
340
|
+
it from a field of the run input, or from `instanceId` when the run input has no field that is different for each run.
|
|
341
|
+
Only a root `workspace()` gets `instanceId` from jr2. A `workspace()` that a different Machine invokes gets it only when
|
|
342
|
+
its parent gives it.
|
|
269
343
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
344
|
+
An Agent, a `command`, a `push`, and an `http` Effect with a file body each name their Worktree by its path: `cwd` for a
|
|
345
|
+
Turn, `worktree` for an Effect. A `push` has no branch in its input. jr2 reads the branch from the cut of that path. So
|
|
346
|
+
an Agent that moves `HEAD` does not change what is pushed.
|
|
273
347
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
no field that is different for each run: ``spec: ({ input }) => ({ branch: `fix/${input.instanceId}` })``. Only a root
|
|
277
|
-
`workspace()` gets `instanceId` from jr2. A `workspace()` that a different Machine invokes gets it only when its parent
|
|
278
|
-
gives it.
|
|
348
|
+
jr2 has no Effect that removes a Worktree. To remove one, run `git worktree remove` in a `command`.
|
|
349
|
+
[Cut a Worktree](../guides/cut-a-worktree.md) gives the procedure.
|
|
279
350
|
|
|
280
351
|
## A Workspace with no Repo
|
|
281
352
|
|
|
@@ -504,13 +575,13 @@ export const machine = workspace(body, { input: runInput });
|
|
|
504
575
|
|
|
505
576
|
In a Workspace with no Repo:
|
|
506
577
|
|
|
507
|
-
- Type the body's input as `Workspaced<RunInput, never>`. The handles are `{ repos: {} }
|
|
578
|
+
- Type the body's input as `Workspaced<RunInput, never>`. The handles are `{ repos: {} }`.
|
|
508
579
|
- An Agent's Turn that gives no `cwd` works in `/work`. The Agent's `workspace` access is the same as in each Workspace:
|
|
509
580
|
`"write"` gives it `write`, `edit` and `bash`, and `"read"` gives it `bash` only.
|
|
510
581
|
- A `command` with no Effect secret runs in `/work`.
|
|
511
582
|
- An `http` Effect sends a file of `/work` with `file(path)`. The path is relative to `/work`.
|
|
512
|
-
- `
|
|
513
|
-
|
|
583
|
+
- A `worktree()` needs a Repo Slot, a `push` needs a branch, and a `command` with an Effect secret runs on a commit.
|
|
584
|
+
Thus `jr2 up` refuses all three.
|
|
514
585
|
|
|
515
586
|
jr2 deletes `/work` with the Sandbox. Send what must stay before the body ends, as the example does with `upload`. A
|
|
516
587
|
Lost Sandbox has lost all of its work, because no commit was pushed.
|
|
@@ -593,8 +664,7 @@ A Workspace goes through these states:
|
|
|
593
664
|
|
|
594
665
|
1. `placing`: jr2 writes the Sandbox, and waits for a node.
|
|
595
666
|
2. `provisioning`: the pod starts.
|
|
596
|
-
3. `attaching`: the Harness clones each Repo Slot
|
|
597
|
-
do.
|
|
667
|
+
3. `attaching`: the Harness clones each Repo Slot. With no Repo Slot, this state has nothing to do.
|
|
598
668
|
4. `running`: the body runs.
|
|
599
669
|
5. `teardown`: the body is in a final state, and jr2 deletes the Sandbox.
|
|
600
670
|
6. `failing`: the body invoked [`fail`](../reference/authoring-surface/fail.md), and jr2 deletes the Sandbox. Then the
|
|
@@ -643,29 +713,37 @@ the Harness container does not lose the Workspace: the pod and `/work` stay.
|
|
|
643
713
|
- A per-run url must match an entry of [`git.credentials`](../reference/config.md#git-credentials). jr2 refuses the url
|
|
644
714
|
before it makes the Sandbox when no entry matches it. Thus a run cannot send the cluster's credentials to a host that
|
|
645
715
|
it chooses.
|
|
646
|
-
- `
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
- With no Repo Slot, `jr2 up` refuses a `push`, and a `command` that names an Effect secret.
|
|
716
|
+
- `jr2 up` refuses a Repo Slot name that starts with `.`, because `/work/.jr2/` is reserved for jr2.
|
|
717
|
+
- A cut of the branch that `default/` holds is `refused`, and the reason names `/work/<slot>/default`.
|
|
718
|
+
- With no Repo Slot, `jr2 up` refuses a `worktree()`, a `push`, and a `command` that names an Effect secret.
|
|
650
719
|
- A Size has only `limits.memory` and `limits.cpu`. jr2 refuses `requests` and each other key.
|
|
651
720
|
- `jr2 up` refuses a Size that leaves the Harness container less than 256Mi of memory, or no cpu.
|
|
652
|
-
- Under a Workspace with
|
|
721
|
+
- Under a Workspace with Repo Slots, a Turn states its `cwd`, and a `command`, a `push` and an `http` Effect with a file
|
|
722
|
+
body state their `worktree`. A Turn that wants `/work` states `cwd: "/work"`. An Agent with `workspace: "none"` needs
|
|
723
|
+
no `cwd`.
|
|
724
|
+
- A `push`, a `command` that names an Effect secret, and an `http` Effect with a file body need a Worktree that a cut of
|
|
725
|
+
this run made.
|
|
726
|
+
- Under a Workspace with more than one Repo Slot, a `push` names its `slot`.
|
|
653
727
|
|
|
654
728
|
The guides and the Reference give the refusal text of each rule.
|
|
655
729
|
|
|
656
730
|
## Read next
|
|
657
731
|
|
|
732
|
+
- [Cut a Worktree](../guides/cut-a-worktree.md)
|
|
658
733
|
- [Look inside a Sandbox](../guides/look-inside-a-sandbox.md)
|
|
659
734
|
- [Add tools to the Sandbox](../guides/add-tools-to-the-sandbox.md)
|
|
660
735
|
- [Size a Workspace](../guides/size-a-workspace.md)
|
|
661
736
|
- [Give the cluster git credentials](../guides/give-the-cluster-git-credentials.md)
|
|
662
737
|
- [Effects](effects.md), [Composition](composition.md), [Architecture](architecture.md)
|
|
663
738
|
- Reference: [`workspace`](../reference/authoring-surface/workspace.md),
|
|
739
|
+
[`worktree`](../reference/authoring-surface/worktree.md),
|
|
664
740
|
[`RepoSlot`](../reference/authoring-surface/type-reposlot.md), [`Size`](../reference/authoring-surface/type-size.md),
|
|
665
741
|
[`UserContainer`](../reference/authoring-surface/type-usercontainer.md),
|
|
666
742
|
[`workspace.lost`](../reference/mechanism-events.md#workspace-lost), [`sandbox`](../reference/config.md#sandbox)
|
|
667
743
|
- [ADR-0012](../reference/decisions/0012-workspace-wrapper-machine.md): `workspace()` wraps a body Machine and owns only
|
|
668
744
|
Sandbox lifecycle
|
|
745
|
+
- [ADR-0075](../reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md): a Machine cuts a
|
|
746
|
+
Worktree, and the Workspace only clones
|
|
669
747
|
- [ADR-0051](../reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md): a Repo is a slot
|
|
670
748
|
on the `workspace()` and a cache on the node
|
|
671
749
|
- [ADR-0060](../reference/decisions/0060-a-workspace-states-its-size-and-jr2-reserves-all-of-it.md): a Workspace states
|
|
@@ -161,7 +161,7 @@ jr2 run task --input '{"prompt":"In docs/site/tutorial/greet, one test fails. Fi
|
|
|
161
161
|
```text
|
|
162
162
|
…
|
|
163
163
|
→ context kind-jr2 / namespace my-instance
|
|
164
|
-
run
|
|
164
|
+
run 290b4be9-1e24-46a2-8cb5-27fabb3bbd3c (task) — attached
|
|
165
165
|
→ active "placing"
|
|
166
166
|
→ active "provisioning"
|
|
167
167
|
→ active "attaching"
|
|
@@ -183,10 +183,12 @@ jr2 status <run id>
|
|
|
183
183
|
```
|
|
184
184
|
|
|
185
185
|
The status is one line of JSON. While the coder works, `gates` is `[]`. When the run waits at `review`, `gates` holds
|
|
186
|
-
the Gate. Its `gate` is `body.review`, and the line ends with its `meta
|
|
186
|
+
the Gate. Its `gate` is `body.review`, and the line ends with its `meta`. After the JSON, `jr2 status` prints one line
|
|
187
|
+
for each Worktree that the run cut:
|
|
187
188
|
|
|
188
189
|
```text
|
|
189
|
-
…"gate":"body.review",…,"meta":{"summary":"Fixed
|
|
190
|
+
…"gate":"body.review",…,"meta":{"summary":"Fixed a bug in docs/site/tutorial/greet/src/greet.js where the name argument wasn't being trimmed. The test \"trims the name\" failed because input like \" ada \" produced \"hello, ada \" instead of \"hello, ada\". Added `.trim()` to the name extraction so whitespace is stripped before constructing the greeting. All 6 tests now pass.","branch":"jr2/task-1f34eef3-5749-4d7c-a16b-488c56ec88cd","worktree":"/work/target/task"}}]}
|
|
191
|
+
worktree: /work/target/task (target), branch jr2/task-1f34eef3-5749-4d7c-a16b-488c56ec88cd
|
|
190
192
|
```
|
|
191
193
|
|
|
192
194
|
Run the command again until `gates` holds the Gate.
|
|
@@ -196,7 +198,7 @@ Run the command again until `gates` holds the Gate.
|
|
|
196
198
|
- `worktree` is the folder in the Sandbox that holds the branch. It is
|
|
197
199
|
[the Worktree](../reference/glossary.md#worktree).
|
|
198
200
|
|
|
199
|
-
Copy `branch` and `worktree` from your output. The part after `jr2/task-`, here `
|
|
201
|
+
Copy `branch` and `worktree` from your output. The part after `jr2/task-`, here `1f34eef3-5749-4d7c-a16b-488c56ec88cd`,
|
|
200
202
|
is the [Instance ID](../reference/glossary.md#instance-id) of the run. `jr2 status` prints it as `instanceId`. It is not
|
|
201
203
|
the run id. Do not make the branch name from the run id. With the Instance token, the drawer of the
|
|
202
204
|
[Console](../reference/glossary.md#console) shows the same `meta`.
|
|
@@ -215,10 +217,10 @@ kubectl -n my-instance get sandboxes -l jr2.dev/run=<run id>
|
|
|
215
217
|
|
|
216
218
|
```text
|
|
217
219
|
NAME PHASE ENDPOINT AGE
|
|
218
|
-
ws-
|
|
220
|
+
ws-290b4be9-x-0-19gh8ze Ready http://ws-290b4be9-x-0-19gh8ze.my-instance.svc:8080 5m25s
|
|
219
221
|
```
|
|
220
222
|
|
|
221
|
-
`ws-
|
|
223
|
+
`ws-290b4be9-x-0-19gh8ze` is the name of the Sandbox. Your Sandbox has a different name. It starts with `ws-` and the
|
|
222
224
|
first 8 characters of the run id. The pod of the Sandbox has the same name. The commands below write it as `<sandbox>`.
|
|
223
225
|
|
|
224
226
|
## Look inside the Sandbox
|
|
@@ -237,12 +239,12 @@ node --test
|
|
|
237
239
|
```
|
|
238
240
|
|
|
239
241
|
```text
|
|
240
|
-
✔ greets the world by default (1.
|
|
241
|
-
✔ greets a name (0.
|
|
242
|
-
✔ shouts (0.
|
|
243
|
-
✔ trims the name (0.
|
|
244
|
-
✔ prints help (
|
|
245
|
-
✔ refuses an unknown flag (0.
|
|
242
|
+
✔ greets the world by default (1.0597ms)
|
|
243
|
+
✔ greets a name (0.162102ms)
|
|
244
|
+
✔ shouts (0.08266ms)
|
|
245
|
+
✔ trims the name (0.057171ms)
|
|
246
|
+
✔ prints help (3.806196ms)
|
|
247
|
+
✔ refuses an unknown flag (0.222015ms)
|
|
246
248
|
ℹ tests 6
|
|
247
249
|
ℹ suites 0
|
|
248
250
|
ℹ pass 6
|
|
@@ -250,7 +252,7 @@ node --test
|
|
|
250
252
|
ℹ cancelled 0
|
|
251
253
|
ℹ skipped 0
|
|
252
254
|
ℹ todo 0
|
|
253
|
-
ℹ duration_ms
|
|
255
|
+
ℹ duration_ms 53.312932
|
|
254
256
|
```
|
|
255
257
|
|
|
256
258
|
Your times are different. Read the commits of the coder. The branch starts at the release tag, so the commits after the
|
|
@@ -261,7 +263,7 @@ git log --oneline v<version>..HEAD
|
|
|
261
263
|
```
|
|
262
264
|
|
|
263
265
|
```text
|
|
264
|
-
|
|
266
|
+
e467788 fix: trim name in greet.js to handle leading/trailing whitespace
|
|
265
267
|
```
|
|
266
268
|
|
|
267
269
|
Each line is one commit. The commit ids and the messages come from the model. The author of each commit is
|
|
@@ -283,7 +285,7 @@ jr2 send <run id> --gate body.review --event request_changes --input '{"notes":"
|
|
|
283
285
|
```text
|
|
284
286
|
…
|
|
285
287
|
→ context kind-jr2 / namespace my-instance
|
|
286
|
-
delivered request_changes to gate "body.review" on
|
|
288
|
+
delivered request_changes to gate "body.review" on 290b4be9-1e24-46a2-8cb5-27fabb3bbd3c
|
|
287
289
|
```
|
|
288
290
|
|
|
289
291
|
The coder continues the same conversation, with your notes as its next prompt. The Sandbox and the branch stay. Run
|
|
@@ -312,7 +314,7 @@ Username for 'https://github.com': <you>
|
|
|
312
314
|
Password for 'https://<you>@github.com':
|
|
313
315
|
…
|
|
314
316
|
To https://github.com/<you>/jr2.git
|
|
315
|
-
* [new branch] jr2/task-
|
|
317
|
+
* [new branch] jr2/task-1f34eef3-5749-4d7c-a16b-488c56ec88cd -> jr2/task-1f34eef3-5749-4d7c-a16b-488c56ec88cd
|
|
316
318
|
```
|
|
317
319
|
|
|
318
320
|
`origin` fetches through the Repo cache of the node, and pushes to your fork. Open your fork on GitHub to see the
|
|
@@ -337,7 +339,7 @@ jr2 send <run id> --gate body.review --event approve
|
|
|
337
339
|
```text
|
|
338
340
|
…
|
|
339
341
|
→ context kind-jr2 / namespace my-instance
|
|
340
|
-
delivered approve to gate "body.review" on
|
|
342
|
+
delivered approve to gate "body.review" on 290b4be9-1e24-46a2-8cb5-27fabb3bbd3c
|
|
341
343
|
```
|
|
342
344
|
|
|
343
345
|
In the first terminal, `jr2 run` prints the end of the run, then the final status as one line of JSON, and stops:
|
|
@@ -346,7 +348,7 @@ In the first terminal, `jr2 run` prints the end of the run, then the final statu
|
|
|
346
348
|
…
|
|
347
349
|
→ active "teardown"
|
|
348
350
|
→ done "done"
|
|
349
|
-
{"runId":"
|
|
351
|
+
{"runId":"290b4be9-1e24-46a2-8cb5-27fabb3bbd3c","workflow":"task",…,"output":{"branch":"jr2/task-1f34eef3-5749-4d7c-a16b-488c56ec88cd"},"worktrees":[{"slot":"target","path":"/work/target/task","branch":"jr2/task-1f34eef3-5749-4d7c-a16b-488c56ec88cd"}]}
|
|
350
352
|
```
|
|
351
353
|
|
|
352
354
|
## Make sure that the Sandbox is gone
|
|
@@ -364,7 +366,7 @@ No resources found in my-instance namespace.
|
|
|
364
366
|
## What happened
|
|
365
367
|
|
|
366
368
|
- `task` is a Machine in a Workspace. The run made a Sandbox for the Workspace and cloned your fork into it. It cut the
|
|
367
|
-
branch from the release tag, in
|
|
369
|
+
branch from the release tag, in the Worktree `/work/target/task`. See [Workspaces](../concepts/workspaces.md).
|
|
368
370
|
- `task` left its Repo Slots and the model of its coder Open. `customize()` bound them where you registered the
|
|
369
371
|
Workflow, and `jr2 up` refuses a Workflow with an Open part. See [Composition](../concepts/composition.md) and
|
|
370
372
|
[ADR-0054](../reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md).
|