Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
3109104
improvement(platform): workspace UI/UX overhaul + integrations catalog
emir-karabeg May 28, 2026
df5ad7d
refactor(platform): remove forms, templates, and creators features
emir-karabeg May 29, 2026
6a1af16
Merge origin/staging into improvement/platform
emir-karabeg May 29, 2026
85265a6
test(workflows): update archiveWorkflow update count after forms removal
emir-karabeg May 30, 2026
6a7e734
upgrade
emir-karabeg Jun 1, 2026
6c05948
improvement(knowledge): polish tag filter dropdowns (#4816)
andresdjasso Jun 1, 2026
c23cb7e
merge(staging): merge origin/staging and add LinqBlockMeta
waleedlatif1 Jun 1, 2026
74a0be9
feat(blocks): add BlockMeta to Quiver and Linq; fix invalid block con…
waleedlatif1 Jun 1, 2026
f51b476
fix(integrations): fix category dropdown by defining missing LANDING_…
waleedlatif1 Jun 1, 2026
645a1d6
fix(sidebar): restore resize handle on all pages
waleedlatif1 Jun 1, 2026
23759bc
fix(sidebar): match staging onKeyDown and tabIndex on resize handle
waleedlatif1 Jun 1, 2026
a320dc7
feat(integrations): show connected credentials on integration detail …
waleedlatif1 Jun 1, 2026
a1b6124
fix(integrations): rename Add in chat to Add to Sim
waleedlatif1 Jun 1, 2026
0447e4a
fix(skills): rename Add button to Add to Sim
waleedlatif1 Jun 1, 2026
cca5054
fix(platform): restore M1/M2/M3 regressions and LazyMotion on landing…
waleedlatif1 Jun 1, 2026
86da193
fix(integrations): revert connected list to credential detail; remove…
waleedlatif1 Jun 1, 2026
90b92bb
feat(sidebar): restore workspace switcher search with updated styling
waleedlatif1 Jun 1, 2026
133959d
fix(sidebar): clean up workspace search — layout, memo, and effect guard
waleedlatif1 Jun 1, 2026
3d6aeb5
fix(sidebar): align workspace rename input selection style with workf…
waleedlatif1 Jun 1, 2026
639294f
perf(sidebar): eliminate React re-renders during sidebar drag resize
waleedlatif1 Jun 1, 2026
1bf4d52
perf(sidebar): add requestAnimationFrame throttle to resize mousemove…
waleedlatif1 Jun 1, 2026
ab6d1cc
fix(sidebar): fix drag-right lag caused by WorkspaceChrome overflow-h…
waleedlatif1 Jun 1, 2026
ea149b2
fix(icons): redesign Download icon to match Upload style; fix Upload/…
waleedlatif1 Jun 1, 2026
977d5de
fix(icons): replace Upload with Download on all remaining export/down…
waleedlatif1 Jun 1, 2026
e641dbb
fix(icons): fix remaining Upload→Download on download actions in file…
waleedlatif1 Jun 1, 2026
04e271a
updated block skills, settings pages, modals, buttons -> chips, block…
waleedlatif1 Jun 2, 2026
590250b
updated skill modal
waleedlatif1 Jun 2, 2026
9c4a5e1
Merge branch 'staging' into improvement/platform
icecrasher321 Jun 2, 2026
621d424
improvement(resource-header): refine breadcrumb truncation ux
andresdjasso Jun 2, 2026
8d0e9dc
improvement(resource): add floating overflow text tooltips
andresdjasso Jun 2, 2026
92da21e
wire up credits counter
icecrasher321 Jun 2, 2026
8c165bb
improvement(resource-header): mute path dropdown title
andresdjasso Jun 2, 2026
8da7e34
refactor(resource-header): share floating-tooltip engine, prune dead …
waleedlatif1 Jun 2, 2026
74705a7
refactor(emcn,resource-header): address PR #4844 review feedback
waleedlatif1 Jun 2, 2026
c190d2c
Merge branch 'improvement/platform' of github.com:simstudioai/sim int…
icecrasher321 Jun 2, 2026
f94052c
upgrade table and styling upgrade
emir-karabeg Jun 2, 2026
8a8d77f
Merge branch 'improvement/platform' of github.com:simstudioai/sim int…
icecrasher321 Jun 2, 2026
72fd5e0
Merge branch 'staging' into improvement/platform
icecrasher321 Jun 2, 2026
2555137
fix schema to include integration
icecrasher321 Jun 2, 2026
350c5be
fix(files): align delete icon with tables view (Trash → Trash2)
waleedlatif1 Jun 2, 2026
21ecc58
fix(mothership): preserve blockType for integration contexts in sent …
waleedlatif1 Jun 2, 2026
13f2cc7
fix(mothership): allow 'integration' resource type in chat resources API
waleedlatif1 Jun 2, 2026
79907b1
fix(ui): Add "File" title next to file resource header
TheodoreSpeaks Jun 3, 2026
a0587a7
fix(ui): fix resource header columns being bolded
TheodoreSpeaks Jun 3, 2026
0f9ea0a
fix(resource): keep the floating tooltip from jumping on click
andresdjasso Jun 3, 2026
59197ad
perf(sidebar): eliminate unnecessary re-renders in workspace switcher…
waleedlatif1 Jun 3, 2026
ad6ced8
feat(search): context-aware cmd-k results on the integrations page
waleedlatif1 Jun 3, 2026
9c96fff
refactor(emcn): make the floating tooltip the one canonical Tooltip
andresdjasso Jun 3, 2026
7a30999
style(emcn): put tooltip text on the design scale (text-caption)
andresdjasso Jun 3, 2026
2df6d39
feat(sidebar): add empty task state and inline task creation
waleedlatif1 Jun 3, 2026
b448f77
invite, billing, home
emir-karabeg Jun 3, 2026
7b32a85
improvement(seats): auto purchase seats on invitations into workspace…
icecrasher321 Jun 3, 2026
eaefa56
feat(knowledge): align connector UI with integrations page styling
waleedlatif1 Jun 3, 2026
b06f757
fix(icons): trim Folder SVG viewBox to remove right-side whitespace
waleedlatif1 Jun 3, 2026
3ad3710
fix(user-input): restore draft text synchronously to preserve context…
waleedlatif1 Jun 3, 2026
9c71774
fix(queue): render context chips in queued messages
waleedlatif1 Jun 3, 2026
c2c2738
fix(mothership): remove integrations from add-resource dropdown
waleedlatif1 Jun 3, 2026
f24ea25
fix(mothership): comment out integrations from add-resource dropdown
waleedlatif1 Jun 3, 2026
598692b
chore(db): drop form, templates, template_creators, template_stars ta…
waleedlatif1 Jun 3, 2026
1a509c0
chore(db): add migration metadata for 0224 drop tables
waleedlatif1 Jun 3, 2026
b102d4f
block icons, sidebar, toolbar
emir-karabeg Jun 3, 2026
8f6a048
chore: remove remaining dead code for template-profile feature
waleedlatif1 Jun 3, 2026
e495979
fix(multi-select): preserve anchor on range selection for tasks and f…
waleedlatif1 Jun 3, 2026
b9cc9bc
feat(emcn): add SearchInput component and unify search bars platform-…
waleedlatif1 Jun 3, 2026
254af5c
fix(files,tables): restore new-file editor autofocus and CSV import e…
waleedlatif1 Jun 3, 2026
107a98e
feat(home): score suggested actions by workspace signals
waleedlatif1 Jun 3, 2026
91bfc08
billing, teammates
emir-karabeg Jun 3, 2026
314dcb0
improvement(credentials): credentials invites, secrets tab wiring up …
icecrasher321 Jun 4, 2026
c501c53
refactor(ui): migrate settings & workspace UI to chip design system
waleedlatif1 Jun 4, 2026
52739a3
fix(mothership): restore integrations to useAvailableResources for @ …
waleedlatif1 Jun 4, 2026
c3189a7
refactor(settings): chip design-system consistency pass across all tabs
waleedlatif1 Jun 4, 2026
f6c1d3c
feat(settings): unify filter dropdowns on ChipSelect (integrations st…
waleedlatif1 Jun 4, 2026
a79b3f4
fix(mentions): require explicit @ for integration mentions; decorate …
waleedlatif1 Jun 4, 2026
b3b86c8
refactor(settings): section the API keys page like secrets
waleedlatif1 Jun 4, 2026
243d2a3
fix(settings): ChipSelect renders above modals + full-width form mode
waleedlatif1 Jun 4, 2026
fe770ee
fix(emcn): ChipSelect uses the emcn flat chevron, not lucide's square…
waleedlatif1 Jun 4, 2026
e5bf7ba
fix(emcn): ChipSelect trigger hugs its content (w-fit)
waleedlatif1 Jun 4, 2026
0dffb7d
fix(emcn): ChipSelect uses a square lucide chevron
waleedlatif1 Jun 4, 2026
c165f54
renamed tasks to chats
emir-karabeg Jun 4, 2026
469781f
rename and file change
emir-karabeg Jun 4, 2026
7c455ce
improvement(billing): wire up billing, org, teammates tabs + remove d…
icecrasher321 Jun 4, 2026
0b0f84e
chore(db): remove migration 0224 to regenerate on top of staging
icecrasher321 Jun 4, 2026
4b0a4c8
Merge remote-tracking branch 'origin/staging' into improvement/platform
icecrasher321 Jun 4, 2026
0187f81
fix type errors and regen migration?
icecrasher321 Jun 4, 2026
fee1cd2
chore(db): drop branch migration 0226 ahead of staging merge; will re…
waleedlatif1 Jun 5, 2026
034f6dd
Merge remote-tracking branch 'origin/staging' into improvement/platform
waleedlatif1 Jun 5, 2026
6322544
chore(db): regenerate migration 0226 after staging merge
waleedlatif1 Jun 5, 2026
4a6051f
externalize before compaction in fallback'
icecrasher321 Jun 5, 2026
cf96b80
fix save/discard chips to be consistent
icecrasher321 Jun 5, 2026
f76bc97
fix(ui): remove smodal tabs in favor of chip modal tabs
TheodoreSpeaks Jun 5, 2026
a68a061
fix(ui): skip auto-scrolling on mouse highlight of workspace
TheodoreSpeaks Jun 5, 2026
000e109
fix(platform): restore settings redirects, forgot-password Enter subm…
waleedlatif1 Jun 6, 2026
bbd7284
chore(db): remove migration 0226_third_spot before staging merge
waleedlatif1 Jun 6, 2026
b3cde30
Merge remote-tracking branch 'origin/staging' into improvement/platform
waleedlatif1 Jun 6, 2026
b0fb041
chore(db): regenerate migration as 0227 after staging merge
waleedlatif1 Jun 6, 2026
8c86122
feat(telemetry): add posthog + audit coverage for new platform actions
waleedlatif1 Jun 6, 2026
c5d0e8f
feat(home): fill textarea on suggested prompt click instead of sending
emir-karabeg Jun 6, 2026
e48fcfa
fix(templates): name owning integration in featured block template pr…
emir-karabeg Jun 6, 2026
47044b1
fix(templates): rewrite fragment prompts so each names its integratio…
emir-karabeg Jun 6, 2026
446c989
fix(templates): name integration in remaining block template prompts
emir-karabeg Jun 6, 2026
3ade3e6
fix(icons): convert monochrome dark brand icons to currentColor for d…
emir-karabeg Jun 6, 2026
d8a3241
removed color, user input, sidebar, suggested actions, chips/emcn
emir-karabeg Jun 6, 2026
b7e38df
removed color migration
emir-karabeg Jun 6, 2026
0b200e8
improve(blocks): audit block catalog metadata for accuracy and fill gaps
waleedlatif1 Jun 6, 2026
9f1e352
Merge branch 'improvement/platform' of https://github.com/simstudioai…
waleedlatif1 Jun 6, 2026
2924f0f
chore(telemetry): drop org_seat.drift_reconciled audit
waleedlatif1 Jun 6, 2026
8e69bf1
chore(db): consolidate branch migrations into single 0227
waleedlatif1 Jun 6, 2026
8e37545
fix(emcn): make ChipModal scroll internally when content exceeds view…
waleedlatif1 Jun 6, 2026
e6d2551
fix(emcn): don't close modal when dismissing a dropdown via outside c…
waleedlatif1 Jun 6, 2026
d4bac08
docs(skills): de-duplicate and correct agent docs; canonical styling …
waleedlatif1 Jun 6, 2026
10320a3
docs(skills): broaden boundary-raw-fetch scope note, sync cursor rule…
waleedlatif1 Jun 6, 2026
c7d1134
fix(emcn): harden modal popper guard and exempt caret-anchored dropdo…
waleedlatif1 Jun 6, 2026
ac7adb0
refactor(billing): drop unnecessary useCallback wrappers from event h…
waleedlatif1 Jun 6, 2026
16fd91e
fix(data-drains): complete chip migration of destination forms and fi…
waleedlatif1 Jun 6, 2026
92bbc7b
fix(emcn): broaden modal popper guard to onInteractOutside
waleedlatif1 Jun 6, 2026
92e3915
fix(emcn): harden modal outside interactions
waleedlatif1 Jun 6, 2026
72c67b8
update audit mock
waleedlatif1 Jun 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
68 changes: 65 additions & 3 deletions .agents/skills/add-block/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,19 +627,78 @@ export const ServiceV2Block: BlockConfig = {
}
```

## Block Metadata (BlockMeta)

Every integration block **must** export a `{Service}BlockMeta` object at the bottom of the block file. This metadata drives the integration catalog, tag filters, and workflow template suggestions shown to users.

### Structure

```typescript
import type { BlockConfig, BlockMeta } from '@/blocks/types'

// ... block definition above ...

export const {Service}BlockMeta = {
tags: ['messaging', 'automation'], // Same tags as the block's tags field
templates: [ // Optional but strongly encouraged
{
icon: {Service}Icon,
title: '{Service} use-case title',
prompt: 'Build a workflow that ...',
modules: ['agent', 'workflows'], // Modules the template uses
category: 'productivity', // Template category
tags: ['automation'], // Template-level tags
alsoIntegrations: ['slack'], // Other blocks referenced in the prompt (optional)
},
],
} as const satisfies BlockMeta
```

### Rules

- **Import `BlockMeta`** from `@/blocks/types` alongside `BlockConfig`
- **`tags`** must match the `tags` array on the block config exactly
- **Templates are optional** but should be added for any integration that has a recognizable use case — aim for 2–4 templates per block
- **Template `prompt`** should start with "Build a workflow that..." or "Create a workflow that..." and be concrete enough to generate a real workflow in Mothership
- **Template `modules`** lists the Sim modules the template relies on: `'knowledge-base' | 'tables' | 'files' | 'workflows' | 'scheduled' | 'agent'`
- **Template `category`** is one of: `'popular' | 'sales' | 'support' | 'engineering' | 'marketing' | 'productivity' | 'operations'`
- **`alsoIntegrations`** names other block types (e.g. `'slack'`, `'linear'`) referenced in the template prompt — helps the catalog surface this template when those blocks are selected
- Place the export **after** the main `{Service}Block` export, at the very bottom of the file

### Register in the blocksMeta object

After adding `{Service}BlockMeta` to the block file, register it in `apps/sim/blocks/registry.ts`:

```typescript
// Add import (alongside the block import, alphabetically)
import { ServiceBlock, ServiceBlockMeta } from '@/blocks/blocks/service'

// Add to blocksMeta object (alphabetically)
export const blocksMeta = {
// ... existing entries ...
service: ServiceBlockMeta,
}
```

## Registering Blocks

After creating the block, remind the user to:
1. Import in `apps/sim/blocks/registry.ts`
1. Import `{Service}Block` and `{Service}BlockMeta` in `apps/sim/blocks/registry.ts`
2. Add to the `registry` object (alphabetically):
3. Add to the `blocksMeta` object (alphabetically):

```typescript
import { ServiceBlock } from '@/blocks/blocks/service'
import { ServiceBlock, ServiceBlockMeta } from '@/blocks/blocks/service'

export const registry: Record<string, BlockConfig> = {
// ... existing blocks ...
service: ServiceBlock,
}

export const blocksMeta = {
// ... existing entries ...
service: ServiceBlockMeta,
}
```

## Complete Example
Expand Down Expand Up @@ -827,7 +886,10 @@ All tool IDs referenced in `tools.access` and returned by `tools.config.tool` MU
- [ ] Tools.access lists all tool IDs (snake_case)
- [ ] Tools.config.tool returns correct tool ID (snake_case)
- [ ] Outputs match tool outputs
- [ ] Block registered in registry.ts
- [ ] Block registered in `registry.ts` blocks object (alphabetically)
- [ ] `{Service}BlockMeta` exported at bottom of block file with `tags` and `templates`
- [ ] `BlockMeta` imported from `@/blocks/types` alongside `BlockConfig`
- [ ] Block meta registered in `registry.ts` blocksMeta object (alphabetically)
- [ ] If icon missing: asked user to provide SVG
- [ ] If triggers exist: `triggers` config set, trigger subBlocks spread
- [ ] Optional/rarely-used fields set to `mode: 'advanced'`
Expand Down
45 changes: 40 additions & 5 deletions .agents/skills/add-integration/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export const {service}{Action}Tool: ToolConfig<Params, Response> = {
### Block Structure
```typescript
import { {Service}Icon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import type { BlockConfig, BlockMeta } from '@/blocks/types'
import { AuthMode } from '@/blocks/types'
import { getScopesForService } from '@/lib/oauth/utils'

Expand Down Expand Up @@ -177,8 +177,32 @@ export const {Service}Block: BlockConfig = {

outputs: { /* ... */ },
}

export const {Service}BlockMeta = {
tags: ['tag1', 'tag2'], // IntegrationTag values matching the service's capabilities
templates: [
{
icon: {Service}Icon,
title: '{Service} use-case title',
prompt: 'Build a workflow that ...',
modules: ['agent', 'workflows'],
category: 'productivity',
tags: ['automation'],
alsoIntegrations: ['slack'], // Optional: other blocks referenced in the prompt
},
],
} as const satisfies BlockMeta
```

### BlockMeta rules

- **Tags**: Use `IntegrationTag` values from `@/blocks/types`. Do NOT add a `tags` field to the `BlockConfig` object — tags belong only in `BlockMeta`.
- **`integrationType`**: Must be a valid `IntegrationType` enum value (AI, Analytics, Commerce, Communication, Databases, DevOps, Documents, Email, HR, Marketing, Observability, Productivity, Sales, Search, Security, Support). Never invent a value that doesn't exist in the enum.
- **Templates**: Aim for 2–4 templates per integration. Prompts should be concrete enough to generate a real workflow in Mothership. Start with "Build a workflow that..." or "Create a workflow that...".
- **`alsoIntegrations`**: List other block type IDs referenced in the template prompt (e.g. `'slack'`, `'linear'`).
- Place `{Service}BlockMeta` at the very bottom of the file, after the main block export.
- Register it in both the import and the `blocksMeta` object in `registry.ts`.

### Key SubBlock Patterns

**Condition-based visibility:**
Expand Down Expand Up @@ -359,14 +383,20 @@ export const tools: Record<string, ToolConfig> = {
### Block Registry (`apps/sim/blocks/registry.ts`)

```typescript
// Add import (alphabetically)
import { {Service}Block } from '@/blocks/blocks/{service}'
// Add import (alphabetically) — include BlockMeta
import { {Service}Block, {Service}BlockMeta } from '@/blocks/blocks/{service}'

// Add to registry (alphabetically)
// Add to blocks registry (alphabetically)
export const registry: Record<string, BlockConfig> = {
// ... existing blocks ...
{service}: {Service}Block,
}

// Add to blocksMeta registry (alphabetically)
export const blocksMeta = {
// ... existing entries ...
{service}: {Service}BlockMeta,
}
```

### Trigger Registry (`apps/sim/triggers/registry.ts`) - If triggers exist
Expand Down Expand Up @@ -433,7 +463,12 @@ If creating V2 versions (API-aligned outputs):
- [ ] Configured tools.access with all tool IDs
- [ ] Configured tools.config.tool selector
- [ ] Defined outputs matching tool outputs
- [ ] Registered block in `blocks/registry.ts`
- [ ] `integrationType` uses a valid `IntegrationType` enum value (no invented values)
- [ ] No `tags` field on the `BlockConfig` object (tags live only in `BlockMeta`)
- [ ] `{Service}BlockMeta` exported at bottom of file with `tags` and `templates`
- [ ] `BlockMeta` type imported from `@/blocks/types` alongside `BlockConfig`
- [ ] Block registered in `blocks/registry.ts` blocks object (alphabetically)
- [ ] Block meta registered in `blocks/registry.ts` blocksMeta object (alphabetically)
- [ ] If triggers: set `triggers.enabled` and `triggers.available`
- [ ] If triggers: spread trigger subBlocks with `getTrigger()`

Expand Down
56 changes: 36 additions & 20 deletions .claude/commands/add-block.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ Maps multiple UI fields to a single serialized parameter:

**Critical constraints:**
- `canonicalParamId` must NOT match any other subblock's `id` in the same block (causes conflicts)
- `canonicalParamId` must be unique per block (only one basic/advanced pair per canonicalParamId)
- A `canonicalParamId` links exactly one basic/advanced pair for a single logical parameter. Do NOT reuse the same `canonicalParamId` for different parameters, even under mutually-exclusive conditions/operations
- ONLY use `canonicalParamId` to link basic/advanced mode alternatives for the same logical parameter
- Do NOT use it for any other purpose

Expand Down Expand Up @@ -519,7 +519,10 @@ tools: {
Block outputs only support:
- `type` - The data type ('string', 'number', 'boolean', 'json', 'array')
- `description` - Human readable description
- Nested object structure (for complex types)
- `condition` - Optional visibility condition
- `hiddenFromDisplay` - Optional flag to hide from the output display

**Nested object/`properties` outputs are tool-output-only and will fail TypeScript at build time on block outputs.** For complex shapes use `type: 'json'` and describe the inner fields in the `description` string.

```typescript
outputs: {
Expand All @@ -542,7 +545,7 @@ outputs: {

### Typed JSON Outputs

When using `type: 'json'` and you know the object shape in advance, **describe the inner fields in the description** so downstream blocks know what properties are available. For well-known, stable objects, use nested output definitions instead:
When using `type: 'json'` and you know the object shape in advance, **describe the inner fields in the description** so downstream blocks know what properties are available. Block outputs have no nested `properties` form — always keep the output flat and put the shape in the `description`:

```typescript
outputs: {
Expand All @@ -554,26 +557,10 @@ outputs: {
type: 'json',
description: 'Zone plan information (id, name, price, currency, frequency, is_subscribed)',
},

// BEST: Use nested output definition when the shape is stable and well-known
plan: {
id: { type: 'string', description: 'Plan identifier' },
name: { type: 'string', description: 'Plan name' },
price: { type: 'number', description: 'Plan price' },
currency: { type: 'string', description: 'Price currency' },
},
}
```

Use the nested pattern when:
- The object has a small, stable set of fields (< 10)
- Downstream blocks will commonly access specific properties
- The API response shape is well-documented and unlikely to change

Use `type: 'json'` with a descriptive string when:
- The object has many fields or a dynamic shape
- It represents a list/array of items
- The shape varies by operation
Nested object outputs (`plan: { id: { type: 'string' }, ... }`) are a **tool-output** feature only — `OutputFieldDefinition` for blocks does not allow them and they fail TypeScript at build time.

## V2 Block Pattern

Expand Down Expand Up @@ -798,6 +785,33 @@ Use `wandConfig` for fields that are hard to fill out manually, such as timestam

All tool IDs referenced in `tools.access` and returned by `tools.config.tool` MUST use `snake_case` (e.g., `x_create_tweet`, `slack_send_message`). Never use camelCase or PascalCase.

## BlockMeta (Required)

Every block file must export a `{Service}BlockMeta` alongside the block — **minimum 7 templates**. Look at existing examples in `apps/sim/blocks/blocks/` (e.g. `browser_use.ts`, `google_sheets.ts`) for the pattern.

```typescript
import type { BlockMeta } from '@/blocks/types'

export const {Service}BlockMeta = {
tags: ['tag1', 'tag2'], // IntegrationTag[]
templates: [
{
icon: {Service}Icon,
title: '{Service} <use-case>', // 2–5 words
prompt: 'Build a workflow that...', // specific use case, 1–3 sentences
modules: ['agent', 'workflows'], // 'agent' | 'workflows' | 'tables' | 'files' | 'scheduled' | 'knowledge-base'
category: 'operations', // 'operations' | 'marketing' | 'sales' | 'engineering' | 'productivity' | 'support' | 'popular'
tags: ['automation'],
alsoIntegrations: ['slack'], // optional — other block IDs referenced in the prompt
featured: true, // optional
},
// ... at least 6 more
],
} as const satisfies BlockMeta
```

Derive templates from the service's real use cases. Each prompt should name a concrete trigger, transformation, and output — not a generic description of what the service does.

## Checklist Before Finishing

- [ ] `integrationType` is set to the correct `IntegrationType` enum value
Expand All @@ -816,6 +830,7 @@ All tool IDs referenced in `tools.access` and returned by `tools.config.tool` MU
- [ ] If triggers exist: `triggers` config set, trigger subBlocks spread
- [ ] Optional/rarely-used fields set to `mode: 'advanced'`
- [ ] Timestamps and complex inputs have `wandConfig` enabled
- [ ] Exported `{Service}BlockMeta` with at least 7 templates

## Final Validation (Required)

Expand All @@ -829,3 +844,4 @@ After creating the block, you MUST validate it against every tool it references:
- Type coercions in `tools.config.params` for any params that need conversion (Number(), Boolean(), JSON.parse())
3. **Verify block outputs** cover the key fields returned by all tools
4. **Verify conditions** — each subBlock should only show for the operations that actually use it
5. **Verify `{Service}BlockMeta` is exported** with at least 7 templates, each having `icon`, `title`, `prompt`, `modules`, `category`, and `tags`
30 changes: 21 additions & 9 deletions .claude/commands/add-connector.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const {service}Connector: ConnectorConfig = {

configFields: [
// Rendered dynamically by the add-connector modal UI
// Supports 'short-input' and 'dropdown' types
// Supports 'short-input', 'dropdown', and 'selector' types — see ConfigField Types below
],

listDocuments: async (accessToken, sourceConfig, cursor) => {
Expand Down Expand Up @@ -408,6 +408,16 @@ Each entry has:
Users can opt out of specific tags in the modal. Disabled IDs are stored in `sourceConfig.disabledTagIds`.
The assigned mapping (`semantic id → slot`) is stored in `sourceConfig.tagSlotMapping`.

## `@/connectors/utils` Helpers

Reuse these instead of inlining the same logic (the validator enforces them):

- `htmlToPlainText(html)` — strip HTML to plain text before indexing `ExternalDocument.content`. Never index raw HTML.
- `computeContentHash(content)` — stable content hash for change detection.
- `parseTagDate(value)` — parse to a valid `Date` or `undefined` (guards Invalid Date). Use in `mapTags` for date fields.
- `joinTagArray(value)` — validate an array and join to a comma-separated string, or `undefined`. Use in `mapTags` for array/label fields.
- `parseMultiValue(value)` — normalize a value into a `string[]`.

## mapTags — Metadata to Semantic Keys

Maps source metadata to semantic tag keys. Required if `tagDefinitions` is set.
Expand All @@ -416,25 +426,27 @@ using the `tagSlotMapping` stored on the connector.

Return keys must match the `id` values declared in `tagDefinitions`.

Use the `@/connectors/utils` helpers for the common transforms — don't hand-roll date/array validation:

```typescript
import { joinTagArray, parseTagDate } from '@/connectors/utils'

mapTags: (metadata: Record<string, unknown>): Record<string, unknown> => {
const result: Record<string, unknown> = {}

// Validate arrays before casting — metadata may be malformed
const labels = Array.isArray(metadata.labels) ? (metadata.labels as string[]) : []
if (labels.length > 0) result.labels = labels.join(', ')
// joinTagArray validates the array and joins to a comma-separated string (undefined if empty)
const labels = joinTagArray(metadata.labels)
if (labels) result.labels = labels

// Validate numbers — guard against NaN
if (metadata.version != null) {
const num = Number(metadata.version)
if (!Number.isNaN(num)) result.version = num
}

// Validate dates — guard against Invalid Date
if (typeof metadata.lastModified === 'string') {
const date = new Date(metadata.lastModified)
if (!Number.isNaN(date.getTime())) result.lastModified = date
}
// parseTagDate returns a valid Date or undefined (guards against Invalid Date)
const lastModified = parseTagDate(metadata.lastModified)
if (lastModified) result.lastModified = lastModified

return result
}
Expand Down
15 changes: 10 additions & 5 deletions .claude/commands/add-hosted-key.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ When a tool has hosted key support, Sim provides its own API key if the user has

| Step | What | Where |
|------|------|-------|
| 1 | Register BYOK provider ID | `tools/types.ts`, `app/api/workspaces/[id]/byok-keys/route.ts` |
| 1 | Register BYOK provider ID | `tools/types.ts`, `lib/api/contracts/byok-keys.ts` |
| 2 | Research the API's pricing and rate limits | API docs / pricing page (before writing any code) |
| 3 | Add `hosting` config to the tool | `tools/{service}/{action}.ts` |
| 4 | Hide API key field when hosted | `blocks/blocks/{service}.ts` |
Expand All @@ -30,10 +30,15 @@ export type BYOKProviderId =
| 'your_service'
```

Then add it to `VALID_PROVIDERS` in `app/api/workspaces/[id]/byok-keys/route.ts`:
Then add the same provider id to the `byokProviderIdSchema` enum in `lib/api/contracts/byok-keys.ts` (this is what the byok-keys route validates against):

```typescript
const VALID_PROVIDERS = ['openai', 'anthropic', 'google', 'mistral', 'your_service'] as const
export const byokProviderIdSchema = z.enum([
'openai',
'anthropic',
// ...existing providers
'your_service',
])
```

## Step 2: Research the API's Pricing Model and Rate Limits
Expand Down Expand Up @@ -230,7 +235,7 @@ Both subblocks share the same `id: 'apiKey'`, so the same value flows to the too
To exclude multiple operations, use an array: `{ field: 'operation', value: ['op_a', 'op_b'] }`.

**Reference implementations:**
- **Exa** (`blocks/blocks/exa.ts`): `research` operation excluded from hosting — lines 309-329
- **Exa** (`blocks/blocks/exa.ts`): `exa_research` operation excluded from hosting — duplicate `apiKey` pair around lines ~348-365
- **Google Maps** (`blocks/blocks/google_maps.ts`): `speed_limits` operation excluded from hosting (deprecated Roads API)

## Step 5: Add to the BYOK Settings UI
Expand Down Expand Up @@ -284,7 +289,7 @@ This summary helps reviewers verify that the pricing and rate limiting are well-
## Checklist

- [ ] Provider added to `BYOKProviderId` in `tools/types.ts`
- [ ] Provider added to `VALID_PROVIDERS` in the BYOK keys API route
- [ ] Provider added to `byokProviderIdSchema` enum in `lib/api/contracts/byok-keys.ts`
- [ ] API pricing docs researched — understand per-unit cost and whether the API reports cost in responses
- [ ] API rate limits researched — understand RPM/TPM limits, per-key vs per-account, and plan tiers
- [ ] `hosting` config added to the tool with `envKeyPrefix`, `apiKeyParam`, `byokProviderId`, `pricing`, and `rateLimit`
Expand Down
Loading
Loading