Design System + Engineering

I tried to make spec drift structurally impossible with an agent harness. It worked, until the enterprise outgrew what could be written down. A postmortem.

RoleDesign Engineer — concept, architecture, build
TimelineJun — Jul 2026
TeamSolo
ToolsClaude Code · Figma · MCP · Design Tokens · Markdown
PlatformFigma · Claude Code
THE GAP

Drift starts the moment the handoff ends

A design system promises one source of truth. The truth splits the second a frame leaves Figma: detached instances, hardcoded hex, placeholder copy, components that won't resolve in Dev Mode. Most teams answer this with review, which means catching drift after it has already cost someone an afternoon.

I wanted the other answer. Not a better review step, but a build step where the wrong thing is not expressible. Hand creative direction to an agent that can only reach for real components and real tokens, and the frame arrives dev-ready by construction.

“Don't review for drift. Build so it can't drift.”

— The premise
THE ONE IDEA

A control plane, not a copy of the design system

The artifacts stay in Figma. They're already the source of truth, and duplicating them only creates a second thing to keep in sync. The control plane is a small git repo that drives the agent: the operating contract, a mirror of the tokens, a component manifest, the design rules, and the skills that load them.

Its only job is to make the agent produce correct Figma output every time, on the smallest possible context budget. Everything else serves that.

WHAT I BUILT

The architecture held. That was never the problem.

Operating contract

A durable PLAYBOOK plus a /design skill that loads the system's rules and HCI laws before a single frame is drawn.

Token mirror + resolver

JSON mirrors of every Figma variable, read through one resolver call per lookup. Raw token files never enter context.

Component manifest

A lookup index of library components, variants, and keys, so the agent reaches for the real instance rather than a copy.

Swappable ds/ folder

The generic core survives any design system. ds/ holds everything specific. Retarget by folder swap, not a rebuild.

The shape of it was clean. Root-level files — the playbook, principles, templates — were system-agnostic. The ds/ folder was the single swap point.

/
├── PLAYBOOK.md              # durable operating contract
├── .claude/skills/
│   ├── design/              # loads rules before any frame
│   └── design-critic/       # the self-review loop
├── ds/                      # the swap point
│   ├── config.md            # Figma file URLs, domain, defaults
│   ├── product-context.md   # kills lorem ipsum
│   ├── design-rules.md      # strict, numeric, overrides the playbook
│   ├── components.md        # manifest: a lookup index, not a copy
│   ├── figma-keys.md        # captured library / variant / text-style keys
│   └── tokens/              # JSON mirrors of Figma variables
│       └── _resolver.sh     # single entry point for any lookup
├── principles/              # DS-agnostic knowledge
└── templates/brief.md
WHERE IT WORKED

The part I got right

I should be precise about this, because the failure was not a failure of execution. On the surfaces the system could actually see, it did exactly what it promised.

0hallucinated components. Every build resolved to a real instance.
1 passA frozen spec handed to a second model, a different vendor, built three components clean on the first attempt.
4Teammates were using it daily by the end. None of them had built it.

That last number is the one I care about. The discipline lived in the repo, not in whoever was driving it. Swapping the model changed nothing about the output quality, which meant the thing I'd built was a system and not a very good prompt.

The critique loop also earned its keep. The agent reviewed its own work against the reference before it ever asked for my time, and the review step that used to catch spec drift genuinely had nothing left to catch.

WHERE IT BROKE

A system can only enforce what someone wrote down

This is the finding, and it took me a project to learn it.

An enterprise design system is thousands of components, tokens, and patterns accumulated over years. A meaningful fraction of it is undocumented, or documented in a way that is true only in the original author's head. There is a reason a button in a given product looks slightly different from its sibling in the next product, and the reason is usually a decision someone made in a meeting six months ago that nobody wrote down.

So the manifest grew, and the rules got stricter, and the agent got more capable of refusing legitimate work.

A pattern nobody had documented

The agent could not compose it, because composing it would have meant inventing a component. It asked. Then it asked again. Then the requester learned to route around the harness.

A one-off that was actually correct

Genuinely the right call for one screen, in a pattern the system had no name for. Indistinguishable, from inside, from drift. The harness could not tell the difference, so it refused both.

The tribal layer

The decisions that actually carry the design are the ones nobody wrote down. A strict registry is blind to exactly the knowledge that matters most.

Every one of those is a false negative. And that is the failure mode you cannot design your way out of, because the only available fix is to loosen the constraint, and loosening the constraint removes the entire premise. Once the agent may improvise, the thing that made it trustworthy is gone, and you are left with a slower, more confident version of the drift you set out to eliminate.

“Enterprise design is too complex to hold in a registry. The parts nobody wrote down are the parts that matter.”

— What it actually taught me
WHY I STOPPED

I stopped instead of loosening it

There was an obvious move: add an escape hatch, allow net-new local components, log them for later governance. It would have made the harness feel more useful inside a week.

I didn't take it, and I think that was the right call, though I was slow to see it. An escape hatch is not a compromise on the constraint, it is a deletion of it. The moment a frame can be built from a component that doesn't trace back to a real one, the system can no longer promise that anything it produces is dev-ready, and the review burden returns to exactly where it started. It would have looked like progress and been a slower route to the original problem.

So I stopped, and wrote down what I'd learned instead.

THE SECOND ATTEMPT

I tried the same thesis again, and it failed the same way

I rebuilt this as Clause, with the constraint pushed harder: an agent that could only compose UI out of components that verifiably trace back to real Figma nodes, with a primitive escape that was explicitly labelled as not-a-component.

It was better engineered and it hit the identical ceiling for the identical reason. Enterprise product design is too complex for an agent to hold reliably, too much undocumented edge-case knowledge, too many decisions that live in people's heads rather than in any registry. I stopped that one too, about a month later.

Two attempts, one cause. That repetition is what convinced me the problem was the premise and not my execution, which is why I stopped building and started writing.

WHAT I'D KEEP

The parts that survived the failure

Nothing here was wasted, and the useful residue isn't the harness.

The resolver pattern

Never putting raw data in context, reading values through one narrow call per lookup. That is just good agent architecture and I use it everywhere now, including in Lapse.

System over prompt

The finding that the discipline has to live in the repo rather than in the session. A frozen spec transferring cleanly to a different vendor is the proof, and it generalises past UI.

The self-critique loop

Having the agent review its own output against a reference before escalating to a human. Cheap, and it works on everything I have built since.

The swappable folder

Generic core, specific leaf. Wrong for a design system that is mostly undocumented, right for almost every other system-shaped problem.

The thing I'd tell someone starting this today: don't try to encode a design system an organisation has never successfully documented. Encode a small one, or encode the part of it that people actually rely on, and let the rest stay human. The constraint is only worth what the documentation underneath it is worth.