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
### OAuth deployment availability (required for integration blocks)
167
173
168
174
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`.
175
+
projected into `packages/deployment-config/src/integrations.json`, then resolved through
176
+
`resolveOAuthClientCapabilityId()` in `packages/deployment-config/src/env-capabilities.ts`.
171
177
172
178
When adding or changing an OAuth integration block:
173
179
@@ -178,13 +184,14 @@ When adding or changing an OAuth integration block:
178
184
3. For a new capability, add its required client fields to `OAUTH_CLIENT_CAPABILITIES` and ensure
179
185
every referenced field exists in the env schema in `apps/sim/lib/core/config/env.ts`. Then add
180
186
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.
187
+
`packages/sim-setup/src/capability-config.ts`. The CLI catalog is exhaustively typed and checked
188
+
against the runtime field list; do not infer secrecy from the field name.
189
+
4. If the canonical OAuth service declares `serviceAccountProviderId`, run
190
+
`bun run deployment-config:generate`; this regenerates the provider-ID facts in
191
+
`packages/deployment-config/src/service-account-providers.generated.ts`. Never hand-edit that
192
+
generated map. Add `deploymentRequirement` policy in
193
+
`packages/deployment-config/src/service-account-metadata.ts` only when the service-account path
194
+
is preview-gated or depends on the OAuth client fields; otherwise omit it.
188
195
189
196
Missing capability metadata is a runtime configuration error, not a reason to make the integration
190
197
silently available.
@@ -945,6 +952,35 @@ Derive templates from the service's real use cases. Each prompt should name a co
945
952
-**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.
946
953
-**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.
947
954
955
+
## Canvas Sentences
956
+
957
+
Every block declares a one-line prose summary that replaces its card's field rows:
958
+
959
+
```
960
+
Slack ← header (already names the block)
961
+
Posts ⟨Ship it 🚀⟩ to ⟨#eng⟩ ← the sentence; ⟨…⟩ are live value chips
962
+
```
963
+
964
+
Write one `byOperation` entry per operation dropdown option (or a single `default`
965
+
when the block has no operation dropdown).
966
+
967
+
**The full authoring contract — voice, structure, and the two mistakes that break
968
+
cards silently — is `apps/sim/blocks/AGENTS.md` → "Canvas sentences". Read it
969
+
before writing any.** The two failures worth repeating here, because both are
970
+
invisible at runtime:
971
+
972
+
1. A clause naming only one member of a `canonicalParamId` pair drops the sentence
973
+
for every advanced-mode user. List all members:
974
+
`field: ['channelSelector', 'manualChannel']`.
975
+
2. A clause referencing a subblock whose `condition` excludes that operation can
976
+
never render.
977
+
978
+
Validate before finishing:
979
+
980
+
```bash
981
+
bun run apps/sim/scripts/check-canvas-sentences.ts --block={service}
982
+
```
983
+
948
984
## Generated artifacts
949
985
950
986
Adding a block on its own needs no **tool metadata** regeneration — a block references existing
@@ -957,12 +993,20 @@ After adding or changing one, run:
957
993
958
994
```bash
959
995
bun run scripts/generate-docs.ts
996
+
bun run deployment-config:generate
960
997
bun run integration-catalog:check
998
+
bun run deployment-config:check
999
+
bun run docs:check
961
1000
```
962
1001
963
1002
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.
1003
+
compares it with the committed `packages/deployment-config/src/integrations.json`. The deployment
1004
+
config check verifies the generated service-account facts against the canonical OAuth registry and
1005
+
catalog. `docs:check` re-renders every generated docs artifact in memory and fails on any committed
1006
+
file that differs — it runs in CI via `check:audits`, so commit the full generator output. If the
1007
+
generator also trues up pages an earlier PR left stale, commit that catch-up too; reverting it as
1008
+
"unrelated drift" makes `docs:check` fail. Review the generated diff and keep only intentional
1009
+
changes.
966
1010
967
1011
## Checklist Before Finishing
968
1012
@@ -984,13 +1028,15 @@ diff and keep only intentional changes.
984
1028
-[ ] If any tool was added, changed or removed alongside the block: ran `bun run tool-metadata:generate` and committed the artifacts
985
1029
-[ ] Ran `bun run scripts/generate-docs.ts`, reviewed the generated diff, and committed the integration catalog changes
986
1030
-[ ]`bun run integration-catalog:check` passes
1031
+
-[ ]`bun run docs:check` passes (CI gate — fails on any stale generated docs page)
-[ ] Optional/rarely-used fields set to `mode: 'advanced'`
990
1035
-[ ] Timestamps and complex inputs have `wandConfig` enabled
991
1036
-[ ] Exported `{Service}BlockMeta` with at least 7 templates
992
1037
-[ ]`url` set on `{Service}BlockMeta` to the external service's verified homepage (omit only for first-party blocks with no external service)
993
1038
-[ ]`skills` added to `{Service}BlockMeta`, each grounded in `tools.access` and sourced from a real online use case (not invented)
1039
+
-[ ]`canvasPresentation.sentences` covers every operation, and `bun run apps/sim/scripts/check-canvas-sentences.ts --block={service}` passes with 100% coverage
994
1040
995
1041
## Final Validation (Required)
996
1042
@@ -1006,3 +1052,34 @@ After creating the block, you MUST validate it against every tool it references:
1006
1052
4.**Verify conditions** — each subBlock should only show for the operations that actually use it
1007
1053
5.**Verify `{Service}BlockMeta` is exported** with at least 7 templates, each having `icon`, `title`, `prompt`, `modules`, `category`, and `tags`
1008
1054
6.**If any tool outputs are still unknown**, explicitly tell the user instead of guessing block outputs
1055
+
1056
+
## Option Lists: `selectorKey` or `options`, never a per-block fetcher
1057
+
1058
+
A sub-block gets its choices from exactly one of two places. There is no third.
1059
+
1060
+
**`selectorKey` — every remote list.** Register the list in `hooks/selectors/providers/<service>/selectors.ts`, add its key to `SelectorKey`, and point the sub-block at it. A selector is parameterized by an explicit `SelectorContext`, so the same definition serves the canvas, the workspace-fork sync modal, and anything added later.
`canonicalParamId: 'oauthCredential'` on the credential sub-block is the line people forget. `buildSelectorContextFromBlock` keys the context on a sub-block's CANONICAL id, so without it `context.oauthCredential` is never set and the picker looks unfixable without reading the store. (A credential field is also recognised by its `oauth-input` TYPE as a fallback, so a block whose shipped param is already named something else does not have to rename it.)
1070
+
1071
+
**`options` — everything else.** A static array, or a pure function of the block's own values for a list that narrows to a sibling's selection. No I/O.
**Never fetch inside `options`, and never reach into the stores from a block definition.** A fetcher that resolves its credential with `readSubBlockValue(blockId, ...)` only works on the canvas — every surface that is not the editor gets an empty list. `fetchOptions`/`fetchOptionById` were removed for exactly this reason.
1081
+
1082
+
Two rules the checks enforce:
1083
+
1084
+
-**A secret never enters a selector's `getQueryKey`.** A query key identifies a resource; a credential authorizes access to it. A credential *id* is fine; a typed password is not (see `imap.mailboxes`).
1085
+
-**A sub-block that `dependsOn` a credential / knowledge-base / table selector must be reconfigurable at fork-sync time** — a `selectorKey`, a canonical pair whose basic member is a selector, or a `short-input`/`long-input`. `bun run check:fork-dependent-coverage` fails otherwise, because a fork sync clears those fields on every push and an unofferable one can never be set anywhere that sticks.
`packages/sim-setup/src/capability-config.ts`. Do not create integration-specific setup logic or
547
+
infer secret fields from naming; the CLI mapping is exhaustively checked against the runtime
548
+
fields.
549
+
4. If the canonical OAuth service has `serviceAccountProviderId`, run
550
+
`bun run deployment-config:generate` to refresh
551
+
`packages/deployment-config/src/service-account-providers.generated.ts`; never hand-edit the
552
+
generated provider-ID map. In `packages/deployment-config/src/service-account-metadata.ts`, use:
551
553
- no `deploymentRequirement` when the service-account path works independently of OAuth client fields;
552
554
-`'oauth-client'` when it requires the same deployment OAuth client fields;
553
555
-`'preview-gated'` when availability is controlled by the service-account preview block.
@@ -560,14 +562,18 @@ a resolvable capability must fail validation.
560
562
Run the documentation generator:
561
563
```bash
562
564
bun run scripts/generate-docs.ts
565
+
bun run deployment-config:generate
563
566
bun run integration-catalog:check
567
+
bun run deployment-config:check
568
+
bun run docs:check
564
569
```
565
570
566
571
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`).
567
572
568
-
The same generator refreshes `apps/sim/lib/integrations/integrations.json`. The catalog check then
569
-
derives the deployment-relevant fields from the executable block registry and compares them with the
570
-
committed projection. Review the generated diff and keep only intentional changes.
573
+
The docs generator refreshes `packages/deployment-config/src/integrations.json`, and the deployment
574
+
config generator projects service-account provider IDs from that catalog plus the canonical OAuth
575
+
registry. The checks compare both committed projections with their sources. Review the generated
576
+
diff and keep only intentional changes.
571
577
572
578
## V2 Integration Pattern
573
579
@@ -646,11 +652,16 @@ If creating V2 versions (API-aligned outputs):
646
652
-[ ] Created `index.ts` barrel export
647
653
-[ ] Registered all triggers in `triggers/registry.ts`
648
654
649
-
### Docs
655
+
### Docs and deployment metadata
650
656
-[ ] Ran `bun run scripts/generate-docs.ts`
657
+
-[ ] Ran `bun run deployment-config:generate` for OAuth or service-account changes
651
658
-[ ] Verified docs file created
652
-
-[ ] Reviewed and committed the generated `apps/sim/lib/integrations/integrations.json` change
659
+
-[ ] Reviewed and committed the generated `packages/deployment-config/src/integrations.json` change
653
660
-[ ]`bun run integration-catalog:check` passes
661
+
-[ ]`bun run docs:check` passes — CI fails on stale generated docs, so commit the full generator
662
+
output, including catch-up regeneration for pages another PR left stale (never revert it as
663
+
"unrelated drift")
664
+
-[ ]`bun run deployment-config:check` passes
654
665
655
666
### Final Validation (Required)
656
667
-[ ] Read every tool file and cross-referenced inputs/outputs against the API docs
@@ -768,9 +779,11 @@ tools: {
768
779
}
769
780
```
770
781
771
-
#### 3. Create Internal API Route
782
+
#### 3. Create Special Internal Tool Execution Route
772
783
773
-
Create `apps/sim/app/api/tools/{service}/{action}/route.ts`. Internal tool routes are HTTP boundaries and follow the same contract policy as public routes — define the request/response shape in `apps/sim/lib/api/contracts/tools/{service}.ts` (or an existing aggregate) and validate with canonical helpers from `@/lib/api/server`. Never write a route-local Zod schema.
784
+
Create `apps/sim/app/api/tools/{service}/{action}/route.ts`. This raw route pattern is only for an integration's provider-execution boundary when it needs special file normalization, large-body handling, or protocol behavior. It is not the pattern for CRUD or other operations on protected Sim resources. For those, use the `migrate-application-operation` skill and an authorized application use case with the ordinary internal/v2 route builders.
785
+
786
+
Internal tool routes are HTTP boundaries and follow the same contract policy as public routes — define the request/response shape in `apps/sim/lib/api/contracts/tools/{service}.ts` (or an existing aggregate) and validate with canonical helpers from `@/lib/api/server`. Never write a route-local Zod schema. Authenticate and perform cheap admission before parsing or downloading files.
11.**Never hardcode scopes** - Use `getScopesForService()` in blocks and `getCanonicalScopesForProvider()` in auth.ts
997
1010
12.**Always add scope descriptions** - New scopes must have entries in `SCOPE_DESCRIPTIONS` within `lib/oauth/utils.ts`
998
1011
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
999
-
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
1012
+
14.**Keep runtime and presentation separate** - Runtime OAuth fields live in `packages/deployment-config/src/env-capabilities.ts`; CLI input modes live in the exhaustively checked `packages/sim-setup/src/capability-config.ts` mapping
0 commit comments