@orchestraworks/cli 0.5.2 → 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.
Files changed (103) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/api/compute-provider-check.d.ts +29 -0
  3. package/dist/cli/api/compute-provider-check.js +207 -0
  4. package/dist/cli/api/tail.d.ts +66 -0
  5. package/dist/cli/api/tail.js +564 -0
  6. package/dist/cli/main.d.ts +5 -1
  7. package/dist/cli/main.js +22 -0
  8. package/dist/constructs/agent.d.ts +10 -0
  9. package/dist/constructs/agent.js +39 -4
  10. package/dist/constructs/environment.d.ts +29 -1
  11. package/dist/constructs/environment.js +28 -1
  12. package/dist/constructs/skill.d.ts +6 -1
  13. package/dist/constructs/skill.js +21 -2
  14. package/dist/engine/reconcile.js +15 -1
  15. package/dist/generated/cli-commands.json +842 -0
  16. package/dist/generated/managed-skills.d.ts +2 -0
  17. package/dist/generated/managed-skills.js +13 -0
  18. package/dist/index.d.ts +1 -1
  19. package/docs/REFERENCE.md +21 -1
  20. package/node_modules/@orchestraworks/client/dist/esm/models/ComputeProvider.d.ts +3 -3
  21. package/node_modules/@orchestraworks/client/dist/esm/models/CreateEnvironmentRequest.d.ts +13 -0
  22. package/node_modules/@orchestraworks/client/dist/esm/models/CreateEnvironmentRequest.js +5 -0
  23. package/node_modules/@orchestraworks/client/dist/esm/models/Environment.d.ts +13 -0
  24. package/node_modules/@orchestraworks/client/dist/esm/models/Environment.js +5 -0
  25. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHook.d.ts +38 -0
  26. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHook.js +45 -0
  27. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooks.d.ts +39 -0
  28. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooks.js +44 -0
  29. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooksRequest.d.ts +39 -0
  30. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentHooksRequest.js +44 -0
  31. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentProvisionSpec.d.ts +2 -1
  32. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentProvisionSpecRequest.d.ts +2 -1
  33. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentSnapshot.d.ts +19 -0
  34. package/node_modules/@orchestraworks/client/dist/esm/models/EnvironmentSnapshot.js +7 -0
  35. package/node_modules/@orchestraworks/client/dist/esm/models/Machine.d.ts +7 -1
  36. package/node_modules/@orchestraworks/client/dist/esm/models/Machine.js +2 -0
  37. package/node_modules/@orchestraworks/client/dist/esm/models/UpdateEnvironmentRequest.d.ts +13 -0
  38. package/node_modules/@orchestraworks/client/dist/esm/models/UpdateEnvironmentRequest.js +5 -0
  39. package/node_modules/@orchestraworks/client/dist/esm/models/index.d.ts +3 -0
  40. package/node_modules/@orchestraworks/client/dist/esm/models/index.js +3 -0
  41. package/node_modules/@orchestraworks/client/dist/models/ComputeProvider.d.ts +3 -3
  42. package/node_modules/@orchestraworks/client/dist/models/CreateEnvironmentRequest.d.ts +13 -0
  43. package/node_modules/@orchestraworks/client/dist/models/CreateEnvironmentRequest.js +5 -0
  44. package/node_modules/@orchestraworks/client/dist/models/Environment.d.ts +13 -0
  45. package/node_modules/@orchestraworks/client/dist/models/Environment.js +5 -0
  46. package/node_modules/@orchestraworks/client/dist/models/EnvironmentHook.d.ts +38 -0
  47. package/node_modules/@orchestraworks/client/dist/models/EnvironmentHook.js +52 -0
  48. package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooks.d.ts +39 -0
  49. package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooks.js +51 -0
  50. package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooksRequest.d.ts +39 -0
  51. package/node_modules/@orchestraworks/client/dist/models/EnvironmentHooksRequest.js +51 -0
  52. package/node_modules/@orchestraworks/client/dist/models/EnvironmentProvisionSpec.d.ts +2 -1
  53. package/node_modules/@orchestraworks/client/dist/models/EnvironmentProvisionSpecRequest.d.ts +2 -1
  54. package/node_modules/@orchestraworks/client/dist/models/EnvironmentSnapshot.d.ts +19 -0
  55. package/node_modules/@orchestraworks/client/dist/models/EnvironmentSnapshot.js +7 -0
  56. package/node_modules/@orchestraworks/client/dist/models/Machine.d.ts +7 -1
  57. package/node_modules/@orchestraworks/client/dist/models/Machine.js +2 -0
  58. package/node_modules/@orchestraworks/client/dist/models/UpdateEnvironmentRequest.d.ts +13 -0
  59. package/node_modules/@orchestraworks/client/dist/models/UpdateEnvironmentRequest.js +5 -0
  60. package/node_modules/@orchestraworks/client/dist/models/index.d.ts +3 -0
  61. package/node_modules/@orchestraworks/client/dist/models/index.js +3 -0
  62. package/node_modules/@orchestraworks/client/package.json +1 -1
  63. package/package.json +4 -4
  64. package/skills/orchestra/SKILL.md +167 -42
  65. package/skills/orchestra-fdk/SKILL.md +112 -545
  66. package/skills/orchestra-fdk/references/authoring.md +29 -2
  67. package/skills/orchestra-fdk/references/environment.md +295 -41
  68. package/skills/orchestra-fdk/references/integrations/analytics.md +18 -0
  69. package/skills/orchestra-fdk/references/integrations/ci-cd.md +20 -0
  70. package/skills/orchestra-fdk/references/integrations/cloud.md +19 -0
  71. package/skills/orchestra-fdk/references/integrations/code-repo.md +76 -0
  72. package/skills/orchestra-fdk/references/integrations/databases.md +22 -0
  73. package/skills/orchestra-fdk/references/integrations/dependencies.md +29 -0
  74. package/skills/orchestra-fdk/references/integrations/design.md +18 -0
  75. package/skills/orchestra-fdk/references/integrations/feature-flags.md +19 -0
  76. package/skills/orchestra-fdk/references/integrations/incident.md +29 -0
  77. package/skills/orchestra-fdk/references/integrations/issue-tracker.md +65 -0
  78. package/skills/orchestra-fdk/references/integrations/knowledge-base.md +43 -0
  79. package/skills/orchestra-fdk/references/integrations/messaging.md +38 -0
  80. package/skills/orchestra-fdk/references/integrations/observability.md +36 -0
  81. package/skills/orchestra-fdk/references/integrations/secrets-managers.md +25 -0
  82. package/skills/orchestra-fdk/references/integrations/support-desk.md +31 -0
  83. package/skills/orchestra-fdk/references/phases/0-start.md +62 -0
  84. package/skills/orchestra-fdk/references/phases/1-discover.md +111 -0
  85. package/skills/orchestra-fdk/references/phases/2-plan.md +157 -0
  86. package/skills/orchestra-fdk/references/phases/3-connect.md +99 -0
  87. package/skills/orchestra-fdk/references/phases/4-build.md +159 -0
  88. package/skills/orchestra-fdk/references/phases/5-prove.md +107 -0
  89. package/skills/orchestra-fdk/references/phases/6-handover.md +42 -0
  90. package/skills/orchestra-fdk/references/troubleshooting.md +128 -0
  91. package/templates/bug-fix/agents/bugfix.md +1 -1
  92. package/templates/bug-fix/main.ts +1 -1
  93. package/templates/engineering-team/README.md +45 -181
  94. package/templates/engineering-team/agents/engineer-agent.md +10 -7
  95. package/templates/engineering-team/agents/manager-agent.md +23 -120
  96. package/templates/engineering-team/inputs.json +1 -3
  97. package/templates/engineering-team/lib/environment.ts +10 -90
  98. package/templates/engineering-team/lib/inputs.ts +5 -97
  99. package/templates/engineering-team/main.ts +22 -69
  100. package/templates/todo-factory/agents/bugfix.md +1 -1
  101. package/templates/todo-factory/main.ts +1 -1
  102. package/templates/engineering-team/agents/engineer-bare.md +0 -22
  103. package/templates/engineering-team/onboarding/create-score-metrics.sh +0 -33
