Skip to content

Commit 7ca8a8b

Browse files
committed
docs(agents): align UI skills with the settings, emcn, and state rules
add-settings-page's audit greps used a pathspec that matches nothing, and its registration steps named types that no longer exist (SETTINGS_SECTION_REGISTRY and SECTION_MODULES are the mechanism). The emcn review taught the legacy Button variants and a destructive Delete chip that sim-settings-pages forbids. The design skills now carry repo precedence notes (no global styles, emcn owns chrome, framer-motion, hover-hover:, fixed fonts and weights). The you-might-not-need-* skills recognize URL state, the list-preference exception, and the Map memo the component rule prescribes.
1 parent 0d5c74a commit 7ca8a8b

13 files changed

Lines changed: 81 additions & 99 deletions

File tree

‎.agents/skills/add-settings-page/SKILL.md‎

Lines changed: 43 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -21,65 +21,54 @@ Key paths:
2121

2222
## Mode A — Add a new settings page
2323

24-
1. **Navigation.** In `navigation.ts`: add the id to the `SettingsSection` union,
25-
then a `NavigationItem` with `label` AND a one-line `description` (verb-first,
26-
~40–55 chars, product voice per `.claude/rules/constitution.md`). Place it in
27-
the right `section` group and set any gating flags (`requiresHosted`,
28-
`requiresEnterprise`, etc.).
29-
2. **Wire the switch.** Add the component to the `effectiveSection` render switch
30-
in `settings/[section]/settings.tsx` (lazy `dynamic(...)` like its siblings).
24+
1. **Navigation.** In `navigation.ts`: add the id to `UnifiedSettingsSection`, then a
25+
`SETTINGS_SECTION_REGISTRY` entry with `label`, `icon`, and
26+
`unified: { id, description, group, order }` (description verb-first, ~40–55 chars,
27+
product voice per `.claude/rules/constitution.md`). Set gating flags
28+
(`requiresHosted`, `requiresEnterprise`, …) on `unified`, and add `planes` only if the
29+
section also exists on a standalone plane.
30+
2. **Wire the switch.** Register the module in `SECTION_MODULES`
31+
(`settings/section-warmers.ts`), then add
32+
`const X = dynamic(() => SECTION_MODULES.x().then((m) => m.X))` and its case in the
33+
`effectiveSection` switch in `settings/[section]/settings.tsx`.
3134
3. **Build the body inside `SettingsPanel`** per the rule's canonical page shape:
3235
`actions`, `search`, `children`, modal siblings in a fragment.
33-
4. **If the page has editable state**, wire the shared save/discard stack — put
34-
`SaveDiscardActions` (dirty-gated Discard+Save chips) in `actions`, and call
35-
`useSettingsUnsavedGuard({ isDirty })` **before any early-return gate**.
36-
Detail sub-views additionally route the back chip through
37-
`guard.guardBack(closeFn)` and render the shared `UnsavedChangesModal`. Never
38-
hand-roll a Save button, a `beforeunload`, or an "Unsaved changes" modal —
39-
they're centralized. See the "Save / Discard + unsaved-changes guard" section
40-
in `.claude/rules/sim-settings-pages.md`.
41-
5. **Verify:** `cd apps/sim && bun run type-check`; `bunx biome check --write <file>`.
36+
4. **If the page has editable state**, wire the shared save/discard stack exactly as in
37+
`.claude/rules/sim-settings-pages.md` "Save / Discard + unsaved-changes guard"
38+
(`saveDiscardActions()`, `useSettingsUnsavedGuard` before any early return).
39+
5. **Verify:** the local gate in the root `CLAUDE.md` ("How your work is checked").
4240

4341
## Mode B — Audit existing settings pages
4442

4543
For each page component, confirm the checklist in `.claude/rules/sim-settings-pages.md`:
4644

