You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Optional companions: `credentialLabels` (override the picker's section/connect-row copy) and `allowServiceAccounts: true` (trigger-mode only — list service accounts, which triggers otherwise exclude; set only when the trigger's polling path can resolve a service-account token). The connect modal, provider families (Google JSON key, Atlassian token, token-paste, client-credential, Slack bot), and the preview gate are all resolved from `serviceAccountProviderId` — you don't wire them per block.
165
165
166
+
### OAuth deployment availability (required for integration blocks)
167
+
168
+
A visible tools-category block with OAuth is deployment-gated. Its `oauth-input.serviceId` is
169
+
projected into `apps/sim/lib/integrations/integrations.json`, then resolved through
170
+
`resolveOAuthClientCapabilityId()` in `apps/sim/lib/core/config/env-capabilities.ts`.
171
+
172
+
When adding or changing an OAuth integration block:
173
+
174
+
1. Keep exactly one distinct OAuth `serviceId` across the block's `oauth-input` subBlocks.
175
+
2. Confirm that service ID resolves to an entry in `OAUTH_CLIENT_CAPABILITIES`. Google and
176
+
Microsoft service IDs intentionally share their provider-level capability; do not add duplicate
177
+
entries for those aliases.
178
+
3. For a new capability, add its required client fields to `OAUTH_CLIENT_CAPABILITIES` and ensure
179
+
every referenced field exists in the env schema in `apps/sim/lib/core/config/env.ts`. Then add
180
+
the matching `text` or `secret` input modes to `OAUTH_CLIENT_SETUP_FIELDS` in
181
+
`scripts/setup/capability-config.ts`. The CLI catalog is exhaustively typed and checked against
182
+
the runtime field list; do not infer secrecy from the field name.
183
+
4. If the canonical OAuth service declares `serviceAccountProviderId`, keep
184
+
`SERVICE_ACCOUNT_METADATA_BY_OAUTH_SERVICE_ID` in
185
+
`apps/sim/lib/integrations/service-account-metadata.ts` aligned. Set
186
+
`deploymentRequirement` only when the service-account path is preview-gated or depends on the
187
+
OAuth client fields; otherwise omit it.
188
+
189
+
Missing capability metadata is a runtime configuration error, not a reason to make the integration
190
+
silently available.
191
+
166
192
### Selectors (with dynamic options)
167
193
```typescript
168
194
// Channel selector (Slack, Discord, etc.)
@@ -919,12 +945,25 @@ Derive templates from the service's real use cases. Each prompt should name a co
919
945
-**Ground every skill in operations the block actually exposes** — cross-check each skill's steps against `tools.access`. Never describe an action the integration cannot perform.
920
946
-**Derive skills from real, popular use cases found online — never invent them.** Web-search the service's documented use cases (vendor use-case/solutions pages, official docs describing the workflow, reputable "top automations for X" articles) and only add a skill you can source as something people genuinely do with the service. Do not hallucinate skills.
921
947
922
-
## Generated tool metadata
948
+
## Generated artifacts
923
949
924
-
Adding a block on its own needs **no** regeneration — a block references existing tool IDs through `tools.access` and does not change any tool's shape.
950
+
Adding a block on its own needs no **tool metadata** regeneration — a block references existing
951
+
tool IDs through `tools.access` and does not change any tool's shape.
925
952
926
953
But if the same change also adds, edits **or removes** a tool, run `bun run tool-metadata:generate` and commit the result, or CI fails on stale artifacts. That matters here because a block's `outputs` are authored to match its tools' outputs, and the UI now reads those from the generated metadata rather than the executable registry — an unregenerated tool change makes the block's outputs disagree with what the panel renders. See `.agents/skills/tool-registry-boundary/SKILL.md`.
927
954
955
+
A visible integration block does require the generated integration catalog and docs to be refreshed.
956
+
After adding or changing one, run:
957
+
958
+
```bash
959
+
bun run scripts/generate-docs.ts
960
+
bun run integration-catalog:check
961
+
```
962
+
963
+
The catalog check independently derives deployment metadata from the executable block registry and
964
+
compares it with the committed `apps/sim/lib/integrations/integrations.json`. Review the generated
965
+
diff and keep only intentional changes.
966
+
928
967
## Checklist Before Finishing
929
968
930
969
-[ ]`integrationType` is set to the correct `IntegrationType` enum value
@@ -934,12 +973,17 @@ But if the same change also adds, edits **or removes** a tool, run `bun run tool
934
973
-[ ] DependsOn set for fields that need other values
935
974
-[ ] Required fields marked correctly (boolean or condition)
936
975
-[ ] OAuth inputs have correct `serviceId` and `requiredScopes: getScopesForService(serviceId)`
976
+
-[ ] Every OAuth `serviceId` resolves through `resolveOAuthClientCapabilityId()` to the correct `OAUTH_CLIENT_CAPABILITIES` entry
977
+
-[ ] Any new OAuth capability fields exist in `apps/sim/lib/core/config/env.ts`
978
+
-[ ] If the OAuth service supports service accounts, `SERVICE_ACCOUNT_METADATA_BY_OAUTH_SERVICE_ID` matches its canonical `serviceAccountProviderId` and deployment requirement
937
979
-[ ] Scope descriptions added to `SCOPE_DESCRIPTIONS` in `lib/oauth/utils.ts` for any new scopes
938
980
-[ ] Tools.access lists all tool IDs (snake_case)
939
981
-[ ] Tools.config.tool returns correct tool ID (snake_case)
940
982
-[ ] Outputs match tool outputs
941
983
-[ ] Block + meta registered in registry-maps.ts (`BLOCK_REGISTRY` / `BLOCK_META_REGISTRY`)
942
984
-[ ] If any tool was added, changed or removed alongside the block: ran `bun run tool-metadata:generate` and committed the artifacts
985
+
-[ ] Ran `bun run scripts/generate-docs.ts`, reviewed the generated diff, and committed the integration catalog changes
- no `deploymentRequirement` when the service-account path works independently of OAuth client fields;
491
+
-`'oauth-client'` when it requires the same deployment OAuth client fields;
492
+
-`'preview-gated'` when availability is controlled by the service-account preview block.
493
+
494
+
Never add a permissive fallback for missing capability metadata. A visible OAuth integration without
495
+
a resolvable capability must fail validation.
496
+
497
+
## Step 8: Generate and Validate the Catalog
469
498
470
499
Run the documentation generator:
471
500
```bash
472
501
bun run scripts/generate-docs.ts
502
+
bun run integration-catalog:check
473
503
```
474
504
475
505
This creates `apps/docs/content/docs/en/integrations/{service}.mdx` — one page per service carrying the block's Actions and, if it has one, its Triggers section. Never hand-edit generated pages; the only editable region is the `{/* MANUAL-CONTENT */}` block (see `scripts/README.md`).
476
506
507
+
The same generator refreshes `apps/sim/lib/integrations/integrations.json`. The catalog check then
508
+
derives the deployment-relevant fields from the executable block registry and compares them with the
509
+
committed projection. Review the generated diff and keep only intentional changes.
510
+
477
511
## V2 Integration Pattern
478
512
479
513
If creating V2 versions (API-aligned outputs):
@@ -524,6 +558,13 @@ If creating V2 versions (API-aligned outputs):
524
558
-[ ] Used `getCanonicalScopesForProvider()` in `auth.ts` (never hardcode)
525
559
-[ ] Used `getScopesForService()` in block `requiredScopes` (never hardcode)
526
560
561
+
### Deployment Availability (if OAuth service)
562
+
-[ ] Block declares exactly one distinct `oauth-input.serviceId`
563
+
-[ ]`resolveOAuthClientCapabilityId(serviceId)` resolves to the intended `OAUTH_CLIENT_CAPABILITIES` entry
564
+
-[ ] Every new OAuth capability field exists in `apps/sim/lib/core/config/env.ts`
565
+
-[ ] Runtime OAuth fields live in `OAUTH_CLIENT_CAPABILITIES`; matching CLI input modes live in the exhaustively checked `OAUTH_CLIENT_SETUP_FIELDS`
566
+
-[ ] If `serviceAccountProviderId` is configured, `SERVICE_ACCOUNT_METADATA_BY_OAUTH_SERVICE_ID` has the matching projection and deployment requirement
567
+
527
568
### Icon
528
569
-[ ] Asked user to provide SVG
529
570
-[ ] Added icon to `components/icons.tsx`
@@ -542,6 +583,8 @@ If creating V2 versions (API-aligned outputs):
542
583
### Docs
543
584
-[ ] Ran `bun run scripts/generate-docs.ts`
544
585
-[ ] Verified docs file created
586
+
-[ ] Reviewed and committed the generated `apps/sim/lib/integrations/integrations.json` change
587
+
-[ ]`bun run integration-catalog:check` passes
545
588
546
589
### Final Validation (Required)
547
590
-[ ] Read every tool file and cross-referenced inputs/outputs against the API docs
10.**Complex inputs need wandConfig** - Timestamps, JSON arrays, and other hard-to-type values should have `wandConfig` enabled
887
930
11.**Never hardcode scopes** - Use `getScopesForService()` in blocks and `getCanonicalScopesForProvider()` in auth.ts
888
931
12.**Always add scope descriptions** - New scopes must have entries in `SCOPE_DESCRIPTIONS` within `lib/oauth/utils.ts`
932
+
13.**OAuth service IDs need deployment capabilities** - Every visible OAuth integration must resolve through `OAUTH_CLIENT_CAPABILITIES`; shared Google/Microsoft aliases map to their provider capability
933
+
14.**Keep runtime and presentation separate** - Runtime OAuth fields live in `env-capabilities.ts`; CLI input modes live in the exhaustively checked `scripts/setup/capability-config.ts` mapping
Copy file name to clipboardExpand all lines: .agents/skills/ship/SKILL.md
+10-5Lines changed: 10 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -54,17 +54,23 @@ When the user runs `/ship`:
54
54
```
55
55
Then `git status --short` to see what regenerated — those files must be staged in step 7 alongside your own changes.
56
56
57
-
**Do NOT blanket-run the domain generators here.**`mship:generate` (`generate-mship-contracts.ts`) is an **umbrella** that drives all nine mothership contract generators (`mship-contracts`, `billing-protocol-contract`, `mship-tools`, the four `trace-*`, `metrics-contract`, `vfs-snapshot-contract`) and biome-formats `apps/sim/lib/copilot/generated/` — never run it *and* its constituents (they write the same files and corrupt each other in parallel), and never run it on an ordinary ship: it reads an **external** copilot-contract source that isn't checked out in most worktrees, so it hard-fails with `ENOENT` and would abort ship for an unrelated reason. `generate:pi-model-catalog` (under `apps/sim`) likewise regenerates from the installed Pi package, not repo source. Only when **this PR's diff actually touches** a domain generator's input do you regenerate it deliberately and run its matching `:check` (`bun run mship:check` / the individual `*:check`) — with the external source present.
57
+
**Do NOT blanket-run the domain generators here.** `mship:generate` (`generate-mship-contracts.ts`) is an **umbrella** that drives all nine mothership contract generators (`mship-contracts`, `billing-protocol-contract`, `mship-tools`, the four `trace-*`, `metrics-contract`, `vfs-snapshot-contract`) and biome-formats `apps/sim/lib/copilot/generated/` — never run it *and* its constituents (they write the same files and corrupt each other in parallel), and never run it on an ordinary ship: it reads an **external** copilot-contract source that isn't checked out in most worktrees, so it hard-fails with `ENOENT` and would abort ship for an unrelated reason. `generate:pi-model-catalog` (under `apps/sim`) likewise regenerates from the installed Pi package, not repo source. `scripts/generate-docs.ts` rewrites the integration docs and client-safe catalog; run it when this PR changes their block/icon/landing-content inputs or when `integration-catalog:check` reports drift, then review its broad generated diff. Only when **this PR's diff actually touches** a domain generator's input do you regenerate it deliberately and run its matching `:check` (`bun run mship:check` / the individual `*:check`) — with the external source present.
58
58
59
-
**Phase B — run lint + every audit CI enforces, in parallel, and abort ship if any fails.**`bun run lint` first (it autofixes formatting and mutates files, so don't parallelize it with the read-only audits), then fan the rest out and collect exit codes. This is exactly the read-only audit set from CI's `Lint and Test` job (all in-repo, runnable in any worktree):
59
+
**Phase B — run lint + every audit CI enforces, in parallel, and abort ship if any fails.**Before running the commands, compare this list with `.github/workflows/test-build.yml`; when CI adds an audit, run it and update this skill instead of trusting a stale snapshot. The env-flag audit is currently an inline workflow block rather than a package script: when `apps/sim/lib/core/config/env-flags.ts` changed, run that current workflow block verbatim instead of copying a second version into this skill. Run `bun run lint` first (it autofixes formatting and mutates files, so don't parallelize it with the read-only audits), then run the base-sensitive block-registry check, then fan the independent audits out and collect exit codes:
60
60
```bash
61
61
# autofix formatting first (mutating; not parallel-safe with the audits). Gate its exit too —
62
62
# a non-zero lint (unfixable errors) must abort before the audits run, not be ignored.
63
63
bun run lint || { echo"❌ lint failed — do not ship";exit 1; }
64
+
bun run apps/sim/scripts/check-block-registry.ts origin/staging || {
- "Tested manually" is acceptable for testing section; include lint, boundary validation, and (when migrations changed) `check:migrations` results when run
0 commit comments