Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
  •  
  •  
  •  
12 changes: 7 additions & 5 deletions .agents/skills/add-settings-page/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
---
name: add-settings-page
description: Add a new Sim settings page, or audit existing settings pages for design-system compliance with the shared SettingsPanel layout. Use when creating a settings tab, or when asked to check/clean up settings pages so they match the design system (consistent title, header, search, spacing).
description: Add or audit settings pages that use SettingsPanel in the existing Sim app. Use implement-platform for isolated Platform settings.
---

# Settings Page (add / audit)

For `apps/sim/platform/**`, use [implement-platform](../implement-platform/SKILL.md). In a mixed request, apply the steps below only to the existing app's settings.

Settings page chrome (header bar, scroll region, content column, nav-driven
title + description) is owned by the `settings/[section]/layout.tsx` shell. Each
page renders through **`SettingsPanel`**, which registers the page's header data
Expand Down Expand Up @@ -45,28 +47,28 @@ For each page component, confirm the checklist in `.claude/rules/sim-settings-pa
Each grep lists candidates; review every match against the expected ones named below.

1. Find hand-rolled shells that should be `SettingsPanel`:
`git grep -n "flex h-full flex-col bg-\[var(--bg)\]" -- 'apps/sim/**/settings/**' 'apps/sim/ee/'`
`git grep -n "flex h-full flex-col bg-\[var(--bg)\]" -- 'apps/sim/**/settings/**' 'apps/sim/ee/' ':(exclude)apps/sim/platform/**'`
— expected matches: the workspace and organization `settings/layout.tsx` shells and the
shared header shell (`components/settings/settings-header.tsx`); an entitlement/loading gate
is also fine. `CredentialDetailLayout` (the `settings/secrets/[credentialId]` exception) is
an exempt hand-rolled shell outside these pathspecs. A detail sub-view is never a match: it
passes `back={{ text, icon: ArrowLeft, onSelect }}` to `SettingsPanel`. Anything else is a
violation: render it through `SettingsPanel`.
2. Find hand-rolled title blocks:
`git grep -n "text-\[var(--text-body)\] text-lg" -- 'apps/sim/**/settings/**' 'apps/sim/ee/'`
`git grep -n "text-\[var(--text-body)\] text-lg" -- 'apps/sim/**/settings/**' 'apps/sim/ee/' ':(exclude)apps/sim/platform/**'`
— the only title is the `<h1>` in `settings-header.tsx`; a non-heading value at that size
(e.g. the credit balance in `ee/organization-usage/components/usage-credits.tsx`) is fine.
3. Find literal pixel text sizes (should be 0 — see "Text Scale" in
`.claude/rules/sim-styling.md`):
`git grep -nE "text-\[1[0-8]px\]" -- 'apps/sim/**/settings/**' 'apps/sim/ee/'`.
`git grep -nE "text-\[1[0-8]px\]" -- 'apps/sim/**/settings/**' 'apps/sim/ee/' ':(exclude)apps/sim/platform/**'`.
Display type above the scale (`text-[40px]` hero headings) is deliberate and out of
scope.
4. Confirm each page imports `SettingsPanel` and that its registry entry has an
accurate `description` of consistent length with its peers.
- Editable pages: confirm Save/Discard go through `saveDiscardActions()` and
dirty is wired via `useSettingsUnsavedGuard` (called before early-return
gates) — flag any hand-rolled Save button, `beforeunload`, or unsaved modal.
`git grep -n "beforeunload" -- 'apps/sim/**/settings/**' 'apps/sim/ee/' 'apps/sim/components/settings/' ':(exclude,glob)**/*.test.*'`
`git grep -n "beforeunload" -- 'apps/sim/**/settings/**' 'apps/sim/ee/' 'apps/sim/components/settings/' ':(exclude)apps/sim/platform/**' 'apps/sim/hooks/use-settings-browser-navigation.ts' ':(exclude,glob)**/*.test.*'`
should only hit the centralized `use-settings-browser-navigation.ts`.
5. Fix each finding with the smallest structural change that satisfies the checklist;
do not touch handlers, state, queries, or gate returns. A pixel-size fix swaps
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/cleanup/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Run these in parallel on the parsed `scope`:
3. `/you-might-not-need-a-callback <scope> fix=false`
4. `/you-might-not-need-state <scope> fix=false`
5. `/react-query-best-practices <scope> fix=false`
6. `/emcn-design-review <scope> fix=false`
6. Design review: route `apps/sim/platform/**` to [implement-platform](../implement-platform/SKILL.md) and existing app EMCN paths to [emcn-design-review](../emcn-design-review/SKILL.md). For a mixed diff, the same pass reviews each subset with its own contract. Both reviews are read-only and return proposals for Step 2.
7. `/you-might-not-need-url-state <scope> fix=false`
8. `/you-might-not-need-a-comment <scope> fix=false`
9. `/test-audit audit <test paths>` — read-only; only when the scope adds or changes test files (`*.test.ts(x)`, `*.integration.ts`, `**/e2e/**`, `apps/sim/scripts/test-*-e2e.ts`). First resolve a free-form scope to the concrete list of added or changed test paths (`git diff --name-only` against the scope's base) and pass those paths. It applies the authoring gate to every new or changed test and proposes deleting the ones that fail it.
Expand Down
4 changes: 2 additions & 2 deletions .agents/skills/emcn-design-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: emcn-design-review
description: Review UI code for alignment with the emcn design system — components, tokens, patterns, and conventions
description: Review the existing Sim app against packages/emcn. Route isolated Platform UI in apps/sim/platform to implement-platform.
argument-hint: "[scope] [fix=true|false]"
---

Expand All @@ -14,7 +14,7 @@ User arguments: $ARGUMENTS

## Context

This codebase uses **emcn**, a custom component library built on Radix UI primitives with CVA variants and CSS variable design tokens. All UI must use emcn components and tokens.
The existing Sim app uses `packages/emcn`, its Radix primitives, CVA variants, and CSS tokens. For `apps/sim/platform/**`, use [implement-platform](../implement-platform/SKILL.md). For mixed scopes, review each file under its owning system and preserve the requested `fix` mode for both.

## Steps

Expand Down
16 changes: 16 additions & 0 deletions .agents/skills/implement-platform/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
name: implement-platform
description: Build, change, consolidate, remove, or review Sim Platform UI in apps/sim/platform. Use for code-first product routes, EMCN components, Paper handoff and design drift in the isolated Next app.
---

# Implement Sim Platform

Start in the Sim checkout containing the requested product work. Read the [Platform contract](../../../apps/sim/platform/AGENTS.md) and [component ownership map](../../../apps/sim/platform/docs/component-ownership.md). These versioned files carry the current rules into a fresh chat. Use the [Platform README](../../../apps/sim/platform/README.md) for the local routes, fixture states, generators, and verification commands.

1. **Establish scope on the real route.** Identify the product entry, interaction, phase, and affected consumers. When rebuilding an existing workflow, trace the old navigation target, its access gate, and the actions reachable by that viewer. Use that evidence to decide which controls belong on the new page before consulting the broader API or provider catalog. Phase 1 owns foundations and the library. Phase 2 owns working UI and transient interaction state, with examples supplied through the server fixture flag. Phase 3 connects real data and operations. Reuse the same renderer in the browser and Sim Desktop. Read the installed Next guides for the file structure or framework behavior you are changing.
For organization Settings, inventory the old sidebar in order, its viewer/deployment gates and every action reachable from each section. Map old header buttons to the row or section they act on. Verify the same destination and drilldown on the fixture and authenticated routes; keep real writes outside fixture sessions.
2. **Resolve design intent.** For Paper-backed work, use `$sim-paper-design` to locate the live Shared or Platform master and the product states that use it. Exclude Marcus. Preserve the key and theme roles. Treat artboard sizes as reference measurements. For code-first changes, follow the latest explicit product direction and inspect the rendered route. Identify any source you could not verify. Update the Paper canvas when the request includes Paper changes.
3. **Choose or change the owner.** Start with the behavior. An action, navigation row, value picker, or disclosure has an existing keyboard and pointer contract. Different interactions may share visual roles while retaining different semantics. Use the existing family and named props for a change in size, intent, icon, or content. Put unique anatomy and its CSS beside the route component. Keep page files free of styling. Only EMCN owns the appearance of its controls. Use Base UI there for complex keyboard, floating, and dismissal behavior.
4. **Trace the full change.** On a second independent feature use, promote the original implementation and migrate both callers. For consolidation, compare semantics, map every consumer to its replacement, then remove the obsolete implementation, export, variant styles, and unused registrations. For deletion, also check menus, preferences, fixture data, workbench references, and tests that existed only for the removed feature. Preserve unrelated consumers and historical Paper evidence. A new variant needs a reachable product use. Edit the source or compiler for generated foundations and recipes.
5. **Verify where people use it.** Run the design audit and applicable checks from the README. Render the changed product route with empty, full, stress, and fixture-off data as relevant. Check both themes, widths between artboards, long content, text scaling, keyboard, and pointer states. Compare shared controls in their actual consumers. Check the actual scroll edge and the open popup when space is tight. For shell, panel, or desktop work, exercise the real Electron renderer. For substantial implementations and consolidations, use an independent agent during design or implementation and for a final review of the changed owners and routes. Provide the working localhost route for visual review.
6. **Keep decisions durable.** Follow the contract’s maintenance guidance when an approved correction changes a shared rule. Record feature-specific decisions with their feature. For sustained work, keep a task checkpoint with the code revision, verified states, evidence, and outstanding work. Include the branch or PR, checkpoint path, and localhost route in a handoff. On resumption, compare the checkpoint with the current branch, working tree, and relevant live sources before acting.
4 changes: 4 additions & 0 deletions .agents/skills/implement-platform/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Implement Sim Platform"
short_description: "Build and review the code-first Sim Platform"
default_prompt: "Use $implement-platform to implement the next Platform product change in Sim."
2 changes: 2 additions & 0 deletions .claude/rules/emcn-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ paths:

# EMCN Components

This guide applies to the existing app. For `apps/sim/platform/**`, use `apps/sim/platform/AGENTS.md`.

Import components, `cn`, and tokens from the `@sim/emcn` barrel; icons come from the `@sim/emcn/icons` subpath, and CSS modules from their file path. Never deep-import other component subpaths. The **chip family** is the platform's primary chrome — always reach for it over the legacy primitives it is progressively replacing (`Input`→`ChipInput`, `Textarea`→`ChipTextarea`, `Modal`→`ChipModal`, `Select`/`Combobox`→`ChipSelect`/`ChipCombobox`/`ChipDropdown`, date field→`ChipDatePicker`). `ChipSwitch` is a segmented choice between options, not a replacement for `Switch`: a boolean on/off toggle stays `Switch`. For context/action menus the canonical control is `DropdownMenu` — the standard menu (not a chip, and never a hand-rolled popover).

## Chip chrome — single source of truth
Expand Down
7 changes: 7 additions & 0 deletions .claude/rules/platform-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
description: Sim Platform implementation from Paper
paths:
- "apps/sim/platform/**"
---

Use the canonical contract in `apps/sim/platform/AGENTS.md` and the `implement-platform` skill. Legacy EMCN and app styling rules do not govern this separate project.
2 changes: 2 additions & 0 deletions .claude/rules/sim-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ paths:

# Sim App Architecture

This guide applies to the existing app. For `apps/sim/platform/**`, use `apps/sim/platform/AGENTS.md`.

Repository layout, package boundaries, the application operation boundary, naming, and utils placement are in the root `CLAUDE.md`. This file holds the app-internal boundaries.

## The `'use client'` server boundary
Expand Down
2 changes: 1 addition & 1 deletion .claude/rules/sim-settings-pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ rendered through `<SettingsActionChips actions={…} />` from
is what keeps tone/icon/variant/tooltip handling from drifting between the two
shells. Reach for it before hand-rolling a `Chip`.
- **`useSettingsUnsavedGuard({ isDirty, navigationBlocked, onDiscard })`** from
`@/components/settings/use-settings-unsaved-guard` registers one editor with the
`@/hooks/use-settings-unsaved-guard` registers one editor with the
shared settings store. Register every full-page draft, including inline creation
forms. Dirty computation stays local and derived; fetched defaults stay clean.
- **`onDiscard` resets the registered draft.** The root `SettingsNavigationGuard`
Expand Down
2 changes: 2 additions & 0 deletions .claude/rules/sim-styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ paths:

# Styling Rules

This guide applies to the existing app. For `apps/sim/platform/**`, use `apps/sim/platform/AGENTS.md`.

## Tailwind

1. **No inline styles** - Use Tailwind classes. Exception: a genuinely dynamic
Expand Down
2 changes: 1 addition & 1 deletion .claude/rules/sim-url-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ const setSearch = useDebouncedSearchSetter(write, { debounceMs: 200 })

- **Never write a trimmed value to a param that controls the input** — trimming on write eats the user's trailing space mid-typing and makes multi-word queries untypable. The hook writes the raw value; trim only for the empty-check (the hook does this) and on *read* where the value feeds a query or filter.
- **Keep fetches/filtering debounced.** Where the search value feeds a React Query key or an expensive in-memory filter, derive a debounced value off the instant nuqs value (`const debounced = useDebounce(urlSearch, SEARCH_DEBOUNCE_MS)` with `SEARCH_DEBOUNCE_MS` from `@/lib/url-state`) and feed *that* to the query — the instant value is only for the input box. Cheap in-memory filtering over a small static list may read the instant value directly.
- Settings list search boxes use `useSettingsSearch()` from `settings/components/use-settings-search` — the shared `?search=` binding for that surface.
- Settings list search boxes use `useSettingsSearch()` from `@/hooks/use-settings-search` — the shared `?search=` binding for that surface.
- Preserve `clearOnDefault` (empty clears the param), the existing default, and `history: 'replace'`. See logs (`use-log-filters.ts` grouped, query stays debounced), integrations (cheap in-memory filter, instant value), and tables (filter stays debounced).

## Sort convention (`sort` + `dir`)
Expand Down
1 change: 1 addition & 0 deletions .claude/skills/implement-platform
2 changes: 2 additions & 0 deletions .cursor/rules/emcn-components.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ globs: ["packages/emcn/**"]

# EMCN Components

This guide applies to the existing app. For `apps/sim/platform/**`, use `apps/sim/platform/AGENTS.md`.

Import components, `cn`, and tokens from the `@sim/emcn` barrel; icons come from the `@sim/emcn/icons` subpath, and CSS modules from their file path. Never deep-import other component subpaths. The **chip family** is the platform's primary chrome — always reach for it over the legacy primitives it is progressively replacing (`Input`→`ChipInput`, `Textarea`→`ChipTextarea`, `Modal`→`ChipModal`, `Select`/`Combobox`→`ChipSelect`/`ChipCombobox`/`ChipDropdown`, date field→`ChipDatePicker`). `ChipSwitch` is a segmented choice between options, not a replacement for `Switch`: a boolean on/off toggle stays `Switch`. For context/action menus the canonical control is `DropdownMenu` — the standard menu (not a chip, and never a hand-rolled popover).

## Chip chrome — single source of truth
Expand Down
8 changes: 8 additions & 0 deletions .cursor/rules/platform-design.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
description: "Sim Platform implementation from Paper"
globs: ["apps/sim/platform/**"]
---

<!-- Generated from .claude/rules/platform-design.md by `bun run skills:sync`. Edit the source, not this file. -->

Use the canonical contract in `apps/sim/platform/AGENTS.md` and the `implement-platform` skill. Legacy EMCN and app styling rules do not govern this separate project.
2 changes: 2 additions & 0 deletions .cursor/rules/sim-architecture.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ globs: ["apps/sim/**"]

# Sim App Architecture

This guide applies to the existing app. For `apps/sim/platform/**`, use `apps/sim/platform/AGENTS.md`.

Repository layout, package boundaries, the application operation boundary, naming, and utils placement are in the root `CLAUDE.md`. This file holds the app-internal boundaries.

## The `'use client'` server boundary
Expand Down
2 changes: 1 addition & 1 deletion .cursor/rules/sim-settings-pages.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ rendered through `<SettingsActionChips actions={…} />` from
is what keeps tone/icon/variant/tooltip handling from drifting between the two
shells. Reach for it before hand-rolling a `Chip`.
- **`useSettingsUnsavedGuard({ isDirty, navigationBlocked, onDiscard })`** from
`@/components/settings/use-settings-unsaved-guard` registers one editor with the
`@/hooks/use-settings-unsaved-guard` registers one editor with the
shared settings store. Register every full-page draft, including inline creation
forms. Dirty computation stays local and derived; fetched defaults stay clean.
- **`onDiscard` resets the registered draft.** The root `SettingsNavigationGuard`
Expand Down
2 changes: 2 additions & 0 deletions .cursor/rules/sim-styling.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ globs: ["apps/sim/**/*.tsx","apps/sim/**/*.css"]

