Why the documentation site does not work
The instinct is to point the agent at the design system site. It rarely helps, for four structural reasons that have nothing to do with the quality of the site.
| Documentation site | What an agent needs | |
|---|---|---|
| Access pattern | Browsed — you go to the page you need | Everything relevant in context, before the first decision |
| Organisation | By component: Button, Input, Card | By decision: colour roles, density, elevation, what is forbidden |
| Voice | Describes intent — "our buttons feel confident and approachable" | States constraints — "font-weight 500, radius 6px, never a gradient" |
| Completeness | Covers what exists | Must also cover what must not exist |
The organisation row is the one people miss. A site organised by component is perfect for someone who already knows they need a Button. An agent about to build a screen has not decided which components to use yet — its first decisions are about density, hierarchy and layout, and those are exactly what a component-organised site never covers.
The completeness row is the most consequential. Documentation describes what exists because that is what documentation is for. But the difference between your interface and a generic one is mostly a set of things you never do, and no component page will ever mention them.
What real files actually contain
We sampled 299 DESIGN.md files published across public repositories and directories — files written deliberately to give AI agents design guidance — and measured their contents. 72 were specifically visual-design files. The pattern is consistent enough to use as a checklist of what to avoid.
| Share of files | |
|---|---|
| Colours as raw hex, no semantic role | 86% |
| No prohibitions of any kind | 76% |
| No dark mode definition | 69% |
| No distinctive motifs | 57% |
| At least one vague adjective doing the work | 54% |
| No concrete size value anywhere | 44% |
| Mention typography at all | 83% |
Set the last two rows against each other. Typography is mentioned in 83% of files and 44% contain no concrete size value anywhere. That gap is the whole problem in one statistic: the files are talking about type without ever saying how big anything is.
The adjective figure is the other half. "Clean" appears in 39% of these files, "modern" in 36%. Both are words a model satisfies by producing the centre of its training distribution, which is precisely the generic look the file was written to prevent.
A model asked for "clean and modern" produces the average of everything it has seen. So does everyone else's model, asked the same thing.
The seven changes
Each of these maps to a measured failure above. Applied together they turn a description into something executable.
- 1
Give every colour a role, not just a value
#6b7280is a value a model will use for body text, borders, icons, placeholders and disabled states alike.--text-muted, described as secondary and supporting text only, is one job. Five roles beat one hex, and they let you change borders later without changing captions.--text-muted: #6b7280 /* secondary and supporting text only */ --border-subtle: #e5e7eb /* structural edges, dividers */ --text-disabled: #9ca3af /* disabled controls only */ - 2
Replace every adjective with a number or a rule
"Generous spacing" becomes "section gap 64px, card padding 24px". "Clean typography" becomes a scale. If a sentence cannot be checked against a rendered screen, it is decoration.
- 3
Write the prohibitions
The single highest-impact section, and the one 76% of files omit entirely. Five lines is enough to start.
## Never - No gradients - No drop shadows — elevation is a surface step plus a 1px border - No font-weight above 600 - No colour value outside the token set - No border-radius above 12px - 4
Define dark mode, do not let it be derived
Left undefined, a model inverts light mode, and the result fails predictably: shadows stop reading, mid-greys lose contrast at both ends, and a saturated accent that looked confident on white glares on near-black. A second token set costs an hour and removes a category of rework.
- 5
State the density decision explicitly
Whether this is a dense tool or a spacious marketing surface changes every subsequent choice, and it is the decision most files never make. If your product has both kinds of surface, that is two files, not one hedged file.
- 6
Name at least two motifs
The recurring specific things that make the design yours: a 2px accent rule on the left of section headings, numeric columns always tabular and right-aligned, a particular way empty states are drawn. 57% of files have none, which is why their output is correct and characterless.
- 7
Point at the token file; never restate it
Once a hex value exists in both the design file and the token file, one will be updated and the other will not, and the model will confidently use the stale one. Reference, do not copy.
If you only do one of these, do the third. A prohibition list is fifteen minutes of work and it changes generated output more than the other six combined, because it constrains the enormous space of decisions your permissions left open.
What the seven changes produce, at the end, is a file whose values an agent can resolve without inventing anything. This is the same information rendered rather than written — useful here as a checklist of what your own file has to be able to answer:
Token specimen · real values
Sage & Slate Editorial
Live renderSage & Slate Editorial's actual tokens — the same values its exports use.
Color tokens
Sage & Slate Editorial
Core
background
H 70 · C1, 0, 5, 7
foreground
H 84 · C7, 0, 17, 88
card
H 60 · C0, 0, 2, 4
muted
H 70 · C1, 0, 5, 10
border
H 69 · C1, 0, 6, 16
Brand
primary
H 119 · C45, 0, 46, 47
primary-fg
H 0 · C0, 0, 0, 100
secondary
H 213 · C59, 33, 0, 33
accent
H 49 · C0, 7, 39, 20
ring
H 119 · C45, 0, 46, 47
Semantic
destructive
H 0 · C0, 68, 68, 21
destructive-fg
H 0 · C0, 0, 0, 0
success
H 119 · C45, 0, 46, 47
warning
H 41 · C0, 22, 68, 31
muted-fg
H 80 · C4, 0, 13, 64
Charts
chart-1
H 119 · C45, 0, 46, 47
chart-2
H 213 · C59, 33, 0, 33
chart-3
H 49 · C0, 7, 39, 20
chart-4
H 120 · C27, 0, 27, 34
chart-5
H 71 · C8, 0, 41, 74
Typography
Sage & Slate Editorial
Scale: major-third
Density: relaxed
Heading · Plus Jakarta Sans · 2.5rem
Sample headline
Subheading · Plus Jakarta Sans · 1.875rem
A warm organic editorial UI kit on a sage-green canvas with generous rounded cards, eyebrow accent chips, and a soft photography-forward layout.
Body · DM Sans · 1rem
A warm editorial system built on a sage-green page background with floating off-white cards that carry large border-radius and soft shadows. Bold geometric headings open with inline eyebrow accent chips, and generous whitespace defines the rhythm. The palette draws from nature: forest greens, dusty blues, and warm wheats, applied as accents on a near-neutral sage canvas. Ideal for photography, lifestyle, wellness, and editorial content surfaces.
Mono · Space Mono · 0.8125rem
npx shadcn add sageslateeditorial.json
Aa
Plus Jakarta Sans · Heading
Aa
DM Sans · Body
ABCDEFGHIJKLM NOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789 & @ # % →
Tokens
Sage & Slate Editorial primitives
Radius scale
Component radius
Elevation
Spacing · base 1rem
How to write a prohibition that holds
Not all prohibitions work equally. Three properties separate the ones that change output from the ones that get ignored.
| Weak | Strong | Why | |
|---|---|---|---|
| Specificity | "Avoid overly decorative styling" | "No gradients, no drop shadows, no decorative borders" | A model cannot evaluate "overly" |
| Checkability | "Keep typography restrained" | "Never use font-weight above 600" | One can be grepped; the other cannot |
| Alternative given | "Do not use box-shadow" | "No box-shadow — elevation is a surface step plus a 1px border" | Forbidding without replacing leaves the model to invent a substitute |
The third row is the one that gets missed. A prohibition with no alternative creates a gap the model has to fill, and it fills it from the same training distribution you were trying to escape. Every "never X" should be followed by "instead, Y".
Structure and length
The file has to fit in context alongside the actual task, which puts a real ceiling on it. Roughly 400 lines is a workable target; past that, individual rules start losing to the task for attention.
Order matters too. Put the intent and the prohibitions early. A model reading top to bottom encounters the general rule before the special case, which is the same ordering Stripe uses in its Appearance API — theme first, then variables, then specific rules.
# DESIGN.md
## Intent <- who reads this product, and what it is for
## Never <- the prohibitions, early and unmissable
## Colour <- roles for light and dark, referencing tokens
## Type <- scale with real numbers, weight band, tracking
## Spacing & density <- the scale, and which surface uses which step
## Elevation <- the strategy, stated once
## Composition <- how components sit together
## Motifs <- what makes this design specifically oursIf your product has genuinely different surfaces — a marketing site and a dense dashboard — do not write one file with caveats in it. "Generous spacing, though tables may be denser" is two rules pretending to be one, and a model has to pick. Write a root file with what never varies and per-surface files with what does.
What belongs in a server instead
Not everything should be in the file, and trying to fit everything is how it grows past useful. The dividing line is whether the agent needs it before deciding or only on demand.
| Where | Why | |
|---|---|---|
| Component APIs, props, variants | Server | Large, changes often, only needed once a component is chosen |
| Icon catalogue | Server | Hundreds of names, needed one at a time |
| Colour roles, scales, density | File | Needed before the first decision, every time |
| Prohibitions | File | An agent never thinks to ask what is forbidden — it has to already know |
IBM's Carbon MCP server is a good model for the first column: it exposes documentation search, component code examples, charts and experimental components as tools. Notably, none of those are prohibitions — because a retrieval tool only surfaces what the agent thought to query. More on the split.
Testing whether it works
Writing the file and assuming it worked is how teams discover the problem three weeks later. Four checks, in increasing order of effort.
- 1
Grep for literal colour values
If the agent is following semantic roles, there should be no hex outside your token file.
grep -rn --include='*.tsx' --include='*.css' -E '#[0-9a-fA-F]{3,8}\b' src \ | grep -v 'tokens\|globals.css' - 2
Grep for the weights you forbade
Weight is where hierarchy quietly reverts to the default, and it is the fastest signal that a prohibition is not landing.
grep -rn --include='*.tsx' -E 'font-(bold|extrabold|black)' src | head -30 - 3
Ask for the same screen twice, in separate sessions
Cross-session consistency is the real test. If two runs differ meaningfully on spacing, radius or hierarchy, the file is not constraining what it needs to — and the diff tells you exactly which section is missing.
- 4
Build one screen in dark mode first
If dark mode was derived rather than defined, this is where it surfaces. Much cheaper to find on screen one than on screen twenty.
The first two belong in CI. A check that fails a pull request containing a raw hex value does more for long-term consistency than any documentation, which is the conclusion Salesforce reached with the SLDS linter and Stripe reached by removing the capability entirely.
Identity Forge design kits ship this structure prebuilt: 28 semantic colour roles across light and dark, type and spacing scales, elevation, motifs and explicit do's and don'ts, serialised into a DESIGN.md. Browse the kits, or read how to generate a DESIGN.md.
Can I just point my AI agent at my design system documentation site?
It rarely works. A site is browsed page by page, organised by component, and describes intent in prose. An agent needs the decisions in context before it picks any component, organised by decision rather than by component, with constraints stated as checkable rules. A file in the repository serves that; a site does not.
How long should a DESIGN.md be?
Roughly 400 lines is a workable ceiling. It has to share context with the actual task, and past that point individual rules start losing attention. If it is growing, that usually means it is covering several surfaces at once and should be split into a root file plus per-surface files.
What is the single most important section?
The prohibitions. 76% of published design files contain none, and the difference between your interface and a generic one is mostly a set of things you never do. Fifteen minutes writing a "Never" section changes output more than any other section of comparable length.
Should I put my token values in the design file?
No — reference them. Once a value exists in two places, one will be updated and the other will not, and the model will confidently use the stale copy. State the role and where it applies; let the token file hold the value.
Do I still need a documentation site if I have a DESIGN.md?
Yes, for humans, and for the component API detail that is too large for a file. The two are not competing: the site documents what exists in depth, the file states the decisions an agent needs before it starts. Large component catalogues are better served by an MCP server than by either.