·10 min read

DESIGN.md in CI: Linting Design Specs

An engineering guide to DESIGN.md: the YAML + Markdown format, lint/diff/export/spec commands, WCAG AA coverage, exit code traps, and a complete CI example.

S
Stitch Prompt Team
Content Team
StitchAITutorialGitHub

Over the past year, "how do we keep an agent producing visually consistent UI" has become a real engineering problem. The answer is converging on a simple idea: write the design system down in a plain-text file and make the agent read it before touching any UI.

DESIGN.md is the most watched take on that idea. It comes from an official Google Labs open-source repository (Apache-2.0, currently alpha) and ships with a standalone CLI: lint, diff, export, and spec. Version 0.4.0 has been widely tested by the community in early October.

The more important shift is positioning: DESIGN.md is no longer just "a document the agent reads", but an engineering artifact you can lint, diff, and block merges with. Design token governance finally has an official, executable toolchain.

Note: the DESIGN.md format is still alpha and will keep changing; pin the CLI version when you wire it into CI. This article reflects v0.4.0 behavior.

1. From "a Document for the Agent" to a Checkable Artifact

A convention is settling in for the agent era: give each responsibility its own plain-text spec file.

FileOwnsCore role
CLAUDE.mdBehaviorHow the agent should work and which processes to follow
DESIGN.mdVisualsColors, type, spacing, component rules, and design intent
AGENTS.mdCollaborationHow multiple agents or tools coordinate

A popular community summary nails it: CLAUDE.md governs behavior, DESIGN.md governs visuals, AGENTS.md governs collaboration.

The real value of DESIGN.md is checkability: contrast, token references, and section completeness can all be verified with a single command, and that check can run in CI so non-compliant specs never reach the main branch.

2. The Format at a Glance: YAML Values + Markdown Intent

DESIGN.md uses a two-layer structure:

  • YAML frontmatter: the canonical values (tokens) such as color hex codes, font names, and type scales.
  • Markdown body: the design intent — why these values exist and how to use them.

The split matters: machines read YAML to lint and export; humans and agents read Markdown to understand context.

Fixed section order

The spec requires a fixed section order, and the lint tool checks completeness against it:

  1. Overview
  2. Colors
  3. Typography
  4. Layout
  5. Elevation & Depth
  6. Shapes
  7. Components
  8. Do's and Don'ts

When writing a prompt-style design spec, or asking an agent to draft a DESIGN.md, follow this order or lint will complain.

Illustrative structure

A minimal structure sketch (fields depend on the actual spec):

---
colors:
  primary: "#1a1a1a"
  background: "#ffffff"
  accent: "#2563eb"
typography:
  base: "Inter"
  scale: "1.25"
---

## Overview

A documentation product that values readability and restrained accent color...

## Colors

primary is for body text and primary buttons; accent is reserved for links and focus states...

3. The Four CLI Commands: lint / diff / export / spec

The four commands cover the full lifecycle of a design spec:

CommandPurpose
lintValidate DESIGN.md against the rule set, including WCAG AA contrast
diffCompare two specs or two revisions
exportExport to Tailwind config or W3C DTCG design tokens
specPrint the normalized spec for team alignment

Run a local check:

npx @google/design.md lint DESIGN.md

What lint covers, and where WCAG AA stops

lint ships with 8 rules. The loudest one is contrast checking: text and background pairs are verified against the WCAG AA 4.5:1 threshold.

Know the boundaries: lint does not inspect focus states, semantics, or motion. It catches hard failures; it is not a substitute for design review.

The exit code trap: why contrast issues do not fail CI

This is the easiest trap to fall into: when lint finds contrast problems it warns but does not error, and the process still exits 0. Wire it into CI as-is, and a non-compliant spec passes.

Strict enforcement means reading the JSON output and returning a non-zero exit code yourself. The check below is illustrative (adapt to the actual output format):

# Illustrative: persist lint output and fail CI when a contrast warning appears
npx @google/design.md lint DESIGN.md > lint-result.json
if grep -qi "contrast" lint-result.json; then
  echo "Contrast check failed"
  exit 1
fi

4. In Practice: Adding DESIGN.md Checks to CI

A GitHub Actions configuration you can adapt directly. Two details matter: use the official designmd command name from the workaround, and pin the version:

name: design-lint

on: [pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - name: Lint DESIGN.md
        run: npx -p @google/design.md@0.4.0 designmd lint DESIGN.md

Strict mode: parsing the JSON output

If the team requires "contrast failures must block merges", add a step on top: persist the JSON output, look for contrast warnings, and exit non-zero when found. The approach matches the earlier snippet — the key is translating a "warning" into CI semantics for "failure".

5. Exporting to Tailwind Config and DTCG

lint keeps the spec correct; export makes it usable:

  • Export to Tailwind config so the frontend consumes design tokens directly instead of scattering colors and fonts across components.
  • Export to W3C DTCG to interoperate with the broader design toolchain.

Worth noting: the DESIGN.md CLI runs independently and needs no Stitch account. Even if your team never uses Stitch to generate interfaces, you can adopt it purely as a spec linter and exporter.

6. Troubleshooting: Three Common Failures

SymptomCauseFix
ENOVERSIONSDependency or version resolution failedPin the CLI version; clear the cache and reinstall
No output on Windowsdesign.md command collides with a file associationUse the workaround command
broken-refThe spec references a missing token or sectionFix the reference at the reported line

On Windows / PowerShell, when the command name collides, use:

npx -p @google/design.md designmd lint DESIGN.md

7. FAQ

Q1: Can I use DESIGN.md and the CLI without a Stitch account?

Yes. Both the format and the CLI are independent projects; local runs and CI integration do not depend on Stitch cloud services.

Q2: Why does a contrast problem not fail CI?

lint reports contrast issues as warnings and exits 0; strict blocking requires parsing the JSON output and returning a non-zero exit code yourself.

Q3: What is the smallest useful setup for a new team?

Two steps: add one line to AGENTS.md ("read DESIGN.md before any UI work"), then add a lint check to CI. Fill in the spec as you go.

8. Summary

DESIGN.md turns "design rules" from a verbal agreement into an engineering artifact: writable, checkable, exportable, and enforceable. For teams already practicing CI, the cost of adoption is nearly zero — one command to check, one pipeline to hold the line.

Keep reading: