# DESIGN.md: The Design System as a File the AI Can Read Too

> What the DESIGN.md format from Google Labs actually delivers: background, AI value, accessibility and CMS integration — on a living example, drawbacks included.

Source: https://www.jpkc.com/db/en/blog/design-md/

Ask any project team why the buttons are rounded. You get four answers: "always been that way", "it's in the Figma", "the client wanted it back then", and "no idea, that predates me". The values themselves take ten seconds to find — they are in the CSS. What is missing is the **reasoning**. And with it, the ability to repeat a decision, defend it, or deliberately reverse it.

That is precisely the gap the **DESIGN.md** format aims to close: a single text file in the project that pairs machine-readable design tokens with human-readable rationale. It sits next to the code, travels with it through Git, and is written so a coding agent can understand it — without a human being any worse off.

This article is the long inventory: where the format comes from, what it actually delivers, what it explicitly does **not**, and how that feels differently to developers, designers, account managers and clients. The living example is the `DESIGN.md` of my main site [jpkc.com](https://www.jpkc.com/en/) — a real, maintained, 406-line file, not a demo snippet.

> **On method:** every number in this article is measured first-hand — against the format's repository, the tool, the two living files and the Git history. As of August 2026. Where I could not verify something, it says so, rather than being smoothed over.

## What a DESIGN.md is

The file has two layers. On top a **front matter** — a YAML block fenced by `---` lines holding machine-readable values. Below it ordinary Markdown prose explaining why those values are what they are.

```md
---
name: Heritage
colors:
  primary: "#1A1C1E"
  tertiary: "#B8422E"
  neutral: "#F7F5F2"
typography:
  h1:
    fontFamily: Public Sans
    fontSize: 3rem
rounded:
  sm: 4px
---

## Overview

Architectural Minimalism meets Journalistic Gravitas. The UI evokes a
premium matte finish — a high-end broadsheet or contemporary gallery.

## Colors

- **Tertiary (#B8422E):** "Boston Clay" — the sole driver for interaction.
- **Neutral (#F7F5F2):** Warm limestone foundation, softer than pure white.
```

A **design token** is nothing more than a named design decision: "the brand colour is called `primary` and it is `#1A1C1E`". The advantage of the name over the value is that it carries intent and can be changed in one place.

Sections in the prose part follow a fixed order — Overview, Colors, Typography, Layout, Elevation & Depth, Shapes, Components, Do's and Don'ts. Omitting is allowed, reordering raises a warning. Inside values you can point at other tokens with `{colors.primary}`, much like a formula in a spreadsheet.

That is the whole mechanism. It gets interesting at the question of which of the two layers is actually the more important one — more on that shortly, because that is where the project's most interesting contradiction lives.

## Where the format comes from

Precision pays off here, because the origin changes how you read the thing.

DESIGN.md is **not an independent standardisation effort**. It is the opened-up format of **Stitch**, a Google Labs product that generates interfaces from descriptions. The repository accordingly lists the Stitch documentation as its homepage. On 21 April 2026 Cassia Xu, a software engineer at Google, announced the opening on the Google blog — verbatim: "Today, we're open-sourcing the draft specification for DESIGN.md, so it can be used across any single tool or platform."

The hard facts, measured in August 2026:

| Detail | Value |
|---|---|
| Repository | `google-labs-code/design.md`, created 10 April 2026 |
| Licence | Apache-2.0 |
| CLI package | `@google/design.md`, version 0.4.0 |
| Format version | explicitly **`alpha`** |
| Releases | 5 in just over three months (0.1.0 to 0.4.0) |
| Commits | 62 on the main branch, from 27 contributors |
| Reach | 27,111 stars, 2,260 forks; roughly 1.39 M CLI downloads |

Three observations you need when weighing it up:

**The alpha status is not coyness.** The README says so itself: "The spec, token schema, and CLI are under active development. Expect changes to the format as it matures." At the same time the format has been remarkably stable in practice: between 0.1.0 and 0.4.0 the specification changed by **+23 / −1 line**. Substantively it was exactly two things — colour values may be any CSS colour notation since June rather than hex only, and an optional `omitted` key was added. The eight sections and eight component properties are unchanged. The big movement happened **before** the first release, in the eleven days between repo start and publication.

**The contributor base is mixed, control is not.** 27 people have contributed, 20 of them with exactly one commit — that is genuine outside participation. At the same time 37 % of commits come from identifiably Google-affiliated authors, all five releases were published by a single maintainer, and every contribution requires Google's **Contributor License Agreement** — an agreement granting Google usage rights to your contribution while you keep the copyright. Standard for Google projects, but it is a hurdle and a governance statement.

**Attention is unevenly distributed.** 27,000 stars face a remarkably quiet technical debate: the most-noticed Hacker News post reached 37 points and four comments, the official announcement post three. Many stars, little discussion — a pattern worth knowing before inferring maturity from a star count.

And one detail that describes activity honestly: development runs **in bursts**, not continuously — spikes on individual merge days, quiet in between. At the time of this research the last commit on the main branch was about two weeks old, even though new items had come in meanwhile.

## The actual thesis: prose before tokens

Reading the format merely as "YAML with comments" misses the point. Six weeks after the opening the project added a `PHILOSOPHY.md` — and it inverts the obvious weighting:

> "The quality of a generated design is determined less by the precision of its values than by how clearly the intent is described."

And more plainly:

> "The prose is where the design lives. Everything else in the document exists to support it."

Three ideas follow from that, and they carry the format's practical value.

### A specific reference beats a list of adjectives

The document's strongest argument is a comparison. "Modern, clean, trustworthy, premium" describes **nothing**, per PHILOSOPHY.md:

> "Adjectives describe a region. A specific reference describes a point."

Against the alternative:

> "A design that references 'A 1970s graduate lecture handout in the tradition of an old and established university' evokes a complete world: the one color of ink, the generous margins, the serif set at a reading size, and the absence of decoration."

That is immediately convincing once read — and it holds for humans exactly as it does for models. A brief made of four adjectives produces the average, because the average sits precisely in the middle of what those four words stake out.

### What you leave out defines the character

The second idea concerns **negative constraints** — the things a design explicitly does *not* do:

> "A clear design reference carries its restrictions automatically. A model knows what a lecture handout is, and it knows what a lecture handout is not. It does not glow or use a gradient. You don't have to list these. Naming the object names them, the same way naming a dog tells the model that dogs don't meow."

From this the document derives a usable quality test: a deliberately chosen list of don'ts is useful — a long, sprawling one is usually a symptom that the description was too vague to carry those constraints by itself.

### The unresolved contradiction — and why I leave it standing

And now the place where the project contradicts itself without resolving it.

The README says: **"The tokens are the normative values. The prose provides context for how to apply them."** PHILOSOPHY.md says: **"The prose is the most vital part of the specification"** and, more sharply, **"The token values serve as context and are not rendering instructions."**

Those are not the same statement. In one, tokens are binding and prose explanatory; in the other, prose is the real thing and tokens merely context. The word "normative" does not appear in PHILOSOPHY.md even once. Neither README nor specification nor philosophy clears the tension.

The community noticed. In an open issue a commenter writes: "That makes 'token values serve as context, not rendering instructions' feel contradictory — that's not the nature of machine-readable tokens. We give a token to an agent, they will use it."

I deliberately do not settle this here, because both positions are in the project. For practice it simply means: **treat both layers as binding and keep them in sync.** Relying on one gets you ambushed by the other.

## The living example

The `DESIGN.md` of jpkc.com describes a dark, monochromatic portfolio in slate blue. It runs to roughly 35 KB across 406 lines — 240 lines of front matter holding **89 tokens** (30 colours, 11 typography scales, 5 corner radii, 12 spacing steps, 31 components) and 166 lines of prose across the eight canonical sections. What it describes is a stylesheet of about 2,100 lines.

What matters is less what is in it than **what exists nowhere else**. Three examples from the file that would have no home in a token file or a Figma document:

**Why the font weight is 300.** The file explains: "This ultra-light treatment is what makes the design feel airy and editorial despite the dark surface — it is **load-bearing, not decorative**." The CSS variable `--fw-light: 300` carries exactly none of that. Anyone raising it to 400 without that sentence is not "fixing" anything; they are dismantling the design.

**An iOS printing bug with its cause.** The dark colour scheme caused iPhone and iPad to render the entire printed page black — unreadable PDFs, while Chrome and Firefox on the desktop never showed anything. The file documents the cause and explicitly warns which two lines must survive a later refactor. That is knowledge which otherwise exists exactly once: in the head of whoever spent the evening tracking it down.

**A workaround for a browser artifact.** The soft inner glow of the main card is stepped down on narrow viewports and removed entirely below 500 px — not out of taste, but because `backdrop-filter` forces the element onto its own GPU layer, where the wide glow can smear over text. Without that note the stepping looks like inconsistency and gets "unified" during the next clean-up.

That is exactly the value PHILOSOPHY.md means. It is **handover capital**: the part that otherwise disappears when the agency, the developer or the tooling changes.

## What the tool can do — and what it only appears to do

The format ships a command-line tool with four commands. I ran all four against the living file.

### `lint` — check the file

```bash
npx @google/design.md lint DESIGN.md
```

The **linter** — a program that checks a file for rule violations — knows eleven rules in version 0.4.0 and emits structured JSON an agent can act on directly. On the jpkc.com file:

```json
{ "summary": { "errors": 0, "warnings": 22, "infos": 1 } }
```

Of those eleven rules, however, exactly **one** carries the "error" level: `broken-ref`, a reference to a token that does not exist. Everything substantive — contrast, unused tokens, divergence from the code — stays a warning and passes an automated pipeline green. Anyone wanting the linter as a quality gate has to promote the warnings themselves.

### `diff` — catch regressions

The second command compares two versions of the same file. It is the most interesting part, because it makes the design system **versionable in the literal sense**. I tested it on a real change — more on that shortly — and measured both directions:

| Case | Result | Exit code |
|---|---|---|
| Genuine improvement (one contrast warning fewer) | `regression: false`, `delta.warnings: -1` | 0 |
| Deliberately broken token reference | `regression: true`, `delta.errors: +1` | **1** |

The command named the two changed components precisely. For an automated pipeline that is usable — with the caveat that `diff` compares **DESIGN.md against DESIGN.md only**, never against the actual code.

### `export` — pass the tokens on

```bash
npx @google/design.md export --format css-tailwind DESIGN.md
npx @google/design.md export --format dtcg DESIGN.md
```

From the jpkc.com file this produces an 83-line `@theme` block for Tailwind CSS v4, or a token file in **DTCG format** — the design-token standard from the Design Tokens Community Group at the W3C, which I covered in more depth in the [article on CSS cascade layers](https://www.jpkc.com/db/en/blog/css-cascade-layers/).

Two limitations you need to know, because the marketing skips them:

**The shape fits, the names do not.** The Tailwind export yields `--color-primary`, `--color-brand-light` and so on. The production stylesheet of this blog, however, uses `--color-page`, `--color-accent`, `--color-surface-d`. An export would therefore **not replace the existing block but sit beside it**. The token names of a maintained DESIGN.md are a hand-written translation layer that no tool models.

**The export loses exactly what the philosophy calls the core.** Neither the Tailwind nor the DTCG export takes the prose along — roughly 4,500 words in the jpkc.com example. The entire component layer with its 31 entries stays behind too. Both exports contain token values and nothing else. On top of that, `lineHeight` gets dropped along the way, even though Tailwind has a namespace for it.

### `spec` — print the specification

The fourth command prints the format description as text, explicitly "useful for injecting spec context into agent prompts". That is authoring context, not design information: roughly 15,000 characters of format rules you can hand an agent so it writes a **correct** DESIGN.md.

## The value for AI agents — soberly

This is the format's advertised core, and it pays to separate mechanism from promise.

### What demonstrably works

The division of labour is sensibly conceived: "Tokens give agents exact values. Prose tells them *why* those values exist and how to apply them." The specification puts the Overview prose's role precisely — it serves as the basis for the agent's stylistic decisions **wherever no specific rule or token is defined**. Which is to say, for the thousand small decisions no design system anticipates.

Add the machine-readable feedback loop: `lint` returns JSON with path, severity and message plus an exit code. An agent can therefore check and correct its own work rather than guess.

Google's official positioning in the announcement is correspondingly restrained: "Instead of guessing intent, AI agents can know exactly what a color is for." The promise is **a replacement for guessing**, not enforcement.

### What does not work — and cannot

Now the four points to know before adopting it.

**There is no defined load path.** Neither README nor specification nor philosophy mentions `CLAUDE.md`, `AGENTS.md`, `.cursorrules` or comparable agent context files even once. There is no statement about where the file should live or how a tool finds it. The maintainer confirms it himself in an issue open since May: "The spec is not opinionated currently… Firstly, we need to determine how to signal to the agent which DESIGN.md to use." The specification defines a **content standard, not a load path**.

In practice: Claude Code does not load a DESIGN.md on its own. `CLAUDE.md` and relatives are read automatically; anything else enters context only through an explicit reference. Exactly that situation exists in my own projects — none of my project instruction files imports the DESIGN.md using the syntax made for it; they merely link to it in prose. The most-noticed collection of DESIGN.md files accordingly describes the usage pattern as two manual steps: "1. Copy a site's DESIGN.md into your project root  2. Tell your AI agent to use it."

**Context is not enforcement.** Even once the file is in context it is a request, not a configuration. Claude Code's documentation states this unambiguously for its own context files: the content is delivered as a message, not as a system instruction — "there's no guarantee of strict compliance". The same holds for a DESIGN.md.

**The linter effectively does not check the prose at all.** This is the finding that surprised me most, and it is confirmed three ways. The linter's data model holds the front matter and the list of headings — **no field holds the Markdown body**. Of eleven rules, exactly one touches the sections at all, and it only checks their order. Three counter-tests:

1. A copy of my DESIGN.md in which I falsified the contrast values in the prose ("9.23 : 1" → "21.00 : 1") and swapped a brand colour for magenta produces **byte-identical** lint output to the original.
2. Even the README's own showcase example is immune: replacing all four prose hex values with contradicting ones → still zero errors, zero warnings.
3. A prose reference to a token that does not exist produces **zero** findings.

That is not a bug; it is the construction. But it means the layer that the philosophy calls "the real thing" is secured by no tool whatsoever.

**Context costs measurably.** Atlassian's design system team benchmarked the approach against alternatives and published in June 2026. On a simple task — a login screen — the DESIGN.md variant needed roughly **92 % more tokens** than a server delivering design knowledge on demand, with about 2.7× the variance between runs. The reason is structural and stated plainly in the original: "A DESIGN.md file, by comparison, loads everything, every time." To get down to 80 KB at all they had to strip most of the usage guidance for their 50-plus components — whereupon the agents began reading component implementations instead, and were more inclined to re-create components rather than use the existing ones.

In fairness, the authors' own caveat belongs here: "These results should not be seen as conclusive; this blog is not a research paper." Which model was used is not stated. As an order of magnitude it remains the most solid public measurement available.

A postscript with symbolic weight: Atlassian's own publicly available DESIGN.md **fails Google's own linter** — 29 errors and 445 warnings. The largest real-world file in this format does not pass the format's own check.

## Accessibility: genuine help and false assurance

This is where the most tangible benefit lives — and the biggest misunderstanding.

### What the file delivers

The jpkc.com DESIGN.md lists verified **contrast ratios** in its Do's — the luminance relationship between text and background that the accessibility guidelines [WCAG](https://en.wikipedia.org/wiki/Web_Content_Accessibility_Guidelines) put at a minimum of 4.5 : 1 for normal text. I recalculated every value: they hold to two decimal places.

More valuable still is the documented **exception**: one token measures 2.58 : 1 and therefore fails. Instead of using it silently, the file explicitly declares it decorative-only and forbids it for readable text. That is exactly the kind of decision that gets accidentally undone at the next redesign without documentation.

The focus rule is likewise honoured verbatim in the code: the file describes a 2 px outline with a defined offset, and precisely that sits in the stylesheet.

### The real case: the linter found something genuine

While writing this article I turned the tool on my own site — and it reported three contrast problems. One was real:

**White on `primary-accent` (`#647c8c`) yields 4.37 : 1**, missing the 4.5 : 1 for normal text. Affected were the `kbd` markup for keyboard shortcuts and the active entry in the dropdown menu. Since the font size there is 87.5 %, the more generous 3 : 1 large-text threshold does not apply either.

The honest framing belongs with it: at that point both rules were **dead CSS** — the site renders neither a `kbd` nor the dropdown. So it was not an active violation but a latent one: it would have gone live the moment somebody used either.

It is fixed regardless — both places now sit on a token at 5.63 : 1, and the DESIGN.md moved in the same step: new Do's rule, revised colour description, updated component tokens. The `diff` command then confirmed `delta.warnings: -1` with no regression. That is the complete cycle the tool is built for.

### And now the limits — they are considerable

The linter's contrast rule is deliberately simple and therefore **unreliable in both directions**:

- It knows exactly **one** threshold: 4.5. No 3 : 1 allowance for large text, no check for non-text elements such as icons or borders, no AAA.
- It only checks pairs **within a component** — body text on a page background is never checked unless modelled as a component.
- It computes **without alpha compositing**, that is, without accounting for transparency.

That last point produces both error types, and I measured both:

**False alarm:** a component with `backgroundColor: "transparent"` is treated as a black surface and reported at 2.28 : 1. That is the one remaining warning on my file — and it is not one.

**False all-clear:** a component with a background at 73 % opacity passes as fully opaque, even though the actually visible contrast differs.

The same blindness hits Google's own showcase: the bundled glass aesthetic produces four contrast warnings with the absurd value **"1.00:1"**, because white text on a 10 %-opaque white surface is computed against opaque white.

An open issue in the repository puts the problem squarely and names ten further gaps. The core charge is **"false sense of assurance"**:

> "A file can pass the linter with zero contrast warnings while containing combinations that fail WCAG at implementation time."

The four associated improvement proposals have been open since late June and are unmerged. Against that, the README promises "check WCAG contrast ratios" flatly.

**My conclusion on this point:** a DESIGN.md is an excellent place to **record and justify** accessibility decisions. It is not a checking tool. Mistaking it for one trades real verification for a green tick.

A structural postscript that underlines it: of all things, the two colours for the focus outline are reported by the linter as "unused". The reason is the schema — the eight permitted component properties simply contain **none** for a focus outline. The property most important for keyboard operation cannot be expressed in the machine-readable layer at all.

## Usability, reproducibility, record-keeping

### Usability: states become explicit

An underrated effect: **48 % of my file's components are state variants** — 15 of 31, eight `hover` and seven `active` or `open` states. That forces a question that tends to get lost in design: what does this actually look like when you press it?

Equally valuable: **discarded decisions survive**. The file records that the dark button hover is "no longer the barely-perceptible step it used to be" — and the Git history confirms it: the value once sat practically on the resting colour and was later deliberately moved to a pronounced contrast jump. Without that sentence, the obvious "correction" at the next clean-up would be to soften the jump again.

### Reproducibility: values yes, names no

The claim that a reimplementation is possible from the file alone holds partly. The **values** are complete. The **names** are not: DESIGN.md speaks of `primary`, `primary-dark`, `on-primary`; the CSS says `--color-brand`, `--color-brand-dark`, `--color-text`. Identical values, entirely different namespaces — and not one line of tooling models that translation.

The real bottleneck lies elsewhere though: **a lot is carried by prose alone.** Seven different breakpoint thresholds and 85 numeric rem values across 25 distinct values live exclusively in the prose. The format provides no breakpoint category — but it does not forbid one either, since custom sections and keys are explicitly permitted.

A nice detail on the side, showing how closely you have to look: the conversion of transparency values into eight-digit hex is **rounded** to 8 bits, not exact. `#ffffff40` means 0.2510, not 0.25. Irrelevant for rendering, not for a generator.

### Record-keeping: the benefit that accumulates quietly

Here is the advantage you only notice after months. The main site's `DESIGN.md` has been touched in **13 commits** since May — and several state the purpose in the title: ".btn-outline :active states + DESIGN.md sync", "a11y for sticky .navBar … + DESIGN.md sync", "docs: Print-Stylesheet in DESIGN.md aktualisieren, iOS color-scheme-Gotcha dokumentieren". In the week before this research the file was touched three times, each time together with the stylesheet.

That produces something a Figma comment cannot: a **searchable, dated history of reasoning**. Why is the navbar background opaque today rather than translucent? The file preserves the rationale for the rollback — and the commit shows when and with which CSS change it happened.

Three honest limitations:

**None of it is enforced.** No hook, no automated check, no compulsion. The practice rests on convention alone — and that convention is not even in the DESIGN.md but in the project instructions beside it.

**The convention contradicts itself between my own projects.** The main project requires "DESIGN.md first, then CSS". This blog project requires the opposite: treat the Tailwind `@theme` block as the source of truth and mirror the rationale afterwards. Both are defensible, but it shows the direction is a project decision the format does not prescribe — and one you had better make deliberately, once.

**The file is not a build input.** It calls itself "a documentary specification"; neither the Eleventy config nor `package.json` references it. It acts exclusively through the humans and agents who read it.

## Relationship to the classic style guide

A DESIGN.md **does not replace a pattern library**, for a simple reason: nothing gets rendered. My file contains zero code blocks, no HTML, no component preview, no state demo. Anyone wanting to see what the button looks like has to open the site.

Conversely it captures what a generic pattern library does not know: project-specific brand signatures. The filename tag along the bottom edge of the main card that carries the IDE metaphor and is explicitly "should not be removed". Or the three window dots in the navigation bar that double as a back-to-home link with a defined click area and focus ring.

The two forms complement each other: **the pattern library shows, the DESIGN.md justifies.**

Two observations from practice:

**Sections are freely extensible** — the philosophy says so explicitly. This blog's DESIGN.md uses three canonical and five custom sections, among them an `## Implementation map` assigning every design concern to exactly one CSS file and the change needed. The linter does not object.

**There is scope creep, and it is telling.** My file now contains a purely editorial rule: it forbids the en dash in compound nouns. That has nothing to do with visual design any more. When a file becomes the central collection point for "things everyone should follow", that is a sign it works — and simultaneously the point at which you have to watch that it does not turn into a catch-all.

## Integration into stacks and CMSs

### Eleventy and Tailwind CSS v4

Eleventy prescribes no style layer — token integration there is a pure CSS decision. Tailwind v4 is the **only directly served stack**: `export --format css-tailwind` produces a `@theme` block Tailwind understands immediately.

With the caveat named above: the shape fits, the names do not. The export sits beside your existing block instead of replacing it. Realistically it is a **starting point for a new project**, not a synchronisation mechanism for an existing one.

### WordPress themes and `theme.json`

For WordPress the question is particularly interesting, because block themes already have their own well-developed token system in `theme.json`. I checked how far the analogy carries.

**How `theme.json` works.** In the current WordPress generation the schema version is **3** — unchanged since WordPress 6.6. The file knows eleven top-level keys; the two that matter are `settings` (what is adjustable) and `styles` (what applies). From `settings` WordPress generates CSS custom properties automatically, on a fixed pattern:

```
settings.color.palette         →  --wp--preset--color--<slug>
settings.spacing.spacingSizes  →  --wp--preset--spacing--<slug>
settings.typography.fontSizes  →  --wp--preset--font-size--<slug>
settings.custom.<key>          →  --wp--custom--<key>
```

There are ten such preset categories in total. A colour entry additionally generates three usable classes (`.has-<slug>-color`, `.has-<slug>-background-color`, `.has-<slug>-border-color`).

**What maps cleanly.** I ran the test: from the DTCG export of my DESIGN.md, a small mapping script can produce a **schema-valid `theme.json`** — 30 colours into the palette, 12 spacing steps into `spacingSizes`, 5 radii into `radiusSizes`, 11 typography scales into `fontSizes` plus two font families. Validation against the official WordPress schema passes.

**Where the analogy ends — the more important part:**

- **The 31 component entries have no equivalent whatsoever.** `theme.json` knows `styles.blocks` for over a hundred core blocks and `styles.elements` for a dozen-odd element types — but that is an entirely different axis from "button at rest, on hover, pressed".
- **Typography carries over only partly.** In `theme.json` only `fontSizes` and `fontFamilies` are real preset lists. `fontWeight`, `lineHeight` and `letterSpacing` are **booleans** there, merely enabling editor controls — they store no values and generate no custom properties. Depending on how you count, 12 to 23 typography settings from my file are left without a home.
- **The slug conventions clash.** WordPress recommends numeric identifiers for spacing (`10`, `20`, … with `50` as the middle) so they merge and sort with the defaults. My spacing steps are called `xs`, `sm`, `md`, `page-padding-x` — none starts with a digit.
- **The export's `--prefix` switch does not help.** An attempt with the WordPress prefix produces `--wp--preset---color-primary` instead of `--wp--preset--color--primary`.

**And no tool closes the gap.** Style Dictionary has no WordPress format. A repository search for converters yields a handful of projects, the largest at 39 stars. The only `theme.json` emitter findable on npm from a token system reads no DTCG but an in-house format. And the only DESIGN.md tool with a WordPress connection works **in the opposite direction**: it generates a DESIGN.md *from* a `theme.json`.

For classic themes without the block editor: `theme.json` is usable there since WordPress 5.8, but essentially for the `settings` part — palette, font sizes, spacing. The corresponding `add_theme_support()` calls then become unnecessary.

**My recommendation for WordPress:** keep DESIGN.md as the **rationale layer**, `theme.json` as the technical implementation, and treat the mapping as a deliberately maintained small script — not as a tool you could buy ready-made. The benefit then lies in the prose and the traceability, not in automation.

### Other systems, briefly and with evidence

- **Drupal** has **no** design-token interface in core to this day. A substantial core issue for it is open, with DTCG format and runtime CSS variables planned — status "Needs work".
- **Shopware 6** has a **same-named but substantively unrelated** `theme.json`. There, `config.fields` defines typed fields (colour, text, number, font family, media) that become SCSS variables **and** input fields in the administration. That is a theme configuration system, not a token format — the similarity is coincidental and a genuine source of confusion.
- **TYPO3 v13** has no design-token concept. Site Sets and Site Settings succeed the TypoScript constants; CSS custom properties do not arise from them by themselves.

### The realistic integration level

In sum: the tool today can **validate, compare and export** — no more. There is no import, no watch mode, no CMS command. An automated gate is therefore possible only for the DESIGN.md **itself**. The path into the stack is one-way and, for anything but Tailwind v4, yours to write.

## Drawbacks — sorted by kind

Not every criticism weighs the same. I sort into three categories because that makes the decision easier.

### Structural drawbacks — these stay

**Prose and tokens cannot be checked against each other.** The key point, evidenced above. Both layers can drift apart without anything raising a flag.

**Duplicate maintenance is real and documented in the project itself as an open item.** An issue titled "Duplicating design facts in front matter and markdown body" was opened on the day of the first release and is open to this day. Its example: the YAML says one colour, the prose another — "the document still looks authoritative, but now contains two versions of the truth."

**And that is exactly what happened to me.** In my own file five components declare `padding: 0.475rem`; the production CSS sets `padding: .475rem .9rem`, and the prose of the same file correctly names both values. The **machine-readable part is the wrong one** — and the linter says nothing, because it never sees the code. In fairness: the correct value would have been permitted; the drift was not forced.

**The `orphaned-tokens` rule is tailored to Material Design 3.** It reports 21 of my palette's 30 colours as "unused" — **20 of them wrongly**, since the values are in use in the CSS. The mechanism explains it: the rule counts references from the `components` block only and additionally knows an allow-list of exactly seven Material Design family names. Choosing your own names gets you punished. The source comment says it outright: "Custom tokens … still get flagged when unused."

The repository demonstrates it nicely: all three official examples produce zero such warnings. Rename just **two** tokens in one of them to project-specific names and two warnings appear immediately. And the rule can be switched off entirely by omitting the `components` block — the more thoroughly you maintain, the louder the linter gets.

**Hard format limits.** There is **no light/dark and no multi-theme** (open since April, called "at the top of the list" by the maintainer), no structured shadow tokens despite an "Elevation & Depth" section, no motion tokens, no icon section, and units are limited to `px`, `em`, `rem`. My workaround — storing shadow and focus colours as ordinary colour tokens — promptly lands all seven of them in the orphan list. My site's runtime light theme does not exist in the front matter at all, only in the prose.

**There is no way to suppress findings.** No config file, no `--disable-rule`, no inline comments. The single switch concerns missing sections only.

### Alpha teething problems — these pass

Annoying, but not structural:

- Version 0.3.0 shipped with a **completely broken `spec` command** — for 42 days, until 0.4.0 fixed the path error.
- A **CLI upgrade alone** made the warning count of an unchanged file jump sevenfold: the same file yielded 31 warnings under 0.3.0 and 228 under 0.4.0.
- 196 of those 228 came from **two lines** — one warning per character, because a font stack was written as a string instead of an object and the linter iterated its characters. After the fix, 32 remained. The actual signal had simply drowned.
- A unitless `lineHeight: 1.5` — the form the specification explicitly **recommends** — is silently discarded by both exporters. Quoted, the same value survives.
- The README trailed the rule count for months, and one export format is missing from the format table to this day.

### Misunderstandings — these are on you

- **"DESIGN.md replaces the token pipeline."** No. The CLI can export, not import. The format sits **before** DTCG, Style Dictionary and Figma, not in their place — and the philosophy says exactly that: it does not want to "reinvent the decades long work established by languages and tools that came before us."
- **"The linter validates the design system."** It validates **the file**. No command ever reads application code. A rule like "Don't use a webfont" is unverifiable in principle.
- **"The agent loads it automatically."** There is no defined load path, and context is not enforcement.
- **"Vendor lock-in."** It is in fact **low**: Markdown with YAML, no proprietary component, Apache-2.0, a single package with four commands. Even if the project were discontinued tomorrow, the file would stay readable and the DTCG export would remain.
- **"No renderer is a shortcoming."** No, it is stated intent.

The most pointed objection came from the technical discussion — and it hits a sore spot:

> "My first reaction is that everything I see defined here in DESIGN.md is already codified in my actual themes configs, or component files."

That is true — **for the token part**. For the 4,500 words of rationale it is not: those have no home in any theme config.

## Four perspectives

The same file looks different from four angles. This is not busywork — anyone introducing it has to answer four different questions.

### Developers

**What you gain:** rules with a direct code connection instead of statements of intent. My file's focus rule sits verbatim in the stylesheet. The blog project's `## Implementation map` assigns every concern to exactly one file. Plus handover knowledge that exists nowhere else — the iOS printing bug, the compositing workaround. And a machine-readable gate for one class of error: broken references and parse errors exit with code 1.

**What it costs:** duplicate maintenance. My file was touched three times in one week, each time with the CSS. 89 tokens plus 166 lines of prose alongside about 2,100 lines of stylesheet. The name translation you do by hand.

**How you notice:** the linter is green while the machine-readable part is wrong. A tool update takes an unchanged file from 31 to 228 warnings. An export runs but replaces nothing.

### Designers

**What you gain:** your reasoning survives. "Font weight 300 is load-bearing, not decorative" is a statement no variable carries. Prohibitions get named exceptions instead of grey zones. States get thought through systematically — nearly half the components are state variants.

**What it costs:** tight guardrails, some well beyond colour — no additional grid abstractions, at most three nesting levels in CSS, no framework. And the format knows no light/dark, no shadow, motion or icon tokens.

**How you notice:** the path to Figma is one-way and patchy. The DTCG export carries colours, spacing, radii and typography only — no components, no prose, no `lineHeight`. And a value like `system-ui`, present in ten of eleven typography scales, is a 16-part fallback stack that cannot be meaningfully resolved in a design tool.

### Account management and project leads

**What you gain:** ready-made **scope classifications** you can quote. "Adding `@font-face` is a substantive change, not a styling choice" ends the discussion about whether a new corporate typeface is "just a small thing". And you can show at a real case that special requests can be solved **inside** the system: the need for a highlighted navigation button became a new button variant — DESIGN.md and CSS in the same commit, contrast recalculated, monochrome rule intact.

**What it costs:** the file makes **no** effort statement. No hours, no days, no effort class. It classifies the *kind* of change, not its price. And the governance — who changes what first — is not in the DESIGN.md, is not enforced, and was even defined in opposite directions across my two projects.

**How you notice:** you can **evidence** "provided for in the system" versus "special request" rather than assert it. For "how long will this take" the file gives you nothing.

*An honest caveat on my example:* jpkc.com is my own site. The button case was a self-imposed requirement, not a third-party client request. The mechanics transfer; the conflict dynamics of a real client relationship it does not model.

### Clients

**What you gain:** independence. Your design system sits as a readable text file in your own repository — 30 colours, 11 typography scales, 12 spacing steps, 5 radii, 31 components in plain text, with no tool or subscription required. The format is Apache-licensed, the tool a single package. Changing agency or tooling does not cost you the values.

Add brand consistency across project boundaries: my blog project inherits the main site's tone and **names its three deliberate deviations explicitly**, rather than performing them silently.

**What it costs:** the substance lives in the prose — and **no exporter takes it along**. The value sits in maintained text, not in tooling. And you pay for duplicate maintenance as a running item.

**How you notice:** in a handover you do not lose the colour values, you lose the **explanation** — precisely what the format's philosophy calls the core. And: the contrast error the prose had not quantified was found and fixed. Both are readable in Git. That is the kind of traceability you only appreciate once you have needed it.

## When it pays off — and when it does not

**It pays off when:**

- You work with coding agents regularly and are tired of re-explaining the same design decisions every session.
- Your project outlives your memory — so, practically always.
- Several people or several sibling projects carry the same brand.
- You have to justify design decisions to third parties.
- Accessibility decisions should be documented so they do not get reverted by accident.

**It rather does not pay off when:**

- The project is small and one person carries it alone. Then duplicate maintenance costs more than it returns.
- You have an established design system with a working token pipeline. Then the token part is duplication — and you should adopt, if anything, **only the prose layer**.
- You are hoping for an accessibility audit. It is not built for that.
- You want to hand very large design systems to agents. Past a certain size the context advantage flips, as Atlassian's measurement shows.

**A pragmatic middle path** I would recommend for most projects: start with the **prose**. Overview, Colors, Do's and Don'ts. You can add tokens later — or not at all, if your values already live in a token pipeline. The rationale layer is the part that exists nowhere else; the value layer is the one you probably already have.

## Glossary

Terms that appear in the text and would have overloaded the sentence there.

| Term | Meaning |
|---|---|
| Alpha compositing | Working out which colour is actually visible when a partly transparent surface sits over another. |
| CLA (Contributor License Agreement) | Agreement granting a project's steward usage rights to your contribution; you keep the copyright. |
| DTCG | Design Tokens Community Group at the W3C — the group behind the vendor-neutral standard format for design tokens. |
| Exit code | Return value of a command-line program. 0 means success, anything else failure — how an automated pipeline knows whether to stop. |
| Front matter | A metadata block at the start of a file, here in YAML and fenced by `---` lines. |
| Linter | A program that checks a file for rule violations without executing it. |
| Material Design 3 | Google's design system; its token names (`primary`, `surface`, `on-primary` …) shape the linter's defaults. |
| Pattern library | A collection of rendered components with their states — it shows how something looks instead of describing it. |
| Preset (WordPress) | A predefined value in `theme.json` from which WordPress generates a CSS variable and helper classes automatically. |
| Slug | A short technical identifier without special characters, used in class and variable names. |
| WCAG | Web Content Accessibility Guidelines — the international standard for accessible web content; level AA requires 4.5 : 1 contrast for normal text. |

## Conclusion

DESIGN.md is a good format with an overstated promise and a weak tool — and I would still adopt it again.

**Good** is the core idea: put design decisions where the code lives, in a form both humans and machines can read. The thesis from the philosophy — a specific reference carries more than a list of adjectives — is the best short summary of good design communication I have read in a long time.

**Overstated** is the promise around AI and accessibility. There is no defined load path, context is not enforcement, and the contrast check is simplified to the point of erring in both directions. Take "check WCAG contrast ratios" literally and you buy a green tick instead of a check.

**Weak** is the tool at exactly the point the project calls its core: the prose is touched by not a single rule. You can turn every piece of rationale into nonsense without the linter flinching.

Three things I take from working on this article:

1. **The value is in the prose, not the tool.** What my file has actually given back was never a lint message but the sentence about the iOS printing bug and the reasoning behind font weight 300.
2. **The linter is a smoke detector, not a fire safety report.** It found a real contrast problem on my own site that I had missed — and simultaneously mis-reported 20 of 21 "unused" colours. Both belong to the truth.
3. **Duplicate maintenance is the price, and it is real.** Touching the same file three times in a week is not a side effect; it is the ticket. Anyone unwilling to pay it should keep the prose only.

If you want to start your own DESIGN.md: don't begin with the colours, begin with the sentence nobody else would write down — the reason your design looks the way it does and not otherwise. The values you will find in the CSS anyway.

## Further reading

- [DESIGN.md on GitHub](https://github.com/google-labs-code/design.md) — repository, specification and CLI
- [`@google/design.md` on npm](https://www.npmjs.com/package/@google/design.md) — the command-line tool
- [Announcement on the Google blog](https://blog.google/innovation-and-ai/models-and-research/google-labs/stitch-design-md/) — the opening of the format, April 2026
- [Design Tokens Format Module](https://www.designtokens.org/TR/drafts/format/) — the W3C standard the token layer builds on
- [WCAG — Wikipedia](https://en.wikipedia.org/wiki/Web_Content_Accessibility_Guidelines) — an introduction to the accessibility guidelines
- [`theme.json` — WordPress developer handbook](https://developer.wordpress.org/block-editor/reference-guides/theme-json-reference/) — reference for block themes
- [Tailwind CSS: theme variables](https://tailwindcss.com/docs/theme) — the `@theme` block the export targets

**From this blog:**

- [CSS @layer in Practice](https://www.jpkc.com/db/en/blog/css-cascade-layers/) — why design tokens inside a layer are weaker than outside it
- [Adversarial Fact-Checking for AI Texts](https://www.jpkc.com/db/en/blog/faktentreue-review/) — the method used to verify the numbers in this article

