How to Write a DESIGN.md

Learn about DESIGN.md Field Reference
On this page

Write DESIGN.md in three passes: extract your real tokens (from code, not from memory), write rationale only where a wrong choice is likely, and cut everything an agent can infer. Keep the file lint-clean and small enough to fit your agent's context budget: completeness is not the goal, decisiveness is.

Most advice on writing design docs for AI is style tips detached from the spec. This guide is anchored to two hard constraints instead: the nine rules the official linter actually checks, and the token budget of a real agent context window. We'll build one file (for a fictional trip-planning app called Fernway) from empty to lint-clean. (New to the format? Read what DESIGN.md is first; the full schema lives in the DESIGN.md guide.)

The memorable version of this whole article: decisiveness over completeness. A DESIGN.md that answers 30 questions unambiguously beats one that mentions 300 things vaguely.

Before you write: extract, don't invent#

Your design system already exists: in your CSS variables, Tailwind config, theme files, and shipped screens. Extract from there. Writing tokens from memory produces values your codebase doesn't use, and the agent will then faithfully apply a design system that isn't yours.

Two data points on scale, from our July 2026 analysis of all 74 files in the awesome-design-md collection: the median file defines 23 colors, 14 typography levels, and 25 components. If your extraction pass finds 60 colors, that's not a documentation problem: it's a signal your codebase has drift worth consolidating before you enshrine it.

Practical extraction sources, in order of reliability:

  1. Design token files you already have: the format is inspired by the W3C Design Token Format, so tokens.json, Figma variables, and Tailwind themes map over cleanly.
  2. CSS custom properties and theme configs in the repo.
  3. A grep for hex values across stylesheets (this is where the 60-color surprise usually comes from).
  4. Screenshots and brand PDFs: a last resort, since you're re-approximating values that exist exactly somewhere else.

You can also have tooling do the first pass for you (see the options in DESIGN.md generators), but the three-pass method below applies either way: generated files especially need Pass 3.

The three-pass method#

Pass 1: extract the tokens#

Get every real, load-bearing value into YAML maps. (Flat maps are the simplest convention; v0.3.0 also supports nested token groups, referenced with dot-separated paths like {colors.brand.primary}, while 0.1.x and 0.2.x were flat-only.) Fernway after Pass 1:

---
version: alpha
name: Fernway
description: Design system for the Fernway trip-planning app
colors:
  primary: "#0F4C3A"
  on-primary: "#F6F4EF"
  secondary: "#8A5A44"
  surface: "#FFFFFF"
  on-surface: "#22271F"
  gray-100: "#F5F5F4"
  gray-200: "#E7E5E4"
  gray-300: "#D6D3D1"
  gray-400: "#A8A29E"
  gray-500: "#78716C"
  gray-600: "#57534E"
typography:
  headline-lg:
    fontFamily: Fraunces
    fontSize: 2.25rem
    fontWeight: 600
    lineHeight: 1.15
  body-md:
    fontFamily: Inter
    fontSize: 1rem
    fontWeight: 400
    lineHeight: 1.6
  label-sm:
    fontFamily: Inter
    fontSize: 0.75rem
    fontWeight: 500
    lineHeight: 1.2
    letterSpacing: 0.06em
rounded:
  sm: 4px
  lg: 12px
spacing:
  sm: 8px
  md: 16px
  lg: 32px
components:
  button-primary:
    backgroundColor: "{colors.primary}"
    textColor: "{colors.on-primary}"
    rounded: "{rounded.sm}"
    padding: 12px
  card:
    backgroundColor: "{colors.surface}"
    textColor: "{colors.on-surface}"
    rounded: "{rounded.lg}"
    padding: 16px
---

Note what Pass 1 honestly captured: six grays, because that's what the CSS audit found. Don't clean while extracting: you'll clean with lint data in Pass 3.

Pass 2: add rationale where a wrong choice is likely#

Tokens say what; prose says when and why. Clearly described intent shapes a generated design more than exact values do, so write prose only where an agent with just the tokens would plausibly choose wrong. Fernway gains three prose sections (shown abridged):

## Overview

Fernway feels like a well-worn field notebook: calm, tactile, unhurried.
Editorial serif headlines over quiet warm neutrals. Nothing glows, nothing
bounces. Density is low; white space is a feature.