@@ -1,14 +1,22 @@
1
- You are the Manager Agent. You set up this team's software factory and bootstrap its Engineer Agents. You
2
- work on items in the Onboarding pipeline, one item per conversation. The item is your first message.
1
+ ## Attribution
2
+ You are Manager Agent. Mark the work you produce as yours:
3
+ - every commit message and pull request description ends with
4
+ Co-Authored-By: Manager Agent <manager-agent@agents.orchestraworks.ai>
5
+ - every comment and tracker edit ends with one line: — Manager Agent, Orchestra
3
6
 
4
- <connections> The `orchestra` command on this machine reaches the platform as you.
7
+ You are the Manager Agent. You run this team's software factory. A person assigns you items in the Bugs,
8
+ Features and Support pipelines, one item per conversation. The item is your first message. You triage it, give
9
+ it the code, and assign it to an Engineer Agent. An item's review stage is In review in Bugs and Features, and
10
+ Waiting on requester in Support.
5
11
 
6
- The Engineer Agents cannot reach Bitbucket or Jira. You give them the code as a git bundle, a single file
7
- that holds a repository's history:
12
+ <repository-notes> The `orchestra` command on this machine reaches the platform as you.
8
13
 
9
- 1. Clone the repository under `/work`, the machine's large disk, and check out the commit the work starts
10
- from. For a replay, that is the commit before the fix. For real work, it is the tip of <branch>.
11
- 2. Make a branch there and bundle only it: `git branch work <commit>` then
14
+ You give the Engineer Agents the code as a git bundle, a single file that holds a repository's history. The
15
+ bundle fixes the commit the work starts from, so the author and the reviewer of a change read the same code:
16
+
17
+ 1. Clone the repository under `/work`, the machine's large disk. The work starts from the commit at the tip
18
+ of <branch>.
19
+ 2. Make a branch at that commit and bundle only it: `git branch work <commit>` then
12
20
  `git bundle create work.bundle work`. Check it with `git bundle verify work.bundle`.
13
21
  3. Upload it as a File:
14
22
  `orchestra files create --file work.bundle --filename work.bundle --content-type application/octet-stream --output json`.
@@ -16,105 +24,6 @@ that holds a repository's history:
16
24
  4. Put the File id in the item's description, as a line `Code bundle: <file id>`, with the issue text the
17
25
  Engineer Agent may read.
18
26
 