4745
1. Find hand-rolled shells that should be `SettingsPanel`:
48-
`git grep -n "flex h-full flex-col bg-\[var(--bg)\]" -- 'apps/sim/**/settings/' 'apps/sim/ee/'`
49-
— every match should be either `settings-panel.tsx`, a **detail sub-view**
50-
(has a `<Chip leftIcon={ArrowLeft}>` back button), or an entitlement/loading
51-
**gate** early-return. Anything else is a page that still needs migrating.
52-
2. Find hand-rolled title blocks (should be 0 outside detail views):
53-
`git grep -n "text-\[var(--text-body)\] text-lg" -- 'apps/sim/**/settings/' 'apps/sim/ee/'`
54-
3. Find literal pixel text sizes (should be 0 — see "Text-scale tokens" in
55-
`.claude/rules/sim-settings-pages.md` for the token map and the row
56-
title/subtitle pairing convention):
57-
`git grep -nE "text-\[1[0-8]px\]" -- 'apps/sim/**/settings/' 'apps/sim/ee/'` — should
58-
be 0. Display type above the scale (`text-[40px]` hero headings) is deliberate
59-
and out of scope.
60-
4. Confirm each page imports `SettingsPanel` and that its `NavigationItem` has an
46+
`git grep -n "flex h-full flex-col bg-\[var(--bg)\]" -- 'apps/sim/**/settings/**' 'apps/sim/ee/'`
47+
— every match should be the settings shell (`settings/layout.tsx`),
48+
`CredentialDetailLayout` (the `settings/secrets/[credentialId]` exception), or an
49+
entitlement/loading gate. A detail sub-view is never a match: it passes
50+
`back={{ text, icon: ArrowLeft, onSelect }}` to `SettingsPanel`. Anything else is a
51+
violation: render it through `SettingsPanel`.
52+
2. Find hand-rolled title blocks (should match only `settings-header.tsx`, the shell):
53+
`git grep -n "text-\[var(--text-body)\] text-lg" -- 'apps/sim/**/settings/**' 'apps/sim/ee/'`
54+
3. Find literal pixel text sizes (should be 0 — see "Text Scale" in
55+
`.claude/rules/sim-styling.md`):
56+
`git grep -nE "text-\[1[0-8]px\]" -- 'apps/sim/**/settings/**' 'apps/sim/ee/'`.
57+
Display type above the scale (`text-[40px]` hero headings) is deliberate and out of
58+
scope.
59+
4. Confirm each page imports `SettingsPanel` and that its registry entry has an
6160
accurate `description` of consistent length with its peers.
62-
- Editable pages: confirm Save/Discard go through `SaveDiscardActions` and
61+
- Editable pages: confirm Save/Discard go through `saveDiscardActions()` and
6362
dirty is wired via `useSettingsUnsavedGuard` (called before early-return
6463
gates) — flag any hand-rolled Save button, `beforeunload`, or unsaved modal.
65-
`git grep -n "beforeunload" -- 'apps/sim/**/settings/' 'apps/sim/ee/'`
64+
`git grep -n "beforeunload" -- 'apps/sim/**/settings/**' 'apps/sim/ee/'`
6665
should only hit the centralized `use-settings-before-unload.ts`.
67-
5. When migrating a page, change ONLY the structural shell→`SettingsPanel` swap:
68-
move header chips to `actions`, the standalone search to `search`, delete the
69-
`<h1>` title block, replace the three closing `</div>` (column/scroll/shell)
70-
with `</SettingsPanel>`, and keep modal siblings in a `<>` fragment. Do NOT
71-
touch handlers, state, queries, conditional rendering, or detail/gate returns.
72-
Drop per-page `gap-*`/`pt-*` on the content column in favor of the panel default.
73-
6. When fixing literal pixel text sizes, replace ONLY the size class with its
74-
exact-pixel-equivalent named token (e.g. `text-[12px]` → `text-caption`,
75-
never a different size) — this must render pixel-identical, not restyle the
76-
page. Leave color tokens (`--text-primary` vs `--text-body`, etc.) untouched
77-
unless they're also being changed for an unrelated, deliberate reason.
78-
7. Remove now-unused imports (`ChipInput`/`Search`) ONLY after grepping that
79-
they are not still used elsewhere in the file (e.g. by a detail view).
80-
8. **Verify the whole sweep:** `bun run type-check`, `biome check` on every touched
81-
file, and run the affected pages' tests. Diff each file against the base and
82-
confirm the change is purely structural before shipping.
66+
5. Fix each finding with the smallest structural change that satisfies the checklist;
67+
do not touch handlers, state, queries, or gate returns. A pixel-size fix swaps
68+
only the size class for its exact-pixel token (`text-[12px]` → `text-caption`).
69+
6. **Verify the whole sweep:** the local gate in the root `CLAUDE.md`, plus the
70+
affected pages' tests. Diff each file against the base and confirm the change is
71+
purely structural before shipping.
8372

8473
## Mode C — Migrate list rows to `SettingsResourceRow`
8574