## Colors

- **Primary (#0F4C3A), "Fern":** the only interactive color: buttons, links,
  active states, and nothing else. If everything is green, nothing is.
- **Secondary (#8A5A44), "Trail Clay":** accents in illustrations and
  selected-state chips only. Never for text, never for buttons.

## Do's and Don'ts

- Do use `headline-lg` (Fraunces) only for page titles: one per screen.
- Don't introduce shadows; hierarchy comes from borders and surface contrast.
- Don't use pure black anywhere; text is `on-surface` (#22271F).
- Do keep primary buttons rare: one per view.

Each line resolves a likely wrong choice (agents love shadows, pure black, and green-everywhere). None of them restates what the YAML already says: that's the boundary between Pass 2 and bloat. The spec states this division of labor directly: "The tokens are the normative values; the prose provides context for how to apply them."

Pass 3: cut what an agent can infer#

Now run the linter and let data drive the deletions:

npx @google/design.md lint DESIGN.md

Fernway's report flags gray-100 through gray-600 as orphaned: defined but never referenced by any component. That mirrors the ecosystem: our analysis found 684 orphaned color tokens across 61 of the 74 community files. Six ramp grays that no component uses are context cost with no decision value; an agent can derive "a slightly lighter gray" on its own. Fernway keeps one, gives it a job, and deletes five:

colors:
  primary: "#0F4C3A"
  on-primary: "#F6F4EF"
  secondary: "#8A5A44"
  surface: "#FFFFFF"
  on-surface: "#22271F"
  outline: "#D6D3D1"

...with one prose line added under Colors: Outline (#D6D3D1): the only border color, used for hairline dividers and input borders. (Component tokens have no border property, so a border color's role can only live in prose.) After this pass, Fernway lints clean: zero errors, zero warnings. When a warning does survive a pass (say, an accent color you keep for illustrations even though no component references it), keep it knowingly. Warnings are signals, not laws; every keep-despite-warning should have a reason you could say out loud.

Pass 3 also cuts prose: any sentence an agent would act identically without ("the design should feel modern and clean") is filler. Size context from the collection: the median file runs about 7,050 tokens, the largest around 11,000. Under the median is a good default target; well past it, you're spending your agent's attention on low-value context.

What should you include, and what should you leave out?#

Atlassian's published test frames the budget honestly: their DESIGN.md file covered only about 30% of a large design system, and using it alone took roughly 92% more tokens per query than their MCP server and skills, which covered about 80%. Even so, Atlassian found the file best for high-level art direction and quick prototyping in unfamiliar environments, taking output "from generic 'slop' to something recognizably Atlassian." A DESIGN.md is not your system's encyclopedia; it's the 30% that decides whether output looks like your brand.

IncludeLeave out
Core palette with semantic roles (primary, surface, on-surface...)Full 10-step color ramps no component references
The typography levels screens actually useEvery weight/size permutation your font ships with
Spacing scale and radius scalePixel specs for every layout in the app
The 10-20 components that define your look (median in the wild: 25)Long-tail components an agent can compose from the core ones
Rules an agent would get wrong (Do's and Don'ts)Rules any competent agent infers (align things, make text readable)
One brand-personality paragraph in OverviewBrand history, mission statements, tone-of-voice essays

When in doubt, apply this test: adjectives describe a region, while a specific reference describes a point. If an entry doesn't move the agent from a region to a point, cut it. Decisiveness over completeness.

Write for the linter: the 9 rules as a quality checklist#

The linter isn't bureaucracy: each rule encodes a way agents get confused. In our analysis, zero of the 74 community files had lint errors, but not a single one was warning-free (1,341 warnings total, median 16 per file). Reading the rules as writing lessons:

RuleSeverityWhat it teaches you
broken-referrorEvery {token.reference} must resolve. A broken reference is a token the agent silently can't use.
missing-primarywarningDefine primary explicitly, or agents auto-generate one: fabrication by omission.
contrast-ratiowarningComponent background/text pairs must hit WCAG AA (4.5:1). 55% of community files (41 of 74) fail this at least once, 179 violations total. Check yours before an agent replicates the failure on every screen.
orphaned-tokenswarningColors no component references are either missing a job (assign one in prose) or dead weight (cut).
token-summaryinfoA per-section census: your quickest sanity check against the medians above.
missing-sectionsinfoIf you define colors but no spacing or rounded scales, agents will invent rhythm and radii.
missing-typographywarningColors without typography means default fonts: half a brand.
section-orderwarningSections follow the canonical order (Overview, Colors, Typography, Layout, Elevation & Depth, Shapes, Components, Do's and Don'ts) so every consumer finds things in the same place.
unknown-keywarningCatches top-level typos like colours: (a typo'd key is a whole token group the parser never sees).

Workflow: run npx @google/design.md lint DESIGN.md after every editing pass; it exits nonzero on errors, so it drops straight into CI. Ship with zero errors, and zero warnings you can't justify in one sentence.

Do's and Don'ts: the most underrated section#

The Do's and Don'ts section is where compliance is won, because it's the only section written in the imperative: the mode agents follow best. Tokens constrain values; Do's and Don'ts constrain behavior. The community agrees by revealed preference: 63 of 74 collection files include one.

The failure pattern is writing adjectives where you need instructions:

Weak (a region): "Buttons should feel approachable and modern."

Strong (a point): "Do use button-primary for exactly one action per view. Don't create new button variants; if a case doesn't fit button-primary or a text link, ask."

Every strong line has the same anatomy: an explicit Do or Don't, a concrete referent (a token, a component, a count), and no room for interpretation. Five such lines outperform twenty mood sentences.

How do you keep DESIGN.md in sync with your design?#

A stale DESIGN.md is worse than none: the agent will confidently apply last quarter's brand. Three habits keep it alive:

  1. Change the file in the same PR as the design change. A rebrand PR that touches theme.css but not DESIGN.md should fail review, same as a behavior change without a test.
  2. Diff on every change. npx @google/design.md diff DESIGN.md DESIGN-v2.md reports token-level adds, removals, and modifications, and exits nonzero on regressions; wire it into CI so design changes are as reviewable as code. This also neutralizes silent breaking changes: nothing about your design system changes without a visible diff.
  3. Re-export derived formats. If Tailwind consumes your tokens, regenerate on change (npx @google/design.md export --format css-tailwind DESIGN.md > theme.css) so the file and the code can't disagree.

Cadence: in practice, review the file whenever design changes, and skim it quarterly for rot (our recommendation, not a spec requirement). The format is at version alpha and under active development, so pin your expectations (and this article) to CLI 0.3.0.


Next step: run your draft through npx @google/design.md lint, then paste it into the DESIGN.md viewer to see your system the way an agent will. Want a benchmark before you start? Browse real-world DESIGN.md examples to see how established brands spend their token budget.

Frequently asked questions

How long should a DESIGN.md be?

The median file in the awesome-design-md collection is about 546 lines and about 7,050 tokens; the largest is around 11,000 tokens. Aim at or below the median. The constraint isn't a hard limit: every token spent on low-value context dilutes the agent's attention on the decisions that matter.

Should I document every component?

No. The median community file defines 25 components. Document the 10 to 20 that carry your visual identity (buttons, cards, inputs, navigation) and let agents compose the long tail from those plus your Do's and Don'ts. Atlassian's roughly 30% coverage number is the honest ceiling for a Markdown file, so spend it deliberately.

Can I generate DESIGN.md instead of writing it?

Yes, for the first pass. Tooling can extract tokens from your codebase or theme config faster than you can by hand. But generated files skip the rationale and cutting passes, which is where agent compliance actually comes from. Generate the skeleton, then edit like an editor.

How do I keep DESIGN.md in sync with code?

Treat it as code: update DESIGN.md in the same pull request as any design change, run the diff command between versions in CI so it exits nonzero on regressions, and regenerate any exported formats like Tailwind themes when tokens change. If the file and the codebase disagree, the agent inherits the disagreement.

YAML or prose, where does a rule belong?

If it's a value, a color, size, radius, or component property, it goes in YAML, since tokens are the normative values. If it's a judgment about when or how to apply values, such as keeping one primary button per view, it goes in prose, ideally as an imperative Do or Don't. Never state the same fact in both; duplicates drift apart.