Skip to content

Commit 0b7e8d2

Browse files
committed
Merge branch 'staging' into improvement/platform
Resolved 47 conflicts, keeping staging's semantics and this branch's platform migration on top of them. - scheduled tasks: kept this branch's removal of the page, modals, hooks and search-params; kept schedule-calendar/ and utils/ for the agents module. Dropped staging's new task-modal/secret-access-section.tsx. - accepted staging's deletion of the deployed-chat voice mode and the knowledge base-card. - took staging's rewrites of chat input/message, the sidebar file list and the sidebar Chats section, then re-applied the icon and token migration on top (emcn icons, no strokeWidth, no font-base). - carried staging's NEXT_PUBLIC_CHAT_DISABLED gate onto the branch's SidebarSection-based Chats section. - migrated the five Globe imports staging added to @sim/emcn/icons, since lucide-react is no longer a dependency. - retargeted document-table.css off the retired --divider token onto --border-width/--border, and updated the test that guards it. - dropped `flush` from the chip call sites staging added; this branch removed the chip cluster margin the prop existed to cancel.
2 parents ea94cdf + 40cbee4 commit 0b7e8d2

1,393 files changed

Lines changed: 182658 additions & 19647 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/add-block/SKILL.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,12 @@ Derive templates from the service's real use cases. Each prompt should name a co
919919
- **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.
920920
- **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.
921921

922+
## Generated tool metadata
923+
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.
925+
926+
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+
922928
## Checklist Before Finishing
923929

924930
- [ ] `integrationType` is set to the correct `IntegrationType` enum value
@@ -933,6 +939,7 @@ Derive templates from the service's real use cases. Each prompt should name a co
933939
- [ ] Tools.config.tool returns correct tool ID (snake_case)
934940
- [ ] Outputs match tool outputs
935941
- [ ] Block + meta registered in registry-maps.ts (`BLOCK_REGISTRY` / `BLOCK_META_REGISTRY`)
942+
- [ ] If any tool was added, changed or removed alongside the block: ran `bun run tool-metadata:generate` and committed the artifacts
936943
- [ ] If icon missing: asked user to provide SVG
937944
- [ ] If triggers exist: `triggers` config set, trigger subBlocks spread
938945
- [ ] Optional/rarely-used fields set to `mode: 'advanced'`
Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,46 @@
11
---
22
name: add-feature-flag
3-
description: Add a runtime gated feature flag (AppConfig-backed on prod, secret fallback off-prod), gated by org id, user id, or admin
3+
description: Add a runtime feature flag (AppConfig-backed on prod, secret fallback off-prod), global by default or optionally gated by org id, user id, or platform admin
44
argument-hint: <flag-name>
55
---
66

77
# Add Feature Flag Skill
88

9-
You add a **runtime, gated feature flag** to Sim — one that can be turned on for specific orgs, users, or admins and changed on prod with no redeploy (AWS AppConfig). When AppConfig isn't the source of truth, the flag falls back to a single **secret** (on/off only).
9+
You add a **runtime feature flag** to Sim that can change on prod with no redeploy (AWS AppConfig). Prefer a global on/off flag unless the rollout actually needs per-organization, per-user, or platform-admin targeting. When AppConfig isn't the source of truth, the flag falls back to a single **secret** (on/off only).
1010

1111
## When to use this vs `env-flags.ts`
1212

13-
- **Feature flag** (`@/lib/core/config/feature-flags.ts`): per-request, gated by `userId`/`orgId`/admin, changeable at runtime. This skill.
13+
- **Feature flag** (`@/lib/core/config/feature-flags.ts`): runtime global on/off by default, optionally scoped by `userId`/`orgId`/admin. This skill.
1414
- **Env flag** (`@/lib/core/config/env-flags.ts`): deploy-time capability/environment detection (`isProd`, `isHosted`, `isBillingEnabled`). A module-load boolean. **Do not add gated flags here.**
1515

1616
If the user wants a fixed per-deployment toggle, send them to `env-flags.ts` instead.
1717

1818
## The flag model
1919

20-
A flag's **gating rule lives only in the hosted AppConfig document**. It is ON for a context when any clause matches:
20+
A flag's **gating rule lives only in the hosted AppConfig document**. It is ON for a context when any configured clause matches:
2121

2222
```ts
2323
interface FeatureFlagRule {
2424
enabled?: boolean // global default for everyone
2525
orgIds?: string[] // allowlisted organization ids
2626
userIds?: string[] // allowlisted user ids
27-
admins?: boolean // platform admins (user.role === 'admin')
27+
adminEnabled?: boolean // platform admins (user.role === 'admin')
2828
}
2929
```
3030

