---
title: "What a DESIGN.md is worth to a coding agent"
author: Dan Birman
url: https://dbirman.com/design-md
updated: 2026-11-10
summary: "Coding agents write a lot of UI now, and most teams have a design system they would like that UI to use."
---

# What a DESIGN.md is worth to a coding agent

November 2026 · 6 min

Coding agents write a lot of UI now, and most teams have a design system they would like that UI to use. I wanted a number for how far an agent wanders from that system when nobody is watching, and how much a DESIGN.md file in the repo changes it.

So I built a small bench and ran it on two agents. Without a DESIGN.md, both drifted off the design system on almost every task. With one, nearly all of that drift went away. What it didn’t catch was the product’s own patterns, the empty states and page headers that live outside the component library.

## The setup

The app is shadcn’s open-source [Taxonomy](https://github.com/shadcn-ui/taxonomy) (a Next.js app with a shadcn/ui design system), pinned to one commit. I wrote 20 features for it, things like a billing history view, a team members page and a webhooks screen, and 10 follow-up requests for each. The follow-ups are product requests with no visual direction: “Add a status filter”, “Add an error state for when invoices fail to load”, “Warn about keys that expire in the next 7 days”. If the agent changes the look, that’s its own choice.

Each feature ran twice. In one copy of the repo the agent had a DESIGN.md (the tokens and the 153 components, generated from the code) referenced from CLAUDE.md and AGENTS.md. In the other copy it had nothing. Each run was a fresh clone with no access to the other runs, and neither agent could see my own settings, skills or instructions. That took some work: Codex was loading my personal design skill until I gave every run its own settings folder.

The agents were Claude Code with Sonnet 5.5 and Codex with gpt-6.1-sol, both at their default effort. Every step was committed, rendered in every state the feature had, and checked with designci, a design-system checker I built. I count drift as decisions: one off-token color, or one hand-built control where the system already has the component, counts once per run however many times it repeats. A model judge also reviewed each run’s final code for copied or inconsistent patterns.

## Results

| Agent | Without DESIGN.md | With DESIGN.md | Tasks where it helped |
| --- | --- | --- | --- |
| Claude, 20 tasks | 134 | 33 | 17 of 20, 3 ties |
| Codex, 15 tasks | 422 | 30 | 15 of 15 |

Across both agents, the file helped on 27 tasks and hurt on none. The odds of that split by chance are about 1 in 70 million.

Codex’s raw count is inflated. It writes each palette color as several classes (background, text, border, light and dark), so one hue can count seven times. Counting each hue once, it’s 129 without the file and 30 with it. On the same 15 tasks Claude drops from 61 to 20 by that count, so Codex drifts about twice as much as Claude without the file and about the same with it.

[Image: Off-system decisions per task, without and with DESIGN.md. The same 15 tasks for both agents. Each color counted once per run. A ringed dot is a tie.]

## Where the drift comes from

Without the file, Claude made 62 off-system color decisions and 45 hand-built controls. With it, 3 and 6.

The colors had a pattern. This design system has no success, warning or info token. When a request needed one (“so successful and failed deliveries are easy to tell apart”, “warn when it is nearly full”), the agents without a DESIGN.md reached for Tailwind’s green, amber and red. With the file, they used the tokens that exist, such as the destructive red and plain foreground text, and neither added a single status color.

Codex used color more freely. On 14 of 15 tasks it used color as a way to tell things apart: a different hue for each member’s avatar, each role, each event type. On the team members page it gave every person a violet, blue, orange or pink avatar, with colored role and status badges. The same request with the DESIGN.md came back with gray avatars and the system’s own badges. Claude did this on 8 tasks.

[Image: The same request, without and with DESIGN.md: Codex, team members task, after all 10 edits. Real renders from the bench, cropped to the member table. Above, without DESIGN.md: 13 off-system decisions (68 before grouping shades). Below, with DESIGN.md: 1 off-system decision.]

## When drift enters

I expected most drift to come from the first build, with later edits copying whatever it chose. A small pilot even suggested that. On the full run it isn’t true. Without the file, two thirds of Claude’s drift (88 of 134 decisions) came after the first build, and about half of Codex’s. Each new request that touched something the system didn’t cover, a status, a chart, a warning, added more. With the file, the line stays nearly flat.

So the title I’d planned for this essay, “Design intent decays in ten edits,” holds, but only for agents working without a DESIGN.md.

## What the file doesn’t cover

Both agents, with the file, still copied or reinvented the app’s own patterns. The judge’s findings for copied and inconsistent patterns were about the same with and without it (Claude 26 and 23 over 20 tasks). Nearly all of them pointed at three things: the empty state component, the dashboard page header, and toast notifications. None of these live in the component library, so the generated DESIGN.md never mentions them.

I tried one fix. A third version of the file added a “Product patterns” section, built by a fixed rule: every component or hook outside the component library that at least two existing pages already import, with its path and a real usage snippet. I ran it on Claude for 15 tasks.

The agents used what it listed. With the plain file, no run imported the empty state, the page header or the page shell. With the patterns section, 8, 7 and 6 of 15 runs did, and the judge’s copied-pattern findings went from 7 to 0, while color drift stayed near zero.

Total drift didn’t move (20 vs 21), because toasts never closed. No agent shipped a toast in any version. That one is partly my bench’s fault: every request has to be visible in a preview screenshot, and a toast isn’t, so the agents chose inline messages. One agent explained its choice: “a toast needs a toast container mounted on the page, and the preview may not have one.”

## What I’d do with this

1. Give your agent a DESIGN.md. It’s the cheapest change with the biggest effect I measured.
2. Add the tokens your system is missing. Much of the color drift was agents inventing status colors the system didn’t have. If you need success and warning colors, define them; otherwise the agent will pick Tailwind’s.
3. List your product’s own patterns next to the component library. In my runs, agents reused the patterns the file named and rebuilt the ones it left out.

## Limits

This is one app, one run per condition, and two agents at default effort. Codex covers 15 of the 20 tasks, because my ChatGPT plan’s usage ran out. The judge can open files in the repo, and it doesn’t log which ones, so I can’t rule out that it read the DESIGN.md in some runs; none of its findings mention it, and the rule-based findings, which are most of the drift, can’t be affected. The preview rule biases against toasts. And I’m scoring with designci, a design-system checker I built, so read the numbers with that in mind.

The whole bench cost about $110 of list-price usage, and a run takes 4 to 9 minutes. The protocol, every change to it and every run are in [the bench repo](https://github.com/danbirman/drift-bench).
