@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
@@ -0,0 +1,29 @@
1
+ # Package registries
2
+
3
+ Public registries need no access: egress is open. A private registry or feed needs a Secret the network edge
4
+ adds on the registry's host. Point the package manager at the registry's address with no user name and no
5
+ token in it: in `.npmrc`, `nuget.config`, `pip.conf` or an env value. The edge adds the credential. The agent
6
+ installs or uses whatever client it prefers.
7
+
8
+ Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
9
+
10
+ | Provider | Access | Scopes | Check command |
11
+ |---|---|---|---|
12
+ | npm, private registry (GitHub Packages, JFrog, Nexus) | `<registry host> → Authorization: Bearer <SECRET>` | Read packages | `curl -fsS https://<registry host>/<package name>` |
13
+ | PyPI, private index (JFrog, Nexus) | `<index host> → Authorization: Basic <user>:<SECRET>`. Ask which user name the index wants | Read packages | `curl -fsS https://<index host>/simple/<package name>/` |
14
+ | NuGet, Azure Artifacts | `pkgs.dev.azure.com → Authorization: Basic pat:<SECRET>` | Packaging (Read) | `curl -fsS "https://pkgs.dev.azure.com/<organization>/_packaging/<feed>/nuget/v3/index.json"` |
15
+ | NuGet, GitHub Packages | `nuget.pkg.github.com → Authorization: Basic <user>:<SECRET>` | `read:packages` | `curl -fsS https://nuget.pkg.github.com/<owner>/index.json` |
16
+ | Maven or Gradle, private repository | `<repository host> → Authorization: Basic <user>:<SECRET>` (check the vendor page) | Read packages | `curl -fsS https://<repository host>/<path to a known artifact>.pom` |
17
+
18
+ The public registries, such as `registry.npmjs.org`, `pypi.org`, `files.pythonhosted.org` and
19
+ `api.nuget.org`, need no rule.
20
+
21
+ ## Never write the token on the machine
22
+
23
+ Never write the token into `.npmrc`, `pip.conf`, `nuget.config`, an env value or the setup script. Every
24
+ process on the machine reads them, and the setup script's output is kept. Keep the codebase's own file when it
25
+ holds the address only, for example:
26
+
27
+ ```
28
+ @<scope>:registry=https://<registry host>/
29
+ ```
@@ -0,0 +1,18 @@
1
+ # Design
2
+
3
+ The agents read design files to build what the designer drew. Give access with a Secret the network edge adds,
4
+ with read scopes only. Egress is open, so add only the rule that adds the credential. The platform has no
5
+ design connection, so no design events reach the platform. The agent installs or uses whatever client it
6
+ prefers. The edge adds the credential to its requests.
7
+
8
+ Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
9
+
10
+ | Provider | Access | Scopes | Check command |
11
+ |---|---|---|---|
12
+ | Figma | `api.figma.com → X-Figma-Token: <SECRET>` | A personal access token with `file_content:read` | `curl -fsS "https://api.figma.com/v1/files/<file key>?depth=1"` |
13
+
14
+ Token page: Figma **Settings › Security › Personal access tokens**.
15
+
16
+ The file key is the part after `/design/` or `/file/` in the file's address.
17
+
18
+ The token sees every file its user can open. Make it for a user who sees only the team's files.
@@ -0,0 +1,19 @@
1
+ # Feature flags
2
+
3
+ The agents read flag settings to see what each user gets, and turn a flag on only in a test environment.
4
+ Give access with a Secret the network edge adds, with read scopes, or write only on non-production
5
+ environments. Egress is open, so add only the rule that adds the credential. The agent installs or uses
6
+ whatever client it prefers. The edge adds the credential to its requests.
7
+
8
+ Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
9
+
10
+ | Provider | Access | Scopes | Check command |
11
+ |---|---|---|---|
12
+ | LaunchDarkly | `app.launchdarkly.com → Authorization: <SECRET>`, with no `Bearer` | An API access token with the Reader role | `curl -fsS https://app.launchdarkly.com/api/v2/projects` |
13
+ | Split | `api.split.io → Authorization: Bearer <SECRET>` | An Admin API key scoped to the test environments (check the vendor page) | `curl -fsS https://api.split.io/internal/api/v2/workspaces` |
14
+ | Unleash | `<unleash host> → Authorization: <SECRET>`, with no `Bearer` | A personal or service account token with read access | `curl -fsS https://<unleash host>/api/admin/projects` |
15
+ | ConfigCat | `api.configcat.com → Authorization: Basic <user>:<SECRET>` | Public API credentials | `curl -fsS https://api.configcat.com/v1/me` |
16
+ | Azure App Configuration | Not released yet: each request is signed with the key, or takes a short-lived Entra token | The App Configuration Data Reader role, when it is released | Not released yet |
17
+
18
+ Token pages: LaunchDarkly **Organization settings › Authorization**; Split **Admin settings › API keys**;
19
+ Unleash **Admin › API access**; ConfigCat **Public API credentials**.
@@ -0,0 +1,29 @@
1
+ # Incidents
2
+
3
+ The agents read incidents and their timelines to find what broke. Give access with a Secret the network edge
4
+ adds, with read scopes only. Egress is open, so add only the rule that adds the credential. The platform has
5
+ no incident connection, so no incident events reach the platform. The agent installs or uses whatever client
6
+ it prefers. The edge adds the credential to its requests.
7
+
8
+ Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
9
+
10
+ | Provider | Access | Scopes | Check command |
11
+ |---|---|---|---|
12
+ | PagerDuty | `api.pagerduty.com → Authorization: Token token=<SECRET>` | A read-only REST API key | `curl -fsS https://api.pagerduty.com/abilities -H 'Accept: application/vnd.pagerduty+json;version=2'` |
13
+ | Opsgenie | `api.opsgenie.com → Authorization: GenieKey <SECRET>`. The EU region is `api.eu.opsgenie.com` | An API key with Read access | `curl -fsS https://api.opsgenie.com/v2/account` |
14
+
15
+ Token pages: PagerDuty **Integrations › API Access Keys**; Opsgenie **Settings › API key management**.
16
+
17
+ ## A header with its own word
18
+
19
+ Both put a word of their own before the key, so neither is `Bearer` nor `Basic`. Bind them with `inject`:
20
+
21
+ ```ts
22
+ .allow("pagerduty", {
23
+ hosts: ["api.pagerduty.com"],
24
+ priority: 300,
25
+ credential: inject(pagerduty, { headers: [{ name: "authorization", value: "Token token=${secret}" }] }),
26
+ })
27
+ ```
28
+
29
+ For Opsgenie, the value is `GenieKey ${secret}`.
@@ -0,0 +1,65 @@
1
+ # Trackers
2
+
3
+ Give access with a Secret the network edge adds, or with the tracker's platform connection. Egress is open,
4
+ so add only the rule that adds the credential. A connection also brings events: a `Trigger` on them makes a
5
+ work item for each new issue. The agent installs or uses whatever client it prefers. The edge adds the
6
+ credential to its requests.
7
+
8
+ Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
9
+
10
+ | Provider | Access | Scopes | Check command |
11
+ |---|---|---|---|
12
+ | Jira Cloud, API token | `<site>.atlassian.net → Authorization: Basic <email>:<SECRET>` | API token without scopes | `curl -fsS https://<site>.atlassian.net/rest/api/3/myself` |
13
+ | Jira Cloud, `jira` | Platform connection `jira` (the Orchestra app for Jira), with `.applyPreset(jira.egressPolicy())` | Set by the app | `curl -fsS https://api.atlassian.com/ex/jira/<cloudId>/rest/api/3/myself` |
14
+ | Jira Cloud, `jira-classic` | Platform connection `jira-classic`, with `.allow(jiraClassic)` on `api.atlassian.com` | Set by the consent | `curl -fsS https://api.atlassian.com/ex/jira/<cloudId>/rest/api/3/myself` |
15
+ | Linear | `api.linear.app → Authorization: <SECRET>`, with no `Bearer`. Or platform connection `linear` | Personal API key | `curl -fsS https://api.linear.app/graphql -H 'Content-Type: application/json' -d '{"query":"{ viewer { id } }"}'` |
16
+ | GitHub Issues | The GitHub access of `code-repo.md`, with Issues read and write | Issues: read and write | `curl -fsS "https://api.github.com/repos/<owner>/<name>/issues?per_page=1"` |
17
+ | Azure Boards | The Azure DevOps access of `code-repo.md` | Work Items (Read & write) | `curl -fsS "https://dev.azure.com/<organization>/<project>/_apis/wit/workitems?ids=<id>&api-version=7.1"` |
18
+
19
+ Token pages: Jira `https://id.atlassian.com/manage-profile/security/api-tokens`; Linear **Settings › Account ›
20
+ Security & access**.
21
+
22
+ ## Jira: three routes
23
+
24
+ - **API token.** Basic auth over the account email and the token: `SecretValue.basicAuth("<email>",
25
+ SecretValue.fromEnv("<VAR>"))`. Make the token without scopes: a token with scopes
26
+ works only through `api.atlassian.com`, and this rule adds it on the site host. The site host, such as
27
+ `acme.atlassian.net`, is an env value or a constant in the code. No events.
28
+ - **`jira`, the Orchestra app for Jira.** `Auth.forgeApp()`, install field `siteUrl`. A Jira admin installs
29
+ the app from the connection's `auth.authorizationUrl` (`npx orchestra connections get jira --output json`).
30
+ The connection turns `ACTIVE` at the first event from the site. The app's key works only on
31
+ `api.atlassian.com`. Grant it with `.applyPreset(jira.egressPolicy())`: the preset adds the key on
32
+ `api.atlassian.com` only, and opens the site host with no key. A plain `.allow(jira)` would add the key on
33
+ both. Events: `CreatedIssue`, `UpdatedIssue`, `DeletedIssue`, `CommentedIssue`. The field `selfGenerated`
34
+ is true on a change the app made: filter it out with `where`.
35
+ - **`jira-classic`.** Install field `projectKey`. `Auth.oauth()`: the apply prints no link for it. Read
36
+ `auth.authorizationUrl` from `npx orchestra connections get <slug> --output json`, the developer consents,
37
+ and you apply again. The platform registers the webhook. Grant the key with
38
+ `.allow(jiraClassic)`, which adds it on `api.atlassian.com`. Events: `IssueCreated`, `IssueUpdated`,
39
+ `IssueDeleted`, `CommentCreated`.
40
+
41
+ A connection keeps its credential apart from the network rules. Without the grant on an environment, the
42
+ agents on it reach Jira with no key.
43
+
44
+ ## GitHub Issues: one item per issue
45
+
46
+ A trigger that makes one work item per issue keys it with a `binding`. Issue numbers repeat across
47
+ repositories, so key on GitHub's global issue id, or put the repository in the key:
48
+
49
+ ```ts
50
+ binding: binding`${context.connection.slug}:${context.event.payload("repository.full_name")}:${context.event.payload("issue.number")}`
51
+ ```
52
+
53
+ A comment on a pull request also arrives as `IssueComment`: filter it out with
54
+ `field("issue.pull_request").isAbsent()`.
55
+
56
+ ## Linear
57
+
58
+ The key goes bare in the `Authorization` header: `header("Authorization", secret)`. With the `linear`
59
+ connection, `Auth.customerManagedToken(<secret>)` or `Auth.oauth()`, and `.allow(linear)` adds its key. The
60
+ platform registers the webhook. Events: `IssueCreate`, `IssueUpdate`, `IssueRemove`, `CommentCreate`.
61
+
62
+ ## Azure Boards
63
+
64
+ A work item comment arrives as `WorkitemUpdated`, with its text at
65
+ `resource.fields["System.History"].newValue`. There is no separate comment event.
@@ -0,0 +1,43 @@
1
+ # Knowledge bases
2
+
3
+ Give access with a Secret the network edge adds, or with the provider's platform connection. Egress is open,
4
+ so add only the rule that adds the credential. The agent installs or uses whatever client it prefers. The
5
+ edge adds the credential to its requests.
6
+
7
+ Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
8
+
9
+ | Provider | Access | Scopes | Check command |
10
+ |---|---|---|---|
11
+ | Notion | `api.notion.com → Authorization: Bearer <SECRET>`. Or platform connection `notion`, with `.allow(notion)` | An internal integration, shared with each page or database the agents need | `curl -fsS https://api.notion.com/v1/users/me -H 'Notion-Version: 2022-06-28'` |
12
+ | Confluence Cloud | `<site>.atlassian.net → Authorization: Basic <email>:<SECRET>` | API token without scopes | `curl -fsS "https://<site>.atlassian.net/wiki/api/v2/spaces?limit=1"` |
13
+ | Guru | `api.getguru.com → Authorization: Basic <email>:<SECRET>`. Or platform connection `guru` (OAuth, read only), with `.allow(guru)` | User API token | `curl -fsS https://api.getguru.com/api/v1/whoami` (check the vendor page) |
14
+
15
+ Token pages: Notion `https://www.notion.so/profile/integrations`; Confluence
16
+ `https://id.atlassian.com/manage-profile/security/api-tokens`; Guru, the user's API tokens in Guru's
17
+ settings.
18
+
19
+ ## Notion
20
+
21
+ The integration sees only the pages and databases the developer shares with it in Notion. Each Notion API
22
+ call also needs a `Notion-Version` header, which the agent's client sends itself.
23
+
24
+ The `notion` connection takes `Auth.customerManagedToken(<secret>)` or `Auth.oauth()`, install fields
25
+ `workspaceId` and `workspaceUrl`, both optional. Its events are `PageCreated` and `PageContentUpdated`.
26
+ The platform does not register the webhook. The developer adds it by hand in the integration's settings in
27
+ Notion, with the connection's address. Write the address to a file the developer can read, and never print
28
+ it: `npx orchestra connections rotate-webhook-token notion --output-file <path>`. Each run makes a new
29
+ address and ends the old one.
30
+
31
+ ## Confluence
32
+
33
+ Basic auth over the account email and the token, on the site host. Make the token without scopes, for the
34
+ same reason as Jira's (`issue-tracker.md`). When the team uses a Jira API token on the same site with the
35
+ same account, reuse that Secret and its rule: one rule on the site host serves both. The platform has no
36
+ Confluence connection, so Confluence sends no events.
37
+
38
+ ## Guru
39
+
40
+ The `guru` connection asks Guru for read access with `Auth.oauth()`. The apply prints no link for it: read
41
+ `auth.authorizationUrl` from `npx orchestra connections get <slug> --output json`, the developer consents, and
42
+ you apply again. The platform registers the webhook. Events: `CardCreated`,
43
+ `CardUpdated`, `CardDeleted`.
@@ -0,0 +1,38 @@
1
+ # Chat
2
+
3
+ Slack and Microsoft Teams take no personal token here. Access is the platform connection only: the developer
4
+ or a tenant admin approves the app in the browser, and the network edge adds the app's key to the agent's
5
+ replies. Egress is open, so the connection's own rule, `.allow(<connection>)`, is the only rule to add. The
6
+ agent installs or uses whatever client it prefers. The edge adds the key to its requests.
7
+
8
+ | Provider | Access | Scopes | Check command |
9
+ |---|---|---|---|
10
+ | Slack | Platform connection `slack` (the Orchestra Slack app), `Auth.oauth()`, with `.allow(slack)` on `slack.com` | Set by the app | `curl -sS -X POST https://slack.com/api/auth.test`. Passes only when the answer holds `"ok":true`: Slack answers `200` with `"ok":false` when no key was added |
11
+ | Microsoft Teams | Platform connection `teams` (the Orchestra bot), `Auth.oauth()`, with `.allow(teams)` | Set by the app; a tenant admin consents | The agent sends one message with its own choice of tool, on a conversation where the bot has seen a message. Passes only when the answer carries the new message's `id` and the message shows in Teams |
12
+
13
+ ## OAuth only
14
+
15
+ Both apps sign in with OAuth, and the platform fills the install fields, so `install` stays empty. The apply
16
+ prints `connection '<slug>' needs attention — authorize at: <link>`. For Slack, the developer opens it and
17
+ adds the app to the workspace. For Teams, the consent is for the whole Microsoft tenant, so a tenant admin
18
+ must open it. Then run the same apply again.
19
+
20
+ Without `.allow(<connection>)` on the agent's environment, a reply is refused at the network edge, and synth
21
+ prints a warning.
22
+
23
+ ## Conversations
24
+
25
+ `Providers.Slack.conversation` and `Providers.Teams.conversation` give the events and the bindings for a
26
+ trigger that starts or wakes an agent's conversation: Slack's `mention`, `dm`, `groupChat` and `threadReply`;
27
+ Teams' `message`, split by `inChannel()`, `inDirectMessage()` and `inGroupChat()`. Both have
28
+ `sessionPerThread()`, `sessionPerConversation()` and `rooms([...])`. Set `attributeConnection: true` on the
29
+ trigger's agent target. `autoRespond` on the connection sets what the app shows on each message: Slack takes
30
+ a reaction, a typing status and a failure notice; Teams takes `typing` and `failureNotice`.
31
+
32
+ The agent replies through the provider's own API: Slack's Web API on `slack.com`, and the Bot Framework for
33
+ Teams. On Teams, the edge adds the bot's key only for a conversation where the bot has already seen a
34
+ message.
35
+
36
+ **Not built yet:** acting as the person who wrote the message (the agent speaks as the app), starting a Teams
37
+ conversation where the bot has not been seen, and dropping the app's own messages before the agent sees
38
+ them.
@@ -0,0 +1,36 @@
1
+ # Observability
2
+
3
+ The agents read errors, traces and metrics to find the cause of a bug. Give access with a Secret the network
4
+ edge adds, with read scopes only. Egress is open, so add only the rule that adds the credential. None of these
5
+ has a platform connection, so none sends events to the platform. The agent installs or uses whatever client
6
+ it prefers. The edge adds the credential to its requests.
7
+
8
+ Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
9
+
10
+ | Provider | Access | Scopes | Check command |
11
+ |---|---|---|---|
12
+ | Sentry | `sentry.io → Authorization: Bearer <SECRET>`. The EU region is `de.sentry.io`; a self-hosted Sentry uses its own host | `project:read`, `event:read` | `curl -fsS https://sentry.io/api/0/organizations/` |
13
+ | Datadog | `api.datadoghq.com → DD-API-KEY: <SECRET>` and `DD-APPLICATION-KEY: <SECRET>`, two Secrets on one rule. Other sites use their own host, such as `api.datadoghq.eu` | An application key with read scopes | `curl -fsS https://api.datadoghq.com/api/v1/validate` |
14
+ | New Relic | `api.newrelic.com → API-Key: <SECRET>`. The EU region is `api.eu.newrelic.com` | A user key | `curl -fsS https://api.newrelic.com/graphql -H 'Content-Type: application/json' -d '{"query":"{ actor { user { email } } }"}'` |
15
+ | Grafana Cloud | `<stack>.grafana.net → Authorization: Bearer <SECRET>` | A service account token with the Viewer role | `curl -fsS "https://<stack>.grafana.net/api/search?limit=1"` |
16
+ | Application Insights | `api.applicationinsights.io → x-api-key: <SECRET>` (check the vendor page: Microsoft is moving this API to Entra sign-in) | Read telemetry | `curl -fsS "https://api.applicationinsights.io/v1/apps/<app id>/metadata"` |
17
+ | CloudWatch | Not released yet. AWS signs each request with its key, so the edge cannot add it as a header | Not released yet | Not released yet |
18
+
19
+ Token pages: Sentry **Settings › Auth Tokens**; Datadog **Organization Settings › API Keys** and
20
+ **Application Keys**; New Relic **API keys**; Grafana **Administration › Service accounts**.
21
+
22
+ ## Datadog: two headers
23
+
24
+ Datadog wants two keys on each API call: the organization's API key and a user's application key. Store each
25
+ as its own Secret, and add both on one rule:
26
+
27
+ ```ts
28
+ .allow("datadog", {
29
+ hosts: ["api.datadoghq.com"],
30
+ priority: 300,
31
+ credentials: [header("DD-API-KEY", datadogApiKey), header("DD-APPLICATION-KEY", datadogAppKey)],
32
+ })
33
+ ```
34
+
35
+ The application key carries the user's rights. Make it for a user, or a service account, with read access
36
+ only.
@@ -0,0 +1,25 @@
1
+ # Secrets managers
2
+
3
+ A secrets manager is a source for the factory's Secrets, not a service the agents call. The developer reads
4
+ each token from the manager into the shell of the apply, on their own computer. The apply stores it as an
5
+ Orchestra Secret, and the network edge adds it. The value is never printed, never in the chat, and never on
6
+ a machine.
7
+
8
+ | Provider | Access | Scopes | Check command |
9
+ |---|---|---|---|
10
+ | 1Password | On the developer's computer: `ORCHESTRA_FDK_<NAME>_TOKEN=$(op read "op://<vault>/<item>/<field>")` in the apply's shell | Read on the vault | `op whoami` |
11
+ | HashiCorp Vault | On the developer's computer: `ORCHESTRA_FDK_<NAME>_TOKEN=$(vault kv get -field=<field> <path>)` in the apply's shell | A policy with `read` on the path | `vault token lookup` |
12
+ | Azure Key Vault | On the developer's computer: `ORCHESTRA_FDK_<NAME>_TOKEN=$(az keyvault secret show --vault-name <vault> --name <name> --query value -o tsv)` in the apply's shell | The Key Vault Secrets User role | `az account show` |
13
+
14
+ The check commands run on the developer's computer, with their own sign-in to the manager.
15
+
16
+ ## How the value travels
17
+
18
+ 1. The developer exports the variable in the shell that runs the apply. You run the apply in that shell
19
+ only when the developer can export it there. Otherwise the developer writes the value into the private
20
+ token file (phase 2, "The private token file") from the manager.
21
+ 2. The factory reads it with `SecretValue.fromEnv("ORCHESTRA_FDK_<NAME>_TOKEN")`.
22
+ 3. Never echo the variable, and never pass the value as a command argument: both can reach a log.
23
+
24
+ A Secret keeps the value it had at its last apply. After the developer rotates a token in the manager, apply
25
+ again with the new value loaded.
@@ -0,0 +1,31 @@
1
+ # Support desks
2
+
3
+ Give access with a Secret the network edge adds, or with the provider's platform connection. Egress is open,
4
+ so add only the rule that adds the credential. A connection also brings events: a `Trigger` on them makes a
5
+ work item in the Support pipeline for each new ticket. The agent installs or uses whatever client it prefers.
6
+ The edge adds the credential to its requests.
7
+
8
+ Phase 3, "From a recipe to code", turns a recipe into a Secret and a rule.
9
+
10
+ | Provider | Access | Scopes | Check command |
11
+ |---|---|---|---|
12
+ | Zendesk | Platform connection `zendesk`, install field `subdomain`, with `.allow(zendesk)` on `<subdomain>.zendesk.com`. Or a token: `<subdomain>.zendesk.com → Authorization: Basic <email>/token:<SECRET>` | An agent's API token | `curl -fsS https://<subdomain>.zendesk.com/api/v2/users/me.json` |
13
+ | Intercom | Platform connection `intercom`, with `.allow(intercom)` on `api.intercom.io`. Or a token: `api.intercom.io → Authorization: Bearer <SECRET>` | An access token from a private app | `curl -fsS https://api.intercom.io/me` |
14
+ | Freshdesk | `<domain>.freshdesk.com → Authorization: Basic <SECRET>:X`. The API key is the user name, and `X` is the password | An agent's API key | `curl -fsS https://<domain>.freshdesk.com/api/v2/agents/me` |
15
+
16
+ Token pages: Zendesk **Admin Center › Apps and integrations › APIs**; Intercom **Developer Hub**; Freshdesk
17
+ **Profile settings › API key**.
18
+
19
+ ## Basic auth with a fixed suffix
20
+
21
+ - **Zendesk:** the user name is the agent's email followed by `/token`, and the password is the token:
22
+ `SecretValue.basicAuth("<email>/token", SecretValue.fromEnv("ORCHESTRA_FDK_ZENDESK_TOKEN"))`.
23
+ - **Freshdesk:** the API key is the user name, and the password is any fixed text, such as `X`. The kit's
24
+ Basic recipe puts the Secret in the password, so store the whole `<api key>:X` pair, base64-encoded, as the
25
+ Secret's value, and bind it with `basic("Authorization", secret)` (check the vendor page).
26
+
27
+ ## Events
28
+
29
+ Each connection's events: `orchestra connections list-event-types <connection>`. The Intercom webhook is set
30
+ up by hand in Intercom's Developer Hub, with the connection's address. Write the address to a file the
31
+ developer can read: `npx orchestra connections rotate-webhook-token <connection> --output-file <path>`.
@@ -0,0 +1,62 @@
1
+ # Phase 0: Start
2
+
3
+ **Goal:** the kit is installed and current, you are signed in to the organization the developer chose, and
4
+ you know what the platform can do.
5
+
6
+ ## 1. Install the kit
7
+
8
+ The kit is the `orchestra` command and the library the factory code imports. It was installed before this
9
+ skill was linked, in one of two places. Keep it and its skills current with the command that matches:
10
+
11
+ - Globally, with `npm install -g @orchestraworks/cli`. Update it with `npm update -g @orchestraworks/cli`.
12
+ Then `orchestra` runs in any folder.
13
+ - In the factory folder, with `npm install @orchestraworks/cli` there. Update it with
14
+ `npm update @orchestraworks/cli`, run in that folder. Run the command there as `npx orchestra`.
15
+
16
+ Use one way to run the command in each place:
17
+
18
+ - Where no factory folder with the kit exists yet (phases 0 to 3), run
19
+ `npx --package @orchestraworks/cli orchestra`. With a global install, plain `orchestra` works too.
20
+ - In a factory folder after its `npm install`, run `npx orchestra`.
21
+
22
+ Find the developer's codebase folder. Call it `<codebase>`. Then run
23
+ `npx --package @orchestraworks/cli orchestra --help`. It prints the command list. Node 22 or later is needed.
24
+
25
+ ## 2. Sign in
26
+
27
+ 1. Tell the developer: "A browser window will open. Sign in to Orchestra there and confirm."
28
+ 2. Run the sign-in with a command timeout of at least five minutes. The CLI opens the browser and waits for
29
+ the answer on a local port of this computer, so the browser must run on this same computer. When the
30
+ developer belongs to one organization, the login selects it. When they belong to several, the login stops
31
+ and asks you to name one. Ask the developer which, then run:
32
+
33
+ ```bash
34
+ npx --package @orchestraworks/cli orchestra auth login --org <organization>
35
+ ```
36
+
37
+ This sign-in renews itself, so a long run stays signed in. The address it signs in to is its first line.
38
+ 3. Use this browser sign-in. `orchestra auth login --no-browser` asks for a token at a hidden prompt
39
+ instead, and a typed token cannot renew itself: it stops working when it expires. Use it only for a short
40
+ run, with a token someone hands the developer. Users cannot create their own API keys in the console
41
+ yet; that is coming. If no browser can open on this computer, tell the developer. Ask them to run you on
42
+ a computer where one can.
43
+ 4. Read the two lines the login prints: `Signed in as <email>.` and
44
+ `Logged in to organization <id> (<slug>).` Tell the developer both, and confirm the organization.
45
+
46
+ ## 3. Read the orchestra skill
47
+
48
+ Read `orchestra/SKILL.md` in your skill folder, in full, before phase 1. It says what each idea is for, what
49
+ the starter declares, and what the platform cannot do yet. The later phases point at its sections. Never
50
+ promise one of its "Cannot yet" lines.
51
+
52
+ ## Exit check
53
+
54
+ ```bash
55
+ npx --package @orchestraworks/cli orchestra me get --output json
56
+ node -p 'require(require("os").homedir() + "/.config/orchestra/config.json").profiles.default.organizationId'
57
+ ```
58
+
59
+ The first answer's `email` is the developer's. A signed-in person's answer names no organization, so the
60
+ second command reads the organization from the profile the sign-in saved. It prints only that id, never the
61
+ token. The id is the one in `Logged in to organization <id> (<slug>).`, which the developer confirmed. You
62
+ have read the orchestra skill. If the check fails, read `../troubleshooting.md`, "The sign-in stops working".
@@ -0,0 +1,111 @@
1
+ # Phase 1: Discover
2
+
3
+ **Goal:** you know what to build: a new factory or a new environment, what the codebase needs to run, and
4
+ which services the agents must reach. You write it down before any factory code exists.
5
+
6
+ Write every finding into `<codebase>/../orchestra-factory-notes.md`, one line for each item, with the file,
7
+ page or command that shows it.
8
+
9
+ ## 1. Read the account: a new factory or a new environment
10
+
11
+ An organization usually holds one factory, or none yet. Read what it holds before you ask the developer
12
+ anything. These commands only read. `--all-pages` follows every page, and prints the rows as one array:
13
+
14
+ ```bash
15
+ npx --package @orchestraworks/cli orchestra agents list --all-pages --output json
16
+ npx --package @orchestraworks/cli orchestra environments list --all-pages --output json
17
+ npx --package @orchestraworks/cli orchestra pipelines list --all-pages --output json
18
+ npx --package @orchestraworks/cli orchestra workflows list --all-pages --output json
19
+ npx --package @orchestraworks/cli orchestra connections list --output json
20
+ ```
21
+
22
+ A row that an apply made carries the label `sfdk.managedBy`, whose value is the factory's name.
23
+
24
+ 1. Infer what the developer most likely wants:
25
+ - *No agents and no pipelines:* the account is empty. Infer **a new factory**.
26
+ - *Rows labeled with a factory name:* a factory exists. Infer **a new environment for that factory**,
27
+ such as another repository, a bigger machine, or a machine of the team's own.
28
+ - *Rows with no label:* someone made them by hand or with the CLI. Infer a new factory. If a row's slug
29
+ is one the starter declares, such as `manager-agent`, the apply updates that row. Say so in phase 2.
30
+ 2. Tell the developer what you found, in one or two sentences, for example: "This organization already has
31
+ the factory `factory`, with the agents Manager Agent, Engineer Agent lg, md and sm."
32
+ 3. Ask once, with your question tool, with the inferred choice first and marked as the recommendation.
33
+
34
+ **A new factory.** Go on with section 2.
35
+
36
+ The starters build one factory per organization. When the organization already holds a factory and the
37
+ developer wants another one, make a separate organization for it:
38
+
39
+ 1. Create it: `npx --package @orchestraworks/cli orchestra organizations create --name "<name>"`. Read
40
+ `organizations create --help` for its other flags. When the command refuses, the developer creates the
41
+ organization in the console at `https://app.orchestraworks.ai`.
42
+ 2. Sign in to it as phase 0 says, with `--org <the new organization>`.
43
+ 3. Start this phase again, in the new organization.
44
+
45
+ **A new environment for the existing factory.** Do not run `orchestra fdk init` in phase 4. Edit the factory
46
+ that exists instead:
47
+
48
+ 1. Find the existing factory's folder: the folder with `fdk.json` and `main.ts`. Ask the developer where it
49
+ is when it is not on this computer.
50
+ 2. Load the factory's inputs, the same way every earlier apply loaded them. The engineering-team starter
51
+ reads `~/.config/orchestra/tokens.env`; the bug-fix starter reads `~/.config/orchestra/fdk-inputs.env`.
52
+ Load the file with `set -a; . <file>; set +a`, and never print it. Ask the developer when the file is not
53
+ there. An apply without these inputs removes the token rules the factory has now.
54
+ 3. With the inputs loaded, run `npm install` and `npx orchestra fdk diff` in that folder. It must be a clean
55
+ diff before you edit anything. If it is not, show the changes to the developer and ask what to keep.
56
+ 4. Then read the repository (section 2) for the new environment only. Phase 2 plans the new environment and
57
+ the agent that works on it, and phase 4 adds them to the existing code.
58
+
59
+ ## 2. Read the repository
60
+
61
+ Read the codebase before you write any factory code. The factory must match it, and the machines most of
62
+ all. Note each item:
63
+
64
+ - **The operating system it builds and runs on.** These mean Windows: a `.sln` or `.csproj` that targets
65
+ .NET Framework, WinForms, WPF or IIS, PowerShell build scripts, or `windows-latest` in CI.
66
+ - **The runtime it needs.** A kernel feature, a GPU, nested virtualization, an Android emulator, or a tool
67
+ for another operating system, such as Xcode, means a full virtual machine or the team's own machine.
68
+ - The languages and toolchains, with their versions: `global.json`, `.nvmrc`, `.tool-versions`, the CI's
69
+ setup steps.
70
+ - The build and test commands, from the CI file first, then the README and the build scripts.
71
+ - The package feeds, private ones included: `nuget.config`, `.npmrc`, `pip.conf`, a feed in the CI file.
72
+ - The services it needs, such as a database or a queue: a compose file, test containers, connection
73
+ settings.
74
+ - Docker use: a `Dockerfile`, a compose file, Testcontainers.
75
+ - The repository size: `du -sh <codebase>` and `git -C <codebase> count-objects -vH`.
76
+ - The code host and the tracker: the remote URL (`git -C <codebase> remote get-url origin`), and links in
77
+ the README, the branch names or the CI file.
78
+
79
+ These are facts for the later phases. Ask the developer only what the files cannot answer.
80
+
81
+ ## 3. Name each service, by category and provider
82
+
83
+ For each outside service the agents need, name its category and its provider. Each category has one file in
84
+ `../integrations/`:
85
+
86
+ | Category | File | Examples |
87
+ |---|---|---|
88
+ | Code host | `code-repo.md` | GitHub, Bitbucket, GitLab, Azure DevOps |
89
+ | Tracker | `issue-tracker.md` | Jira, Linear, GitHub Issues, Azure Boards |
90
+ | Knowledge base | `knowledge-base.md` | Notion, Confluence, Guru |
91
+ | Chat | `messaging.md` | Slack, Microsoft Teams |
92
+ | Package registries | `dependencies.md` | npm, PyPI, NuGet, Maven |
93
+ | CI and CD | `ci-cd.md` | GitHub Actions, Azure Pipelines, Jenkins, CircleCI |
94
+ | Observability | `observability.md` | Sentry, Datadog, New Relic, Grafana |
95
+ | Support desk | `support-desk.md` | Zendesk, Intercom, Freshdesk |
96
+ | Design | `design.md` | Figma |
97
+ | Cloud | `cloud.md` | AWS, Azure, Google Cloud |
98
+ | Databases | `databases.md` | A staging database or a read replica |
99
+ | Secrets managers | `secrets-managers.md` | 1Password, Vault, Azure Key Vault |
100
+ | Incidents | `incident.md` | PagerDuty, Opsgenie |
101
+ | Analytics | `analytics.md` | Pendo, Mixpanel, Amplitude |
102
+ | Feature flags | `feature-flags.md` | LaunchDarkly, Split, Unleash, ConfigCat |
103
+
104
+ Infer each one from the codebase and the connections list. Then tell the developer what you found, and ask
105
+ once, with your question tool, which code host, which tracker and which other services the agents need.
106
+ Put your inference first, marked as the recommendation. No provider is a default.
107
+
108
+ ## Exit check
109
+
110
+ `orchestra-factory-notes.md` has a line for each item in sections 2 and 3, or says the item does not apply,
111
+ and it records the answer to section 1: a new factory, or a new environment for a named factory.