DESIGN.md is a Markdown file with YAML front matter that tells an AI coding agent what your UI looks like: colors, type, radii, spacing and a few components. The tokens go in the front matter, and the Markdown body says how to use them. Google publishes the format along with a CLI, @google/design.md, that lints it.
I wrote a first draft by hand for Northwind Roasters, a fictional coffee shop site I use for demos, ran the linter (v0.4.0), and fixed what it found. Here is what it caught, and what it doesn't check.
The first draft
This is the kind of file you write in five minutes from DevTools:
--- version: alpha name: "Northwind Roasters" colors: brand: "#c2410c" amber: "#f59e0b" background: "#fffaf3" surface: "#f6eadb" text: "#2b1d14" muted: "#7a6656" components: button-primary: backgroundColor: "{colors.brand}" textColor: "#ffffff" badge-new: backgroundColor: "{colors.amber}" textColor: "#ffffff" card: backgroundColor: "{colors.surfce}" textColor: "{colors.text}" --- Components point at tokens with {colors.name} references instead of repeating hex values, so the agent knows the card background is the surface color rather than a near-identical one.
What the linter found
npx @google/design.md lint DESIGN.md The summary: 1 error, 4 warnings, 3 infos. It exits with code 1, so you can fail a CI step on it. The findings, shortened:
| Rule | Severity | Message |
|---|---|---|
| broken-ref | error | Reference {colors.surfce} does not resolve to any defined token. |
| missing-primary | warning | No 'primary' color defined. The agent will auto-generate key colors… |
| contrast-ratio | warning | textColor (#ffffff) on backgroundColor (#f59e0b) has contrast ratio 2.15:1, below WCAG AA minimum of 4.5:1. |
| orphaned-tokens | warning | 'muted' is defined but never referenced by any component. |
| missing-typography | warning | No typography tokens defined. Agents will use default font choices… |
| missing-sections | info | No 'spacing' section defined. (and the same for 'rounded') |
Each one in turn:
- broken-ref. A typo. Without the linter, the agent gets a card whose background points at nothing and has to guess.
- missing-primary. I called my brand color
brand. The format expects a color namedprimary, and without one the agent picks its own key colors. Renaming the token was the whole fix. - contrast-ratio. White on amber is 2.15:1. Amber is bright, so it works as a fill with dark text on it:
#2b1d14on the same amber is 7.59:1. - orphaned-tokens.
mutedis my caption color, but no component used it. An unused token is just a hex value with no instructions, so I added acaptioncomponent. - missing-typography. No fonts at all, so the agent would have used its defaults. That is the most visible miss of the lot, since the serif headings are most of this site's look.
The fixed file
--- version: alpha name: "Northwind Roasters" colors: primary: "#c2410c" amber: "#f59e0b" background: "#fffaf3" surface: "#f6eadb" text: "#2b1d14" muted: "#7a6656" typography: headline-display: fontFamily: "Fraunces" fontSize: 64px fontWeight: 600 lineHeight: 1.04 letterSpacing: -1.28px body-md: fontFamily: "Hanken Grotesk" fontSize: 17px fontWeight: 400 lineHeight: 1.6 rounded: lg: 10px spacing: base: 4px components: page: backgroundColor: "{colors.background}" textColor: "{colors.text}" button-primary: backgroundColor: "{colors.primary}" textColor: "#ffffff" rounded: "{rounded.lg}" badge-new: backgroundColor: "{colors.amber}" textColor: "{colors.text}" card: backgroundColor: "{colors.surface}" textColor: "{colors.text}" caption: textColor: "{colors.muted}" --- Lint result: 0 errors, 0 warnings, 1 info (the token summary). White on #c2410c for the button is 5.18:1, so that pair passes as well.
design.md diff old.md new.md gives a JSON report of what changed: brand removed, primary added, two typography tokens added, page and caption added, three components modified. It also shows the finding counts before and after (errors -1, warnings -4). That's handy for a PR description when someone edits the file.
What a clean lint doesn't tell you
Zero warnings doesn't mean the file is right. Three things I checked by hand:
Contrast is only checked inside a component. The rule looks at a component's own backgroundColor/textColor pair. My caption component only has a text color, so nothing checked it. On the page background, muted is 5.24:1. On a card it is 4.59:1, which still passes, but only just. If your agent puts captions on cards, that's the pair to check yourself.
The values have to be the real ones. The linter can't know that the body text is 17px and not 16px, or that the h1 is tracked to -1.28px. Copy those from DevTools Computed on the real site, not from memory.
Exports drop some things. design.md export --format css-tailwind turns the file into a Tailwind v4 @theme block. For this file it wrote colors, font families, sizes, tracking, weights, radius and spacing, but in v0.4.0 the lineHeight values didn't appear in the output, and the font families came out without fallbacks (--font-body-md: "Hanken Grotesk";). Add those by hand if you use the export.
Short version
- Name your brand color
primary. - Point components at tokens with
{colors.x}, and give every color at least one component that uses it. - Include typography; an agent can't guess your fonts.
- Run
npx @google/design.md lintin CI, then check contrast on cards and the real values by hand.
I made a Chrome extension, Stylasso, that writes a DESIGN.md from the page you're on: real colors with roles, fonts, type scale, radii and spacing, with components referencing the tokens. The three demo-site files it generates lint with 0 errors; one gets the same white-on-violet contrast warning I'd expect, because that's what the site really uses. There's a short guide here: DESIGN.md from any website. Writing the file by hand, as above, works too.
Written with help from an AI assistant. Every lint result, diff and export above comes from running @google/design.md v0.4.0 on the files shown.