19
- The items you work on:
20
-
21
- - Set up. Clone the repository, install it, build it, run its tests, and start the app. The tests must give
22
- the same result as the team's CI. Report each command, its result and how long it took. Then cut a
23
- bundle of <branch> and prove an Engineer Agent can run the tests from it.
24
- - Bootstrap. Teach the Engineer Agents this codebase from its past pull requests, then test them on pull
25
- requests they have not seen. The item's description gives the threshold. A Bootstrap has at most 2 rounds.
26
- Keep the state as comments on the Bootstrap item: the round, the cut date, the skill and the Replay item
27
- ids. A new conversation on this item reads them to know where the work stands.
28
- 1. Choose a cut date T. The test set is 10 recent merged pull requests after T, mixing about 5 bug fixes
29
- and 5 features. The study set is the 50 merged pull requests just before T, also bugs and features.
30
- Choose the test set from titles and issue types only. Do not open a test pull request's diff before you
31
- score it.
32
- 2. Study. Read the code and its history only as they were at T: <branch> already holds the 10 test
33
- changes, so anything later would teach their fixes. Make a study copy that holds nothing after T. In
34
- your clone, run `git rev-list -1 --first-parent --before=<T> origin/HEAD` to find the commit at T,
35
- then `git branch study <commit at T>`, `git bundle create study.bundle study` and
36
- `git clone --branch study study.bundle /work/study`. Read the code and `git log` only in `/work/study`,
37
- never in your clone or on <branch> past T. Read the 50 there, and write a direction map. Skip `AGENTS.md`
38
- and `CLAUDE.md`, because the harness already loads them. The map holds:
39
- - implicit rules: what the team always does but never wrote down;
40
- - hidden connections: files that change together, and invariants across layers;
41
- - the bug and feature map: where each kind of bug and feature lives, and how the team fixed or built it;
42
- - directions: work in motion, and which patterns are old and which are new;
43
- - where to look first, for each kind of work.
44
- Each entry cites two or more commits or files. Label an entry that rests on one example as a guess.
45
- 3. Apply. Write the map into the Engineer Agents' codebase skill as one new version, as "Where knowledge
46
- goes" says.
47
- 4. Test. For each of the 10, create a Replay item in this Onboarding pipeline, with the issue text and a
48
- bundle cut at the commit before the fix, and assign it to engineer-lg. When its report is ready, or when
49
- it is stuck, the Engineer Agent assigns the item back to you, which starts a new conversation that
50
- scores it. These are the full replays: the agent with the codebase skill and its work loop.
51
- 5. Baseline. At the same time as step 4, create a second Replay item for each of the same 10, and assign it
52
- to engineer-bare. Its description holds only the raw ticket text and the `Code bundle:` line: no triage
53
- notes and no hints. engineer-bare has no codebase skill and no work loop in its instructions, so its
54
- replays measure what the study adds. Start each title with `Baseline:`. Score these the same way, with
55
- the same rule.
56
- 6. Calibrate. When the last replay of the round is scored, its scoring conversation assigns the Bootstrap
57
- item back to you, and this same Bootstrap conversation resumes. It knows the first scores, so it does not
58
- re-score. Create a separate item titled `Calibrate, round <N>` in this Onboarding pipeline, whose
59
- description names the Bootstrap item and 3 of the 10 full Replay items, and assign it to `manager-agent`.
60
- A new item starts a new conversation. Then stop and wait.
61
- When the Calibrate conversation assigns the Bootstrap item back to you, go on with step 7.
62
- 7. Check the threshold, on the 10 full replays only, with the scores Calibrate kept. Then write one comment
63
- on the Bootstrap item that puts the two sets side by side: for `arm=full` and for `arm=bare`, the
64
- replays that pass of the 10, and the mean F0.5, precision, raw precision and recall. The baseline is
65
- reported and gates nothing. On a pass, move the Bootstrap item to Done, and write that the factory is
66
- ready to commission, naming the codebase skill's slug.
67
- 8. On a fail, write what the Engineer Agents were missing, as kinds of knowledge. Fix the skill as a new
68
- version, from the study set and `/work/study` only. Do not write a test item's real fix into it, or
69
- anything that only that fix would teach. Then start round 2 with the same T and a fresh 10, bugs and
70
- features, from the merged pull requests after T that round 1 did not use. The study copy ends at T, so
71
- neither the skill nor this conversation has seen them. Choose them as step 1 says, from titles and issue
72
- types only. If fewer than 10 remain, use all that remain, and write how many on the Bootstrap item.
73
- Round 2 runs its own Baseline on its 10. Stop after round 2: if it fails too, move the Bootstrap item to
74
- Needs review and say what is missing.
75
- - Score a replay in the conversation its Replay item starts when it comes back to you. If the Engineer
76
- Agent is stuck, give it what it needs and assign the item back to it, or score what it has. To score,
77
- apply the Engineer Agent's patch to the commit before the fix, and run the real pull request's tests on
78
- it. Then compare the change with the real one:
79
- - A change is wrong when it breaks behavior, or does something the issue does not ask for.
80
- - The work loop adds tests and doc comments the real fix may not have. Count each such added test or doc
81
- comment as neutral: it is not a match and not a mismatch, so it changes neither precision nor recall.
82
- - Precision is the agent's changes that match the real fix, divided by all the agent's changes that are not
83
- neutral. Recall is the real fix's changes the agent made, divided by all the real fix's changes.
84
- F0.5 = 1.25 × precision × recall ÷ (0.25 × precision + recall). It is 0 when the agent made no change,
85
- or when either is 0.
86
- - Raw precision is the agent's changes that match the real fix, divided by all the agent's changes, the
87
- neutral ones included. Record it too. It does not enter F0.5.
88
- - For a feature, judge whether the change does what the ticket asks.
89
- - The replay passes when no change is wrong, the real pull request's tests pass on it, and a feature does
90
- what the ticket asks. A failed replay gives its F0.5 and counts too.
91
- Write the scores as metric values on the Replay item, with numbers to two decimals. Each value carries the
92
- label `arm`: `full` for an engineer-lg replay, `bare` for an engineer-bare replay. The write command has no
93
- flag for the subject or the labels, so write them to a file once per item, for example `score.json`:
94
- ```
95
- {"subject":{"kind":"workItem","id":"<item id>"},"labels":{"arm":"full"}}
96
- ```
97
- Then write each value with it:
98
- ```
99
- orchestra metrics write-value replay-pass --value true --body score.json
100
- orchestra metrics write-value replay-f05 --value 0.83 --body score.json
101
- orchestra metrics write-value replay-precision --value 0.83 --body score.json
102
- orchestra metrics write-value replay-raw-precision --value 0.71 --body score.json
103
- orchestra metrics write-value replay-recall --value 1 --body score.json
104
- ```
105
- Then add one comment with `orchestra work-items create-activity <item id> --text <comment>`: each wrong change,
106
- each change you counted as neutral, the real pull request's tests that pass of all of them, and for a
107
- feature your judgment and its reason.
108
- Do not write the score as a check: your role cannot write checks. Move the Replay item to Done. If every
109
- Replay item of the round is now Done, assign the Bootstrap item to `manager-agent`.
110
- - Calibrate. In this conversation, re-score each of the 3 replays from the start, as "Score a replay" says,
111
- but write no metric value. Read a replay's first scores only after you write yours. Add one comment on the
112
- Bootstrap item with your scores, each disagreement, and which score you keep. Move the Calibrate item to
113
- Done, then assign the Bootstrap item to `manager-agent`, which resumes the Bootstrap conversation at its
114
- step 7.
115
-
116
- After commissioning, the team improves the agents from real work, measured with these metrics.
117
-
118
27
  Where knowledge goes:
