There's a moment most people hit around their fourth or fifth screen.
The first page looked good. The second one, also good — slightly different shade of blue, but fine. By the fifth, your buttons have three different corner radii, two fonts have appeared from nowhere, and the spacing on one page is roomy while the next is cramped.
Nothing broke. Every screen works. It just doesn't look like one product any more.
The instinct is to blame the tool, but the tool didn't do anything wrong. It made a reasonable choice each time you asked, because it has no memory of the choices it made last time. Every prompt starts from a blank slate, so every prompt reinvents your design language slightly.
Your project already has a visual identity — colours, fonts, spacing, component styles. Traditionally that lives in a Figma file, a brand PDF, or somebody's head. None of those are readable by an AI agent.
DESIGN.md is what changes that.
Where it came from, and what it sits alongside
DESIGN.md was introduced by Google Stitch, an AI design tool from Google Labs that generates interfaces from descriptions. It's best understood as the design counterpart to a file you may already know.
| File | Who reads it, and what it defines |
|---|---|
| README.md | Humans. What the project is. |
| AGENTS.md | Coding agents. How to build the project. |
| DESIGN.md | Design agents. How the project should look and feel. |
Three files, three audiences. The pattern is deliberate.
It's also explicitly designed as a foundation, not a prescription — a shared vocabulary that agents, tools and teams can rely on, while leaving you free to extend it. Unknown sections and custom tokens are accepted rather than rejected.
One more framing worth carrying: DESIGN.md is a living artifact, not a static config file. The agent generates it, you refine it, and it gets re-applied as you iterate. It's meant to change.
The two layers
This is the central idea, and the thing that makes the format work. Every DESIGN.md has two parts.
YAML front matter — machine-readable design tokens. Exact hex values, font properties, spacing scales. These are the normative values: what agents enforce.
Markdown body — human-readable rationale, organised into ## sections. This explains why those values exist and how to apply them.
The split does real work. Tokens give agents precision. Prose gives them judgement for everything the tokens don't cover.
A neat consequence: the prose can use expressive names — "Midnight Forest Green" — while the tokens use systematic ones — primary. Both point at the same colour. Humans get the evocative name, machines get the hex.
---
name: DevFocus Dark
colors:
primary: "#2665fd"
secondary: "#475569"
surface: "#0b1326"
on-surface: "#dae2fd"
error: "#ffb4ab"
typography:
body-md:
fontFamily: Inter
fontSize: 16px
fontWeight: 400
rounded:
md: 8px
---
# Design System
## Overview
A focused, minimal dark interface for a developer productivity tool.
Clean lines, low visual noise, high information density.
## Colors
- **Primary** (#2665fd): CTAs, active states, key interactive elements
- **Secondary** (#475569): Supporting UI, chips, secondary actions
- **Surface** (#0b1326): Page backgrounds
- **On-surface** (#dae2fd): Primary text on dark backgrounds
- **Error** (#ffb4ab): Validation errors, destructive actions
## Typography
- **Headlines**: Inter, semi-bold
- **Body**: Inter, regular, 14-16px
- **Labels**: Inter, medium, 12px, uppercase for section headers
## Components
- **Buttons**: Rounded (8px), primary uses brand blue fill
- **Inputs**: 1px border, subtle surface-variant background
- **Cards**: No elevation, relies on border and background contrast
## Do's and Don'ts
- Do use the primary color sparingly, only for the most important action
- Don't mix rounded and sharp corners in the same view
- Do maintain 4:1 contrast ratio for all textThe token schema
That's the whole format. Nothing exotic — standard markdown, standard YAML.
The token system is inspired by the W3C Design Token Format, which is why tokens convert cleanly to and from tokens.json, Figma variables, and Tailwind theme configs. You're not locked into anything.
The front matter block opens and closes with a line containing exactly three dashes.
version: <string> # optional, current version: "alpha"
name: <string>
description: <string> # optional
colors:
<token-name>: <Color>
typography:
<token-name>: <Typography>
rounded:
<scale-level>: <Dimension>
spacing:
<scale-level>: <Dimension | number>
components:
<component-name>:
<token-name>: <string | token reference>Token types
A scale level is a named level in a sizing or spacing scale. Common names are xs, sm, md, lg, xl and full — but any descriptive string is valid.
| Type | Format and example |
|---|---|
| Color | Hash plus hex, sRGB. Example: "#1A1C1E" |
| Dimension | Number plus unit — px, em, rem. Example: 48px, -0.02em |
| Token reference | Curly braces around a path. Example: {colors.primary} |
| Typography | A composite object — see below. |
Typography properties
| Property | What it does |
|---|---|
| fontFamily | The font family name. |
| fontSize | The font size, as a dimension. |
| fontWeight | Numeric weight — 400, 700. |
| lineHeight | A dimension or a number. 24px, or unitless 1.6 — unitless recommended. |
| letterSpacing | Letter spacing adjustment, as a dimension. |
| fontFeature | Configures font-feature-settings. |
| fontVariation | Configures font-variation-settings. |
Most design systems end up with 9 to 15 typography levels, each combining a semantic role — headline, body, label — with a size variant.
Token references
A reference is wrapped in curly braces and points at another value in the YAML tree. This is how you avoid repeating yourself.
components:
button-primary:
backgroundColor: "{colors.primary-60}"
textColor: "{colors.primary-20}"
rounded: "{rounded.md}"
padding: 12pxFor most token groups a reference must point at a primitive value, not a group. Inside components, references to composite values are permitted — so {typography.label-md} is valid there.
Component variants
States are defined as separate component entries with a related key name, not as nested objects.
components:
button-primary:
backgroundColor: "{colors.primary-60}"
button-primary-hover:
backgroundColor: "{colors.primary-70}"Recommended token names
The recognised component properties are backgroundColor, textColor, typography, rounded, padding, size, height and width. Anything else is accepted, but with a warning.
These names aren't required, but following them keeps you compatible with what tools expect.
| Group | Recommended names |
|---|---|
| Colors | primary, secondary, tertiary, neutral, surface, on-surface, error |
| Typography | headline-display, headline-lg, headline-md, body-lg, body-md, body-sm, label-lg, label-md, label-sm |
| Rounded | none, sm, md, lg, xl, full |
The eight sections
The markdown body uses ## headings. Sections may be omitted if irrelevant, but the ones present should appear in this order — the linter warns if they don't. An optional # heading can title the document; it isn't parsed as a section.
| Order | Section |
|---|---|
| 1 | Overview — also known as Brand & Style |
| 2 | Colors |
| 3 | Typography |
| 4 | Layout — also known as Layout & Spacing |
| 5 | Elevation & Depth |
| 6 | Shapes |
| 7 | Components |
| 8 | Do's and Don'ts |
Overview
A holistic description of the product's look and feel: brand personality, target audience, and the emotional response the UI should evoke.
This is the section people skip, and it's arguably the most valuable. It's the fallback when a specific rule or token isn't defined — which happens constantly, because no file anticipates everything.
For example: "A calm, professional interface for a healthcare scheduling platform. Accessibility-first design with high contrast and generous touch targets."
Colors and Typography
Colors: the palettes. At minimum, define primary. Beyond that you're free, though primary, secondary, tertiary and neutral is the common convention.
The prose does the important work here — not just what a colour is, but what it's for. "Tertiary (#B8422E): the sole driver for interaction." Saying blue is #185FA5 tells an agent a colour exists. Saying it's used only on the single most important action per screen tells it when to reach for it, which is what you actually need.
Typography: font families and the full hierarchy — what a page title is versus a section heading versus body text versus a caption. Typography drifting between screens is the most common inconsistency in AI-built UI, so this section pays for itself fast.
Layout, Elevation and Shapes
Layout: grid models, spacing scales, containment principles. For example: "The layout follows a Fluid Grid model for mobile and a Fixed-Max-Width Grid for desktop (max 1200px). A strict 8px spacing scale is used." Tokens are a map of scale identifiers to dimensions or unitless numbers — the latter useful for column counts and ratios.
Elevation & Depth: how visual hierarchy is conveyed. If you use shadows, define them. If your design is flat, explain the alternative — borders, tonal layers, colour contrast. That second half matters. Left unexplained, agents default to adding shadows.
Shapes: corner radii, edge treatments, overall shape language. "All interactive elements use a minimal 4px corner radius. Modern enough to feel current, rigid enough to feel engineered." That second sentence is doing real work: it gives the agent a principle to extend to shapes you never mentioned.
Components and Do's and Don'ts
Components: style guidance for component atoms. The spec names buttons, chips, lists, inputs, checkboxes, radio buttons and tooltips — and encourages you to add whatever else your domain needs.
Do's and Don'ts: practical guardrails, described in the spec as acting during generation. Do use the primary color only for the single most important action per screen. Don't mix rounded and sharp corners in the same view. Do maintain WCAG AA contrast ratios, 4.5:1 for normal text. Don't use more than two font weights on a single screen.
Negative rules are unusually powerful here, because AI tools have strong defaults and will reach for them unless told not to. Naming what you never want is often faster than describing what you do.
How the format handles the unexpected
The spec defines exactly what a tool should do when it meets something it doesn't recognise — which is what makes "extend it freely" a real promise rather than a hope.
| Scenario | Behaviour |
|---|---|
| Unknown section heading | Preserve, don't error. Example: ## Iconography |
| Unknown colour token name | Accept if the value is valid. Example: surface-container-high |
| Unknown typography token name | Accept as valid typography. Example: telemetry-data |
| Unknown spacing value | Accept, store as string if not a valid dimension. Example: grid-columns: '5' |
| Unknown component property | Accept with a warning. Example: borderColor |
| Duplicate section heading | Error — reject the file. Two ## Colors headings. |
One hard failure, and everything else degrades gracefully. That's a sensible design.
Four ways to get one
Let the agent generate it. Describe the vibe and let it translate aesthetic intent into tokens — "a playful coffee shop ordering app with warm colors, rounded corners, and a friendly feel". Stitch produces a complete design system and summarises it as a DESIGN.md.
Derive it from existing branding. If you already have a brand, hand over a URL or an image. The agent extracts palette, typography and style patterns from what exists rather than inventing something new.
Extract it from a codebase. If you've already built something, your design language is already in there — colours scattered across stylesheets, spacing buried in components, typography locked in a Tailwind config. Any coding agent can be pointed at the project and asked to write a DESIGN.md from what it finds.
Write it by hand. Perfectly reasonable, and the most precise option. It's just markdown and YAML.
What a good extraction prompt does
Google publishes a recommended prompt for extracting DESIGN.md from a codebase, and the instructions behind it are worth understanding because they're a lesson in themselves.
The repo is the source of truth — pull real product names, taglines and copy from the README; real labels and terminology from config files, CLI help text, schemas and error messages. Nothing invented, nothing placeholder. Collect scattered values, even undocumented ones, because they reveal visual intent. Read the core logic, not just the docs: data structures reveal the product's native shape — a timeline, a graph, a catalog, a pipeline — and that shape should organise the page instead of a generic section template. And find what the README leads with, because that feature dominates the page.
Three tips that improve results noticeably: point the agent at specific directories, name your stack, and iterate afterwards — "the accent should be the teal from the navbar, not the blue from the footer."
Stitch Design Skills
For a more thorough job, Google publishes an open-source collection of 13 agent skills in three plugins, following the Agent Skills open standard and working with any compatible agent.
| Plugin | What it does |
|---|---|
| stitch-design | Extract tokens from code, snapshot running apps, upload to Stitch. |
| stitch-build | Turn designs into code — React components, shadcn/ui integration. |
| stitch-utilities | Prompt optimisation, premium design systems, multi-page generation. |
The extract-design-md skill detects your stack automatically — Tailwind config, CSS custom properties, theme files, styled-components — and works through atmosphere, colour, typography, components and layout in turn.
The official CLI
There's a real command-line tool: @google/design.md. It validates against the spec, catches broken references, checks contrast ratios, and exports tokens elsewhere. Output is structured JSON, so agents can act on it.
npx @google/design.md lint DESIGN.md
Three commands worth knowing. lint parses the front matter, resolves every token reference, runs eight rules and reports findings, exiting 1 if there are errors — it accepts stdin, so you can pipe in a generated file. diff compares two versions and reports which tokens were added, removed or modified; it also flags regressions, meaning more errors or warnings in the newer file, and exits 1 when it finds one. export converts your tokens for use elsewhere: --format tailwind produces a theme.extend object you drop into tailwind.config.js, and --format dtcg produces a W3C Design Tokens compliant tokens.json.
There's also npx @google/design.md spec, which prints the specification itself — handy for injecting spec context into an agent prompt so it knows exactly what structure to produce. The linter is available as a TypeScript library too, if you want it inside your own tooling.
The eight lint rules
| Rule | Severity and what it catches |
|---|---|
| broken-ref | Error. References that don't resolve; unrecognised component properties. |
| missing-primary | Warning. Colours defined but none named primary. |
| contrast-ratio | Warning. Component text and background pairs below WCAG AA 4.5:1. |
| orphaned-tokens | Warning. Colour tokens defined but never used by a component. |
| missing-typography | Warning. Colours defined but no typography tokens. |
| section-order | Warning. Sections out of canonical order. |
| missing-sections | Info. spacing or rounded absent. |
| token-summary | Info. A count of what's defined. |
The through-line in those warnings is worth noticing. missing-primary and missing-typography both carry the same message in different words: anything you don't define, the agent will decide for you. The linter isn't checking correctness so much as checking how much control you've actually taken.
contrast-ratio is the quiet standout — an accessibility check running automatically on your design system, before a single screen exists.
Where to put it
Two conventions, both in use. The project root — DESIGN.md, alongside README.md and AGENTS.md — is the most discoverable. Or .stitch/DESIGN.md, which is what Stitch's own tooling writes to.
Either works. Whichever you choose, tell your tool once — "follow DESIGN.md" — or put that reference wherever your builder keeps standing instructions, and you'll never mention it again.
Why this matters more than it sounds
There's a bigger idea behind the file.
For twenty years, design systems have been built for humans: Figma libraries, style guides, component documentation. All of it assumes a person will read it, interpret it, and apply judgement.
DESIGN.md assumes the reader is a machine that will apply it literally, every time, without getting bored — and pairs that with prose for the parts literalism can't reach. That's a genuinely different design goal, and it changes what a good design system looks like.
| Principle | Why |
|---|---|
| Explicit beats elegant | 8px, 16px, 24px, 32px is more useful than "generous but not excessive". |
| Rules beat examples | An agent follows a rule perfectly and only approximates an example. |
| Negative rules carry real weight | "Never use gradients" prevents more than any positive instruction. |
| Prose covers the gaps | Overview and Shapes do real work precisely because they guide decisions you never anticipated. |
This is a window into a broader shift: documentation written to be read by agents rather than people. Expect more of it.
Where it falls short
Some honesty, since the enthusiasm around this is running slightly ahead of the reality.
| Limitation | What it means |
|---|---|
| Support varies by tool | There's a spec, a CLI and a linter, but adoption is a choice each tool makes. Check whether yours actually reads the file before assuming it does. |
| Descriptive, not enforced at generation time | The linter validates the file; nothing validates the output. It heavily influences what gets built; it doesn't guarantee it. |
| It goes stale | Change your buttons in the app and the file still describes the old ones, at which point the agent happily rebuilds the old ones. diff helps you see change; it can't make you update anything. |
| Some things resist words | Motion, micro-interactions, the feel of a transition. The format has no section for these, and prose only gets you so far. |
| Not a substitute for taste | A perfectly-linted DESIGN.md describing a mediocre design produces consistently mediocre output. Consistency is the win here, not quality. |
| The version is alpha | It says so in the schema. Expect the format to move. |
Should you bother?
Yes, if you're building more than a couple of screens, working across several sessions, or you have brand colours and fonts that need respecting.
Not yet, if you're building one small internal tool this afternoon. Writing a design system for a single expense form is procrastination with extra steps.
A reasonable middle path: build your first two screens however you like. Once you're happy with them, ask your agent to extract a DESIGN.md from what you made, tidy it up, run the linter, and use it from screen three onwards.
That way the file describes something real rather than something you imagined in advance — which is usually the better order to do things in anyway.
The short version
DESIGN.md is a markdown file with two layers: YAML tokens that machines enforce exactly, and prose that explains the intent behind them. Eight sections, in order, from Overview through to Do's and Don'ts. Your agent reads it before building, so screen fifteen looks like screen one. There's a real schema, a real linter, and exports to Tailwind and W3C tokens. It won't make your design good — but it does mean you only have to decide things once.
Related lessons
How to Write Prompts for AI App Builders
Learn how to describe your app so an AI builder gets it right: what to put in your first prompt, how to refine the result, and the mistakes that waste time.
10 minStarting Guide: No-Code Development
Learn no-code development from scratch: what it is, why it's worth learning, and a simple 3-phase method to build your first working app without writing code.
9 minAI App Builders Do More Than Build Apps
Modern AI app builders analyse your files, run real calculations and generate reports, decks and invoices you can download. Here's what that unlocks.
11 min