@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
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: WorktreePath
|
|
3
|
+
description: A Worktree of the Repo Slots `S`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# `WorktreePath`
|
|
7
|
+
|
|
8
|
+
Type, 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
|
+
type WorktreePath<S extends string> = `/work/${S}/${NameStart}${string}`;
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
A Worktree of the Repo Slots `S`. One segment below the slot, that starts with a letter, a
|
|
15
|
+
digit or `_`: `${context.workspace.repos.app}/run`. The compiler sees the start of the name; a
|
|
16
|
+
`/` further on is the Effect's own refusal.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: WorktreeReady
|
|
3
|
+
description: Type, an export of @jr2/orchestrator.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# `WorktreeReady`
|
|
7
|
+
|
|
8
|
+
Type, 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
|
+
type WorktreeReady<S extends string = string> = {
|
|
12
|
+
outcome: "ready";
|
|
13
|
+
slot: S;
|
|
14
|
+
path: WorktreePath<S>;
|
|
15
|
+
branch: string | null;
|
|
16
|
+
head: string;
|
|
17
|
+
found: WorktreeFound;
|
|
18
|
+
stale?: string;
|
|
19
|
+
};
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Fields**
|
|
23
|
+
|
|
24
|
+
- `outcome`: `"ready"`
|
|
25
|
+
- `slot`: `S`
|
|
26
|
+
- `path`: `WorktreePath<S>`
|
|
27
|
+
- `branch`: `string | null`
|
|
28
|
+
|
|
29
|
+
The branch of the cut, from git and the cut's record, never from the folder or HEAD. `null`
|
|
30
|
+
when the Worktree is detached.
|
|
31
|
+
- `head`: `string`
|
|
32
|
+
|
|
33
|
+
The tip of `branch` (of the commit, when detached). Never HEAD.
|
|
34
|
+
- `found`: [`WorktreeFound`](type-worktreefound.md)
|
|
35
|
+
- `stale` (optional): `string`
|
|
36
|
+
|
|
37
|
+
[ADR-0053](../decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md)'s words when the remote did not answer. The cut used what the clone holds.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: WorktreeRefused
|
|
3
|
+
description: "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."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# `WorktreeRefused`
|
|
7
|
+
|
|
8
|
+
Type, 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
|
+
type WorktreeRefused = { outcome: "refused"; reason: string };
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
No Worktree, and nothing changed: a bad path, a name git or the push refuses, a re-cut that does
|
|
15
|
+
not agree with the first, a branch that another Worktree holds, an `expect` that does not hold, or a
|
|
16
|
+
name that the remote cannot confirm.
|
|
17
|
+
|
|
18
|
+
**Fields**
|
|
19
|
+
|
|
20
|
+
- `outcome`: `"refused"`
|
|
21
|
+
- `reason`: `string`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: workspace
|
|
3
|
-
description: "Run a body Machine in a Sandbox: a pod of its own, with a
|
|
3
|
+
description: "Run a body Machine in a Sandbox: a pod of its own, with a clone of each Repo Slot."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# `workspace`
|
|
@@ -20,30 +20,33 @@ function workspace<
|
|
|
20
20
|
): WorkspaceMachine<WithoutEmptyIndex<z.infer<TSchema>>, OutputFrom<TBody>, TBody, TSlots>
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Run a body Machine in a Sandbox: a pod of its own, with a
|
|
24
|
-
|
|
23
|
+
Run a body Machine in a Sandbox: a pod of its own, with a clone of each Repo Slot. The result is
|
|
24
|
+
a Machine. Register it as a Workflow, or invoke it from another Machine as
|
|
25
25
|
an actor slot.
|
|
26
26
|
|
|
27
27
|
When a run enters it, the Workspace makes the Sandbox and waits for room on a node, with no
|
|
28
|
-
deadline. It clones each Repo Slot
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
deadline. It clones each Repo Slot to `/work/<slot>/default`, on the Binding's base, and makes no
|
|
29
|
+
Worktree: the body cuts each Worktree that it needs with `worktree()`. A slot that is only read
|
|
30
|
+
needs no cut. No work happens in `default/`. Then it runs the body with the run input plus
|
|
31
|
+
`workspace`, the handles (see [`Workspaced`](type-workspaced.md)). The Agents with Working tools and the `command` Effects in the body run in that Sandbox. An Agent
|
|
31
32
|
with `workspace: "none"` runs on the Instance Harness. When the body reaches a final state, the
|
|
32
|
-
Workspace deletes the Sandbox, and its output is the body's output. Push
|
|
33
|
+
Workspace deletes the Sandbox, and its output is the body's output. Push each branch before
|
|
33
34
|
then: jr2 deletes the Sandbox's commits with it.
|
|
34
35
|
|
|
36
|
+
The author chooses how many Agents work in a Workspace. Agents in one Worktree share git, as
|
|
37
|
+
people in one checkout do. Each coder that needs its own branch gets its own Worktree of the one
|
|
38
|
+
clone.
|
|
39
|
+
|
|
35
40
|
Leave out `repos` for a Workspace with no Repo Slot: its Agents and `command` Effects share
|
|
36
|
-
`/work`, as the steps of one job share a folder,
|
|
37
|
-
`
|
|
38
|
-
|
|
39
|
-
need a Repo Slot, so jr2 refuses them there. jr2 deletes `/work` with the Sandbox: send what
|
|
41
|
+
`/work`, as the steps of one job share a folder. The body's input is then `Workspaced<RunInput, never>`. An `http` Effect sends a
|
|
42
|
+
file of `/work` with `file(path)`. A `worktree()`, a `push`, and a `command` with an Effect secret in its
|
|
43
|
+
`env`, need a Repo Slot, so jr2 refuses them there. jr2 deletes `/work` with the Sandbox: send what
|
|
40
44
|
must stay before the body ends.
|
|
41
45
|
|
|
42
46
|
Give each run a different branch, so that two runs do not push to one branch. Make it from a
|
|
43
47
|
field of the run input, or from `instanceId` when the run input has no field that is different
|
|
44
|
-
for each run: ``
|
|
45
|
-
`
|
|
46
|
-
`workspace()` gets `instanceId` from jr2. A `workspace()` that a different Machine invokes gets
|
|
48
|
+
for each run: ``branch: `fix/${context.instanceId}` `` in the input of the cut. Add
|
|
49
|
+
`HostInjectedInput` to the body's input type to read it. Only a root `workspace()` gets `instanceId` from jr2. A `workspace()` that a different Machine invokes gets
|
|
47
50
|
it only when its parent gives it.
|
|
48
51
|
|
|
49
52
|
The Sandbox is Lost when its pod is evicted or its node goes. Then the body gets the event
|
|
@@ -67,7 +70,7 @@ It refuses, when you call it:
|
|
|
67
70
|
- a body with its own `input`: ``workspace(): the body "<id>" declares its own run input, which
|
|
68
71
|
nothing will ever serve or enforce — the wrapper feeds the body the run input PLUS the injected
|
|
69
72
|
`workspace` handles, so the body's schema is not the door. Move it to the wrapper:
|
|
70
|
-
workspace(body, { input
|
|
73
|
+
workspace(body, { input }) (ADR-0033).``
|
|
71
74
|
- an empty `image`: ``workspace(): `image` must be a non-empty string (got <value>) — either a
|
|
72
75
|
`file:` URL to a docker context this module ships (`import.meta.resolve("./image")`) or a
|
|
73
76
|
registry ref (ADR-0037).``
|
|
@@ -77,9 +80,7 @@ It refuses, when you call it:
|
|
|
77
80
|
`repos: { app: "https://…" }` — or `open` whole, for a map the consumer names; leave it out
|
|
78
81
|
for a Workspace with no Repo Slot (ADR-0051).``
|
|
79
82
|
- a bad Repo Slot name or value (see [`RepoSlot`](type-reposlot.md))
|
|
80
|
-
- a `
|
|
81
|
-
`spec` must be a function from the run input to the spec — spec: ({ input }) => ({ branch }) —
|
|
82
|
-
and only a Workspace with no Repo Slot may leave it out (ADR-0051).``
|
|
83
|
+
- a `workGroup` that is not a gid: ``workspace(): `workGroup` must be a gid (got <value>)``
|
|
83
84
|
- a bad `secrets` list: ``workspace(): `secrets` must be a list of distinct names from
|
|
84
85
|
jr2.config.ts's `secrets` list (got <value>) — secrets: ["JIRA_TOKEN"] (ADR-0059).``
|
|
85
86
|
- a bad `effector`: ``workspace(): `effector` is { image } — a `file:` URL to a docker context
|
|
@@ -95,19 +96,16 @@ It refuses, when you call it:
|
|
|
95
96
|
(ADR-0060)``, or the same text for `resources.limits.<key>`. The other texts are in
|
|
96
97
|
[`Size`](type-size.md).
|
|
97
98
|
|
|
98
|
-
And when a run enters it, a
|
|
99
|
-
|
|
100
|
-
does `jr2 run --input` carry every field this workflow's workspace()
|
|
101
|
-
Repo Slot, a spec with a `branch` or a `reviewSha`: ``workspace spec invalid: <field> (the
|
|
102
|
-
Workspace has no Repo Slot, so it has no branch and no review Worktree; its spec gives only
|
|
103
|
-
workGroup) …``
|
|
99
|
+
And when a run enters it, a per-run Repo Slot's mapper that gives no `url`, or a bad `ref`:
|
|
100
|
+
``workspace invalid: repos.<slot> mapper returned <fields> — the mapper derives from run
|
|
101
|
+
input; does `jr2 run --input` carry every field this workflow's workspace() slot reads?``
|
|
104
102
|
|
|
105
103
|
**Parameters**
|
|
106
104
|
|
|
107
105
|
- `body`: The Machine to run in the Sandbox. Its input is `Workspaced<RunInput, Slots>`.
|
|
108
106
|
- `options` ([`WorkspaceOptions`](type-workspaceoptions.md) | [`NoSlotWorkspaceOptions`](type-noslotworkspaceoptions.md)): What the Sandbox is made of (`image`, `user`, `resources`, `effector`), the
|
|
109
|
-
Repo Slots it clones (`repos`), the Held secrets it can use (`secrets`), the
|
|
110
|
-
(`
|
|
107
|
+
Repo Slots it clones (`repos`), the Held secrets it can use (`secrets`), the pod's `fsGroup`
|
|
108
|
+
(`workGroup`), and the run input (`input`).
|
|
111
109
|
|
|
112
110
|
**Returns**: A Machine whose input is the run input and whose output is the body's output.
|
|
113
111
|
|
|
@@ -118,8 +116,10 @@ import { z } from "zod";
|
|
|
118
116
|
import {
|
|
119
117
|
command,
|
|
120
118
|
fail,
|
|
119
|
+
isReady,
|
|
121
120
|
jr2Setup,
|
|
122
121
|
workspace,
|
|
122
|
+
worktree,
|
|
123
123
|
type CommandOutput,
|
|
124
124
|
type Workspaced,
|
|
125
125
|
} from "@jr2/orchestrator";
|
|
@@ -127,23 +127,36 @@ import {
|
|
|
127
127
|
const runInput = z.object({ ticket: z.string(), repo: z.string() });
|
|
128
128
|
type BodyInput = Workspaced<z.infer<typeof runInput>, "app" | "docs">;
|
|
129
129
|
|
|
130
|
+
// The Worktree of this run. An Agent or a command that only reads `docs` uses `/work/docs/default`.
|
|
131
|
+
const buildTree = (context: BodyInput) => `${context.workspace.repos.app}/build` as const;
|
|
132
|
+
|
|
130
133
|
const passed = (output: CommandOutput): boolean =>
|
|
131
134
|
output.outcome === "exited" && output.code === 0;
|
|
132
135
|
|
|
133
136
|
const body = jr2Setup({
|
|
134
|
-
types: {} as { input: BodyInput },
|
|
137
|
+
types: {} as { input: BodyInput; context: BodyInput },
|
|
135
138
|
actors: {
|
|
136
|
-
|
|
139
|
+
cut: worktree(),
|
|
140
|
+
build: command(["npm", "run", "build"]),
|
|
137
141
|
fail: fail(),
|
|
138
142
|
},
|
|
139
143
|
}).createMachine({
|
|
140
144
|
id: "build",
|
|
145
|
+
context: ({ input }) => input,
|
|
141
146
|
on: { "workspace.lost": ".lost" },
|
|
142
|
-
initial: "
|
|
147
|
+
initial: "cutting",
|
|
143
148
|
states: {
|
|
149
|
+
cutting: {
|
|
150
|
+
invoke: {
|
|
151
|
+
src: "cut",
|
|
152
|
+
input: ({ context }) => ({ path: buildTree(context), branch: `fix/${context.ticket}` }),
|
|
153
|
+
onDone: [{ guard: ({ event }) => isReady(event.output), target: "building" }, { target: "notCut" }],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
144
156
|
building: {
|
|
145
157
|
invoke: {
|
|
146
158
|
src: "build",
|
|
159
|
+
input: ({ context }) => ({ worktree: buildTree(context) }),
|
|
147
160
|
onDone: [
|
|
148
161
|
{ guard: ({ event }) => passed(event.output), target: "built" },
|
|
149
162
|
{ target: "broken" },
|
|
@@ -152,6 +165,7 @@ const body = jr2Setup({
|
|
|
152
165
|
},
|
|
153
166
|
built: { type: "final" },
|
|
154
167
|
broken: { invoke: { src: "fail", input: { reason: "npm run build did not pass" } } },
|
|
168
|
+
notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
|
|
155
169
|
lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
|
|
156
170
|
},
|
|
157
171
|
});
|
|
@@ -164,7 +178,6 @@ export const machine = workspace(body, {
|
|
|
164
178
|
app: ({ input }) => input.repo,
|
|
165
179
|
docs: { url: "https://github.com/you/docs.git", ref: "main" },
|
|
166
180
|
},
|
|
167
|
-
spec: ({ input }) => ({ branch: `fix/${input.ticket}` }),
|
|
168
181
|
});
|
|
169
182
|
```
|
|
170
183
|
|
|
@@ -175,9 +188,12 @@ import { z } from "zod";
|
|
|
175
188
|
import {
|
|
176
189
|
command,
|
|
177
190
|
fail,
|
|
191
|
+
isReady,
|
|
178
192
|
jr2Setup,
|
|
179
193
|
workspace,
|
|
194
|
+
worktree,
|
|
180
195
|
type CommandOutput,
|
|
196
|
+
type HostInjectedInput,
|
|
181
197
|
type Workspaced,
|
|
182
198
|
} from "@jr2/orchestrator";
|
|
183
199
|
|
|
@@ -187,18 +203,30 @@ const passed = (output: CommandOutput): boolean =>
|
|
|
187
203
|
// The run input has no field that is different for each run, so the branch comes from
|
|
188
204
|
// `instanceId`.
|
|
189
205
|
const runInput = z.object({});
|
|
206
|
+
type BodyInput = Workspaced<z.infer<typeof runInput> & HostInjectedInput, "app">;
|
|
207
|
+
|
|
208
|
+
const nightlyTree = (context: BodyInput) => `${context.workspace.repos.app}/nightly` as const;
|
|
190
209
|
|
|
191
210
|
const body = jr2Setup({
|
|
192
|
-
types: {} as { input:
|
|
193
|
-
actors: { test: command(["npm", "test"]
|
|
211
|
+
types: {} as { input: BodyInput; context: BodyInput },
|
|
212
|
+
actors: { cut: worktree(), test: command(["npm", "test"]), fail: fail() },
|
|
194
213
|
}).createMachine({
|
|
195
214
|
id: "nightly",
|
|
215
|
+
context: ({ input }) => input,
|
|
196
216
|
on: { "workspace.lost": ".lost" },
|
|
197
|
-
initial: "
|
|
217
|
+
initial: "cutting",
|
|
198
218
|
states: {
|
|
219
|
+
cutting: {
|
|
220
|
+
invoke: {
|
|
221
|
+
src: "cut",
|
|
222
|
+
input: ({ context }) => ({ path: nightlyTree(context), branch: `nightly/${context.instanceId}` }),
|
|
223
|
+
onDone: [{ guard: ({ event }) => isReady(event.output), target: "testing" }, { target: "notCut" }],
|
|
224
|
+
},
|
|
225
|
+
},
|
|
199
226
|
testing: {
|
|
200
227
|
invoke: {
|
|
201
228
|
src: "test",
|
|
229
|
+
input: ({ context }) => ({ worktree: nightlyTree(context) }),
|
|
202
230
|
onDone: [
|
|
203
231
|
{ guard: ({ event }) => passed(event.output), target: "tested" },
|
|
204
232
|
{ target: "red" },
|
|
@@ -207,6 +235,7 @@ const body = jr2Setup({
|
|
|
207
235
|
},
|
|
208
236
|
tested: { type: "final" },
|
|
209
237
|
red: { invoke: { src: "fail", input: { reason: "npm test did not pass" } } },
|
|
238
|
+
notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
|
|
210
239
|
lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
|
|
211
240
|
},
|
|
212
241
|
});
|
|
@@ -215,7 +244,6 @@ export const machine = workspace(body, {
|
|
|
215
244
|
input: runInput,
|
|
216
245
|
image: "docker.io/library/node:24",
|
|
217
246
|
repos: { app: "https://github.com/you/app.git" },
|
|
218
|
-
spec: ({ input }) => ({ branch: `fix/${input.instanceId}` }),
|
|
219
247
|
});
|
|
220
248
|
```
|
|
221
249
|
|
|
@@ -234,10 +262,10 @@ export const machine = workspace(body, {
|
|
|
234
262
|
function workspace<
|
|
235
263
|
TBody extends AnyStateMachine,
|
|
236
264
|
TSlots extends string = never,
|
|
237
|
-
TInput =
|
|
265
|
+
TInput = DoorlessInput<TBody>,
|
|
238
266
|
>(
|
|
239
267
|
body: TBody & BodyAcceptsSlots<TBody, TSlots>,
|
|
240
|
-
options: PermissiveWorkspaceOptions<TSlots, TInput
|
|
268
|
+
options: PermissiveWorkspaceOptions<TSlots, Exclude<TInput, undefined>> | PermissiveNoSlotWorkspaceOptions,
|
|
241
269
|
): WorkspaceMachine<TInput, OutputFrom<TBody>, TBody, TSlots>
|
|
242
270
|
```
|
|
243
271
|
|
|
@@ -249,7 +277,7 @@ what it refuses.
|
|
|
249
277
|
|
|
250
278
|
- `body`: The Machine to run in the Sandbox. Its input is the input of the Workspace plus
|
|
251
279
|
`workspace`, the handles.
|
|
252
|
-
- `options` ([`PermissiveWorkspaceOptions`](type-permissiveworkspaceoptions.md) | [`PermissiveNoSlotWorkspaceOptions`](type-permissivenoslotworkspaceoptions.md)): The options of the Sandbox
|
|
280
|
+
- `options` ([`PermissiveWorkspaceOptions`](type-permissiveworkspaceoptions.md) | [`PermissiveNoSlotWorkspaceOptions`](type-permissivenoslotworkspaceoptions.md)): The options of the Sandbox. There is no `input`.
|
|
253
281
|
|
|
254
282
|
**Returns**: A Machine whose input is the run input and whose output is the body's output.
|
|
255
283
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: worktree
|
|
3
|
+
description: "Make a `worktree` Effect: it cuts a Worktree of a Repo Slot, or reads the one that is there."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# `worktree`
|
|
7
|
+
|
|
8
|
+
Function, 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
|
+
function worktree(options: WorktreeOptions = {}): EffectLogic<WorktreeInput, WorktreeOutput>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Make a `worktree` Effect: it cuts a Worktree of a Repo Slot, or reads the one that is there. Put it
|
|
15
|
+
in `actors`, and invoke it from a `workspace()` body.
|
|
16
|
+
|
|
17
|
+
With `{ path, branch, from? }`, the branch resolves in this order, after a fetch: a local branch;
|
|
18
|
+
`origin/<branch>`, tracked; a new branch from `from` or the Binding's base, with no upstream. With
|
|
19
|
+
`{ path, detach }`, the Worktree is forced to that commit and cleaned, each time. `path` is exactly
|
|
20
|
+
`/work/<slot>/<name>`. Each outcome is output: `ready`, `refused`, `unknown`.
|
|
21
|
+
|
|
22
|
+
`expect` says if the branch can exist: `worktree({ expect: "new" })` refuses a branch that exists,
|
|
23
|
+
and `worktree({ expect: "existing" })` refuses a branch that does not exist. A run cannot change it.
|
|
24
|
+
|
|
25
|
+
A cut needs a Repo Slot. Under a Workspace with no Repo Slot, `jr2 up` refuses it, and the invoke
|
|
26
|
+
fails with `worktree "<slot>" runs under a Workspace with no Repo Slot: a cut makes a Worktree of a
|
|
27
|
+
Repo Slot, and there is none — declare one: repos: { app: "<url>" } (ADR-0075)`.
|
|
28
|
+
|
|
29
|
+
**Parameters**
|
|
30
|
+
|
|
31
|
+
- `options` ([`WorktreeOptions`](type-worktreeoptions.md)): Optional. `expect`, and `timeout`, how long the fetch and the cut can take.
|
|
32
|
+
Default: `"10m"`.
|
|
33
|
+
|
|
34
|
+
**Returns**: The actor logic of the Effect's slot. Its output is a [`WorktreeOutput`](type-worktreeoutput.md).
|
|
35
|
+
|
|
36
|
+
**Example**
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { fail, isReady, jr2Setup, worktree, type Workspaced } from "@jr2/orchestrator";
|
|
40
|
+
|
|
41
|
+
type BodyInput = Workspaced<{ branch: string }, "app">;
|
|
42
|
+
const tree = (context: BodyInput) => `${context.workspace.repos.app}/fix` as const;
|
|
43
|
+
|
|
44
|
+
export const body = jr2Setup({
|
|
45
|
+
types: {} as { input: BodyInput; context: BodyInput },
|
|
46
|
+
actors: { cut: worktree({ expect: "new" }), fail: fail() },
|
|
47
|
+
}).createMachine({
|
|
48
|
+
context: ({ input }) => input,
|
|
49
|
+
on: { "workspace.lost": ".notCut" },
|
|
50
|
+
initial: "cutting",
|
|
51
|
+
states: {
|
|
52
|
+
cutting: {
|
|
53
|
+
invoke: {
|
|
54
|
+
src: "cut",
|
|
55
|
+
input: ({ context }) => ({ path: tree(context), branch: context.branch }),
|
|
56
|
+
// The last arm has no guard: it takes `refused`, `unknown` and each later outcome.
|
|
57
|
+
onDone: [{ guard: ({ event }) => isReady(event.output), target: "done" }, { target: "notCut" }],
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
done: { type: "final" },
|
|
61
|
+
notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**See also**
|
|
67
|
+
|
|
68
|
+
- [Cut a Worktree](../../guides/cut-a-worktree.md)
|
|
69
|
+
- [Workspaces](../../concepts/workspaces.md)
|
|
70
|
+
- [Effects](../../concepts/effects.md)
|
|
71
|
+
- [ADR-0075: A Machine cuts a Worktree, and the Workspace only clones](../decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md)
|
|
@@ -35,8 +35,8 @@ An Agent slot and the definition it carries ([ADR-0028](decisions/0028-what-an-a
|
|
|
35
35
|
|
|
36
36
|
A Sandbox and the Repo Slots it binds ([ADR-0012](decisions/0012-workspace-wrapper-machine.md), [ADR-0051](decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md)).
|
|
37
37
|
|
|
38
|
-
- [`workspace`](authoring-surface/workspace.md) (function): Run a body Machine in a Sandbox: a pod of its own, with a
|
|
39
|
-
- [`Workspaced`](authoring-surface/type-workspaced.md) (type): The input of a `workspace()` body: the run input, plus `workspace`, the handles that the Workspace adds (`workspace.repos`,
|
|
38
|
+
- [`workspace`](authoring-surface/workspace.md) (function): Run a body Machine in a Sandbox: a pod of its own, with a clone of each Repo Slot.
|
|
39
|
+
- [`Workspaced`](authoring-surface/type-workspaced.md) (type): 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).
|
|
40
40
|
- [`Binding`](authoring-surface/type-binding.md) (type): The repository of a Repo Slot: `{ url, ref }`.
|
|
41
41
|
- [`RepoSlot`](authoring-surface/type-reposlot.md) (type): The value of one Repo Slot in `workspace({ repos })`.
|
|
42
42
|
|
|
@@ -46,6 +46,7 @@ Work a Machine does outside itself, as an actor slot ([ADR-0067](decisions/0067-
|
|
|
46
46
|
|
|
47
47
|
- [`arg`](authoring-surface/arg.md) (constant): Mark one argv entry of a `command` that the input of the Effect fills.
|
|
48
48
|
- [`CommandOutput`](authoring-surface/type-commandoutput.md) (type): The output of a `command` Effect: what the `onDone` of its state gets as `event.output`.
|
|
49
|
+
- [`LaterOutcome`](authoring-surface/type-lateroutcome.md) (type): A value of `outcome` that this kit does not give.
|
|
49
50
|
- [`command`](authoring-surface/command.md) (function): Make a `command` Effect: an actor slot that runs one program in the Workspace's Sandbox when a state invokes it.
|
|
50
51
|
- [`basic`](authoring-surface/basic.md) (function): Make the `auth` of an `http` Effect that sends `Authorization: Basic <value>`, where the value is the base64 of `user:password`.
|
|
51
52
|
- [`bearer`](authoring-surface/bearer.md) (function): Make the `auth` of an `http` Effect that sends `Authorization: Bearer <value>`, with the value of an Effect secret.
|
|
@@ -54,8 +55,22 @@ Work a Machine does outside itself, as an actor slot ([ADR-0067](decisions/0067-
|
|
|
54
55
|
- [`secret`](authoring-surface/secret.md) (function): Name an Effect secret: `secret("jira")`.
|
|
55
56
|
- [`text`](authoring-surface/text.md) (function): Make a string from literal text and Effect secrets, as a tagged template: `` text`Token ${secret("x")}` ``.
|
|
56
57
|
- [`HttpOutput`](authoring-surface/type-httpoutput.md) (type): The output of an `http` Effect: what the `onDone` of its state gets as `event.output`.
|
|
57
|
-
- [`push`](authoring-surface/push.md) (function): Make a `push` Effect: it pushes the branch of
|
|
58
|
+
- [`push`](authoring-surface/push.md) (function): Make a `push` Effect: it pushes the branch of a Worktree to the Binding of its Repo Slot.
|
|
58
59
|
- [`PushOutput`](authoring-surface/type-pushoutput.md) (type): The output of a `push` Effect: what the `onDone` of its state gets as `event.output`.
|
|
60
|
+
- [`branchName`](authoring-surface/branchname.md) (constant): A kit schema for a pick param that names a branch.
|
|
61
|
+
- [`isReady`](authoring-surface/isready.md) (constant): Is it `ready`?
|
|
62
|
+
- [`readyOf`](authoring-surface/readyof.md) (function): The `ready` output of an `onDone` arm that `isReady` guards.
|
|
63
|
+
- [`worktree`](authoring-surface/worktree.md) (function): Make a `worktree` Effect: it cuts a Worktree of a Repo Slot, or reads the one that is there.
|
|
64
|
+
- [`AnyFramePath`](authoring-surface/type-anyframepath.md) (type): A Turn's Frame: a Worktree, or `/work`, stated.
|
|
65
|
+
- [`AnyWorktreePath`](authoring-surface/type-anyworktreepath.md) (type): A Worktree of any Repo Slot: what a kit factory states, before `jr2Setup` narrows it to the slots of the body.
|
|
66
|
+
- [`FramePath`](authoring-surface/type-framepath.md) (type): A Turn's Frame in a Workspace with the Repo Slots `S`.
|
|
67
|
+
- [`WorktreeFound`](authoring-surface/type-worktreefound.md) (type): 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.
|
|
68
|
+
- [`WorktreeInput`](authoring-surface/type-worktreeinput.md) (type): The input of a `worktree()`: a branch Worktree, or a detached one.
|
|
69
|
+
- [`WorktreeOptions`](authoring-surface/type-worktreeoptions.md) (type): The options of `worktree()`.
|
|
70
|
+
- [`WorktreeOutput`](authoring-surface/type-worktreeoutput.md) (type): The output of a `worktree()`.
|
|
71
|
+
- [`WorktreePath`](authoring-surface/type-worktreepath.md) (type): A Worktree of the Repo Slots `S`.
|
|
72
|
+
- [`WorktreeReady`](authoring-surface/type-worktreeready.md) (type)
|
|
73
|
+
- [`WorktreeRefused`](authoring-surface/type-worktreerefused.md) (type): 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.
|
|
59
74
|
- [`dispatch`](authoring-surface/dispatch.md) (function): Make a `dispatch` Effect: it starts a run of a Workflow.
|
|
60
75
|
- [`DispatchOutput`](authoring-surface/type-dispatchoutput.md) (type): The output of a `dispatch` Effect.
|
|
61
76
|
- [`answer`](authoring-surface/answer.md) (function): Set what the Agent reads when jr2 answers its pick.
|
|
@@ -74,6 +89,7 @@ A part left Open, a Machine's parts retuned, a Pool over a Source ([ADR-0017](de
|
|
|
74
89
|
- [`UserContainer`](authoring-surface/type-usercontainer.md) (type): The User Container in its object form: its image, and its part of the Workspace's Size.
|
|
75
90
|
- [`pool`](authoring-surface/pool.md) (function): Make a Pool: a Machine that runs one worker Machine for each item that a Source gives, with at most `cap` workers at once.
|
|
76
91
|
- [`source`](authoring-surface/source.md) (function): Declare a Source: where a `pool()` gets its work items, one at a time.
|
|
92
|
+
- [`PoolNextInput`](authoring-surface/type-poolnextinput.md) (type): 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.
|
|
77
93
|
|
|
78
94
|
## Charts
|
|
79
95
|
|
|
@@ -109,7 +125,7 @@ The signature of an export, or a type here, names each of these types. They are
|
|
|
109
125
|
- [`WithoutEmptyIndex`](authoring-surface/type-withoutemptyindex.md): The fields of the run input `T`.
|
|
110
126
|
- [`PermissiveWorkspaceOptions`](authoring-surface/type-permissiveworkspaceoptions.md): The options of a `workspace()` with no `input`: it starts with any input.
|
|
111
127
|
- [`PermissiveNoSlotWorkspaceOptions`](authoring-surface/type-permissivenoslotworkspaceoptions.md): The options of a `workspace()` with no Repo Slot and no `input`: it starts with any input.
|
|
112
|
-
- [`WorkspaceHandles`](authoring-surface/type-workspacehandles.md): What the body of a `workspace()` gets as `input.workspace`: the
|
|
128
|
+
- [`WorkspaceHandles`](authoring-surface/type-workspacehandles.md): What the body of a `workspace()` gets as `input.workspace`: the folder of each Repo Slot.
|
|
113
129
|
- [`ExecOutcome`](authoring-surface/type-execoutcome.md): How an exec ended.
|
|
114
130
|
- [`Unknown`](authoring-surface/type-unknown.md): The output `{ outcome: "unknown", reason }`: the Effect may have acted, and jr2 cannot tell.
|
|
115
131
|
- [`Arg`](authoring-surface/type-arg.md): One entry of a command's argv that the input of the Effect fills, as `arg("name")` makes it.
|
|
@@ -119,11 +135,14 @@ The signature of an export, or a type here, names each of these types. They are
|
|
|
119
135
|
- [`Secret`](authoring-surface/type-secret.md): What `secret("name")` gives: an Effect secret, by its name in the `secrets` list of `jr2.config.ts`.
|
|
120
136
|
- [`Text`](authoring-surface/type-text.md): What the `text` template gives: a string of literal text and Effect secrets, in order.
|
|
121
137
|
- [`FromInput`](authoring-surface/type-frominput.md): A value of a file body's part: as written, or from the Effect's input.
|
|
122
|
-
- [`FileBody`](authoring-surface/type-filebody.md): `file(path, {
|
|
138
|
+
- [`FileBody`](authoring-surface/type-filebody.md): `file(path, { segments?, contentType? })`: a Worktree file as an `http` body.
|
|
123
139
|
- [`HttpDefinition`](authoring-surface/type-httpdefinition.md): An `http` Effect's definition.
|
|
140
|
+
- [`HttpFileInput`](authoring-surface/type-httpfileinput.md): The input of an `http` Effect with a Worktree file as its body.
|
|
124
141
|
- [`OpenSecret`](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).
|
|
125
142
|
- [`PushOptions`](authoring-surface/type-pushoptions.md): The options of `push()`.
|
|
126
|
-
- [`PushInput`](authoring-surface/type-pushinput.md): The input of a `push` Effect: `{ sha }` with `pin`, and `{ message }` with `squash`.
|
|
143
|
+
- [`PushInput`](authoring-surface/type-pushinput.md): The input of a `push` Effect: the Worktree that a cut made, `{ sha }` with `pin`, and `{ message }` with `squash`.
|
|
144
|
+
- [`Duration`](authoring-surface/type-duration.md): A length of time: a positive number and a unit, `s`, `m` or `h`.
|
|
145
|
+
- [`NameStart`](authoring-surface/type-namestart.md): What a Worktree's name may start with: neither `.` nor `-`, and not the end of the path.
|
|
127
146
|
- [`DispatchDefinition`](authoring-surface/type-dispatchdefinition.md): The definition of a `dispatch` Effect (ADR-0071).
|
|
128
147
|
- [`DispatchInput`](authoring-surface/type-dispatchinput.md): A dispatch's input: the run's body — the slot's schema's type, or any JSON object.
|
|
129
148
|
- [`DispatchOpenParts`](authoring-surface/type-dispatchopenparts.md): The Open part a dispatch definition states: its target, when it is `open`.
|
|
@@ -138,10 +157,7 @@ The signature of an export, or a type here, names each of these types. They are
|
|
|
138
157
|
- [`Sender`](authoring-surface/type-sender.md): Who delivered an event: an Agent by its slot, or a Gate by its invoke id (ADR-0015).
|
|
139
158
|
- [`FailureInput`](authoring-surface/type-failureinput.md): What a Failure carries: `reason`, text for a person, and `detail`, optional JSON for a machine reader.
|
|
140
159
|
- [`SandboxOptions`](authoring-surface/type-sandboxoptions.md): The options of a `workspace()` that say what its Sandbox is made of and which Repos it clones.
|
|
141
|
-
- [`WorkspaceSpec`](authoring-surface/type-workspacespec.md): What the `spec` of a `workspace()` returns: the branch that the Workspace works on, and two optional fields.
|
|
142
|
-
- [`NoSlotSpec`](authoring-surface/type-noslotspec.md): What the `spec` of a `workspace()` with no Repo Slot returns: only `workGroup`.
|
|
143
160
|
- [`SlotHandles`](authoring-surface/type-slothandles.md): The handles of a Workspace that declares Repo Slots.
|
|
144
|
-
- [`Duration`](authoring-surface/type-duration.md): A length of time: a positive number and a unit, `s`, `m` or `h`.
|
|
145
161
|
- [`CommandEnv`](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.
|
|
146
162
|
- [`TextPart`](authoring-surface/type-textpart.md): One part of a `Text`: `{ text }`, literal text, or `{ secret }`, the name of an Effect secret.
|
|
147
163
|
- [`HttpMethod`](authoring-surface/type-httpmethod.md): The method of an `http` Effect: `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE` or `OPTIONS`.
|
|
@@ -165,18 +181,20 @@ The signature of an export, or a type here, names each of these types. They are
|
|
|
165
181
|
- [`ToProvidedActor`](authoring-surface/type-toprovidedactor.md)
|
|
166
182
|
- [`MergedActors`](authoring-surface/type-mergedactors.md)
|
|
167
183
|
- [`ToParameterizedObject`](authoring-surface/type-toparameterizedobject.md)
|
|
184
|
+
- [`BindActors`](authoring-surface/type-bindactors.md)
|
|
168
185
|
- [`SentByGuards`](authoring-surface/type-sentbyguards.md)
|
|
169
186
|
- [`AgentLogic`](authoring-surface/type-agentlogic.md)
|
|
170
187
|
- [`BodyAcceptsDoor`](authoring-surface/type-bodyacceptsdoor.md)
|
|
171
188
|
- [`WorkspaceMachine`](authoring-surface/type-workspacemachine.md)
|
|
189
|
+
- [`DoorlessInput`](authoring-surface/type-doorlessinput.md)
|
|
172
190
|
- [`BodyAcceptsSlots`](authoring-surface/type-bodyacceptsslots.md)
|
|
173
191
|
- [`EffectLogic`](authoring-surface/type-effectlogic.md)
|
|
174
192
|
- [`OpenOf`](authoring-surface/type-openof.md)
|
|
175
193
|
- [`EnvOpenParts`](authoring-surface/type-envopenparts.md)
|
|
176
194
|
- [`OpenEffect`](authoring-surface/type-openeffect.md)
|
|
177
195
|
- [`MarkedIf`](authoring-surface/type-markedif.md)
|
|
178
|
-
- [`HttpInput`](authoring-surface/type-httpinput.md)
|
|
179
196
|
- [`HttpOpenParts`](authoring-surface/type-httpopenparts.md)
|
|
197
|
+
- [`HttpInput`](authoring-surface/type-httpinput.md)
|
|
180
198
|
- [`PushWireOutput`](authoring-surface/type-pushwireoutput.md)
|
|
181
199
|
- [`SyncState`](authoring-surface/type-syncstate.md)
|
|
182
200
|
- [`AnswerAction`](authoring-surface/type-answeraction.md)
|
|
@@ -192,6 +210,8 @@ The signature of an export, or a type here, names each of these types. They are
|
|
|
192
210
|
- [`PoolMachine`](authoring-surface/type-poolmachine.md)
|
|
193
211
|
- [`EventFrom`](authoring-surface/type-eventfrom.md)
|
|
194
212
|
- [`ArgNames`](authoring-surface/type-argnames.md)
|
|
213
|
+
- [`WorktreeKey`](authoring-surface/type-worktreekey.md)
|
|
214
|
+
- [`NotWorktreeKeys`](authoring-surface/type-notworktreekeys.md)
|
|
195
215
|
- [`OpenSecretMark`](authoring-surface/type-opensecretmark.md)
|
|
196
216
|
|
|
197
217
|
These names come from a dependency: from `zod`, `z.ZodObject`, `z.infer`, `z.ZodType`; from `xstate`, `MachineContext`, `UnknownActorLogic`, `ParameterizedObject`, `NonReducibleUnknown`, `EventObject`, `MetaObject`, `ActionFunction`, `GuardPredicate`, `DelayConfig`, `SetupReturn`, `AnyStateMachine`, `OutputFrom`, `ProvidedActor`, `AnyActorRef`, `InputFrom`, `PromiseActorLogic`.
|
package/docs/reference/cli.md
CHANGED
|
@@ -196,7 +196,7 @@ jr2 kit push <registry>
|
|
|
196
196
|
|
|
197
197
|
Mirror the published kit images into a registry.
|
|
198
198
|
|
|
199
|
-
The v0.
|
|
199
|
+
The v0.6.0 kit images (harness, operator, orchestrator) from their canonical home, and the Custodian's pinned Envoy from its own, for a cluster whose `kitRegistry` names the registry.
|
|
200
200
|
|
|
201
201
|
**Arguments**
|
|
202
202
|
|
package/docs/reference/config.md
CHANGED
|
@@ -76,8 +76,9 @@ config loads: `<file> at secrets[<i>]<path>: <problem>`, followed by the shape o
|
|
|
76
76
|
- Type: `string`
|
|
77
77
|
- Required: yes
|
|
78
78
|
|
|
79
|
-
As a Held secret, the name of
|
|
80
|
-
|
|
79
|
+
As a Held secret, the name of its Stand-in: the file the Harness reads it from, the env var
|
|
80
|
+
that the engine reads a model key from, and the env var of the Agent's programs when the
|
|
81
|
+
`workspace()` lists it under `secrets`. As an Effect secret, the name that `secret("<name>")` names, and the name of the
|
|
81
82
|
Effector's file. For a Held secret, it must match `[A-Z_][A-Z0-9_]*`:
|
|
82
83
|
`secrets[<i>].name "<name>" is not an env var name ([A-Z_][A-Z0-9_]*)`. It must not start with
|
|
83
84
|
`JR2_` and must not be a proxy or trust variable of the kit:
|
|
@@ -377,7 +378,7 @@ checks from inside the cluster that the endpoint answers.
|
|
|
377
378
|
|
|
378
379
|
The API key, when the endpoint needs one. Read it from `process.env`. It is a Held secret,
|
|
379
380
|
`JR2_PROVIDER_API_KEY`: `jr2 up` gives the value to the Custodian only, bound to the host of
|
|
380
|
-
`baseUrl`, and the Harness
|
|
381
|
+
`baseUrl`, and the Harness process holds only its secret Stand-in. Thus `baseUrl` must be
|
|
381
382
|
`https://` when you set it:
|
|
382
383
|
`harness.provider.apiKey is set, and harness.provider.baseUrl is not https://`.
|
|
383
384
|
|
|
@@ -467,6 +468,11 @@ deployments, so read it from `process.env` (`.env`).
|
|
|
467
468
|
|
|
468
469
|
Env vars for the Harness container. The Agent can read every one of them, so do not put a
|
|
469
470
|
credential here. A known model key is refused here. Put it in the top-level `secrets` list.
|
|
471
|
+
The Harness process gets each one, except a name that loads code from a path, such as
|
|
472
|
+
`NODE_OPTIONS` or `LD_PRELOAD`, and `HOME`, which is its own; the Agent's programs get each
|
|
473
|
+
one. A name that starts with `JR2_` is jr2's own, and is refused. A credential file that the
|
|
474
|
+
Harness process reads, such as `AWS_CONFIG_FILE`, is refused in a folder that the Agent's code
|
|
475
|
+
writes (`/work`, `/tmp`, `/home/jr2`), and gives a warning anywhere else.
|
|
470
476
|
See `HarnessEnvVar`.
|
|
471
477
|
|
|
472
478
|
<a id="harness-env-name"></a>
|
|
@@ -508,7 +514,10 @@ pod as it is. A reference to a Secret of the kit is refused:
|
|
|
508
514
|
- Required: no
|
|
509
515
|
|
|
510
516
|
Secrets and ConfigMaps that you manage, whose keys all become env vars of the Harness
|
|
511
|
-
|
|
517
|
+
process and of the Agent's programs, as `env` does. In the container's spec each key has the
|
|
518
|
+
prefix `JR2_ENVFROM_`, so that the Harness can tell jr2's names from the image's; the Harness
|
|
519
|
+
removes it. A key that starts with `JR2_` is refused: `jr2 up` refuses it, and the Harness does
|
|
520
|
+
not start with one. See `HarnessEnvFromSource`.
|
|
512
521
|
|
|
513
522
|
<a id="harness-envfrom-prefix"></a>
|
|
514
523
|
|
|
@@ -34,7 +34,7 @@ Sandbox will run must be in the spec at spin-up.
|
|
|
34
34
|
|
|
35
35
|
One Harness **image** serves many **Agents** — the Harness resolves model, instructions, and its Menu at runtime without
|
|
36
36
|
a rebuild, reading the definition each admission carries (ADR-0018, ADR-0049) and reading the Menu through the Custodian
|
|
37
|
-
per turn (ADR-0013). So the Orchestrator injects a fixed Harness image plus **config** (env + the prepared
|
|
37
|
+
per turn (ADR-0013). So the Orchestrator injects a fixed Harness image plus **config** (env + the prepared clones),
|
|
38
38
|
never a per-Agent image build. The HTTP prompt body itself carries only `{message, images}`, so anything persona-shaping
|
|
39
39
|
is set at provision time, not per request.
|
|
40
40
|
|
|
@@ -91,14 +91,15 @@ one keeps the name and the endpoint and costs no node anything. Deferred until a
|
|
|
91
91
|
These are accepted gaps in the current operator, recorded so they aren't silently forgotten. Each is a deliberate
|
|
92
92
|
deferral.
|
|
93
93
|
|
|
94
|
-
- **Egress is
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
credential
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
- **Egress is open.** The pod is hardened at the host boundary — `automountServiceAccountToken: false`, pod/container
|
|
95
|
+
`securityContext` (`runAsNonRoot`, `allowPrivilegeEscalation: false`, drop `ALL`, seccomp `RuntimeDefault`) — and its
|
|
96
|
+
_ingress_ is the Orchestrator's alone: `jr2 up` converges a NetworkPolicy that admits no other pod to a Sandbox
|
|
97
|
+
([ADR-0058](0058-a-harness-answers-the-orchestrator-alone.md)), which kind's `kindnet` enforces. _Egress_ is open
|
|
98
|
+
except for the cloud metadata addresses, which no Harness pod reaches
|
|
99
|
+
([ADR-0076](0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md)): an untrusted Agent can
|
|
100
|
+
still reach the cluster's API server IP (it holds no credential there) and the internet. A default-deny egress policy
|
|
101
|
+
with an allowlist is the next layer, and ADR-0058 records it open. The ADR-0013 boundary does not depend on either:
|
|
102
|
+
only the token bounds what a pod may _do_; NetworkPolicy bounds where it may _talk_.
|
|
102
103
|
- **Sidecars are plain containers, not native sidecars.** They are scheduled as ordinary `containers`, not Kubernetes
|
|
103
104
|
≥1.29 native sidecars (`initContainers` with `restartPolicy: Always`). There is no start-ordering or
|
|
104
105
|
termination-ordering guarantee between the Harness and its sidecars — the Harness may begin serving before the
|