@orchestraworks/cli 0.5.1 → 0.5.3
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 +1 -1
- package/dist/cli/api/compute-provider-check.d.ts +29 -0
- package/dist/cli/api/compute-provider-check.js +207 -0
- package/dist/cli/api/tail.d.ts +66 -0
- package/dist/cli/api/tail.js +564 -0
- package/dist/cli/main.d.ts +5 -1
- package/dist/cli/main.js +22 -0
- package/dist/constructs/agent.d.ts +10 -0
- package/dist/constructs/agent.js +39 -4
- package/dist/constructs/environment.d.ts +29 -1
- package/dist/constructs/environment.js +28 -1
- package/dist/constructs/skill.d.ts +6 -1
- package/dist/constructs/skill.js +21 -2
- package/dist/engine/reconcile.js +15 -1
- package/dist/generated/cli-commands.json +876 -1
- package/dist/generated/managed-skills.d.ts +2 -0
- package/dist/generated/managed-skills.js +13 -0
- package/dist/index.d.ts +1 -1
- package/docs/REFERENCE.md +21 -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/ComputeProvider.d.ts +3 -3
- 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/esm/models/CreateEnvironmentRequest.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/CreateEnvironmentRequest.js +5 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/Environment.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/Environment.js +5 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHook.d.ts +38 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHook.js +45 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooks.d.ts +39 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooks.js +44 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooksRequest.d.ts +39 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooksRequest.js +44 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentProvisionSpec.d.ts +2 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentProvisionSpecRequest.d.ts +2 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentSnapshot.d.ts +19 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentSnapshot.js +7 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/Machine.d.ts +7 -1
- package/node_modules/@orchestraworks/client/dist/esm/models/Machine.js +2 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/UpdateEnvironmentRequest.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/UpdateEnvironmentRequest.js +5 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/index.d.ts +3 -0
- package/node_modules/@orchestraworks/client/dist/esm/models/index.js +3 -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/ComputeProvider.d.ts +3 -3
- 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/dist/models/CreateEnvironmentRequest.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/models/CreateEnvironmentRequest.js +5 -0
- package/node_modules/@orchestraworks/client/dist/models/Environment.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/models/Environment.js +5 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHook.d.ts +38 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHook.js +52 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooks.d.ts +39 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooks.js +51 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooksRequest.d.ts +39 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooksRequest.js +51 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentProvisionSpec.d.ts +2 -1
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentProvisionSpecRequest.d.ts +2 -1
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentSnapshot.d.ts +19 -0
- package/node_modules/@orchestraworks/client/dist/models/EnvironmentSnapshot.js +7 -0
- package/node_modules/@orchestraworks/client/dist/models/Machine.d.ts +7 -1
- package/node_modules/@orchestraworks/client/dist/models/Machine.js +2 -0
- package/node_modules/@orchestraworks/client/dist/models/UpdateEnvironmentRequest.d.ts +13 -0
- package/node_modules/@orchestraworks/client/dist/models/UpdateEnvironmentRequest.js +5 -0
- package/node_modules/@orchestraworks/client/dist/models/index.d.ts +3 -0
- package/node_modules/@orchestraworks/client/dist/models/index.js +3 -0
- package/node_modules/@orchestraworks/client/package.json +1 -1
- package/package.json +4 -4
- package/skills/orchestra/SKILL.md +167 -42
- package/skills/orchestra-fdk/SKILL.md +112 -545
- package/skills/orchestra-fdk/references/authoring.md +130 -3
- package/skills/orchestra-fdk/references/environment.md +352 -43
- package/skills/orchestra-fdk/references/integrations/analytics.md +18 -0
- package/skills/orchestra-fdk/references/integrations/ci-cd.md +20 -0
- package/skills/orchestra-fdk/references/integrations/cloud.md +19 -0
- package/skills/orchestra-fdk/references/integrations/code-repo.md +76 -0
- package/skills/orchestra-fdk/references/integrations/databases.md +22 -0
- package/skills/orchestra-fdk/references/integrations/dependencies.md +29 -0
- package/skills/orchestra-fdk/references/integrations/design.md +18 -0
- package/skills/orchestra-fdk/references/integrations/feature-flags.md +19 -0
- package/skills/orchestra-fdk/references/integrations/incident.md +29 -0
- package/skills/orchestra-fdk/references/integrations/issue-tracker.md +65 -0
- package/skills/orchestra-fdk/references/integrations/knowledge-base.md +43 -0
- package/skills/orchestra-fdk/references/integrations/messaging.md +38 -0
- package/skills/orchestra-fdk/references/integrations/observability.md +36 -0
- package/skills/orchestra-fdk/references/integrations/secrets-managers.md +25 -0
- package/skills/orchestra-fdk/references/integrations/support-desk.md +31 -0
- package/skills/orchestra-fdk/references/phases/0-start.md +62 -0
- package/skills/orchestra-fdk/references/phases/1-discover.md +111 -0
- package/skills/orchestra-fdk/references/phases/2-plan.md +157 -0
- package/skills/orchestra-fdk/references/phases/3-connect.md +99 -0
- package/skills/orchestra-fdk/references/phases/4-build.md +159 -0
- package/skills/orchestra-fdk/references/phases/5-prove.md +107 -0
- package/skills/orchestra-fdk/references/phases/6-handover.md +42 -0
- package/skills/orchestra-fdk/references/troubleshooting.md +128 -0
- package/templates/bug-fix/agents/bugfix.md +1 -1
- package/templates/bug-fix/main.ts +1 -1
- package/templates/engineering-team/README.md +45 -181
- package/templates/engineering-team/agents/engineer-agent.md +10 -7
- package/templates/engineering-team/agents/manager-agent.md +23 -120
- package/templates/engineering-team/inputs.json +1 -3
- package/templates/engineering-team/lib/environment.ts +10 -90
- package/templates/engineering-team/lib/inputs.ts +5 -97
- package/templates/engineering-team/lib/setup.sh +5 -5
- package/templates/engineering-team/main.ts +22 -69
- package/templates/todo-factory/agents/bugfix.md +1 -1
- package/templates/todo-factory/main.ts +1 -1
- package/templates/engineering-team/agents/engineer-bare.md +0 -22
- package/templates/engineering-team/onboarding/create-score-metrics.sh +0 -33
|
@@ -103,6 +103,21 @@ 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
|
+
### Every agent's instructions start with an Attribution section
|
|
107
|
+
|
|
108
|
+
The starter's agents start their instructions with it. When you write an agent of your own, start its
|
|
109
|
+
instructions with the same section, with the agent's display name and slug filled in:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
## Attribution
|
|
113
|
+
You are <agent display name>. Mark the work you produce as yours:
|
|
114
|
+
- every commit message and pull request description ends with
|
|
115
|
+
Co-Authored-By: <agent display name> <<agent-slug>@agents.orchestraworks.ai>
|
|
116
|
+
- every comment and tracker edit ends with one line: — <agent display name>, Orchestra
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
A person who reads a commit, a pull request, a comment or a tracker edit then sees which agent made it.
|
|
120
|
+
|
|
106
121
|
### Platform skills are attached by id
|
|
107
122
|
|
|
108
123
|
An agent uses a platform skill only when its `skills` list names it: `Skill.fromId(factory, "skill_<key>")`
|
|
@@ -516,7 +531,7 @@ const claudeSignIn = new Secret(factory, "claude-sign-in", {
|
|
|
516
531
|
});
|
|
517
532
|
|
|
518
533
|
// …in the Environment's props:
|
|
519
|
-
env: { CLAUDE_CODE_OAUTH_TOKEN: "placeholder", ANTHROPIC_API_KEY: "" },
|
|
534
|
+
env: { CLAUDE_CODE_OAUTH_TOKEN: "software-factory-egress-placeholder", ANTHROPIC_API_KEY: "" },
|
|
520
535
|
egress: EgressPolicy.allowAll()
|
|
521
536
|
.allow("claude-sign-in", { hosts: ["api.anthropic.com"], priority: 300, credential: claudeSignIn }),
|
|
522
537
|
```
|
|
@@ -604,6 +619,106 @@ which the harness would otherwise send instead.
|
|
|
604
619
|
(the recipe supplies the headers), or use `bearer(header, secret)` / `basic(...)` / `header(...)`
|
|
605
620
|
for one-header bindings, or `inject(secret, recipe)` for a binding-owned recipe.
|
|
606
621
|
|
|
622
|
+
## How the agents reach a model
|
|
623
|
+
|
|
624
|
+
Ask the person which of three ways they want, and walk them through its steps once.
|
|
625
|
+
|
|
626
|
+
**1. Subscription: their own Claude or Codex sign-in.** The person makes the sign-in in a real terminal
|
|
627
|
+
on their own computer; run from your shell, its browser step hangs. Never read or copy a value yourself.
|
|
628
|
+
|
|
629
|
+
- **Claude: a long-lived token in a Secret, the recommended way.** `claude setup-token` prints an
|
|
630
|
+
`sk-ant-oat…` token made for servers. It lasts about a year, and nothing on a machine renews or revokes
|
|
631
|
+
it, so it needs no shared `/home`. The person copies it and saves it to a file only they can read,
|
|
632
|
+
without pasting it into a chat: `umask 077 && pbpaste | tr -d '\n' > <file> && pbcopy </dev/null`.
|
|
633
|
+
At apply, the shell exports it from that file into the variable the Secret reads. Declare the Claude
|
|
634
|
+
sign-in recipe (§ Secrets are recipes, never values): a `Secret`, an egress rule that allows
|
|
635
|
+
`api.anthropic.com` and sets `Authorization: Bearer ${secret}` with `x-api-key` removed, and, in the
|
|
636
|
+
environment's `env`, `CLAUDE_CODE_OAUTH_TOKEN: "software-factory-egress-placeholder"` and an empty
|
|
637
|
+
`ANTHROPIC_API_KEY`. Turn `enableModelGateway` off for the agent. The machine holds only the
|
|
638
|
+
placeholder; the edge adds the token. Copying the renewing credentials file instead is the fallback,
|
|
639
|
+
and follows the ChatGPT sign-in steps below.
|
|
640
|
+
- **Codex: a personal access token, where the workspace allows one.** A ChatGPT Business or Enterprise
|
|
641
|
+
member creates it at chatgpt.com/admin/access-tokens, once the workspace owner allows access tokens,
|
|
642
|
+
and chooses how long it lasts, such as 7 to 90 days. Codex never renews it, so it needs no shared
|
|
643
|
+
`/home`; the person supplies a new one before it expires. It begins `at-` and goes in
|
|
644
|
+
`ORCHESTRA_WORKER_CODEX_PERSONAL_ACCESS_TOKEN`, which outranks a ChatGPT sign-in or an API key beside
|
|
645
|
+
it. On their own computer, `codex login --with-access-token` reads the same token from standard input.
|
|
646
|
+
- **Codex otherwise: a separate ChatGPT sign-in on a shared `/home`.** The other long-lived choice is an
|
|
647
|
+
OpenAI API key, billed by use rather than by the subscription (option 3).
|
|
648
|
+
1. **Make a separate sign-in, never a copy of the local one:** `mkdir -p <dir> && CODEX_HOME=<dir>
|
|
649
|
+
codex login`, with `--device-auth` only on a machine with no browser. Its tokens in
|
|
650
|
+
`<dir>/auth.json` go in the `ORCHESTRA_WORKER_CODEX_` variables below, or a setup step writes the
|
|
651
|
+
file.
|
|
652
|
+
2. **Put it on a shared `/home`.** Give the environment a durable `/home` volume, shared by every
|
|
653
|
+
machine that uses the sign-in, so one file renews for all of them. Separate copies fight: each
|
|
654
|
+
renewal replaces the refresh token, so the first copy to renew signs out the others. Two machines
|
|
655
|
+
that renew in the same second can still sign each other out; then make a new separate sign-in.
|
|
656
|
+
Remove the variables after the first machine starts, or each new machine writes the old token back.
|
|
657
|
+
3. **Never sign in again in the default folder after the copy.** A new `codex login` in `~/.codex`
|
|
658
|
+
revokes the cloud copy, and every machine then answers "refresh token was revoked". If it
|
|
659
|
+
happened, make a new separate sign-in.
|
|
660
|
+
- **Keep a Codex sign-in off an agent that uses the model gateway.** With a ChatGPT sign-in or a personal
|
|
661
|
+
access token, Codex compresses its requests, and the gateway refuses them with `model_not_found`, a
|
|
662
|
+
known issue. Give such an agent the subscription directly, with `enableModelGateway` off, or keep the
|
|
663
|
+
homes apart.
|
|
664
|
+
|
|
665
|
+
**2. Model gateway: Orchestra provides the key.** One endpoint reaches OpenAI, Anthropic and open-source
|
|
666
|
+
models, on the organization's credits. The person can also bring their own provider key to the gateway:
|
|
667
|
+
`orchestra fdk init --model-key anthropic` (or `openai`) declares a `ModelProviderKey`, which the gateway uses for
|
|
668
|
+
that provider's calls. The gateway also routes models: `orchestra model-configs` sets which providers serve a
|
|
669
|
+
model and in what order, so a call falls back to the next one when a provider is down, and
|
|
670
|
+
`orchestra model-aliases` gives a model a name of the organization's own, such as `default`, that one change
|
|
671
|
+
points elsewhere.
|
|
672
|
+
|
|
673
|
+
**3. Own API key via the vault.** Their Anthropic or OpenAI API key is a platform `Secret`, added at the
|
|
674
|
+
network edge on calls straight to the provider, with no gateway in between, and nothing to sync, because
|
|
675
|
+
an API key does not renew. Declare it as the Claude sign-in recipe (§ Secrets are recipes) does, with the provider's own
|
|
676
|
+
header, and leave `enableModelGateway` off in the agent's model settings:
|
|
677
|
+
|
|
678
|
+
```ts
|
|
679
|
+
const anthropicKey = new Secret(factory, "anthropic-api-key", {
|
|
680
|
+
value: SecretValue.fromEnv("ORCHESTRA_FDK_ANTHROPIC_API_KEY"),
|
|
681
|
+
injection: { headers: [{ name: "x-api-key", value: "${secret}" }] },
|
|
682
|
+
});
|
|
683
|
+
// …in the Environment's props:
|
|
684
|
+
egress: EgressPolicy.allowAll()
|
|
685
|
+
.allow("anthropic", { hosts: ["api.anthropic.com"], priority: 300, credential: anthropicKey }),
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
For OpenAI, inject `authorization: Bearer ${secret}` on `api.openai.com`. Recommend this over a
|
|
689
|
+
subscription when the person has an API key: there is no file to copy and no shared `/home`.
|
|
690
|
+
|
|
691
|
+
### The subscription variables
|
|
692
|
+
|
|
693
|
+
The worker writes each value into the file the harness reads, once per machine start, and hands none of
|
|
694
|
+
these variables to the harness. pi can also run on the provider you name.
|
|
695
|
+
|
|
696
|
+
| Variable | claude | codex | pi |
|
|
697
|
+
|---|---|---|---|
|
|
698
|
+
| `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 |
|
|
699
|
+
| `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 |
|
|
700
|
+
| `ORCHESTRA_WORKER_OPENAI_API_KEY` | — | yes | yes |
|
|
701
|
+
| `ORCHESTRA_WORKER_CODEX_PERSONAL_ACCESS_TOKEN`: a Codex personal access token, which outranks the other Codex rows | — | yes | — |
|
|
702
|
+
| `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 | — |
|
|
703
|
+
| `ORCHESTRA_WORKER_PI_PROVIDER`: pi's `defaultProvider`, such as `anthropic` or `openai` | — | — | yes |
|
|
704
|
+
|
|
705
|
+
You can also bake the harness's own sign-in or settings file into the image with the setup script. With
|
|
706
|
+
no variable set, the worker leaves a value already in that file alone. For pi, your own
|
|
707
|
+
`ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_OAUTH_TOKEN`, `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` in `env` still works: the worker then leaves that provider's
|
|
708
|
+
placeholder out of pi's sign-in file, which pi would otherwise read first, and holds back the image's
|
|
709
|
+
`ANTHROPIC_OAUTH_TOKEN` placeholder beside your own `ANTHROPIC_API_KEY`.
|
|
710
|
+
|
|
711
|
+
- **The value is plain text.** `env` is stored unencrypted, and an environment read returns it. Anyone
|
|
712
|
+
who can read the environment can read its setup script.
|
|
713
|
+
- **Allow the sign-in hosts with no credential bound**: `platform.claude.com` for a copied Claude
|
|
714
|
+
credentials file, `api.openai.com` for an OpenAI key, `auth.openai.com` and `chatgpt.com` for ChatGPT. A
|
|
715
|
+
rule that binds a credential on one of these hosts replaces your sign-in on every call.
|
|
716
|
+
- **Name pi's provider when the model is not a Claude one.** pi runs the agent's model under its
|
|
717
|
+
`defaultProvider`, which `ORCHESTRA_WORKER_PI_PROVIDER` sets; with no variable, pi keeps the image's
|
|
718
|
+
`anthropic` or the provider you configured. The platform never picks it from the model.
|
|
719
|
+
- **On a Mac outpost, Claude Code reads the login Keychain first.** Sign out of Claude Code there, or
|
|
720
|
+
use `ORCHESTRA_WORKER_CLAUDE_OAUTH_TOKEN`, which Claude Code reads before the Keychain.
|
|
721
|
+
|
|
607
722
|
## Egress: apply the bundles, hand-write the rest
|
|
608
723
|
|
|
609
724
|
An environment's `egress` is a policy you build up from one of **two starting points**:
|
|
@@ -977,9 +1092,9 @@ cookie your app sets must carry `SameSite=None; Secure; Partitioned`, or the bro
|
|
|
977
1092
|
frame and your app's own sign-in or session state is lost on each load. The platform's own access
|
|
978
1093
|
cookie is already set this way, and your app never sees it.
|
|
979
1094
|
|
|
980
|
-
### Typed flows: `user-grants grant` and `sessions
|
|
1095
|
+
### Typed flows: `user-grants grant`, `sessions wait` and `sessions tail`
|
|
981
1096
|
|
|
982
|
-
|
|
1097
|
+
Three commands stay hand-shaped, because the orchestration is the value a bare generated call would
|
|
983
1098
|
drop. Both are platform commands — they read and write the live factory, not your code.
|
|
984
1099
|
|
|
985
1100
|
```bash
|
|
@@ -1004,6 +1119,18 @@ taking no more messages), which settles too. `--interval` and `--timeout` are yo
|
|
|
1004
1119
|
any settlement (the printed state
|
|
1005
1120
|
carries the outcome) and non-zero only on a timeout or a failed call.
|
|
1006
1121
|
|
|
1122
|
+
```bash
|
|
1123
|
+
orchestra sessions tail session_01abc --until-settled
|
|
1124
|
+
```
|
|
1125
|
+
|
|
1126
|
+
Prints each item of the session as it is saved: a reply line by line as it grows, a tool call as one
|
|
1127
|
+
line, printed again when its status changes. With `--output json` it prints each item once, as one
|
|
1128
|
+
JSON line, when the item can no longer change. It starts with the items that
|
|
1129
|
+
already exist; `--after <item id>` starts after that item instead. While a turn runs, each read waits
|
|
1130
|
+
on the platform for the next saved output, so the command does not poll on a timer. `--until-settled`
|
|
1131
|
+
exits once the turn has ended and prints the session's status, with exit 0 whatever the status, as
|
|
1132
|
+
`sessions wait` does. Without it, the command follows the session until Ctrl-C.
|
|
1133
|
+
|
|
1007
1134
|
### The backup: `orchestra api`
|
|
1008
1135
|
|
|
1009
1136
|
`orchestra api GET "/sessions?limit=5"` makes a raw authenticated call — exactly `gh api`'s role — through
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Port a codebase's setup to Orchestra machines
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Phase 4 of the orchestra-fdk skill, "Build", sends you here, for a new factory and for a new environment in
|
|
4
|
+
an existing factory. When you finish section 6, go back to phase 4 for the apply.
|
|
5
5
|
|
|
6
6
|
An agent can fix, test or show a codebase only if its machine can install and run it. You find out how
|
|
7
7
|
this team sets up their code, prove it on this computer first, write it into the factory, and apply it.
|
|
@@ -319,7 +319,7 @@ Orchestra Secret, and our network edge adds it to each model call, so no machine
|
|
|
319
319
|
|
|
320
320
|
- For the gateway, `apply` creates the gateway key and its secret. The starter already declares them.
|
|
321
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
|
|
322
|
+
host, as phase 2 of the orchestra-fdk skill, "The model route", says (orchestra skill, sections 6 and 7).
|
|
323
323
|
|
|
324
324
|
Ask the developer to revoke the `local-dev` gateway key, at **Settings › Gateway keys**, when local work is
|
|
325
325
|
done.
|
|
@@ -332,6 +332,116 @@ fails and why. Report which tests ran and which could not. Then run `orchestra l
|
|
|
332
332
|
Ask the developer to confirm the path you recommend, with your question tool. The mode you proved points
|
|
333
333
|
to the path, as the table in section 2 says: a container machine to A, the host outpost to B.
|
|
334
334
|
|
|
335
|
+
### The machine's runtime, by operating system
|
|
336
|
+
|
|
337
|
+
An environment's `platform` is `{ os, arch, runtime }`, set when the environment is created. `runtime` never
|
|
338
|
+
changes. On a provisioned environment it is `microvm` (the default) or `vm`. An enrolled environment is
|
|
339
|
+
`host`: the team's own machine, as it is, with no network rules of ours.
|
|
340
|
+
|
|
341
|
+
The setup script runs once, as root or as the machine's service account, on each new machine, before the
|
|
342
|
+
agent arrives and before any code is cloned. It is at most 64 KiB. It has 10 minutes. The limit is fixed for
|
|
343
|
+
now, and an environment cannot raise it. A worker that starts again on the same
|
|
344
|
+
machine reuses the result it kept, and does not run the script again.
|
|
345
|
+
|
|
346
|
+
#### Linux
|
|
347
|
+
|
|
348
|
+
Most code: web, backend, mobile build tools, anything that runs in Docker.
|
|
349
|
+
|
|
350
|
+
| Runtime and where it runs | Base image: what's in it | Sizes | Disks and shared volumes | Setup script | Home and continuity | Requirements and limits |
|
|
351
|
+
|---|---|---|---|---|---|---|
|
|
352
|
+
| `microvm`: a Kata micro VM on Kubernetes, amd64. `vm`: an EC2 Ubuntu VM, amd64 or arm64 | `microvm`: Debian with Node 24, Java 21 and 25, Python 3, a C and C++ build toolchain, git, the GitHub CLI `gh`, and Docker with Compose and Buildx (not started until the setup script starts it). `vm`: Ubuntu 24.04 with Node 24, git, and rootless Docker with Buildx, which runs from boot as the agent's user. The VM has no Java and no Compose plugin: install the ones the code needs in the setup script. Both carry the worker and the `claude`, `codex`, `pi` and `script` harnesses | `microvm`: 0.5, 1, 2, 4, 8, 16 or 32 CPU. `vm`: 2, 4 or 8 CPU. 2 GB of memory per CPU | `vm`: a 40 GiB root disk. Up to four extra disks (`disks`), such as `/var/lib/docker` and `/work`. Shared volumes (`volumeMounts`) on EFS, which every machine of an environment can mount together | Bash, run with `bash -e`. One exit code per step | A volume at `/home` keeps the agent's home across machines. Without it, nothing in `/home` outlives the machine | No Windows or macOS programs. A kernel of its own, an Android device or nested virtualization needs `vm` |
|
|
353
|
+
|
|
354
|
+
#### Windows
|
|
355
|
+
|
|
356
|
+
Code that builds or runs only on Windows: .NET Framework, WinForms, WPF, IIS, Windows-only tools.
|
|
357
|
+
|
|
358
|
+
| Runtime and where it runs | Base image: what's in it | Sizes | Disks and shared volumes | Setup script | Home and continuity | Requirements and limits |
|
|
359
|
+
|---|---|---|---|---|---|---|
|
|
360
|
+
| `vm`: an EC2 Windows Server VM, amd64. Set `platform: { os: "windows", arch: "amd64", runtime: "vm" }` | Our image only: Windows Server 2025 Core, Node 24, Docker for Windows containers with the Containers feature, the worker, the `orchestra` command, and the `claude`, `codex`, `pi` and `script` harnesses. No git: install it in the setup script. A hosted Windows machine cannot start from another image | 4 or 8 CPU, 2 GB of memory per CPU | The image's 100 GiB root disk. No extra disks: remove `disks`. Shared volumes: not stated | PowerShell 5.1, run as the machine's service account. One exit code per step. Template: "A Windows setup script" below | The machine is parked when idle and keeps its disk, so the home (`C:\sf\home`) and `C:\work` stay. The setup script runs once per machine | Docker runs Windows containers only, for administrators only. A machine takes up to 15 minutes to start the first time |
|
|
361
|
+
|
|
362
|
+
**Windows in three stages.** Guide a Windows team through these stages, in order. Write the stage you plan
|
|
363
|
+
into `orchestra-factory-notes.md`.
|
|
364
|
+
|
|
365
|
+
1. **Start on hosted Windows, with our image.** This proves the factory works, with nothing to run in the
|
|
366
|
+
team's own cloud. The setup script installs what fits in its 10 minutes: Git, and the small tools. A
|
|
367
|
+
larger toolchain, such as Visual Studio Build Tools or an old SDK, goes in the agent's first turn. The
|
|
368
|
+
machine is parked when idle and keeps its disk, so the next turn finds the toolchain installed. The agent
|
|
369
|
+
runs the install in the turn and waits for it: a park stops the VM and kills an install still running.
|
|
370
|
+
The machine is deleted after `ttl`, 2 hours by default, and a new one starts without the toolchain.
|
|
371
|
+
2. **Then move to the team's own Windows image, through a compute provider in their cloud.** The benefit:
|
|
372
|
+
each machine starts with the whole toolchain installed, with no setup limit, and the team's licenses,
|
|
373
|
+
such as Visual Studio's, stay in their own image. The Launcher, the program the team runs in their
|
|
374
|
+
cloud, starts Windows VMs from the image its environment names. The Launcher runs on Azure (the
|
|
375
|
+
orchestra skill, section 18). The team bakes the image on Windows Server 2025 and adds their own
|
|
376
|
+
toolchain: git, MSBuild and .NET are theirs to install. Windows 11 is not supported, and a plain
|
|
377
|
+
captured Windows VM does not register. The image must contain these three parts:
|
|
378
|
+
- The worker's release package, for example at `C:\ProgramData\sfdk\worker\package`.
|
|
379
|
+
- The worker's Windows service, `SfdkWorker`. It runs `worker.exe run --root C:\ProgramData\sfdk\worker
|
|
380
|
+
--service` as LocalSystem. It is demand-start (`Manual`), not automatic. On a failure it restarts
|
|
381
|
+
three times, 2 seconds apart, and a clean stop with a non-zero exit code counts as a failure.
|
|
382
|
+
- The startup task `orchestra-azure-userdata`. It runs `azure-userdata.ps1` as SYSTEM at each boot
|
|
383
|
+
(`AtStartup`). The script writes the files that the VM's startup data carries, then starts
|
|
384
|
+
`SfdkWorker`.
|
|
385
|
+
|
|
386
|
+
Our image builds the same parts: `install-vm-runtime.ps1` and the image template
|
|
387
|
+
`infra/packer/azure-windows-runtime.pkr.hcl`. Under a Launcher, the image needs no WinDivert, no
|
|
388
|
+
redirect firewall rule, no Docker, no Node and no preinstalled harness: a harness installs itself on
|
|
389
|
+
its first turn, in about 60 seconds. Credentials are the team's to set on the VM (part C, "Tokens on a
|
|
390
|
+
compute provider's machines"). Our own image is in a public Azure gallery:
|
|
391
|
+
`/CommunityGalleries/orchestraworks-881a796f-0a84-4be1-af80-0a38564a406a/Images/runtime-win/Versions/0.0.136`
|
|
392
|
+
(Gen2). An environment that names no image boots its `Versions/latest`. Not released yet: a one-command
|
|
393
|
+
installer for a team's own image, the Launcher on AWS, and a team's own image on hosted Windows.
|
|
394
|
+
3. **Then keep machines ready, for speed.** `standbyCapacity` on the agent (`Agent` in the kit) keeps
|
|
395
|
+
`count` machines started, set up and with the agent installed, on a schedule or always. A new
|
|
396
|
+
conversation then starts at once, with no wait for a Windows first boot. The platform refuses it only
|
|
397
|
+
for an enrolled environment or a `custom` harness, so it applies to hosted Windows and to a compute
|
|
398
|
+
provider. Proven on a compute provider's Windows VM: a new conversation got a ready machine, and its
|
|
399
|
+
turn started in 3.5 seconds. A standby minute is billed: the plan page shows the price.
|
|
400
|
+
`npx orchestra agents get <agent>` shows `standbyStatus`: how many machines are ready now, and why
|
|
401
|
+
fewer when that is so.
|
|
402
|
+
|
|
403
|
+
#### macOS
|
|
404
|
+
|
|
405
|
+
Code that needs Xcode, the iOS Simulator or another Apple tool.
|
|
406
|
+
|
|
407
|
+
Not released yet: Orchestra launches no Mac. A Mac works only as the team's own enrolled machine
|
|
408
|
+
(`host`), with the worker installed on it, no network rules of ours and no keys added at the edge. Agree it
|
|
409
|
+
with the Orchestra team first (the orchestra skill, section 18).
|
|
410
|
+
|
|
411
|
+
#### A custom image
|
|
412
|
+
|
|
413
|
+
A team's own image, when the stock image plus a setup script is too slow or cannot hold the toolchain.
|
|
414
|
+
|
|
415
|
+
- Build it `FROM` our runtime image, so it keeps the worker and the harnesses. The public name is
|
|
416
|
+
`public.ecr.aws/orchestraworks/runtime` (until AWS approves that alias: `public.ecr.aws/z8d3m6s5/runtime`).
|
|
417
|
+
Pin it by digest; the Orchestra team gives the current one.
|
|
418
|
+
- Push it to the team's own registry. `Image.fromBuild` builds and pushes it at apply. The environment names
|
|
419
|
+
a pull key Secret in `imagePullCredential` (`provisionSpec.imagePullSecretId` on the platform), made with
|
|
420
|
+
`SecretValue.registryCredential(<user>, <password>)` or `SecretValue.ecrCredential(<key id>, <secret>)`.
|
|
421
|
+
The platform reads it at each machine create, and never gives it to the agent. The bug-fix starter's
|
|
422
|
+
`main.ts` shows the code.
|
|
423
|
+
- Not released yet: a registry hosted by Orchestra.
|
|
424
|
+
- A custom image applies to `microvm`. An EC2 VM starts from our machine image, not from a container image.
|
|
425
|
+
|
|
426
|
+
#### On this computer
|
|
427
|
+
|
|
428
|
+
`orchestra local` runs Linux containers only, on Docker Desktop, OrbStack or Docker Engine. On an
|
|
429
|
+
Apple-silicon Mac it runs an `amd64` environment natively as `arm64` when the image carries that pair, and
|
|
430
|
+
never by emulation. Docker set to Windows containers is refused.
|
|
431
|
+
|
|
432
|
+
A Windows agent runs locally only as an enrolled machine: `orchestra outpost up --agent <id>` on a Windows
|
|
433
|
+
PC, against the local environment (section 4, "Host outpost"). Use it to work out the build, run and test
|
|
434
|
+
commands before the cloud.
|
|
435
|
+
|
|
436
|
+
Locally the network edge does nothing: no egress rule is enforced, no key is added, and no certificate is
|
|
437
|
+
re-signed. The cloud proves those.
|
|
438
|
+
|
|
439
|
+
#### Which to pick
|
|
440
|
+
|
|
441
|
+
Pick `microvm` when the code runs on Linux, with or without Docker. This is most code.
|
|
442
|
+
Pick `vm` when the code needs Windows, an Android device or a kernel of its own.
|
|
443
|
+
Pick `host` when the code must run on the team's own machine, such as a Mac.
|
|
444
|
+
|
|
335
445
|
### A. Containers on Linux
|
|
336
446
|
|
|
337
447
|
Choose A when the code and its services run on Linux, in Docker, Docker Compose, or a setup script. Most
|
|
@@ -349,7 +459,7 @@ agent can run the team's own `docker compose up` unchanged.
|
|
|
349
459
|
machine's processes, the agent included, read every value.
|
|
350
460
|
3. Put each dev server's port in `PORTS`, with a short name. The agent can then show the app at a
|
|
351
461
|
*machine endpoint*, a web address that only signed-in members of the organization can open.
|
|
352
|
-
4. Write the app's own settings files (`.env.local`) into the Set up item's
|
|
462
|
+
4. Write the app's own settings files (`.env.local`) into the Set up item's description, because the code
|
|
353
463
|
is not on the machine when the setup script runs. Put only local or test values there. A real secret
|
|
354
464
|
becomes a Secret plus a rule that adds it.
|
|
355
465
|
5. Choose the size by what CI uses for the same work. The template's sizes are fixed per agent: lg is
|
|
@@ -358,6 +468,28 @@ agent can run the team's own `docker compose up` unchanged.
|
|
|
358
468
|
the inner Docker's images across machine starts (next part).
|
|
359
469
|
7. Not released yet: `workingDirectory`, the folder where every conversation starts. Today each agent clones
|
|
360
470
|
or uses its code under `/work` in its own first turn, as the starter's agents do.
|
|
471
|
+
8. To keep the agent's home, such as a harness sign-in, across machines, mount one volume at `/home` on
|
|
472
|
+
every environment that shares it. Make the volume once with `npx orchestra volumes create`, then add
|
|
473
|
+
`volumeMounts: [{ volume: Volume.fromSlug(factory, "<slug>"), mountPath: "/home" }]`. Without it,
|
|
474
|
+
nothing in `/home` outlives the machine.
|
|
475
|
+
|
|
476
|
+
#### Network
|
|
477
|
+
|
|
478
|
+
Egress starts open, and stays open for the first run: `EgressPolicy.allowAll()`. Any host is reachable, and
|
|
479
|
+
only the hosts that need a key, such as the model gateway, have rules that add one. Never close it while the
|
|
480
|
+
factory is being set up.
|
|
481
|
+
|
|
482
|
+
Tightening is a later, optional step, after the factory works and the developer asks for it:
|
|
483
|
+
|
|
484
|
+
1. Start from `EgressPolicy.denyAll()`. A host that no rule allows is refused.
|
|
485
|
+
2. Add `applyPreset(egressPreset.softwareDevelopment())`: package and container registries, and reads
|
|
486
|
+
from common services, with no key.
|
|
487
|
+
3. Keep `routeModelsViaGateway(...)` or the model key's rule, and every token or connection rule.
|
|
488
|
+
4. Add one `allow` rule for each other host the agents reach, with `priority: 100` and the methods it needs.
|
|
489
|
+
|
|
490
|
+
Prove the closed list on Orchestra's cloud, not locally: a local run enforces no egress rule ("On this
|
|
491
|
+
computer" above). Apply the tightened policy, then ask an agent to run the build and the tests once on a cloud
|
|
492
|
+
machine. A refused host shows as `destination is not allowed` (`troubleshooting.md`).
|
|
361
493
|
|
|
362
494
|
#### Setup script or a baked image
|
|
363
495
|
|
|
@@ -392,27 +524,152 @@ Choose B when the code needs a particular kernel or operating system.
|
|
|
392
524
|
|
|
393
525
|
- **Windows:** possible. Set `platform: { os: "windows", arch: "amd64", runtime: "vm" }` on the
|
|
394
526
|
environment. A Windows machine is a full EC2 virtual machine with 4 or 8 CPU. Docker data disks are not
|
|
395
|
-
available on Windows, so remove `disks` and the Docker setup. The Linux `setup.sh` cannot run there
|
|
396
|
-
|
|
527
|
+
available on Windows, so remove `disks` and the Docker setup. The Linux `setup.sh` cannot run there: write
|
|
528
|
+
a PowerShell script from "A Windows setup script" below. Follow "Windows in three stages" in section 5.
|
|
397
529
|
- **Linux on a full VM:** possible with `runtime: "vm"`, at 2, 4 or 8 CPU.
|
|
398
530
|
- **macOS:** only as the team's own Mac, enrolled with the worker. Say what that needs before you offer it
|
|
399
531
|
(the orchestra skill, section 18), and agree it with the Orchestra team first.
|
|
400
532
|
|
|
401
|
-
###
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
533
|
+
### A Windows setup script
|
|
534
|
+
|
|
535
|
+
Tried by us: not yet.
|
|
536
|
+
|
|
537
|
+
A Windows machine runs the setup script with PowerShell 5.1 (`powershell -NonInteractive -NoProfile
|
|
538
|
+
-ExecutionPolicy Bypass -File setup.ps1`), as the worker's service account, once per machine. A parked VM that
|
|
539
|
+
starts again does not run it again. A new VM does, for example after `ttl` deletes the old one. So write each
|
|
540
|
+
step so that it can run again: check before you install, as the template does. Start from this template. Keep the steps in this order, and give each one its own exit code. The work folder is
|
|
541
|
+
`C:\work\code`. The setup script does not clone the code. It runs before any code host key exists, so a
|
|
542
|
+
clone of a private repository fails, and the machine start fails with it. The agent clones the code in its
|
|
543
|
+
turn, from a git bundle or a public address (`phases/5-prove.md`, section 1).
|
|
544
|
+
|
|
545
|
+
```powershell
|
|
546
|
+
$ErrorActionPreference = 'Stop'
|
|
547
|
+
$ProgressPreference = 'SilentlyContinue'
|
|
548
|
+
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
549
|
+
|
|
550
|
+
# 10: the egress edge's certificate authority is trusted machine-wide. The worker hands the script its path.
|
|
551
|
+
$ca = $env:GIT_SSL_CAINFO
|
|
552
|
+
if ($ca) {
|
|
553
|
+
try {
|
|
554
|
+
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($ca)
|
|
555
|
+
if (-not (Test-Path "Cert:\LocalMachine\Root\$($cert.Thumbprint)")) {
|
|
556
|
+
Import-Certificate -FilePath $ca -CertStoreLocation Cert:\LocalMachine\Root | Out-Null
|
|
557
|
+
}
|
|
558
|
+
} catch { Write-Output "trusting the edge authority failed: $_"; exit 10 }
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
# 11: the work folder, for the service account and the administrators only.
|
|
562
|
+
try { New-Item -ItemType Directory -Force -Path C:\work | Out-Null } catch { exit 11 }
|
|
563
|
+
icacls C:\work /inheritance:r /grant:r '*S-1-5-18:(OI)(CI)F' '*S-1-5-32-544:(OI)(CI)F' | Out-Null
|
|
564
|
+
if ($LASTEXITCODE -ne 0) { exit 11 }
|
|
565
|
+
|
|
566
|
+
# 12: Git for Windows. Set the version the team uses.
|
|
567
|
+
$git = 'C:\Program Files\Git\cmd\git.exe'
|
|
568
|
+
if (-not (Test-Path $git)) {
|
|
569
|
+
$version = '<version, such as 2.47.1>'
|
|
570
|
+
$installer = 'C:\work\git-setup.exe'
|
|
571
|
+
try {
|
|
572
|
+
Invoke-WebRequest -UseBasicParsing -OutFile $installer `
|
|
573
|
+
-Uri "https://github.com/git-for-windows/git/releases/download/v$version.windows.1/Git-$version-64-bit.exe"
|
|
574
|
+
} catch { exit 12 }
|
|
575
|
+
$run = Start-Process -FilePath $installer -ArgumentList '/VERYSILENT', '/NORESTART', '/NOCANCEL', '/SP-' -Wait -PassThru
|
|
576
|
+
if ($run.ExitCode -ne 0) { exit 12 }
|
|
577
|
+
}
|
|
578
|
+
# For the rest of this script only. The agent does not get this PATH.
|
|
579
|
+
$env:Path = "C:\Program Files\Git\cmd;$env:Path"
|
|
580
|
+
|
|
581
|
+
# 13: git trusts the Windows certificate store, for every process on the machine.
|
|
582
|
+
& $git config --system http.sslBackend schannel
|
|
583
|
+
if ($LASTEXITCODE -ne 0) { exit 13 }
|
|
584
|
+
|
|
585
|
+
# 14 and on: the team's toolchain that fits in the time limit, one exit code per step.
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
Why each step is there:
|
|
589
|
+
|
|
590
|
+
- `$ErrorActionPreference = 'Stop'` stops on a failing PowerShell command, but not on a failing program such as
|
|
591
|
+
`icacls` or `git`. So each program call is followed by a `$LASTEXITCODE` check that exits non-zero.
|
|
592
|
+
- The worker already imports the edge's authority into `Cert:\LocalMachine\Root` before the script runs, and
|
|
593
|
+
logs a failure without stopping. Step 10 checks it, and imports it when it is missing. The worker sets each
|
|
594
|
+
certificate variable a harness reads, `GIT_SSL_CAINFO` among them, to the authority's file.
|
|
595
|
+
- PowerShell 5.1 does not always offer TLS 1.2, so a download can fail before it reaches the edge.
|
|
596
|
+
- The Windows image has no git.
|
|
597
|
+
- The agent does not find git on its PATH. Its PATH is the worker's, fixed when the worker started, before
|
|
598
|
+
the setup script ran. The installer's change to the machine PATH and the script's `$env:Path` do not
|
|
599
|
+
reach it. So the agent calls git by its full path, `C:\Program Files\Git\cmd\git.exe`. Write this in the
|
|
600
|
+
agent's instructions or in the codebase skill.
|
|
601
|
+
- Git for Windows reads its own certificate bundle, not the Windows store. The worker sets `GIT_SSL_CAINFO` for
|
|
602
|
+
the setup script and the harness only, so git run any other way fails on the edge's certificate. The
|
|
603
|
+
`schannel` setting makes every git on the machine read the Windows store.
|
|
604
|
+
- The SIDs `S-1-5-18` (the service account, LocalSystem) and `S-1-5-32-544` (the administrators) work on every
|
|
605
|
+
language of Windows, where the account names do not. On Windows the agent runs as the worker's account.
|
|
606
|
+
- The setup script has 10 minutes, and the limit is fixed for now. A toolchain such as Visual Studio Build
|
|
607
|
+
Tools can take 10 to 20 minutes to install. Leave such an install to the agent's first turn: a Windows
|
|
608
|
+
machine is parked when idle and keeps its disk, so it stays installed. The agent waits for the install in
|
|
609
|
+
the turn: a park kills an install that is still running. A process the setup script leaves running is
|
|
610
|
+
killed the same way. For machines that start with it
|
|
611
|
+
installed, use the team's own image ("Windows in three stages", stage 2).
|
|
612
|
+
- The output is kept as it is. Never print a token.
|
|
613
|
+
|
|
614
|
+
### C. Where the machines run, when the code needs private services
|
|
615
|
+
|
|
616
|
+
Choose here when development needs a database, internal APIs or a package feed inside the team's network
|
|
617
|
+
or cloud. List what the code needs, host by host, before you choose.
|
|
618
|
+
|
|
619
|
+
| | Hosted | A compute provider in their cloud | Their own machine | The whole platform in their cloud |
|
|
620
|
+
|---|---|---|---|---|
|
|
621
|
+
| Benefit | The simplest start. Nothing to run. Keys added at our network edge, machine endpoints and views, machines kept ready, and we keep it running. | Keeps their setup, networks, images and private services inside their own cloud, under their own account and controls. | Their own machine or network, as it is. | Nothing leaves their cloud. |
|
|
622
|
+
| What reaches what | Our machines reach their services over the internet, through the network edge | Their Launcher asks our platform for orders over HTTPS. Their machines connect out to our platform. Nothing connects in. | The worker on their machine connects out to our platform | All inside their cloud |
|
|
623
|
+
| Where keys live | Secrets, added at our network edge | On their machines, set by their own boot step. No network edge of ours stands in front of their machines yet | On their machine | In their cloud |
|
|
624
|
+
| Where files rest | Our object store (S3) | Not stated yet | Not stated yet | Their cloud |
|
|
625
|
+
| Setup | None | Make a compute provider record, deploy the Launcher template to their Azure subscription, name the record in `provisionSpec.computeProviderId` | Enroll the machine (`orchestra worker enroll`) | An installation of the platform's Helm chart |
|
|
626
|
+
| Status | Released | Released on Azure. Not released yet: AWS | Released | Not released yet |
|
|
627
|
+
|
|
628
|
+
Pick hosted when the private services can be reached over the internet with a key.
|
|
629
|
+
Pick a compute provider when the services must stay inside their cloud, and they use Azure.
|
|
630
|
+
Pick their own machine when the code needs one machine they already run, such as a Mac.
|
|
631
|
+
|
|
632
|
+
Tell the developer the benefit of each choice first. The limits are for troubleshooting. Do not lead with
|
|
633
|
+
them when you present the choice.
|
|
634
|
+
|
|
635
|
+
Cannot do:
|
|
636
|
+
|
|
637
|
+
- Hosted: reach a service that is not on the internet.
|
|
638
|
+
- A compute provider: run on AWS or Google Cloud; run on arm64; keep `/home` on a Kata pod target; add
|
|
639
|
+
keys at our network edge.
|
|
640
|
+
|
|
641
|
+
Tokens on a compute provider's machines:
|
|
642
|
+
|
|
643
|
+
- The team manages every credential on their own machines. The platform delivers none there.
|
|
644
|
+
- The model sign-in goes in the worker service's own environment, by harness:
|
|
645
|
+
- `claude` with a Claude subscription token: `ORCHESTRA_WORKER_CLAUDE_OAUTH_TOKEN`.
|
|
646
|
+
- `claude` with an Anthropic API key or an Orchestra gateway key: `ANTHROPIC_API_KEY`. This value
|
|
647
|
+
replaces the placeholder that our image sets. With a gateway key, keep the agent's model gateway on:
|
|
648
|
+
the platform sets the gateway address.
|
|
649
|
+
- `codex`: `ORCHESTRA_WORKER_OPENAI_API_KEY`, or `ORCHESTRA_WORKER_CODEX_PERSONAL_ACCESS_TOKEN`.
|
|
650
|
+
- On Windows, the worker service is `SfdkWorker`, and its environment is the service's `Environment`
|
|
651
|
+
registry value.
|
|
652
|
+
- Other tokens, such as for git, a package feed or an Azure DevOps personal access token: the team's own
|
|
653
|
+
boot step sets them. For example, the step reads their Key Vault with a managed identity on the VM.
|
|
654
|
+
- The worker reads its environment when its service starts. So the boot step runs before the worker
|
|
655
|
+
starts, or restarts the worker service after it sets the values. On our Windows image, the startup task
|
|
656
|
+
`orchestra-azure-userdata` starts `SfdkWorker` at each boot.
|
|
657
|
+
- Do not put a token in the environment's `env` (`provisionSpec.env`). The platform stores it, an
|
|
658
|
+
environment read returns it, and it travels in plain text in the VM's startup data.
|
|
659
|
+
- The Launcher attaches no managed identity to the VMs it creates. The team's automation finds the VMs by
|
|
660
|
+
two tags: `orchestra-launcher` holds the compute provider record's id, and `orchestra-machine` holds
|
|
661
|
+
the machine's id. Not released yet: a managed identity attached when the Launcher creates a VM.
|
|
662
|
+
- Never bake a credential into an image: that is not supported.
|
|
663
|
+
- Not released yet: our network edge for machines in the team's own network, which adds keys from
|
|
664
|
+
Secrets as it does for hosted machines.
|
|
665
|
+
|
|
666
|
+
The Launcher's VM targets use the `Dsv5` size family by default. A subscription with no `Dsv5` capacity
|
|
667
|
+
sets `vmSizeFamily: Dsv6` on each VM target in the Launcher's settings.
|
|
668
|
+
- Their own machine: hold network rules; add keys at the edge; start a machine on demand.
|
|
669
|
+
|
|
670
|
+
When no choice fits, write down what is missing and stop here. Report it to the developer, and go back to
|
|
671
|
+
the orchestra-fdk skill. They can still see a first fix on the todo sample, or on the parts of the code
|
|
672
|
+
that need no private service.
|
|
416
673
|
|
|
417
674
|
## 6. Write and check
|
|
418
675
|
|
|
@@ -421,38 +678,89 @@ Write down what is missing and stop here. Report it to the developer, and go bac
|
|
|
421
678
|
2. In `<factory>`, run `npm run typecheck`, then `npx orchestra fdk synth`. The starter is one program, at the folder's
|
|
422
679
|
root.
|
|
423
680
|
3. Read `<factory>/fdk.out/plan.json`. Every environment has your setup script, ports and settings, and
|
|
424
|
-
the model rule
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
681
|
+
the model rule of the orchestra-fdk skill's phase 2: the `model-gateway` rule, or a Secret's rule on the
|
|
682
|
+
provider's host. On a new factory, no environment has a code host or tracker rule yet: phase 3 adds them
|
|
683
|
+
after the first run. On an existing factory, with its token file loaded, the rules it has now stay as
|
|
684
|
+
they are.
|
|
428
685
|
4. Write `ENVIRONMENT.md` in `<factory>`: what you found and where, the mode you proved in and its result
|
|
429
686
|
for each success criterion, the commands, every outbound attempt the proof logged, and what is still
|
|
430
687
|
unknown.
|
|
431
688
|
|
|
432
689
|
**Check:** the typecheck and the synth pass, and the plan is as in item 3. Go back to the orchestra-fdk
|
|
433
|
-
|
|
690
|
+
skill's phase 4 for the apply.
|
|
434
691
|
|
|
435
692
|
## 7. The cloud
|
|
436
693
|
|
|
437
694
|
The cloud is the fallback when no local mode can run. It is also the confirmation after the local proof:
|
|
438
|
-
the
|
|
439
|
-
|
|
440
|
-
|
|
695
|
+
the Set up item, which phase 5 of the orchestra-fdk skill starts. It proves what only the cloud can: the
|
|
696
|
+
micro VM, Docker, the network edge and the machine endpoints. The Engineer Agents start each item from a git
|
|
697
|
+
bundle, so Set up also proves the tests run from one.
|
|
441
698
|
|
|
442
699
|
It is slower. Each try is an apply plus a machine start, and access problems show one at a time.
|
|
443
700
|
|
|
444
|
-
To prove in the cloud, write the environment as in sections 5 and 6, apply it, and run Set up
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
1.
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
701
|
+
To prove in the cloud, write the environment as in sections 5 and 6, apply it, and run Set up. Egress stays
|
|
702
|
+
open. Keep the safety rule this way:
|
|
703
|
+
|
|
704
|
+
1. Use only local settings in the Set up item's description.
|
|
705
|
+
2. Ask the Manager Agent to note any production host it sees in a setting or a log, and to continue.
|
|
706
|
+
|
|
707
|
+
When a step fails, fix it here, prove the fix locally if a local mode runs, apply again, and assign Set up
|
|
708
|
+
again. `troubleshooting.md` names each failure.
|
|
709
|
+
|
|
710
|
+
### The model in the cloud: subscription, model gateway, or own key via the vault
|
|
711
|
+
|
|
712
|
+
The cloud agents reach a model in one of three ways. Ask the developer which one, and walk them through
|
|
713
|
+
its steps once. They copy every value themselves; you never read, print or copy it.
|
|
714
|
+
|
|
715
|
+
1. **Subscription: their own Claude or Codex sign-in.** Follow the sign-in steps below.
|
|
716
|
+
2. **Model gateway: Orchestra provides the key.** One endpoint reaches OpenAI, Anthropic and open-source
|
|
717
|
+
models, on the organization's credits. They can also bring their own provider key to the gateway, with
|
|
718
|
+
`orchestra fdk init --model-key anthropic` or `openai`. The gateway also routes models:
|
|
719
|
+
`orchestra model-configs` sets which providers serve a model and in what order, so a call falls back to
|
|
720
|
+
the next one when a provider is down, and `orchestra model-aliases` gives a model a name of their own, such as `default`.
|
|
721
|
+
3. **Own API key via the vault.** Their Anthropic or OpenAI API key is a platform Secret, added at the
|
|
722
|
+
network edge on calls straight to `api.anthropic.com` or `api.openai.com`, with no gateway in between
|
|
723
|
+
and with the agent's gateway setting off. Nothing to sync, because an API key does not renew. When they
|
|
724
|
+
have an API key, recommend this over a subscription: no file to copy and no shared `/home`.
|
|
725
|
+
`references/authoring.md` § How the agents reach a model shows the declaration.
|
|
726
|
+
|
|
727
|
+
The sign-in steps. The developer makes the sign-in in a real terminal on their computer; run from an
|
|
728
|
+
agent's shell, its browser step hangs.
|
|
729
|
+
|
|
730
|
+
- **Claude: a long-lived token in a Secret, the recommended way.** `claude setup-token` prints an
|
|
731
|
+
`sk-ant-oat…` token made for servers. It lasts about a year, and nothing on a machine renews or revokes
|
|
732
|
+
it, so it needs no shared `/home`. Save it to a file only the developer can read, never through a chat:
|
|
733
|
+
copy it, then `umask 077 && pbpaste | tr -d '\n' > <file> && pbcopy </dev/null`. At apply, the shell
|
|
734
|
+
exports it from that file into the variable a `Secret` reads. An egress rule allows `api.anthropic.com`
|
|
735
|
+
and adds `Authorization: Bearer ${secret}`, removing `x-api-key`. The environment's `env` holds only
|
|
736
|
+
`CLAUDE_CODE_OAUTH_TOKEN=software-factory-egress-placeholder` and an empty `ANTHROPIC_API_KEY`, and the
|
|
737
|
+
agent's gateway setting is off. Never put the token itself in `env`. The Claude sign-in recipe in
|
|
738
|
+
`references/authoring.md` shows the declaration. Copying the renewing credentials file is the fallback,
|
|
739
|
+
and follows the ChatGPT sign-in steps below.
|
|
740
|
+
- **Codex: a personal access token, where the workspace allows one.** A ChatGPT Business or Enterprise
|
|
741
|
+
member creates it at chatgpt.com/admin/access-tokens, once the workspace owner allows access tokens,
|
|
742
|
+
and chooses how long it lasts, such as 7 to 90 days. Codex never renews it, so it needs no shared
|
|
743
|
+
`/home`; the developer supplies a new one before it expires. It begins `at-` and goes in
|
|
744
|
+
`ORCHESTRA_WORKER_CODEX_PERSONAL_ACCESS_TOKEN`, which outranks a ChatGPT sign-in or an API key beside
|
|
745
|
+
it. On their own computer, `codex login --with-access-token` reads the same token from standard input.
|
|
746
|
+
- **Codex otherwise: a separate ChatGPT sign-in on a shared `/home`.** The other long-lived choice is an
|
|
747
|
+
OpenAI API key, billed by use rather than by the subscription (option 3).
|
|
748
|
+
1. **Make a separate sign-in, never a copy of the local one:** `mkdir -p <dir> && CODEX_HOME=<dir> codex
|
|
749
|
+
login` (`--device-auth` only with no browser). Its tokens in `<dir>/auth.json` go in the
|
|
750
|
+
`ORCHESTRA_WORKER_CODEX_` variables, or a setup step writes the file.
|
|
751
|
+
2. **Give the environment a durable `/home` volume,** shared by every machine that uses the sign-in, so
|
|
752
|
+
one file renews for all of them. Each renewal replaces the refresh token, so separate copies sign
|
|
753
|
+
each other out; two machines that renew in the same second can too, and then need a new sign-in.
|
|
754
|
+
Remove the variables after the first machine starts.
|
|
755
|
+
3. **Never sign in again in the default folder after the copy.** A new `codex login` in `~/.codex`
|
|
756
|
+
revokes the cloud copy, and every machine answers "refresh token was revoked". If it happened, make
|
|
757
|
+
a new separate sign-in.
|
|
758
|
+
- **Keep a Codex sign-in off an agent that uses the model gateway.** With a ChatGPT sign-in or a personal
|
|
759
|
+
access token, Codex compresses its requests, and the gateway refuses them with `model_not_found`, a
|
|
760
|
+
known issue. Give such an agent the subscription directly, with its gateway setting off, or keep the
|
|
761
|
+
homes apart.
|
|
762
|
+
|
|
763
|
+
The sign-in values are plain text: the environment's settings are stored unencrypted and shown on every read.
|
|
456
764
|
|
|
457
765
|
## What the platform can do
|
|
458
766
|
|
|
@@ -460,8 +768,9 @@ Use the orchestra skill to build an answer for a case the paths do not cover. Ne
|
|
|
460
768
|
yet" lines. The sections this work needs:
|
|
461
769
|
|
|
462
770
|
- Section 4: environments, machines, sizes, images, setup scripts, disks, Windows and full VMs.
|
|
463
|
-
- Section 5: network rules, their live effect on running machines
|
|
771
|
+
- Section 5: network rules, and their live effect on running machines.
|
|
464
772
|
- Section 6: secrets, and where their values come from.
|
|
465
773
|
- Section 7: the model gateway rule every environment needs.
|
|
466
|
-
- Section 17: connections
|
|
774
|
+
- Section 17: connections. The files under `references/integrations/` say how to give access to each
|
|
775
|
+
service.
|
|
467
776
|
- Section 18: the team's own machines, the local environment, and private networks.
|