@@ -91,20 +80,13 @@ contract. Then, per page:
9180
Every match outside `settings-resource-row.tsx` is either a row to migrate or a
9281
genuinely different shape (multi-line body, tabular columns, a grid) that stays
9382
bespoke — decide which, and say so.
94-
2. Replace the row *and* its wrapper: a `<button>`/`<Link>` around the row becomes
95-
`onClick`/`href` on the row itself. Wrapping the row is what the primitive
96-
exists to stop — it is also invalid HTML once `trailing` holds a control.
97-
3. Sort the trailing content: interactive → `trailing`, decorative → `badge`.
98-
Getting this backwards makes the row's right edge a dead zone.
99-
4. Add `navigable` only if the row opens a detail page, and `clickLabel` always.
100-
5. Drop the container's `-mx-2` — the row now owns the bleed. Use
101-
`RESOURCE_LIST_STACK` / `RESOURCE_LIST_GRID`; do not hand-write the gap.
102-
6. Unlike Mode B, this migration **may** change conditional rendering: a
103-
`<button disabled={!can}>` becomes `onClick={can ? … : undefined}` +
104-
`navigable={can}`, which renders a plain non-interactive row. Verify the gated
105-
state has no clickable affordance left.
106-
7. Check what the old row rendered *beside* the title (a badge, a timestamp, a
83+
2. Convert the row and its wrapper per "The resource row" (props, `trailing` vs
84+
`badge`, bleed, `navigable`/`clickLabel`). Unlike Mode B, this conversion **may**
85+
change conditional rendering (a permission gate becomes
86+
`onClick={can ? … : undefined}` + `navigable={can}`); verify the gated state has no
87+
clickable affordance left.
88+
3. Check what the hand-rolled row rendered *beside* the title (a badge, a timestamp, a
10789
transport label). The row's title truncates as one unit, so anything folded
10890
into it can be ellipsised away — move it to `description` or `badge`.
109-
8. Verify: `bun run type-check`, `biome check`, the page's tests, and a diff read of
91+
4. Verify: the local gate, the page's tests, and a diff read of
11092
every converted block for lost props, conditions, and `key` placement.

‎.agents/skills/design-taste-frontend/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ source: https://github.com/leonxlnx/taste-skill — skills/taste-skill/SKILL.md
44
description: Anti-slop frontend skill for landing pages, portfolios, and redesigns. The agent reads the brief, infers the right design direction, and ships interfaces that do not look templated. Real design systems when applicable, audit-first on redesigns, strict pre-flight check.
55
---
66

7-
> **In this repo:** Tailwind 4 (CSS-first config in `apps/sim/app/_styles/globals.css`); animation via `import { motion } from 'framer-motion'` (not `motion/react` — rewrite every `motion/react` import in the samples below); icons from `@sim/emcn/icons`; colors through the CSS-variable tokens in `.claude/rules/sim-styling.md` (no hardcoded `text-gray-*`/hex/`zinc` utilities, no paired `dark:` utilities). This note overrides any conflicting guidance or code sample anywhere in this file.
7+
> **In this repo:** Tailwind 4 (CSS-first config in `apps/sim/app/_styles/globals.css`); animation via `import { motion } from 'framer-motion'` (not `motion/react` — rewrite every `motion/react` import in the samples below); icons from `@sim/emcn/icons`; colors through the CSS-variable tokens in `.claude/rules/sim-styling.md` (no hardcoded `text-gray-*`/hex/`zinc` utilities, no paired `dark:` utilities). This note overrides any conflicting guidance or code sample anywhere in this file. Fonts are fixed (Season body, Inter, Martian Mono); never introduce new families. Font weight is only `font-normal`/`font-medium`/`font-semibold`. Elevation uses the `shadow-subtle|medium|overlay|card` tokens. Type size uses named tokens, never `text-[Npx]`. Product forms use `ChipModalField`. Use `bunx`, never `npx`. Do not add GSAP, Lenis, Three, or shadcn. Landing copy and SEO follow `.claude/rules/constitution.md` and `.claude/rules/landing-seo-geo.md`.
88
99
# tasteskill: Anti-Slop Frontend Skill
1010

‎.agents/skills/emcn-design-review/SKILL.md‎

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ This codebase uses **emcn**, a custom component library built on Radix UI primit
3232

3333
## Design Tokens
3434

35-
Use CSS variable pattern (`text-[var(--text-primary)]`), never Tailwind semantics (`text-muted-foreground`) or hardcoded colors (`text-gray-500`, `#333`).
35+
Use CSS variable pattern (`text-[var(--text-body)]`), never Tailwind semantics (`text-muted-foreground`) or hardcoded colors (`text-gray-500`, `#333`).
3636

3737
**Text**: `--text-primary`, `--text-secondary`, `--text-tertiary`, `--text-muted`, `--text-body` (canonical value text), `--text-icon`, `--text-placeholder`, `--text-subtle`, `--text-inverse`, `--text-error`
3838
**Surfaces**: `--bg`, `--surface-1` through `--surface-7`, `--surface-hover`, `--surface-active`
@@ -42,22 +42,13 @@ Use CSS variable pattern (`text-[var(--text-primary)]`), never Tailwind semantic
4242
**Shadows**: `shadow-subtle`, `shadow-medium`, `shadow-overlay`, `shadow-card`
4343
**Badges**: `--badge-*` semantic families (success/error/gray/blue/purple/orange/amber/teal/cyan/pink, each with `-bg`/`-text`)
4444

45-
## Buttons
45+
## Buttons and chips
4646

47-
Intent-to-variant mapping (read the actual `buttonVariants` in `packages/emcn/src/components/button/button.tsx` for the full variant set — it exposes more than listed here):
48-
49-
| Action | Variant |
50-
|--------|---------|
51-
| Toolbar, icon-only | `ghost` |
52-
| Create, save, submit | `primary` |
53-
| Cancel, close | `default` |
54-
| Delete, remove | `destructive` |
55-
| Selected state | `active` |
56-
| Toggle | `outline` |
47+
Header/action chrome is `Chip`/`ChipLink` (variants `primary`, `destructive`, `outline`, `border`, `border-shadow`, bare). Selection and toggles use the `active` prop, never a variant. A single-resource Delete is a plain chip behind `ChipConfirmModal`; `destructive` is only for at-scale actions (`.claude/rules/sim-settings-pages.md` "Deleting a resource"). `Button` is only for icon-only toolbar controls (`ghost`/`quiet`, `size='icon'`).
5748

5849
## Delete/Remove Confirmations
5950

60-
`ChipModal` `size='sm'`, title "Delete/Remove {ItemType}", destructive confirm button, plain Cancel (follow the chip footer layout in `.claude/rules/emcn-components.md`). Use `text-[var(--text-error)]` for irreversible warnings.
51+
Use `ChipConfirmModal` (title "Delete/Remove {ItemType}", `confirm={{ label, onClick }}`, which defaults to destructive). Keep its fail-safe `defaultAction='dismiss'` per `.claude/rules/emcn-components.md` "Modal keyboard defaults". Put irreversible-consequence copy in `text`.
6152

6253
## Toast
6354

‎.agents/skills/emil-design-eng/SKILL.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ description: This skill encodes Emil Kowalski's philosophy on UI polish, compone
66

77
# Design Engineering
88

9+
> **In this repo:** emcn owns component chrome (press states, tooltip/popover/menu animation, easing): apply these principles by proposing changes in `packages/emcn`, not per call site, and add no global CSS variables or keyframes (CLAUDE.md "Styling and EMCN"). Animation uses `import { motion } from 'framer-motion'`. Gate touch-unsafe hover with the `hover-hover:` Tailwind variant (plain `hover:` is intentionally ungated). `.claude/rules/sim-styling.md` and `.claude/rules/emcn-components.md` win on any conflict.
10+
911
You are a design engineer with the craft sensibility. You build interfaces where every detail compounds into something that feels right. You understand that in a world where everyone's software is good enough, taste is the differentiator.
1012

1113
## Core Philosophy

‎.agents/skills/make-interfaces-feel-better/SKILL.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Animate contextual icons with opacity, scale, and blur instead of toggling visib
4949

5050
### 8. Font Smoothing
5151

52-
Apply `-webkit-font-smoothing: antialiased` to the root layout on macOS for crisper text.
52+
Apply `-webkit-font-smoothing: antialiased` to the root layout on macOS for crisper text. In this repo, do not add root-level smoothing or other global styles (CLAUDE.md "Styling and EMCN"); raise it as a design-system proposal instead.
5353

5454
### 9. Tabular Numbers
5555

@@ -61,7 +61,7 @@ Use `text-wrap: balance` on headings. Use `text-wrap: pretty` for body text to a
6161

6262
### 11. Image Outlines
6363

64-
Add a subtle 1px low-opacity outline to images (`outline-black/10` light, `outline-white/10` dark); see surfaces.md.
64+
Add a subtle 1px low-opacity outline to images; see surfaces.md. In this repo, use the `--border` token (`outline-[var(--border)]`), not raw black/white alphas.
6565

6666
### 12. Scale on Press
6767

@@ -119,7 +119,7 @@ Present changes as markdown tables with **Before** and **After** columns, one ta
119119
#### Scale on press
120120
| Before | After |
121121
| --- | --- |
122-
| `<button className="...">` | Added `active:scale-[0.96] transition-transform` |
122+
| `Chip` has no press affordance | Proposed in `packages/emcn/src/components/chip/chip.tsx` (`chipVariants`): `active:scale-[0.96] transition-transform` |
123123
| `scale(0.9)` on press | Raised to `scale(0.96)` — anything below `0.95` feels exaggerated |
124124

125125
Rows should cite the specific file and the specific property that changed when it isn't obvious from the snippet. If a principle was reviewed but nothing needed to change, omit that table entirely — empty tables add noise.

‎.agents/skills/make-interfaces-feel-better/animations.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Animations
22

3+
> In this repo: `import { motion, AnimatePresence } from 'framer-motion'`; never `motion/react`.
4+
35
Interruptible animations, enter/exit transitions, and contextual icon animations.
46

57
## Interruptible Animations

‎.agents/skills/react-query-best-practices/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Read these before analyzing:
2929
Enforce `.claude/rules/sim-queries.md` (key factory with `all` + plural prefixes, `signal` forwarding, named `staleTime` constants reused by prefetches, `keepPreviousData` only on variable keys, `requestJson` boundary). Additionally:
3030
- Key factories live next to their hooks — except a factory, standalone fetcher/mapper, or `staleTime` constant that a server module (a `prefetch.ts`, route, block, trigger) imports, which must live in a non-`'use client'` module under `hooks/queries/utils/` per `.claude/rules/sim-queries.md` (a `'use client'` export called from the server crashes SSR)
3131
- Use `enabled` to prevent queries from running without required params
32-
- Warm data for hover/focus intent with `queryClient.prefetchQuery` and shared `queryOptions`; never temporarily enable a mounted hidden observer, which can remain active after focus restoration and refetch data for closed UI
32+
- Warm data for hover/focus intent with `prefetchQueryOnIntent(queryClient, sharedQueryOptions)` (`hooks/queries/utils/prefetch-query-on-intent.ts`, which cleans up a speculative failure per `sim-react-performance.md`); never temporarily enable a mounted hidden observer, which can remain active after focus restoration and refetch data for closed UI
3333
- When gating a query by view or modal state, move every consumer to the active query too: imperative refresh/pagination, loading and error feedback, and data-derived controls must never read a disabled query or placeholder data from a previous key
3434
- Compose caller-controlled `enabled` options with required-param guards (`Boolean(id) && (options?.enabled ?? true)`). Never spread options after an internal guard, because `{ enabled: true }` can silently re-enable an invalid request.
3535
- A disabled query can still report `isPending: true`. Aggregate loading state only for queries that are applicable/enabled, or an optional query can hold the whole surface in a permanent loading state.

‎.agents/skills/you-might-not-need-a-comment/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ This codebase's convention: **TSDoc for documentation; an inline `//` only for a
3232

3333
- A `//` comment that explains a **non-obvious why**: a workaround for an upstream bug, an ordering constraint, a perf reason, a spec/edge-case the code can't self-document (`// first-match wins — matches the old find() semantics`).
3434
- Existing TSDoc `/** ... */` blocks on declarations — leave them (only tighten if verbose).
35-
- `// boundary-raw-fetch:`, `// double-cast-allowed:`, `// boundary-raw-json:`, `// untyped-response:`, `// migration-safe:`, `// rq-lint-allow:`, `// client-boundary-allow:` and any other `<kebab-tag>: <reason>` annotation a script under `scripts/` greps for, in line-comment or block-comment form (e.g. the `/** svg-path-precision-exception: ... */` directive on icon paths) — these are load-bearing, never touch them.
35+
- `// boundary-raw-fetch:`, `// double-cast-allowed:`, `// boundary-raw-json:`, `// untyped-response:`, `-- migration-safe:` (SQL migrations), `// rq-lint-allow:`, `// client-boundary-allow:` and any other `<kebab-tag>: <reason>` annotation a script under `scripts/` greps for, in line-comment or block-comment form (e.g. the `/** svg-path-precision-exception: ... */` directive on icon paths) — these are load-bearing, never touch them.
3636
- `// biome-ignore`, `// eslint-disable`, `// @ts-expect-error` and other tooling directives.
3737
- `// TODO` / `// FIXME` that point at real, still-open work.
3838

0 commit comments

Comments
 (0)