DEV Community

dubleCC
dubleCC

Posted on • Originally published at heycc.cn

DESIGN.md: The '.cursorrules for Your Design System' That Stops AI UI Style Drift

Originally published at heycc.cn. This is a mirrored copy — the canonical version is kept up to date at the source.

DESIGN.md: The '.cursorrules for Your Design System' That Stops AI UI Style Drift

You ask your AI coding agent to build a settings panel. It looks great. Next session, you ask for a billing page in the same app — and the agent picks a slightly different blue, a 6px radius instead of 8px, a card shadow that doesn't match anything else you've shipped. Nothing is wrong, exactly. It just doesn't look like the same product. This is visual-identity drift, and it happens because the agent has no persistent memory of your design system. Every prompt re-derives spacing, color, and component conventions from scratch.

DESIGN.md is the fix, and the shortest way to describe it is this: it's .cursorrules for your design system. It's a single file that gives an AI coding agent a durable, structured understanding of how your product is supposed to look — so it stops guessing.

The drift problem: why AI keeps reinventing your UI

LLM-based coding agents are stateless about your intent. They can read the code already in your repo, but inferring a coherent design system from scattered Tailwind classes and inline hex values is lossy guesswork. Was #2563eb your brand primary, or just the color someone happened to type that day? Is rounded-lg the house standard, or an accident? The agent can't tell, so across prompts and sessions its choices wander.

Google Labs frames the goal precisely: "Instead of guessing intent, AI agents can know exactly what a color is for, and can validate their choices against WCAG accessibility rules." The key phrase is know exactly — replacing inference with a declared source of truth. This is the same persistent-context pattern that durable project-rules files apply to coding conventions; DESIGN.md applies it to your visual identity.

DESIGN.md in one sentence: '.cursorrules for your design system'

If you've used Cursor's rules to give the editor durable project context, or a CLAUDE.md to give Claude Code durable project memory, you already understand the mental model — DESIGN.md is the same move, scoped to design. (For the general pattern, see our Cursor rules guide and CLAUDE.md memory guide; one naming note there worth flagging here too — the single-file .cursorrules this piece's title nods to is now legacy in Cursor, with current docs marking it "will be deprecated" in favor of per-file .cursor/rules/*.mdc Project Rules, so it's the durable-context pattern DESIGN.md borrows, not that exact filename.) Where those files carry "use pnpm, prefer functional components, run the linter before committing," DESIGN.md carries "primary is this blue, it means interactive, body text is this stack at this scale, cards get this elevation and never this one."

It was incubated inside Stitch, Google Labs' AI-powered UI design tool, where it let users export and import their design rules from project to project. Google then open-sourced the draft specification — in their words, "so it can be used across any single tool or platform." That last clause is the point: DESIGN.md is meant to be a portable, vendor-neutral file your agents read, not a feature locked to one product.

The dual-layer format and why an LLM consumes it well

DESIGN.md's design insight is that an LLM needs two different things to render a UI correctly, and most formats only give one. A tokens.json gives exact values but no reasoning. A design doc gives reasoning but no machine-precise values. DESIGN.md carries both in one file, in two layers.

How DESIGN.md feeds an AI coding agent

Layer 1 — machine-readable YAML front matter. Fenced by ---, this block holds the design tokens an agent must reproduce exactly: colors, typography, spacing, rounded, and components, plus version/name/description metadata. Tokens can reference other tokens with curly-brace path syntax — "{colors.primary}" or "{rounded.sm}" — so a button's background isn't a duplicated hex string that can fall out of sync; it points at the canonical token. The agent gets a precise, dereferenceable graph of values.

Layer 2 — human-readable Markdown body. Below the front matter, ordinary ## sections carry the rationale: why primary is reserved for interactive elements, when to use elevation, what the brand voice implies for spacing density. This is the "why" that lets an agent make a new decision the tokens don't literally cover — and it's just as readable to your human teammates.

An LLM reads both at once: the exact values from Layer 1 and the intent from Layer 2. That combination is what lets it extend your system correctly instead of merely pattern-matching it.

The canonical section order

The spec defines a canonical order for the prose sections, and the linter enforces it. Predictable structure is what makes the file agent-parseable and human-skimmable at the same time:

Order Section Alias Carries
1 Overview Brand & Style Identity, voice, overall feel
2 Colors Palette, roles (primary/surface/etc.)
3 Typography Families, scale, weights
4 Layout Layout & Spacing Grid, spacing scale
5 Elevation & Depth Elevation Shadows, layering
6 Shapes Corner radii, geometry
7 Components Buttons, cards, inputs
8 Do's and Don'ts Guardrails, anti-patterns

When an agent injects the file into context, this fixed order means it always finds colors before components, and guardrails last — no scavenger hunt.

The CLI: lint, diff, export, spec

DESIGN.md ships as the npm package @google/design.md, run with npx @google/design.md <command>. Four commands cover the lifecycle.

