AGENTS.md@packages/design-tokens · git:20260722.c0f07a3 · 2026-07-22 · sha256 38e90eb551445891

AGENTS.md@packages/design-tokens git:20260722.c0f07a3A

Immutable. This exact content never changes and is served at /api/v1/blob/38e90eb551445891.

# design-tokens Agent Notes

Scoped instructions for `packages/design-tokens/`. Read together with
the [root `AGENTS.md`](../../AGENTS.md) and the
[`README.md`](README.md) (which is the consumer-facing doc).

## Authority order

1. The published Figma library (file key in `figma-tokens.lock`).
   - Canonical **semantic colours** come from the committed DTCG export under
     `figma-export/`, regenerated by `:sync-export`. Variables are not
     reachable via the REST `:sync` without Figma Enterprise, so the Plugin-API
     export is the source of truth for their per-mode values.
2. `src/overrides.ts` — only for values Figma doesn't own.
3. Nothing else. Atoms must not declare hex codes; consumers must not
   re-derive radii or spacing.

If a value belongs to the design system, put it in Figma and re-sync.
If it doesn't belong (font fallback stack, motion curve, breakpoint),
add it to `overrides.ts` with a doc comment explaining why.

## Token sync flows

- **Figma plugin push:** branch `design-tokens/figma-sync`, token path
  `packages/design-tokens/figma-export/`. CI triggers on `push` to that branch
  (`figma-export/**` only) and merges `main` into the sync branch before
  generating so workflow helpers stay current.
- `:sync-export` (`scripts/sync-from-export.ts`) — a **generic, file-name
  agnostic** DTCG resolver. It reads *every* `*.json` under `figma-export/`,
  builds one cross-collection registry, resolves every `{alias}` (including
  per-mode Light/Dark chains) to a concrete value, and writes the resolved
  shadcn surface to `src/generated/figma.tokens.json`. It **fails loud** on any
  unresolved reference or an empty colour surface — never filter exports by file
  name, and never downgrade a resolution failure to a warning.
- `:sync` (`scripts/sync-from-figma.ts`) — Figma REST / Enterprise. Does not
  fetch variables on standard plans.

After any sync, run `:generate` and review the snapshot diff.

## Coexistence: legacy vs shadcn

Two colour systems ship at once so consumers migrate incrementally:

- **Legacy** (`--zl-color-surface-*`, `--zl-color-text-*`, `--zl-color-gray-*`,
  spacing, radius) is frozen in `src/legacy.tokens.json` and emitted verbatim by
  `build.ts`. Do not change its values or names — that is the migration's stable
  floor. In the typed export it stays under `tokens.color.*`.
- **shadcn** (`--zl-background`, `--zl-foreground`, `--zl-primary`, `--zl-card`,
  `--zl-border`, `--zl-sidebar-*`, `--zl-chart-*`) comes from the designer export
  and lives under `tokens.theme.*`. This is the target surface.

When migrating a consumer, replace legacy `--zl-color-*` references with the new
`--zl-*` names (or `bg-zl-*` / `text-zl-*` Tailwind utilities) and verify light +
dark in the browser. Retire legacy names only once no consumer references them.

**Console exception:** `apps/console` imports `css/shadcn.css` and authors the
**unprefixed** shadcn contract (`bg-background`, `text-muted-foreground`). Do
not reintroduce `bg-zl-*` there — the bridge file owns the mapping.

## Surfaces you can change

- `src/overrides.ts` — hand-written supplements. Adding a new category
  here means updating `scripts/build.ts` to emit it.
- `scripts/sync-from-figma.ts` — Figma REST handling. Be careful: this
  runs in CI with a real token; preserve the pinned-library guarantee.
- `scripts/sync-from-export.ts` + `figma-export/` — offline DTCG sync and its
  committed export provenance. Re-export from Figma and re-run `:sync-export`
  to refresh values.
- `scripts/build.ts` — emitter. Output must remain deterministic for
  the snapshot test to be meaningful.
- `src/tokens.snapshot.spec.ts` — snapshot. Update intentionally when
  the Figma sync legitimately renames a token; never blanket-accept the
  snapshot diff without reviewing what consumers will need.

## Surfaces you must NOT change by hand

- `src/generated/figma.tokens.json` — overwritten by `:sync` /
  `:sync-export`.
- `src/generated/tokens.css`, `tokens.ts`, `tailwind.css`, `shadcn.css` —
  overwritten by `:generate`.
- `src/legacy.tokens.json` — frozen legacy colour source. Only touch it to
  deliberately retire a legacy token once no consumer references it.
- `figma-tokens.lock` — only bumped as part of a sync PR.

## Output ordering

`scripts/build.ts` emits legacy semantic colours, then the new shadcn colours
(`theme.*`), then the remaining categories in a fixed order (spacing → radius →
font → motion → focus → breakpoint → container → layout). Spacing keys are
numeric-sorted. Keep new categories appended at the end so existing diffs stay
small.

## Tests

Single Vitest project, Node mode: `tokens.snapshot.spec.ts` (public-name guard,
both surfaces) and `sync-from-export.spec.ts` (resolver logic + real-export
regression). If you add a token category, extend the snapshot to cover its keys
so it can't silently disappear.

## Branding overrides at runtime

Tenants override colours/typography/shape on a per-flow basis through
`<zitadel-login branding="...">`. That overlay is applied by
`packages/components/src/orchestrator/branding-to-tokens.ts` — it
writes to the same `--zl-*` variables that `tokens.css` defines, on
the orchestrator's own shadow root. Do not introduce a separate
"branding tokens" surface; everything routes through `--zl-*`.

## Don't

- Don't add a token category to `overrides.ts` that Figma should own.
- Don't import this package from `packages/api` or `packages/api-mock`.
  Tokens are a UI concern.
- Don't hand-edit anything under `src/generated/`. If the generated
  output is wrong, fix the input (lock, json, or overrides) and re-run
  `:generate`.
- Don't re-couple `:sync-export` to specific export file names. The designer
  reorganises collections freely; the resolver must stay shape-driven.