---
name: "design_system"
description: "Build a design system for agent-generated UIs: W3C DTCG token pipeline (primitives, semantics, component tier), component specs with accessibility baked in, and docs that keep builds consistent. Use when setting up shared styling, tokenizing a codebase, or making generated UIs look coherent."
metadata: { "includeInPrompt": true }
---

# Design System

## Purpose

Turn one-off generated UIs into a coherent product surface. The system is a machine contract, not a brand book: a token file agents read and write, component specs with exact states and keyboard behavior, and an accessibility floor that gets checked, not wished for. Built for the case where the author is an agent generating screens all day.

## Workflow

1. **Define the contract first.** Write `tokens/tokens.json` in W3C DTCG format before any component work. Three tiers:
   - **Primitives** (`color.blue.500`, `space.4`): raw values. Components never touch these.
   - **Semantics** (`color.bg.accent`, `text.body`, `space.section-gap`): meaning, referencing primitives with `{color.blue.500}`. Components consume these almost exclusively. Retheme by swapping references, never grepping code.
   - **Component tier** (only when a component needs it): `--button-primary-background-hover`. Scale/state segment always last: `--input-border-color-focus`, never `--input-focus-border-color`.
   - Every leaf needs `$value` and `$type`. Dimensions are strings with units (`"12px"`), fontWeight is numeric (`600`). See `references/token-format.md`. Starter file in `assets/tokens.starter.json`.

2. **Generate the outputs.** One source, all targets. Style Dictionary is the canonical transform:
   - CSS custom properties: `:root` gets everything; `[data-theme="dark"]` overrides only the semantics that change.
   - Tailwind: `theme.extend` values point at CSS vars (`var(--color-bg-accent)`), never baked hexes, so dark mode works for free.
   - TypeScript declarations of token names for autocomplete and compile-time validity.
   - Automate it: a CI job rebuilds on any `tokens/**` change and fails (`git diff --exit-code`) if built outputs are stale. Figma variables, if they exist, are the source of truth; code consumes generated artifacts. Nobody hand-transcribes hex.

3. **Spec each component.** One `components/<name>.md` per component covering: states (default, hover, active, focus, disabled, loading, error), which semantic tokens it binds, keyboard behavior, and ARIA roles. The template in `assets/component-spec.template.md` forces this. A component without its spec is not part of the system.

4. **Bake in accessibility from the first token.** The non-negotiable floor is WCAG 2.2 AA (see `references/accessibility.md`):
   - Text contrast: 4.5:1 normal, 3:1 large (>=18pt / 24px regular, or >=14pt / 18.67px bold).
   - Non-text: 3:1 for UI components, input borders, icons, state indicators.
   - Focus: `:focus-visible` with a 3px solid outline + 2px offset, 3:1 against adjacent colors. Never `:focus { outline: none }` without a replacement.
   - Targets: 24x24 CSS px minimum for interactive elements.
   - Component specs must name the checked contrast pairs (e.g. "primary button text #ffffff on bg-accent: 5.9:1, passes 1.4.3").

5. **Write docs that enforce themselves.** Keep a `DESIGN.md` with token front matter plus prose rationale. Then lint it: run `bin/lint-tokens.py tokens/tokens.json` to verify every `{alias}` resolves to a real token and every named semantic contrast pair passes AA. Wire that check into CI alongside the Style Dictionary rebuild. When tokens change, `diff` the before/after token files and review what the change recolors before merging.

## Output Contract

A completed design system ships:
- `tokens/tokens.json` (W3C DTCG, primitives + semantics, lint-clean)
- Generated outputs: `build/css/tokens.css` (light + dark), Tailwind theme or TS declarations as the project needs
- `components/*.md`: one spec per component, states + tokens + keyboard + ARIA + contrast pairs
- `DESIGN.md`: front matter tokens + prose rationale, linted
- CI wiring: token rebuild on change, stale-output failure, alias + contrast lint

## Operating Rules

1. Components consume semantic tokens only. A raw hex or primitive in component code is a bug.
2. Every factual accessibility claim cites its WCAG criterion number. "Passes AA" without a ratio and a pair is a wish.
3. Token names are semantic, not chromatic: `--color-action-primary`, not `--color-blue-500`. You can change blue to purple without renaming the codebase.
4. Never remove or weaken a checked state to fix a lint failure. Fix the color, not the check.
5. Keep SKILL.md-scale discipline on the system itself: the token file is the single source of truth, docs point at it, nothing duplicates it.