Command What it does Why you'd run it
lint "Validate a DESIGN.md file for structural correctness" Catch broken refs and contrast failures in CI
diff "Compare two DESIGN.md files and report token-level changes" Review what actually changed between versions
export "Export DESIGN.md tokens to other formats" Generate Tailwind config or DTCG tokens
spec "Output the DESIGN.md format specification" Inject the spec itself into an agent's prompt

Linting is the gate. The rules include broken-ref (an error — a {path.to.token} that doesn't resolve), plus warnings: section-order, missing-primary, missing-typography, orphaned-tokens (a color nothing references), unknown-key (a likely typo), and contrast-ratio, which flags component text/background pairs below the WCAG AA 4.5:1 threshold. That last rule is how the file actively validates accessibility instead of merely documenting it.

Two of these are exercised directly in the linter's own test suite, which doubles as a spec of what actually trips each rule: contrast-ratio has a fixture pairing white text (#ffffff) on a yellow background (#ffff00) — a combination that computes to roughly 1.07:1 against the WCAG formula, nowhere close to the 4.5:1 floor, and the rule emits a warning naming both colors and the computed ratio. broken-ref has a fixture where a token points at {colors.nonexistent} — a reference to a token that was never defined — and the rule fails with an error stating the reference does not resolve. Neither is a fabricated worked example; both are the project's own test fixtures, which is a reasonable proxy for "here's what the linter actually catches" since no public bug reports or production case studies exist yet for a spec this new.

Export bridges to the tooling you already use. json-tailwind (alias tailwind) emits a Tailwind v3 theme.extend config; css-tailwind emits a Tailwind v4 @theme { ... } block of CSS custom properties; and dtcg emits the W3C Design Tokens Format Module as tokens.json. The spec is explicit that tokens are "easily converted from or to tokens.json, Figma variables, and Tailwind theme configs" — so DESIGN.md is meant to be a hub, not a silo. One caveat on today's tooling: in the current alpha CLI, export is one-directional — it writes those formats out, but there is no import command and no Figma converter yet, so "converted from" describes the format's intent more than what the CLI ships today.

spec is the cleverest command for agent workflows: it prints the format specification itself, which you pipe into an agent's prompt so the model knows how to read and write DESIGN.md before it touches yours.

Windows / PowerShell gotcha

On Windows, the .md bin name collides with the Markdown file association. The docs route you to the designmd alias:

npx -p @google/design.md designmd lint DESIGN.md
Enter fullscreen mode Exit fullscreen mode

Use that form in PowerShell-based CI and npm scripts to avoid the file-association conflict.

Where it fits — and where it doesn't (yet)

DESIGN.md targets AI coding agents broadly — GitHub Copilot, Claude Code, and Cursor — each consuming both the precise token values and the prose explanations. A pragmatic adoption path: commit a DESIGN.md at the repo root, add designmd lint DESIGN.md to CI so a broken ref or AA contrast failure blocks the merge, and reference the file in your agent's rules ("read DESIGN.md before generating any UI"). On a version bump, run diff in the PR to surface token-level changes for review.

The honest caveat: the format is alpha. Google states plainly that "the spec, token schema, and CLI are under active development. Expect changes to the format as it matures." Treat your DESIGN.md as a living file, pin a known CLI version in CI, and don't build irreversible tooling on token-schema details that may shift.

Verification note (2026-06-28; re-verified 2026-07-16)

Package name (@google/design.md), CLI commands, lint rules and severities, export formats (json-tailwind/css-tailwind/dtcg), the WCAG AA 4.5:1 contrast threshold, the designmd Windows alias, and the alpha status were verified against the official GitHub repository and spec. The origin story and the "guessing intent" / WCAG-validation framing were verified against Google's official Stitch + DESIGN.md announcement. Because the format is explicitly alpha and "under active development," specific rule names, section aliases, and schema keys may change after this date — re-check the repo before relying on exact identifiers.

On 2026-07-16, every claim was re-checked line by line against the live GitHub repo (README.md, docs/spec.md, and the linter's own test fixtures in packages/cli/src/linter/linter/rules/*.test.ts), plus the npm registry entry for @google/design.md. All token schema, CLI, lint-rule, and export claims still hold verbatim, including the two test-fixture examples (contrast-ratio's #ffffff-on-#ffff00 pair, independently recomputed here at ≈1.07:1 via the WCAG relative-luminance formula, and broken-ref's {colors.nonexistent} fixture). One drift found and fixed: Cursor's own docs now state "[t]he .cursorrules file in your project root is legacy and will be deprecated" in favor of .cursor/rules/*.mdc Project Rules — this piece's title and lede use .cursorrules as a recognizable shorthand for the durable-project-context pattern, so a clarifying aside was added rather than rewriting the hook. The "GitHub Copilot, Claude Code, and Cursor" adopter list is accurate as a description of coding agents capable of reading the file, but is this site's own framing, not a claim sourced to Google's docs.

Sources

Top comments (0)