31-
Critically, **none of this is expressible in code** — gating (especially `admins`) can only be set through AppConfig, so no environment can grant access from a code literal. Off-AppConfig (self-hosted/OSS/local), a flag is simply on or off, derived from its fallback secret.
31+
Critically, **none of this is expressible in code** — gating (especially `adminEnabled`) can only be set through AppConfig, so no environment can grant access from a code literal. Off-AppConfig (self-hosted/OSS/local), a flag is simply on or off, derived from its fallback secret.
3232

3333
## Steps
3434

35-
1. **Define the flag.** Add one entry to the `FEATURE_FLAGS` registry in `apps/sim/lib/core/config/feature-flags.ts`. Each entry is the flag's whole definition — name (kebab-case key), `description`, and the `fallback` secret consulted when AppConfig isn't the source of truth (truthy ⇒ on globally):
35+
1. **Confirm the granularity before editing code.** If the user has not already specified it, stop and ask:
36+
37+
> Should `<flag-name>` be a global on/off flag (recommended), or does it need rollout targeting by organization, user, and/or platform admin?
38+
39+
- Recommend **global**. Do not infer scoped gating merely because the call site already has a user or organization id.
40+
- If the user chooses scoped gating but does not name the dimensions, ask which of organization, user, and platform admin it needs. Wire only the selected dimensions.
41+
- If the user wants a fixed per-deployment toggle rather than a runtime AppConfig flag, use `env-flags.ts` instead.
42+
43+
2. **Define the flag.** Add one entry to the `FEATURE_FLAGS` registry in `apps/sim/lib/core/config/feature-flags.ts`. Each entry is the flag's whole definition — name (kebab-case key), `description`, and the `fallback` secret consulted when AppConfig isn't the source of truth (truthy ⇒ on globally):
3644

3745
```ts
3846
const FEATURE_FLAGS = {
@@ -45,7 +53,19 @@ Critically, **none of this is expressible in code** — gating (especially `admi
4553

4654
`fallback` is the env/secret key (typed as `keyof typeof env`), so add `<FLAG_SECRET>` to `apps/sim/lib/core/config/env.ts` first (and the deployment's secret store) — it won't typecheck otherwise. Do **not** add org/user/admin defaults here — that gating exists only in AppConfig. Adding the entry makes `<flag-name>` a valid `FeatureFlagName`.
4755

48-
2. **Gate the call site.** Call `isFeatureEnabled` with whatever ids you have — admin status is resolved internally, so callers never pass it:
56+
3. **Gate the call site at the chosen granularity.** For the recommended global mode, pass no context:
57+
58+
```ts
59+
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
60+
61+
if (await isFeatureEnabled('<flag-name>')) {
62+
// gated behavior
63+
}
64+
```
65+
66+
Do not fetch, resolve, or thread through user or organization context solely for a global flag.
67+
68+
For scoped rollout, pass only the dimensions the user selected. Admin status is resolved internally, so ordinary callers pass `userId`, not a role:
4969

5070
```ts
5171
import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
@@ -55,19 +75,21 @@ Critically, **none of this is expressible in code** — gating (especially `admi
5575
}
5676
```
5777

78+
- Organization targeting uses `orgId`; user and platform-admin targeting require `userId`.
5879
- Missing ids are fine — a clause with no matching id is skipped; with no `userId`, the admin clause resolves to `false` without a DB read.
5980
- Admin routes that already know the caller is an admin may pass `{ userId, isAdmin: true }` to skip the role lookup.
6081
- **Client/UI flags:** resolve server-side (in a server component, route, or loader) and pass the boolean down as a prop. There is no client AppConfig.
6182

62-
3. **(Prod) configure in AppConfig.** The infra `feature-flags` profile schema is permissive, so a new flag needs **no infra change**. Operators add the flag under `flags` in the hosted `feature-flags` document — including any `orgIds`/`userIds`/`admins` gating — and start a `sim-<env>-fast` deployment (see the AppConfig runbook in the infra README — same flow as `access-control`). The fallback secret only applies when AppConfig is disabled.
83+
4. **(Prod) configure in AppConfig.** The infra `feature-flags` profile schema is permissive, so a new flag needs **no infra change**. Operators add the flag to the hosted `feature-flags` document using `enabled` for global rollout or only the selected `orgIds`/`userIds`/`adminEnabled` clauses for scoped rollout, then start a `sim-<env>-fast` deployment (see the AppConfig runbook in the infra README — same flow as `access-control`). The fallback secret only applies when AppConfig is disabled.
6384

64-
4. **Test.** Add a case to `apps/sim/lib/core/config/feature-flags.test.ts`: use `withAppConfig({ flags: { ... } })` to cover the gating rule (mock `isPlatformAdmin` for the `admins` clause), and toggle the fallback secret to cover the off-AppConfig path.
85+
5. **Test.** Add a case to `apps/sim/lib/core/config/feature-flags.test.ts` that matches the chosen granularity. For a global flag, exercise `isFeatureEnabled('<flag-name>')` with an AppConfig `enabled` rule and toggle the fallback secret for the off-AppConfig path. For scoped rollout, cover only the selected clauses and mock `isPlatformAdmin` when testing `adminEnabled`.
6586

66-
5. **Clean up after rollout.** When the feature ships to everyone, delete the flag's entry from `FEATURE_FLAGS`, the `<FLAG_SECRET>` env entry, the AppConfig document, the call sites, and the test. Leaving dead flags around is the main failure mode of flag systems.
87+
6. **Clean up after rollout.** When the feature ships to everyone, delete the flag's entry from `FEATURE_FLAGS`, the `<FLAG_SECRET>` env entry, the AppConfig document, the call sites, and the test. Leaving dead flags around is the main failure mode of flag systems.
6788

6889
## Notes
6990

7091
- Flag keys are `kebab-case`.
7192
- Never read flags via raw `fetch` or a new AppConfig client — always go through `isFeatureEnabled` / `getFeatureFlags`.
7293
- Never bake gating into code. The fallback is a single boolean secret; org/user/admin scoping is AppConfig-only.
73-
- The admin check reads the DB **replica** (`dbReplica`) and is resolved lazily, so an admin-gated flag adds at most one cheap replica read, and only when `admins` is the deciding clause.
94+
- Never add or propagate request context unless the user chose scoped rollout.
95+
- The admin check reads the DB **replica** (`dbReplica`) and is resolved lazily, so an admin-gated flag adds at most one cheap replica read, and only when `adminEnabled` is the deciding clause.

.agents/skills/add-integration/SKILL.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,16 @@ export const tools: Record<string, ToolConfig> = {
415415
}
416416
```
417417

