@orchestraworks/cli 0.5.0 → 0.5.2
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/README.md +15 -11
- package/dist/cli/core/banner.d.ts +10 -0
- package/dist/cli/core/banner.js +63 -0
- package/dist/cli/core/package-root.d.ts +3 -2
- package/dist/cli/core/package-root.js +4 -4
- package/dist/cli/core/skill-pointer.d.ts +7 -2
- package/dist/cli/core/skill-pointer.js +13 -3
- package/dist/cli/main.js +5 -3
- package/dist/cli/skill-install-fs.d.ts +0 -2
- package/dist/cli/skill-install-fs.js +0 -2
- package/dist/generated/cli-commands.json +34 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/ApiKey.d.ts +6 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/ApiKey.js +2 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/CreateApiKeyRequest.d.ts +7 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/CreateApiKeyRequest.js +2 -0
- package/node_modules/@orchestraworks/client/dist/models/ApiKey.d.ts +6 -0
- package/node_modules/@orchestraworks/client/dist/models/ApiKey.js +2 -0
- package/node_modules/@orchestraworks/client/dist/models/CreateApiKeyRequest.d.ts +7 -1
- package/node_modules/@orchestraworks/client/dist/models/CreateApiKeyRequest.js +2 -0
- package/node_modules/@orchestraworks/client/package.json +1 -1
- package/package.json +4 -4
- package/skills/orchestra/SKILL.md +139 -124
- package/skills/orchestra-fdk/SKILL.md +269 -120
- package/skills/orchestra-fdk/references/authoring.md +113 -2
- package/skills/orchestra-fdk/references/environment.md +94 -24
- package/templates/engineering-team/lib/setup.sh +5 -5
|
@@ -49,7 +49,7 @@ orchestra fdk init --repository acme/shop
|
|
|
49
49
|
writes a bug-fix factory for that GitHub repository: `fdk.json`, `tsconfig.json`, `main.ts`, the machine
|
|
50
50
|
image under `image/`, the agent's standing instructions and an empty codebase skill. In `package.json` it
|
|
51
51
|
sets `"type": "module"`, adds a `typecheck` script, and adds `tsx`, `typescript` and `@types/node`. `--model-key anthropic` or `--model-key openai` adds the organization's own
|
|
52
|
-
model key; without it the agent runs
|
|
52
|
+
model key; without it the agent runs through the model gateway. It touches no platform and
|
|
53
53
|
overwrites nothing. **Setting up a factory for a codebase is the `orchestra-fdk` skill's job**: the fast
|
|
54
54
|
path from `orchestra fdk init` to a first fix, and the traps on the way.
|
|
55
55
|
|
|
@@ -103,6 +103,17 @@ entrypoint decides what answers. Omit `harness`, or misspell it, and synth fails
|
|
|
103
103
|
a message naming the five; there is no default, because guessing which one an author meant would pick a
|
|
104
104
|
different program than the one they wanted.
|
|
105
105
|
|
|
106
|
+
### Platform skills are attached by id
|
|
107
|
+
|
|
108
|
+
An agent uses a platform skill only when its `skills` list names it: `Skill.fromId(factory, "skill_<key>")`
|
|
109
|
+
in the kit, or `skillIds` on the API. Not released yet: managed skills that the kit and the create request
|
|
110
|
+
add by default (`includeManagedSkills`).
|
|
111
|
+
|
|
112
|
+
### Not released yet: an environment's working folder, `workingDirectory`
|
|
113
|
+
|
|
114
|
+
Today the harness starts outside the code. The agent clones or uses its code under `/work` in its own first
|
|
115
|
+
turn, as the starter's agents do.
|
|
116
|
+
|
|
106
117
|
### Identity comes from the construct path
|
|
107
118
|
|
|
108
119
|
With no explicit `slug`, a resource's slug is the **factory name + full construct path**,
|
|
@@ -505,7 +516,7 @@ const claudeSignIn = new Secret(factory, "claude-sign-in", {
|
|
|
505
516
|
});
|
|
506
517
|
|
|
507
518
|
// …in the Environment's props:
|
|
508
|
-
env: { CLAUDE_CODE_OAUTH_TOKEN: "placeholder", ANTHROPIC_API_KEY: "" },
|
|
519
|
+
env: { CLAUDE_CODE_OAUTH_TOKEN: "software-factory-egress-placeholder", ANTHROPIC_API_KEY: "" },
|
|
509
520
|
egress: EgressPolicy.allowAll()
|
|
510
521
|
.allow("claude-sign-in", { hosts: ["api.anthropic.com"], priority: 300, credential: claudeSignIn }),
|
|
511
522
|
```
|
|
@@ -593,6 +604,106 @@ which the harness would otherwise send instead.
|
|
|
593
604
|
(the recipe supplies the headers), or use `bearer(header, secret)` / `basic(...)` / `header(...)`
|
|
594
605
|
for one-header bindings, or `inject(secret, recipe)` for a binding-owned recipe.
|
|
595
606
|
|
|
607
|
+
## How the agents reach a model
|
|
608
|
+
|
|
609
|
+
Ask the person which of three ways they want, and walk them through its steps once.
|
|
610
|
+
|
|
611
|
+
**1. Subscription: their own Claude or Codex sign-in.** The person makes the sign-in in a real terminal
|
|
612
|
+
on their own computer; run from your shell, its browser step hangs. Never read or copy a value yourself.
|
|
613
|
+
|
|
614
|
+
- **Claude: a long-lived token in a Secret, the recommended way.** `claude setup-token` prints an
|
|
615
|
+
`sk-ant-oat…` token made for servers. It lasts about a year, and nothing on a machine renews or revokes
|
|
616
|
+
it, so it needs no shared `/home`. The person copies it and saves it to a file only they can read,
|
|
617
|
+
without pasting it into a chat: `umask 077 && pbpaste | tr -d '\n' > <file> && pbcopy </dev/null`.
|
|
618
|
+
At apply, the shell exports it from that file into the variable the Secret reads. Declare the Claude
|
|
619
|
+
sign-in recipe (§ Secrets are recipes, never values): a `Secret`, an egress rule that allows
|
|
620
|
+
`api.anthropic.com` and sets `Authorization: Bearer ${secret}` with `x-api-key` removed, and, in the
|
|
621
|
+
environment's `env`, `CLAUDE_CODE_OAUTH_TOKEN: "software-factory-egress-placeholder"` and an empty
|
|
622
|
+
`ANTHROPIC_API_KEY`. Turn `enableModelGateway` off for the agent. The machine holds only the
|
|
623
|
+
placeholder; the edge adds the token. Copying the renewing credentials file instead is the fallback,
|
|
624
|
+
and follows the ChatGPT sign-in steps below.
|
|
625
|
+
- **Codex: a personal access token, where the workspace allows one.** A ChatGPT Business or Enterprise
|
|
626
|
+
member creates it at chatgpt.com/admin/access-tokens, once the workspace owner allows access tokens,
|
|
627
|
+
and chooses how long it lasts, such as 7 to 90 days. Codex never renews it, so it needs no shared
|
|
628
|
+
`/home`; the person supplies a new one before it expires. It begins `at-` and goes in
|
|
629
|
+
`ORCHESTRA_WORKER_CODEX_PERSONAL_ACCESS_TOKEN`, which outranks a ChatGPT sign-in or an API key beside
|
|
630
|
+
it. On their own computer, `codex login --with-access-token` reads the same token from standard input.
|
|
631
|
+
- **Codex otherwise: a separate ChatGPT sign-in on a shared `/home`.** The other long-lived choice is an
|
|
632
|
+
OpenAI API key, billed by use rather than by the subscription (option 3).
|
|
633
|
+
1. **Make a separate sign-in, never a copy of the local one:** `mkdir -p <dir> && CODEX_HOME=<dir>
|
|
634
|
+
codex login`, with `--device-auth` only on a machine with no browser. Its tokens in
|
|
635
|
+
`<dir>/auth.json` go in the `ORCHESTRA_WORKER_CODEX_` variables below, or a setup step writes the
|
|
636
|
+
file.
|
|
637
|
+
2. **Put it on a shared `/home`.** Give the environment a durable `/home` volume, shared by every
|
|
638
|
+
machine that uses the sign-in, so one file renews for all of them. Separate copies fight: each
|
|
639
|
+
renewal replaces the refresh token, so the first copy to renew signs out the others. Two machines
|
|
640
|
+
that renew in the same second can still sign each other out; then make a new separate sign-in.
|
|
641
|
+
Remove the variables after the first machine starts, or each new machine writes the old token back.
|
|
642
|
+
3. **Never sign in again in the default folder after the copy.** A new `codex login` in `~/.codex`
|
|
643
|
+
revokes the cloud copy, and every machine then answers "refresh token was revoked". If it
|
|
644
|
+
happened, make a new separate sign-in.
|
|
645
|
+
- **Keep a Codex sign-in off an agent that uses the model gateway.** With a ChatGPT sign-in or a personal
|
|
646
|
+
access token, Codex compresses its requests, and the gateway refuses them with `model_not_found`, a
|
|
647
|
+
known issue. Give such an agent the subscription directly, with `enableModelGateway` off, or keep the
|
|
648
|
+
homes apart.
|
|
649
|
+
|
|
650
|
+
**2. Model gateway: Orchestra provides the key.** One endpoint reaches OpenAI, Anthropic and open-source
|
|
651
|
+
models, on the organization's credits. The person can also bring their own provider key to the gateway:
|
|
652
|
+
`orchestra fdk init --model-key anthropic` (or `openai`) declares a `ModelProviderKey`, which the gateway uses for
|
|
653
|
+
that provider's calls. The gateway also routes models: `orchestra model-configs` sets which providers serve a
|
|
654
|
+
model and in what order, so a call falls back to the next one when a provider is down, and
|
|
655
|
+
`orchestra model-aliases` gives a model a name of the organization's own, such as `default`, that one change
|
|
656
|
+
points elsewhere.
|
|
657
|
+
|
|
658
|
+
**3. Own API key via the vault.** Their Anthropic or OpenAI API key is a platform `Secret`, added at the
|
|
659
|
+
network edge on calls straight to the provider, with no gateway in between, and nothing to sync, because
|
|
660
|
+
an API key does not renew. Declare it as the Claude sign-in recipe (§ Secrets are recipes) does, with the provider's own
|
|
661
|
+
header, and leave `enableModelGateway` off in the agent's model settings:
|
|
662
|
+
|
|
663
|
+
```ts
|
|
664
|
+
const anthropicKey = new Secret(factory, "anthropic-api-key", {
|
|
665
|
+
value: SecretValue.fromEnv("ORCHESTRA_FDK_ANTHROPIC_API_KEY"),
|
|
666
|
+
injection: { headers: [{ name: "x-api-key", value: "${secret}" }] },
|
|
667
|
+
});
|
|
668
|
+
// …in the Environment's props:
|
|
669
|
+
egress: EgressPolicy.allowAll()
|
|
670
|
+
.allow("anthropic", { hosts: ["api.anthropic.com"], priority: 300, credential: anthropicKey }),
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
For OpenAI, inject `authorization: Bearer ${secret}` on `api.openai.com`. Recommend this over a
|
|
674
|
+
subscription when the person has an API key: there is no file to copy and no shared `/home`.
|
|
675
|
+
|
|
676
|
+
### The subscription variables
|
|
677
|
+
|
|
678
|
+
The worker writes each value into the file the harness reads, once per machine start, and hands none of
|
|
679
|
+
these variables to the harness. pi can also run on the provider you name.
|
|
680
|
+
|
|
681
|
+
| Variable | claude | codex | pi |
|
|
682
|
+
|---|---|---|---|
|
|
683
|
+
| `ORCHESTRA_WORKER_CLAUDE_OAUTH_TOKEN`: a `claude setup-token` token as a worker setting, in plain text; the Claude sign-in recipe's Secret is the recommended way | yes | — | yes |
|
|
684
|
+
| `ORCHESTRA_WORKER_CLAUDE_ACCESS_TOKEN` and `ORCHESTRA_WORKER_CLAUDE_REFRESH_TOKEN`, plus `ORCHESTRA_WORKER_CLAUDE_EXPIRES_AT` in milliseconds if you have it: a renewing Claude sign-in | yes | — | yes |
|
|
685
|
+
| `ORCHESTRA_WORKER_OPENAI_API_KEY` | — | yes | yes |
|
|
686
|
+
| `ORCHESTRA_WORKER_CODEX_PERSONAL_ACCESS_TOKEN`: a Codex personal access token, which outranks the other Codex rows | — | yes | — |
|
|
687
|
+
| `ORCHESTRA_WORKER_CODEX_ID_TOKEN`, `ORCHESTRA_WORKER_CODEX_ACCESS_TOKEN`, `ORCHESTRA_WORKER_CODEX_REFRESH_TOKEN` and `ORCHESTRA_WORKER_CODEX_ACCOUNT_ID` (`tokens.account_id`, which Codex needs to renew): a ChatGPT sign-in | — | yes | — |
|
|
688
|
+
| `ORCHESTRA_WORKER_PI_PROVIDER`: pi's `defaultProvider`, such as `anthropic` or `openai` | — | — | yes |
|
|
689
|
+
|
|
690
|
+
You can also bake the harness's own sign-in or settings file into the image with the setup script. With
|
|
691
|
+
no variable set, the worker leaves a value already in that file alone. For pi, your own
|
|
692
|
+
`ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_OAUTH_TOKEN`, `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` in `env` still works: the worker then leaves that provider's
|
|
693
|
+
placeholder out of pi's sign-in file, which pi would otherwise read first, and holds back the image's
|
|
694
|
+
`ANTHROPIC_OAUTH_TOKEN` placeholder beside your own `ANTHROPIC_API_KEY`.
|
|
695
|
+
|
|
696
|
+
- **The value is plain text.** `env` is stored unencrypted, and an environment read returns it. Anyone
|
|
697
|
+
who can read the environment can read its setup script.
|
|
698
|
+
- **Allow the sign-in hosts with no credential bound**: `platform.claude.com` for a copied Claude
|
|
699
|
+
credentials file, `api.openai.com` for an OpenAI key, `auth.openai.com` and `chatgpt.com` for ChatGPT. A
|
|
700
|
+
rule that binds a credential on one of these hosts replaces your sign-in on every call.
|
|
701
|
+
- **Name pi's provider when the model is not a Claude one.** pi runs the agent's model under its
|
|
702
|
+
`defaultProvider`, which `ORCHESTRA_WORKER_PI_PROVIDER` sets; with no variable, pi keeps the image's
|
|
703
|
+
`anthropic` or the provider you configured. The platform never picks it from the model.
|
|
704
|
+
- **On a Mac outpost, Claude Code reads the login Keychain first.** Sign out of Claude Code there, or
|
|
705
|
+
use `ORCHESTRA_WORKER_CLAUDE_OAUTH_TOKEN`, which Claude Code reads before the Keychain.
|
|
706
|
+
|
|
596
707
|
## Egress: apply the bundles, hand-write the rest
|
|
597
708
|
|
|
598
709
|
An environment's `egress` is a policy you build up from one of **two starting points**:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Port a codebase's setup to Orchestra machines
|
|
2
2
|
|
|
3
|
-
Step
|
|
3
|
+
Step 8 of the orchestra-fdk skill, "Set up the machines", sends you here, and so does its step 3 for a new
|
|
4
|
+
environment in an existing factory. When you finish, go back to the step that sent you.
|
|
4
5
|
|
|
5
6
|
An agent can fix, test or show a codebase only if its machine can install and run it. You find out how
|
|
6
7
|
this team sets up their code, prove it on this computer first, write it into the factory, and apply it.
|
|
@@ -10,9 +11,15 @@ An *environment* is the declared shape of a machine, and every machine an agent
|
|
|
10
11
|
The orchestra skill, sections 4 to 6, explains environments, machines, network rules and secrets, and says what
|
|
11
12
|
they cannot do yet. Read those sections before you choose a mode.
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
Where you edit depends on the starter:
|
|
15
|
+
|
|
16
|
+
- *Engineering-team starter:* every environment is built by `declareEnvironment` in
|
|
17
|
+
`<factory>/lib/environment.ts`. You edit only the section marked `WHAT THE CODE NEEDS`, and the end of
|
|
18
|
+
`<factory>/lib/setup.sh`, unless the chosen path needs more.
|
|
19
|
+
- *Bug-fix starter:* each environment is a `new Environment` in `<factory>/main.ts`. Its setup script is
|
|
20
|
+
`<factory>/image/setup.sh`, and its image is built from `<factory>/image/Dockerfile`.
|
|
21
|
+
|
|
22
|
+
Below, *the setup script* and *the environment code* mean these files for your starter.
|
|
16
23
|
|
|
17
24
|
## 1. Find the sources
|
|
18
25
|
|
|
@@ -74,7 +81,7 @@ the computer's own operating system picks among them.
|
|
|
74
81
|
|
|
75
82
|
Even when rows 1 and 2 do not work, a Linux full VM is the preferred cloud machine, on a Mac or Windows
|
|
76
83
|
computer too. Use a hosted Mac or a Windows full VM only when the project truly depends on that operating
|
|
77
|
-
system, such as iOS or Xcode. A hosted Mac is a dedicated Apple machine
|
|
84
|
+
system, such as iOS or Xcode. A hosted Mac is a dedicated Apple machine.
|
|
78
85
|
Today Orchestra launches no Mac: path B says what works now.
|
|
79
86
|
|
|
80
87
|
**Open: proving a Linux full VM locally on a Mac or Windows computer.** The host outpost there runs on
|
|
@@ -149,16 +156,16 @@ proves the agent works in the environment.
|
|
|
149
156
|
|
|
150
157
|
### The agent's model key, locally
|
|
151
158
|
|
|
152
|
-
The local agent needs a model key. The developer
|
|
159
|
+
The local agent needs a model key. The developer uses one of three sources, the one they have, and exports
|
|
153
160
|
it in the shell that starts `orchestra local`:
|
|
154
161
|
|
|
155
162
|
1. **A local token from their own subscription,** such as the one `claude setup-token` prints for Claude
|
|
156
163
|
Code.
|
|
157
164
|
2. **An API key from the model provider.**
|
|
158
|
-
3. **A model gateway key from Orchestra
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
165
|
+
3. **A model gateway key from Orchestra.** It is a separate key for local work, such as `local-dev`, with a
|
|
166
|
+
monthly cap. The developer creates it in the console at **Settings › Gateway keys**, which shows the
|
|
167
|
+
value once. The model gateway is a public service at `models.orchestraworks.ai`, so the key works locally
|
|
168
|
+
too.
|
|
162
169
|
|
|
163
170
|
**What each harness itself accepts:**
|
|
164
171
|
|
|
@@ -183,7 +190,7 @@ sign-in is reported by the Orchestra team and not yet verified in pi's docs.
|
|
|
183
190
|
| `pi` | `ANTHROPIC_OAUTH_TOKEN` for Anthropic. OpenAI: not wired yet | Anthropic and OpenAI keys: not wired yet | `ANTHROPIC_OAUTH_TOKEN` (not proven yet) |
|
|
184
191
|
| `script`, `custom` | No key needed | No key needed | No key needed |
|
|
185
192
|
|
|
186
|
-
The path that works
|
|
193
|
+
The path that works today is a `claude` agent with `CLAUDE_CODE_OAUTH_TOKEN`. Use it unless the agent
|
|
187
194
|
must run another harness.
|
|
188
195
|
|
|
189
196
|
- **For a gateway key,** also export
|
|
@@ -222,9 +229,12 @@ the settings are stored as plain text and shown on every read.
|
|
|
222
229
|
2. The two export lines point `orchestra` at this local run. Load them only into the commands meant for the
|
|
223
230
|
run. Never load them into a command meant for Orchestra's cloud.
|
|
224
231
|
3. Create the environment and an agent on the run with `npx orchestra environments create --body @<file>` and
|
|
225
|
-
`npx orchestra agents create --body @<file>`. Build each body from the
|
|
226
|
-
|
|
227
|
-
|
|
232
|
+
`npx orchestra agents create --body @<file>`. Build each body from the entries in
|
|
233
|
+
`<factory>/fdk.out/plan.json` for the environment you are proving and an agent on it. For a new
|
|
234
|
+
engineering-team factory, that is `manager-work-lg` and `manager-agent`. For a new environment in an
|
|
235
|
+
existing factory, it is the environment and the agent you added. Keep that environment's setup script in
|
|
236
|
+
its body: `<factory>/lib/setup.sh` or `<factory>/image/setup.sh`, as the top of this file says. The
|
|
237
|
+
network rules may stay: the local environment does not enforce them. Set the
|
|
228
238
|
agent's model settings for the key source, as "The agent's model key, locally" says.
|
|
229
239
|
`npx orchestra fdk apply` does not work against a run: it stops at the first thing the run does not serve.
|
|
230
240
|
4. Cut a git bundle of the default branch outside the codebase:
|
|
@@ -240,7 +250,7 @@ the settings are stored as plain text and shown on every read.
|
|
|
240
250
|
`orchestra local status` shows checks 1 and 2 (the machine started, and the harness opened its
|
|
241
251
|
conversation).
|
|
242
252
|
2. Find the machine's container with `docker ps`. Copy in the bundle with `docker cp`.
|
|
243
|
-
3. Change the setup in
|
|
253
|
+
3. Change the setup in the setup script, so the script you prove is the script you apply. Then
|
|
244
254
|
update the environment on the run and start a new machine.
|
|
245
255
|
*Fallback until the local environment runs the setup script:* copy the script in with `docker cp` and run
|
|
246
256
|
it as root yourself: `docker exec -u root <container> bash /tmp/setup.sh`.
|
|
@@ -308,10 +318,10 @@ The local key is never carried over. It stays on the developer's computer. In th
|
|
|
308
318
|
Orchestra Secret, and our network edge adds it to each model call, so no machine and no person holds it:
|
|
309
319
|
|
|
310
320
|
- For the gateway, `apply` creates the gateway key and its secret. The starter already declares them.
|
|
311
|
-
- For a provider key, declare a Secret and a rule that adds it on the provider's
|
|
312
|
-
sections 6 and 7).
|
|
321
|
+
- For a subscription token or a provider key, declare a Secret and a rule that adds it on the provider's
|
|
322
|
+
host, as step 6 of the orchestra-fdk skill says (orchestra skill, sections 6 and 7).
|
|
313
323
|
|
|
314
|
-
Ask the developer to revoke the `local-dev` gateway key, at **Settings
|
|
324
|
+
Ask the developer to revoke the `local-dev` gateway key, at **Settings › Gateway keys**, when local work is
|
|
315
325
|
done.
|
|
316
326
|
|
|
317
327
|
**Check:** milestones 1 and 2 pass and the agent turn completes in the chosen mode, or you know which one
|
|
@@ -346,6 +356,8 @@ agent can run the team's own `docker compose up` unchanged.
|
|
|
346
356
|
32 CPU, md 16, sm 2.
|
|
347
357
|
6. When the project runs containers, keep the disk at `/var/lib/docker`. The starter declares it. It keeps
|
|
348
358
|
the inner Docker's images across machine starts (next part).
|
|
359
|
+
7. Not released yet: `workingDirectory`, the folder where every conversation starts. Today each agent clones
|
|
360
|
+
or uses its code under `/work` in its own first turn, as the starter's agents do.
|
|
349
361
|
|
|
350
362
|
#### Setup script or a baked image
|
|
351
363
|
|
|
@@ -404,23 +416,26 @@ Write down what is missing and stop here. Report it to the developer, and go bac
|
|
|
404
416
|
|
|
405
417
|
## 6. Write and check
|
|
406
418
|
|
|
407
|
-
1. Edit `lib/environment.ts`
|
|
419
|
+
1. Edit the environment code for the chosen path: `lib/environment.ts` in the engineering-team starter,
|
|
420
|
+
`main.ts` and `image/` in the bug-fix starter.
|
|
408
421
|
2. In `<factory>`, run `npm run typecheck`, then `npx orchestra fdk synth`. The starter is one program, at the folder's
|
|
409
422
|
root.
|
|
410
423
|
3. Read `<factory>/fdk.out/plan.json`. Every environment has your setup script, ports and settings, and
|
|
411
|
-
the
|
|
412
|
-
|
|
424
|
+
the model rule from step 6 of the orchestra-fdk skill: the `model-gateway` rule,
|
|
425
|
+
or a Secret's rule on the provider's host. On a new factory, no environment has a Bitbucket or Jira rule
|
|
426
|
+
yet: those come with the tokens, in step 12 of the orchestra-fdk skill. On an existing factory, with its
|
|
427
|
+
inputs loaded, the rules it has now stay as they are.
|
|
413
428
|
4. Write `ENVIRONMENT.md` in `<factory>`: what you found and where, the mode you proved in and its result
|
|
414
429
|
for each success criterion, the commands, every outbound attempt the proof logged, and what is still
|
|
415
430
|
unknown.
|
|
416
431
|
|
|
417
|
-
**Check:** the typecheck and the synth pass, and the plan is as in item 3. Go back to
|
|
418
|
-
|
|
432
|
+
**Check:** the typecheck and the synth pass, and the plan is as in item 3. Go back to the orchestra-fdk
|
|
433
|
+
step that sent you for the apply.
|
|
419
434
|
|
|
420
435
|
## 7. The cloud
|
|
421
436
|
|
|
422
437
|
The cloud is the fallback when no local mode can run. It is also the confirmation after the local proof:
|
|
423
|
-
the Manager Agent's "Set up" item, which step
|
|
438
|
+
the Manager Agent's "Set up" item, which step 10 of the orchestra-fdk skill starts. It proves what only the
|
|
424
439
|
cloud can: the micro VM, Docker, the network rules and the tokens. The Engineer Agents' machines cannot clone from
|
|
425
440
|
Bitbucket, so the Set up item also proves the tests run from a git bundle.
|
|
426
441
|
|
|
@@ -439,6 +454,61 @@ bundle. Keep the safety rule:
|
|
|
439
454
|
When a step fails, fix it here, prove the fix locally if a local mode runs, apply again, and assign the
|
|
440
455
|
item again.
|
|
441
456
|
|
|
457
|
+
### The model in the cloud: subscription, model gateway, or own key via the vault
|
|
458
|
+
|
|
459
|
+
The cloud agents reach a model in one of three ways. Ask the developer which one, and walk them through
|
|
460
|
+
its steps once. They copy every value themselves; you never read, print or copy it.
|
|
461
|
+
|
|
462
|
+
1. **Subscription: their own Claude or Codex sign-in.** Follow the sign-in steps below.
|
|
463
|
+
2. **Model gateway: Orchestra provides the key.** One endpoint reaches OpenAI, Anthropic and open-source
|
|
464
|
+
models, on the organization's credits. They can also bring their own provider key to the gateway, with
|
|
465
|
+
`orchestra fdk init --model-key anthropic` or `openai`. The gateway also routes models:
|
|
466
|
+
`orchestra model-configs` sets which providers serve a model and in what order, so a call falls back to
|
|
467
|
+
the next one when a provider is down, and `orchestra model-aliases` gives a model a name of their own, such as `default`.
|
|
468
|
+
3. **Own API key via the vault.** Their Anthropic or OpenAI API key is a platform Secret, added at the
|
|
469
|
+
network edge on calls straight to `api.anthropic.com` or `api.openai.com`, with no gateway in between
|
|
470
|
+
and with the agent's gateway setting off. Nothing to sync, because an API key does not renew. When they
|
|
471
|
+
have an API key, recommend this over a subscription: no file to copy and no shared `/home`.
|
|
472
|
+
`references/authoring.md` § How the agents reach a model shows the declaration.
|
|
473
|
+
|
|
474
|
+
The sign-in steps. The developer makes the sign-in in a real terminal on their computer; run from an
|
|
475
|
+
agent's shell, its browser step hangs.
|
|
476
|
+
|
|
477
|
+
- **Claude: a long-lived token in a Secret, the recommended way.** `claude setup-token` prints an
|
|
478
|
+
`sk-ant-oat…` token made for servers. It lasts about a year, and nothing on a machine renews or revokes
|
|
479
|
+
it, so it needs no shared `/home`. Save it to a file only the developer can read, never through a chat:
|
|
480
|
+
copy it, then `umask 077 && pbpaste | tr -d '\n' > <file> && pbcopy </dev/null`. At apply, the shell
|
|
481
|
+
exports it from that file into the variable a `Secret` reads. An egress rule allows `api.anthropic.com`
|
|
482
|
+
and adds `Authorization: Bearer ${secret}`, removing `x-api-key`. The environment's `env` holds only
|
|
483
|
+
`CLAUDE_CODE_OAUTH_TOKEN=software-factory-egress-placeholder` and an empty `ANTHROPIC_API_KEY`, and the
|
|
484
|
+
agent's gateway setting is off. Never put the token itself in `env`. The Claude sign-in recipe in
|
|
485
|
+
`references/authoring.md` shows the declaration. Copying the renewing credentials file is the fallback,
|
|
486
|
+
and follows the ChatGPT sign-in steps below.
|
|
487
|
+
- **Codex: a personal access token, where the workspace allows one.** A ChatGPT Business or Enterprise
|
|
488
|
+
member creates it at chatgpt.com/admin/access-tokens, once the workspace owner allows access tokens,
|
|
489
|
+
and chooses how long it lasts, such as 7 to 90 days. Codex never renews it, so it needs no shared
|
|
490
|
+
`/home`; the developer supplies a new one before it expires. It begins `at-` and goes in
|
|
491
|
+
`ORCHESTRA_WORKER_CODEX_PERSONAL_ACCESS_TOKEN`, which outranks a ChatGPT sign-in or an API key beside
|
|
492
|
+
it. On their own computer, `codex login --with-access-token` reads the same token from standard input.
|
|
493
|
+
- **Codex otherwise: a separate ChatGPT sign-in on a shared `/home`.** The other long-lived choice is an
|
|
494
|
+
OpenAI API key, billed by use rather than by the subscription (option 3).
|
|
495
|
+
1. **Make a separate sign-in, never a copy of the local one:** `mkdir -p <dir> && CODEX_HOME=<dir> codex
|
|
496
|
+
login` (`--device-auth` only with no browser). Its tokens in `<dir>/auth.json` go in the
|
|
497
|
+
`ORCHESTRA_WORKER_CODEX_` variables, or a setup step writes the file.
|
|
498
|
+
2. **Give the environment a durable `/home` volume,** shared by every machine that uses the sign-in, so
|
|
499
|
+
one file renews for all of them. Each renewal replaces the refresh token, so separate copies sign
|
|
500
|
+
each other out; two machines that renew in the same second can too, and then need a new sign-in.
|
|
501
|
+
Remove the variables after the first machine starts.
|
|
502
|
+
3. **Never sign in again in the default folder after the copy.** A new `codex login` in `~/.codex`
|
|
503
|
+
revokes the cloud copy, and every machine answers "refresh token was revoked". If it happened, make
|
|
504
|
+
a new separate sign-in.
|
|
505
|
+
- **Keep a Codex sign-in off an agent that uses the model gateway.** With a ChatGPT sign-in or a personal
|
|
506
|
+
access token, Codex compresses its requests, and the gateway refuses them with `model_not_found`, a
|
|
507
|
+
known issue. Give such an agent the subscription directly, with its gateway setting off, or keep the
|
|
508
|
+
homes apart.
|
|
509
|
+
|
|
510
|
+
The sign-in values are plain text: the environment's settings are stored unencrypted and shown on every read.
|
|
511
|
+
|
|
442
512
|
## What the platform can do
|
|
443
513
|
|
|
444
514
|
Use the orchestra skill to build an answer for a case the paths do not cover. Never promise one of its "Cannot
|
|
@@ -45,11 +45,11 @@ chown agent:agent /work || exit 16
|
|
|
45
45
|
|
|
46
46
|
# ---- Add the team's system setup here: packages, language runtimes, tools. -----------------------------------
|
|
47
47
|
|
|
48
|
-
# Optional, off by default: a Node major version other than the image's. To turn it on, remove the
|
|
49
|
-
# from the lines from NODE_MAJOR to `esac`, and set NODE_MAJOR. It replaces the image's Node in
|
|
50
|
-
# image's own npm and corepack go first: unpacking a second Node over them leaves a mix of two npm
|
|
51
|
-
# every npm command then exits 1. Use this Node's own corepack for pnpm or yarn.
|
|
52
|
-
# NODE_MAJOR=
|
|
48
|
+
# Optional, off by default: a Node major version other than the image's Node 24. To turn it on, remove the
|
|
49
|
+
# leading `# ` from the lines from NODE_MAJOR to `esac`, and set NODE_MAJOR. It replaces the image's Node in
|
|
50
|
+
# /usr/local. The image's own npm and corepack go first: unpacking a second Node over them leaves a mix of two npm
|
|
51
|
+
# versions, and every npm command then exits 1. Use this Node's own corepack for pnpm or yarn.
|
|
52
|
+
# NODE_MAJOR=22
|
|
53
53
|
# case "$(node --version 2>/dev/null)" in "v$NODE_MAJOR".*) ;; *)
|
|
54
54
|
# case "$(uname -m)" in aarch64 | arm64) node_arch=arm64 ;; *) node_arch=x64 ;; esac
|
|
55
55
|
# node_version=$(curl -fsSL --retry 3 https://nodejs.org/dist/index.json |
|