# Styling Rules

This guide applies to the existing app. For `apps/sim/platform/**`, use `apps/sim/platform/AGENTS.md`.

## Tailwind

1. **No inline styles** - Use Tailwind classes. Exception: a genuinely dynamic
Expand Down
2 changes: 1 addition & 1 deletion .cursor/rules/sim-url-state.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ const setSearch = useDebouncedSearchSetter(write, { debounceMs: 200 })

- **Never write a trimmed value to a param that controls the input** — trimming on write eats the user's trailing space mid-typing and makes multi-word queries untypable. The hook writes the raw value; trim only for the empty-check (the hook does this) and on *read* where the value feeds a query or filter.
- **Keep fetches/filtering debounced.** Where the search value feeds a React Query key or an expensive in-memory filter, derive a debounced value off the instant nuqs value (`const debounced = useDebounce(urlSearch, SEARCH_DEBOUNCE_MS)` with `SEARCH_DEBOUNCE_MS` from `@/lib/url-state`) and feed *that* to the query — the instant value is only for the input box. Cheap in-memory filtering over a small static list may read the instant value directly.
- Settings list search boxes use `useSettingsSearch()` from `settings/components/use-settings-search` — the shared `?search=` binding for that surface.
- Settings list search boxes use `useSettingsSearch()` from `@/hooks/use-settings-search` — the shared `?search=` binding for that surface.
- Preserve `clearOnDefault` (empty clears the param), the existing default, and `history: 'replace'`. See logs (`use-log-filters.ts` grouped, query stays debounced), integrations (cheap in-memory filter, instant value), and tables (filter stays debounced).

## Sort convention (`sort` + `dir`)
Expand Down
Loading