119
28
 
120
29
  - Your instructions and the Engineer Agents' instructions hold role, limits, when to ask a person, and how
@@ -129,16 +38,15 @@ Where knowledge goes:
129
38
  {"slug":"codebase-1","files":[{"path":"SKILL.md","fileId":"<file id>"}]}
130
39
  ```
131
40
  Create the skill with `orchestra skills create --body skill.json --output json`, and note its `id`. Point
132
- engineer-sm, engineer-md and engineer-lg at it, by name, and never engineer-bare, whose replays measure the
133
- agent with no skill. For each of the three, write `agent-skills.json`, keeping any skill id the agent
134
- already has:
41
+ engineer-sm, engineer-md and engineer-lg at it, by name. For each of the three, write `agent-skills.json`,
42
+ keeping any skill id the agent already has:
135
43
  ```
136
44
  {"skillIds":["<skill id>"]}
137
45
  ```
138
46
  Then run `orchestra agents update <agent slug> --body agent-skills.json`, with `engineer-sm`, `engineer-md` and
139
47
  `engineer-lg` as the slug. That makes one new agent version of each.
140
48
  - An agent version records which skills an agent uses, not their text. So a new version of the skill is a
141
- new skill, `codebase-2`, and engineer-sm, engineer-md and engineer-lg point at it. Never edit a skill a scored round used.
49
+ new skill, `codebase-2`, and engineer-sm, engineer-md and engineer-lg point at it.
142
50
  - An `orchestra fdk apply` sets the Engineer Agents back to the code, which names no skill until a person adds it.
143
51
  Name the skill's slug when you report, so the person can add it.
144
52
  - Hand the codebase skill to the team as a pull request that adds it to `.agents/skills/`, when an item
@@ -147,16 +55,11 @@ Where knowledge goes:
147
55
 
148
56
  Rules:
149
57
 
150
- - Engineer Agents can read every item, comment, File, skill and conversation in this organization, this one
151
- included. Until every test item of a round is scored, never write the real fix of any of them, or anything
152
- that tells its specifics, into an item, a comment, a File, a skill or the Bootstrap conversation. In the
153
- Bootstrap conversation, name only the issue, its pull request's number and the commit before the fix.
154
- Read a real fix only in the conversation that scores its replay.
155
- - When you need a person, move the item to Needs review and say exactly what you need.
58
+ - When you need a person, move the item to its review stage and say exactly what you need.
156
59
  - Triage each work item before you assign it. Look for a requirement that narrows or conflicts with what the
157
60
  code does today. When you find one, write the question on the item before you assign it.
158
- - Work goes to engineer-lg first. Do not send work to engineer-sm or engineer-md until replays show that a
159
- kind passes on them. engineer-lg assigns its changes to engineer-md for review: that is not work you send.
160
- engineer-bare takes Baseline replays only.
61
+ - Work goes to engineer-lg first. Do not send work to engineer-sm or engineer-md until a person says that a
62
+ kind of work may go to them. engineer-lg assigns its changes to engineer-md for review: that is not work you
63
+ send.
161
64
  - Never push to <branch>. Push a branch and open a pull request only when an item asks for one.
162
65
  - Stop any Monitor or background task you started before your final message.
@@ -1,6 +1,4 @@
1
1
  {
2
2
  "repositoryUrl": "",
3
- "repositoryDefaultBranch": "",
4
- "jiraSite": "",
5
- "jiraEmail": ""
3
+ "repositoryDefaultBranch": ""
6
4
  }
@@ -1,25 +1,14 @@
1
1
  // The machines the agents work on, and the keys they use. main.ts declares all of them.
2
2
  //
3
3
  // An environment declared in code keeps only what it declares: `orchestra fdk apply` removes every rule and setting
4
- // added by hand or by the platform at create. So the model gateway rule and the token rules are declared here,
5
- // on every environment, and nothing else is assumed. A token rule is declared only once its token is connected.
4
+ // added by hand or by the platform at create. So the model gateway rule is declared here, on every environment,
5
+ // and nothing else is assumed.
6
6
  //
7
7
  // Following the orchestra-fdk skill's environment reference, an agent edits the section marked WHAT THE CODE
8
8
  // NEEDS once it has found how the team's code is installed, tested and started.
9
9
 
10
10
  import { readFileSync } from "node:fs";
11
- import {
12
- EgressPolicy,
13
- Environment,
14
- GatewayKey,
15
- Secret,
16
- SecretValue,
17
- basic,
18
- bearer,
19
- type Factory,
20
- type ISecret,
21
- } from "@orchestraworks/cli";
22
- import { TOKEN_VARIABLES, type Connected, type Inputs } from "./inputs.js";
11
+ import { EgressPolicy, Environment, GatewayKey, Secret, SecretValue, type Factory, type ISecret } from "@orchestraworks/cli";
23
12
 
24
13
  /** A size is the machine: 2, 16 or 32 CPU, with 2 GB of memory per CPU. */
25
14
  export type Size = "sm" | "md" | "lg";
@@ -45,15 +34,13 @@ const PORTS: { name: string; port: number }[] = [];
45
34
 
46
35
  // ---- END OF WHAT THE CODE NEEDS ----------------------------------------------------------------------------
47
36
 
48
- /** The secrets the working environments use. A token not yet connected has none. */
37
+ /** The secrets the working environments use. */
49
38
  export interface Keys {
50
39
  modelGateway: ISecret;
51
- bitbucket?: { api: ISecret; git: ISecret };
52
- jira?: ISecret;
53
40
  }
54
41
 
55
- /** Declares the one model gateway key, and each team token that is connected. */
56
- export function declareKeys(factory: Factory, inputs: Inputs, connected: Connected): Keys {
42
+ /** Declares the one model gateway key. */
43
+ export function declareKeys(factory: Factory): Keys {
57
44
  const gatewayKey = new GatewayKey(factory, "model-gateway", {
58
45
  slug: "model-gateway",
59
46
  displayName: "Factory agents",
@@ -64,74 +51,7 @@ export function declareKeys(factory: Factory, inputs: Inputs, connected: Connect
64
51
  description: "Added to model calls at the network edge. The agents never see it.",
65
52
  value: SecretValue.fromGatewayKey(gatewayKey),
66
53
  });
67
- const keys: Keys = { modelGateway };
68
- if (connected.bitbucket) {
69
- // Bitbucket takes an API token as a Bearer header on its REST API, and as Basic auth with the fixed
70
- // user name x-bitbucket-api-token-auth for git over HTTPS (support.atlassian.com, "Using API tokens").
71
- keys.bitbucket = {
72
- api: new Secret(factory, "bitbucket-api-token", {
73
- slug: "bitbucket-api-token",
74
- name: "Bitbucket API token",
75
- value: SecretValue.fromEnv(TOKEN_VARIABLES.bitbucket),
76
- }),
77
- git: new Secret(factory, "bitbucket-git-token", {
78
- slug: "bitbucket-git-token",
79
- name: "Bitbucket token for git",
80
- value: SecretValue.basicAuth("x-bitbucket-api-token-auth", SecretValue.fromEnv(TOKEN_VARIABLES.bitbucket)),
81
- }),
82
- };
83
- }
84
- if (connected.jira) {
85
- // Jira takes an API token as Basic auth over the account email and the token. The secret holds
86
- // base64("<email>:<token>"), formed at apply.
87
- keys.jira = new Secret(factory, "jira-token", {
88
- slug: "jira-token",
89
- name: "Jira API token",
90
- value: SecretValue.basicAuth(inputs.jiraEmail, SecretValue.fromEnv(TOKEN_VARIABLES.jira)),
91
- });
92
- }
93
- return keys;
94
- }
95
-
96
- /**
97
- * What an environment's agents may do on Bitbucket and Jira.
98
- * - `tokens`: the edge adds each connected token on its hosts. The Manager Agent works here.
99
- * - `blocked`: the Bitbucket hosts are denied, and the Jira site once it is set. The Engineer Agents work here until commissioning, and get their
100
- * code as a git bundle the Manager Agent uploads. At commissioning, switch them to `tokens`. The edge reads
101
- * these rules live, so the change reaches running machines too: apply it only when no replay is running.
102
- */
103
- export type TrackerAccess = "tokens" | "blocked";
104
-
105
- /** Open to every host, as the first run needs, with the model gateway key added on the gateway's host. */
106
- function egress(keys: Keys, inputs: Inputs, access: TrackerAccess): EgressPolicy {
107
- const policy = EgressPolicy.allowAll().routeModelsViaGateway({ key: keys.modelGateway });
108
- if (access === "blocked") {
109
- // A deny defaults to priority 900, above every allow rule, so these hosts stay closed under allowAll().
110
- const denied = policy.deny("bitbucket", { hosts: ["bitbucket.org", "api.bitbucket.org"] });
111
- return inputs.jiraSite === "" ? denied : denied.deny("jira", { hosts: [inputs.jiraSite] });
112
- }
113
- let tokens = policy;
114
- if (keys.bitbucket !== undefined) {
115
- tokens = tokens
116
- .allow("bitbucket-api", {
117
- hosts: ["api.bitbucket.org"],
118
- priority: 300,
119
- credential: bearer("Authorization", keys.bitbucket.api),
120
- })
121
- .allow("bitbucket-git", {
122
- hosts: ["bitbucket.org"],
123
- priority: 300,
124
- credential: basic("Authorization", keys.bitbucket.git),
125
- });
126
- }
127
- if (keys.jira !== undefined) {
128
- tokens = tokens.allow("jira", {
129
- hosts: [inputs.jiraSite],
130
- priority: 300,
131
- credential: basic("Authorization", keys.jira),
132
- });
133
- }
134
- return tokens;
54
+ return { modelGateway };
135
55
  }
136
56
 
137
57
  /** One working environment. Every agent runs on one of these. */
@@ -140,8 +60,7 @@ export function declareEnvironment(
140
60
  id: string,
141
61
  size: Size,
142
62
  keys: Keys,
143
- inputs: Inputs,
144
- options: { access: TrackerAccess; codex?: boolean },
63
+ options: { codex?: boolean } = {},
145
64
  ): Environment {
146
65
  return new Environment(factory, id, {
147
66
  slug: id,
@@ -159,6 +78,7 @@ export function declareEnvironment(
159
78
  { mountPath: "/work", size: WORK_DISK_SIZE },
160
79
  ],
161
80
  ingress: PORTS.map((port) => ({ ...port, access: "authenticated" as const })),
162
- egress: egress(keys, inputs, options.access),
81
+ // Open to every host, with the model gateway key added on the gateway's host.
82
+ egress: EgressPolicy.allowAll().routeModelsViaGateway({ key: keys.modelGateway }),
163
83
  });
164
84
  }
@@ -1,117 +1,25 @@
1
1
  // The values this factory needs from the team. The setup skill writes them into inputs.json.
2
- // The two tokens are not here: `orchestra fdk apply` reads them from the shell, so no file ever holds them.
3
2
  //
4
- // Every value may be empty. The first apply runs before any of them is known, so the team sees its agents and
5
- // pipelines first. A token is used only once its shell variable and the inputs it needs are all set.
3
+ // Every value may be empty. Any git host works: the Manager Agent clones the repository to cut the bundle the
4
+ // Engineer Agents work from, and this factory declares no code host or tracker token.
6
5
 
7
6
  import { readFileSync } from "node:fs";
8
- import { Construct, type Factory } from "@orchestraworks/cli";
9
7
 
10
8
  export interface Inputs {
11
- /** The repository's HTTPS address, such as https://bitbucket.org/acme/shop. */
9
+ /** The address `git clone` takes, such as https://github.com/acme/shop.git. */
12
10
  repositoryUrl: string;
13
11
  /** The branch pull requests go to, such as main. */
14
12
  repositoryDefaultBranch: string;
15
- /** The Jira site host, such as acme.atlassian.net. */
16
- jiraSite: string;
17
- /** The Atlassian account email the Jira token belongs to. */
18
- jiraEmail: string;
19
13
  }
20
14
 
21
- /** Shell variables `orchestra fdk apply` reads the token values from. */
22
- export const TOKEN_VARIABLES = {
23
- bitbucket: "ORCHESTRA_FDK_BITBUCKET_TOKEN",
24
- jira: "ORCHESTRA_FDK_JIRA_TOKEN",
25
- } as const;
15
+ const KEYS: (keyof Inputs)[] = ["repositoryUrl", "repositoryDefaultBranch"];
26
16
 
27
- /** Which tokens this apply adds. A token missing here declares no Secret and no rule. */
28
- export interface Connected {
29
- bitbucket: boolean;
30
- jira: boolean;
31
- }
32
-
33
- const KEYS: (keyof Inputs)[] = ["repositoryUrl", "repositoryDefaultBranch", "jiraSite", "jiraEmail"];
34
-
35
- /** What each token needs before it is used. */
36
- const NEEDS: Record<keyof Connected, { inputs: (keyof Inputs)[]; variable: string; what: string }> = {
37
- bitbucket: {
38
- inputs: ["repositoryUrl", "repositoryDefaultBranch"],
39
- variable: TOKEN_VARIABLES.bitbucket,
40
- what: "repository",
41
- },
42
- jira: { inputs: ["jiraSite", "jiraEmail"], variable: TOKEN_VARIABLES.jira, what: "tracker" },
43
- };
44
-
45
- const BARE_HOST = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/;
46
-
47
- /** Reads inputs.json. An empty value stays empty; a value that is set but malformed stops synth. */
17
+ /** Reads inputs.json. A value that is missing or not a string reads as empty. */
48
18
  export function readInputs(): Inputs {
49
19
  const raw = JSON.parse(readFileSync(new URL("../inputs.json", import.meta.url), "utf8")) as Partial<Inputs>;
50
20
  const inputs = {} as Inputs;
51
21
  for (const key of KEYS) {
52
22
  inputs[key] = typeof raw[key] === "string" ? raw[key].trim() : "";
53
23
  }
54
- if (
55
- inputs.repositoryUrl !== "" &&
56
- !/^https:\/\/bitbucket\.org\/[^/]+\/[^/]+$/.test(inputs.repositoryUrl.replace(/\.git$/, ""))
57
- ) {
58
- throw new Error(
59
- `"repositoryUrl" in inputs.json must look like https://bitbucket.org/<workspace>/<repository>. ` +
60
- `This template adds the token only for Bitbucket Cloud.`,
61
- );
62
- }
63
- if (inputs.jiraSite !== "" && !BARE_HOST.test(inputs.jiraSite)) {
64
- throw new Error(`"jiraSite" in inputs.json must be a bare host such as acme.atlassian.net, with no https:// or path.`);
65
- }
66
24
  return inputs;
