@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.
@@ -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 on credits through the model gateway. It touches no platform and
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 6 of the orchestra-fdk skill sends you here. When you finish, go back to that 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
- In the engineering team template, every environment is built by `declareEnvironment` in
14
- `<factory>/lib/environment.ts`. You edit only the section marked `WHAT THE CODE NEEDS`, and the end of
15
- `<factory>/lib/setup.sh`, unless the chosen path needs more.
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, billed for a 24-hour minimum.
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 picks one of three sources, in this order, and exports
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,** when neither of those is at hand. It is a separate key for local
159
- work, such as `local-dev`, with a monthly cap. The developer creates it in the console at
160
- **Settings > Gateway keys**, which shows the value once. The model gateway is a public service at
161
- `models.orchestraworks.ai`, so the key works locally too. Usage is charged to the organization's credit.
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 tonight is a `claude` agent with `CLAUDE_CODE_OAUTH_TOKEN`. Use it unless the agent
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 `manager-work-lg` and `manager-agent`
226
- entries in `<factory>/fdk.out/plan.json`. Keep the setup script from `<factory>/lib/setup.sh` in the
227
- environment's body. The network rules may stay: the local environment does not enforce them. Set the
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 `<factory>/lib/setup.sh`, so the script you prove is the script you apply. Then
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 host (orchestra skill,
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 > Gateway keys**, when local work is
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` for the chosen path.
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 `model-gateway` rule. No environment has a Bitbucket or Jira rule yet: those come with the tokens,
412
- in step 10 of the orchestra-fdk skill.
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 step 6 of the
418
- orchestra-fdk skill for the apply.
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 7 of the orchestra-fdk skill starts. It proves what only the
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 leading `# `
49
- # from the lines from NODE_MAJOR to `esac`, and set NODE_MAJOR. It replaces the image's Node in /usr/local. The
50
- # image's own npm and corepack go first: unpacking a second Node over them leaves a mix of two npm versions, and
51
- # every npm command then exits 1. Use this Node's own corepack for pnpm or yarn.
52
- # NODE_MAJOR=24
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 |