418+
Then regenerate the generated tool metadata and commit it:
419+
420+
```bash
421+
bun run tool-metadata:generate
422+
```
423+
424+
Client code reads `params`/`outputs` from these artifacts rather than importing
425+
the registry, so a tool you add, change or remove is invisible to the UI until they are regenerated,
426+
and CI fails on stale ones. See `.agents/skills/tool-registry-boundary/SKILL.md`.
427+
418428
### Block Registry (`apps/sim/blocks/registry-maps.ts`)
419429

420430
The data maps (`BLOCK_REGISTRY` + `BLOCK_META_REGISTRY`) live in `registry-maps.ts`; `registry.ts` holds only the accessor functions. Add the import and an entry to each map alphabetically:
@@ -490,6 +500,7 @@ If creating V2 versions (API-aligned outputs):
490500
- [ ] All optional outputs have `optional: true`
491501
- [ ] Created `index.ts` barrel export
492502
- [ ] Registered all tools in `tools/registry.ts`
503+
- [ ] Ran `bun run tool-metadata:generate` and committed the regenerated artifacts
493504

494505
### Block
495506
- [ ] Created `blocks/blocks/{service}.ts`

.agents/skills/add-tools/SKILL.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,17 @@ export const tools = {
296296
}
297297
```
298298

299+
3. Regenerate the tool metadata artifacts:
300+
301+
```bash
302+
bun run tool-metadata:generate
303+
```
304+
305+
Client code reads a tool's `params`/`outputs` from generated metadata rather than
306+
importing the registry, so a tool you add, change or remove is invisible to the UI until
307+
these are regenerated — and CI fails on stale artifacts. Commit the result. See
308+
`.agents/skills/tool-registry-boundary/SKILL.md`.
309+
299310
## Wiring Tools into the Block (Required)
300311

301312
After registering in `tools/registry.ts`, you MUST also update the block definition at `apps/sim/blocks/blocks/{service}.ts`. This is not optional — tools are only usable from the UI if they are wired into the block.
@@ -443,6 +454,7 @@ All tool IDs MUST use `snake_case`: `{service}_{action}` (e.g., `x_create_tweet`
443454
- [ ] Types file has all interfaces
444455
- [ ] Index.ts exports all tools and re-exports types (`export * from './types'`)
445456
- [ ] Tools registered in `tools/registry.ts`
457+
- [ ] `bun run tool-metadata:generate` run and the regenerated artifacts committed
446458
- [ ] Block wired: `tools.access`, dropdown options, subBlocks, `tools.config`, outputs, inputs
447459

448460
## Final Validation (Required)

0 commit comments

Comments
 (0)