67
25
  }
68
-
69
- /**
70
- * Decides which tokens this apply adds, and declares one synth warning naming everything still missing.
71
- * `orchestra fdk synth`, `diff` and `apply` print it and carry on.
72
- */
73
- export function connect(factory: Factory, inputs: Inputs, env: NodeJS.ProcessEnv = process.env): Connected {
74
- const connected = {} as Connected;
75
- const missingInputs: string[] = [];
76
- const missingVariables: string[] = [];
77
- const notConnected: string[] = [];
78
- for (const token of Object.keys(NEEDS) as (keyof Connected)[]) {
79
- const need = NEEDS[token];
80
- const inputsMissing = need.inputs.filter((key) => inputs[key] === "");
81
- const variableMissing = (env[need.variable] ?? "").trim() === "";
82
- connected[token] = inputsMissing.length === 0 && !variableMissing;
83
- if (!connected[token]) {
84
- notConnected.push(need.what);
85
- missingInputs.push(...inputsMissing);
86
- if (variableMissing) missingVariables.push(need.variable);
87
- }
88
- }
89
- if (notConnected.length > 0) {
90
- const still = [
91
- ...(missingInputs.length > 0 ? [`${missingInputs.join(", ")} in inputs.json`] : []),
92
- ...(missingVariables.length > 0 ? [`${missingVariables.join(", ")} in the shell`] : []),
93
- ];
94
- new Warning(
95
- factory,
96
- "not-connected",
97
- `The ${notConnected.join(" and ")} ${notConnected.length > 1 ? "are" : "is"} not connected yet, so this ` +
98
- `apply adds no token for ${notConnected.length > 1 ? "them" : "it"}. Still missing: ${still.join("; ")}. ` +
99
- `Set them and apply again.`,
100
- );
101
- }
102
- return connected;
103
- }
104
-
105
- /** One plain warning in synth's output. It declares nothing on the platform. */
106
- class Warning extends Construct {
107
- readonly #message: string;
108
-
109
- constructor(scope: Factory, id: string, message: string) {
110
- super(scope, id);
111
- this.#message = message;
112
- }
113
-
114
- override _synthWarnings(): string[] {
115
- return [this.#message];
116
- }
117
- }
@@ -1,48 +1,33 @@
1
- // The whole factory, in the organization with no project: the five agents, their machines, the keys, and the
2
- // Onboarding, Bugs, Features and Support pipelines. `orchestra fdk diff` shows what this file declares, and `orchestra fdk apply`
3
- // creates it. It applies with no inputs and no tokens: each token joins once it and its inputs are set.
1
+ // The whole factory, in the organization with no project: the four agents, their machines, the model gateway
2
+ // key, and the Bugs, Features and Support pipelines. `orchestra fdk diff` shows what this file declares, and
3
+ // `orchestra fdk apply` creates it. It declares no code host or tracker, so it applies with no token.
4
4
 
5
5
  import { readFileSync } from "node:fs";
6
6
  import { Agent, Factory, Pipeline, type HarnessFamily } from "@orchestraworks/cli";
7
7
  import { declareEnvironment, declareKeys, type Size } from "./lib/environment.js";
8
- import { connect, readInputs, type Connected } from "./lib/inputs.js";
8
+ import { readInputs, type Inputs } from "./lib/inputs.js";
9
9
 
10
10
  const inputs = readInputs();
11
11
  const factory = new Factory({ name: "factory" });
12
12
 
13
- const connected = connect(factory, inputs);
14
- const keys = declareKeys(factory, inputs, connected);
13
+ const keys = declareKeys(factory);
15
14
 
16
15
  function instructions(file: string): string {
17
16
  return readFileSync(new URL(`./agents/${file}`, import.meta.url), "utf8")
18
- .replace("<connections>", connections(connected))
17
+ .replace("<repository-notes>", repositoryNotes(inputs))
19
18
  .replaceAll("<repository>", inputs.repositoryUrl)
20
- .replaceAll("<branch>", inputs.repositoryDefaultBranch || "the default branch")
21
- .replaceAll("<jira-site>", inputs.jiraSite);
19
+ .replaceAll("<branch>", inputs.repositoryDefaultBranch || "the default branch");
22
20
  }
23
21
 
24
- /** What the Manager Agent is told about the repository and the tracker, by what this apply connects. */
25
- function connections({ bitbucket, jira }: Connected): string {
26
- if (bitbucket && jira) {
27
- return [
28
- "The team's code is in <repository>. Pull requests go to <branch>. Their issues are in Jira at <jira-site>.",
29
- "The platform adds the Bitbucket and Jira tokens to your requests, so git and the two APIs work without a",
30
- "password.",
31
- ].join("\n");
32
- }
33
- const lines = [
34
- bitbucket
35
- ? "The team's code is in <repository>. Pull requests go to <branch>. The platform adds the Bitbucket token " +
36
- "to your requests, so git and its API work without a password."
37
- : "The team's repository is not connected yet.",
38
- jira
39
- ? "Their issues are in Jira at <jira-site>. The platform adds the Jira token to your requests, so its API " +
40
- "works without a password."
41
- : "The team's tracker is not connected yet.",
42
- "Until a person connects it, do not start an item that needs it: move the item to Needs review and ask for " +
43
- "the connection.",
44
- ];
45
- return lines.join("\n");
22
+ /** What the Manager Agent is told about where the code is, by what inputs.json names. */
23
+ function repositoryNotes({ repositoryUrl }: Inputs): string {
24
+ return [
25
+ repositoryUrl !== ""
26
+ ? "The team's code is in <repository>. Pull requests go to <branch>."
27
+ : "This factory names no repository. Take the repository's address from the item.",
28
+ "No code host or tracker token is set up for you. A public repository clones without one. When you cannot",
29
+ "read the repository, move the item to its review stage and ask a person how to reach it.",
30
+ ].join("\n");
46
31
  }
47
32
 
48
33
  const ENGINEERS: { size: Size; harness: HarnessFamily; model: string }[] = [
@@ -56,69 +41,37 @@ function reviewerOf(size: Size): string {
56
41
  return size === "lg" ? "engineer-md" : "engineer-lg";
57
42
  }
58
43
 
59
- // The Manager Agent reaches Bitbucket and Jira with the team's tokens.
60
44
  new Agent(factory, "manager-agent", {
61
45
  slug: "manager-agent",
62
46
  name: "Manager Agent",
63
- environment: declareEnvironment(factory, "manager-work-lg", "lg", keys, inputs, { access: "tokens" }),
47
+ environment: declareEnvironment(factory, "manager-work-lg", "lg", keys),
64
48
  harness: "claude",
65
49
  modelSettings: { model: "claude-opus-5-5", enableModelGateway: true },
66
50
  instructions: instructions("manager-agent.md"),
67
51
  });
68
52
 
69
53
  for (const { size, harness, model } of ENGINEERS) {
70
- // Blocked from Bitbucket and Jira until commissioning: the code arrives as a git bundle instead.
71
- const environment = declareEnvironment(factory, `engineer-work-${size}`, size, keys, inputs, {
72
- access: "blocked",
73
- codex: harness === "codex",
74
- });
75
54
  new Agent(factory, `engineer-${size}`, {
76
55
  slug: `engineer-${size}`,
77
56
  name: `Engineer Agent ${size}`,
78
- environment,
57
+ environment: declareEnvironment(factory, `engineer-work-${size}`, size, keys, {
58
+ codex: harness === "codex",
59
+ }),
79
60
  harness,
80
61
  modelSettings: { model, enableModelGateway: true },
81
62
  instructions: instructions("engineer-agent.md")
63
+ .replaceAll("<self-name>", `Engineer Agent ${size}`)
82
64
  .replaceAll("<self>", `engineer-${size}`)
83
65
  .replaceAll("<reviewer>", reviewerOf(size)),
84
66
  });
85
- if (size === "lg") {
86
- // The Bootstrap's baseline, on engineer-lg's machine shape and model, with no codebase skill and no work
87
- // loop, so its replays measure what the study and the loop add. Never give it a skill.
88
- new Agent(factory, "engineer-bare", {
89
- slug: "engineer-bare",
90
- name: "Engineer Agent bare",
91
- environment,
92
- harness,
93
- modelSettings: { model, enableModelGateway: true },
94
- instructions: instructions("engineer-bare.md"),
95
- });
96
- }
97
67
  }
98
68
 
99
69
  // No stage limits where an item may move next: a person or an agent moves it wherever the work stands.
100
-
101
- // Set up, Bootstrap and every Replay item live here, until commissioning.
102
- new Pipeline(factory, "onboarding", {
103
- slug: "onboarding",
104
- name: "Onboarding",
105
- description:
106
- "The steps to a working factory: connect the code and the tracker, make the repository run on our machines, learn how this team works, and prove the agents on past fixes before they take real work. Each step is an item here. This pipeline is retired after commissioning.",
107
- itemSlugPrefix: "onbd",
108
- stages: [
109
- { slug: "todo", name: "Todo", category: "TODO" },
110
- { slug: "in-progress", name: "In progress", category: "IN_PROGRESS" },
111
- { slug: "needs-review", name: "Needs review", category: "IN_PROGRESS" },
112
- { slug: "done", name: "Done", category: "DONE" },
113
- ],
114
- });
115
-
116
- // The pipelines real work flows through.
117
70
  new Pipeline(factory, "bugs", {
118
71
  slug: "bugs",
119
72
  name: "Bugs",
120
73
  description:
121
- "Bugs the Engineer Agents fix. New issues land in Triage. Parked holds a bug that waits until the Bootstrap passes, or a bug a person has set aside. A fix waits in In review as a pull request with a test that failed before and passes after.",
74
+ "Bugs the Engineer Agents fix. New issues land in Triage. Parked holds a bug a person has set aside. A fix waits in In review as a pull request with a test that failed before and passes after.",
122
75
  itemSlugPrefix: "bug",
123
76
  stages: [
124
77
  { slug: "triage", name: "Triage", category: "TODO" },
@@ -6,5 +6,5 @@ You fix bugs in the GitHub repository <repository>, one bug per conversation. Th
6
6
  3. Fix it with the smallest change and run the test again. Keep the passing output.
7
7
  4. Push a branch as soon as the test passes, then open a pull request against the default branch with gh:
8
8
  what was wrong, the fix, and the tests you ran.
9
- 5. Publish a report with your sf-report skill: the failing and the passing output, and the change.
9
+ 5. Publish a report with your artifacts skill: the failing and the passing output, and the change.
10
10
  End with the pull request's link and the report's slug.
@@ -106,7 +106,7 @@ new Agent(factory, "bugfix", {
106
106
  modelSettings: { enableModelGateway: true },
107
107
  instructions: readFile("agents/bugfix.md").replaceAll("<repository>", REPOSITORY),
108
108
  skills: [
109
- Skill.fromId(factory, "skill_sf-report"),
109
+ Skill.fromId(factory, "skill_artifacts"),
110
110
  new Skill(factory, "codebase", { source: "skills/codebase" }),
111
111
  ],
112
112
  });
@@ -1,22 +0,0 @@
1
- You are Engineer Agent engineer-bare. You make the change one item asks for, in this team's code, one item
2
- per conversation. The item is your first message.
3
-
4
- You cannot reach Bitbucket or Jira from this machine. The code comes as a git bundle, a file the Manager
5
- Agent uploaded. Its id is on the item's `Code bundle:` line.
6
-
7
- 1. Get the code in `/work`, the disk that holds the code and build output so they do not fill the root disk.
8
- Run `cd /work`, then `orchestra files get-content <file id> --output-file work.bundle`, then
9
- `git clone --branch work work.bundle code`, and work in `/work/code`.
10
- 2. Make the change the item asks for.
11
- 3. Write your whole change as one patch, new files and any commits included, against the commit the bundle
12
- holds: `git -C /work/code add -A`, then
13
- `git -C /work/code diff --cached --binary origin/work > /work/change.patch`. Upload it with
14
- `orchestra files create --file /work/change.patch --filename change.patch --output json`.
15
- 4. Add a comment to the item with `orchestra work-items create-activity <item id> --text <comment>` that gives the
16
- patch's File id. Move the item to Needs review and assign it to `manager-agent`. Assigning it starts the
17
- Manager Agent's conversation, which scores your change.
18
-
19
- Do not try to find the issue's real fix anywhere else. When you are stuck, say what you need in the comment,
20
- move the item to Needs review and assign it to `manager-agent`.
21
-
22
- Stop any Monitor or background task you started before your final message.