Case Study
Designsystemsdon'tsurviveanAIbuildpartner.
Lune · DSYS: Brand Foundation & Design System
Models drift, invent tokens and lose the brand between sessions. DSYS is fifteen markdown files and a pre-commit hook that keep a language model on-brand. A full visual iteration that changed no component code proved it.
Project
Lune · Wedding Planning App
Role
Product Designer · Design System Lead
Stack
Claude · Cursor · Figma MCP · Tailwind
Year
2026

Impact at a glance
The system in numbers.
15 files
Markdown written for a language model to parse. One concern per file.
1 pre-commit hook
Checks colour, type, spacing and components against the token list on every staged change. Nothing pushes until it passes.
0 components rebuilt
A new palette, ink and AI signal shipped as changes to token values.
The Problem
An LLM starts every session with no memory of your brand.
Working with Claude and Cursor as build partners exposed a failure no design system I'd used was built for. Ask for a card at 9am and you get the documented one. Ask at 4pm in a fresh context and you get a hex value that appears nowhere else in the codebase.
Storybook doesn't fix this. It's a rendered artifact behind a build step, made for people browsing components. The model needs each decision written as text, with its constraints attached.
Context
At Komodo, changing a token took a ticket.
Komodo Health's Fire design system was mature and well built, in Storybook, with documentation owned by engineering. I couldn't change any of it myself. That works for a large org. It can't work on a two-week sprint with one engineer.
Komodo · Fire design system
Days or weeks
Docs were MDX that engineering deployed. Figma and Storybook could disagree for weeks.
Lune · DSYS
Minutes, alone, no handoff
The spec file is both the documentation and the build partner's briefing.
Step 01
The brand came first, in one day.
I gave Claude the positioning and asked it to attack the assumptions. Where does “warm” tip into sentimental? Where does “intelligent” read as cold? Several of my first instincts didn't survive.
Every line in the brief had to name the token it produced. Fraunces for display, DM Sans for UI, espresso ink, one accent, and one colour kept for AI and availability. A token nobody can trace to a reason is the first to get overridden, by a build partner or by me late in the day.

The strategic root
Positioning, archetype and audience sit on the same page as the tokens they produced.
Reasons it can act on
Why parchment and not white? The answer is one file away.
The strategic root
Positioning, archetype and audience sit on the same page as the tokens they produced.
Reasons it can act on
Why parchment and not white? The answer is one file away.
Step 02
The system defends itself.
The markdown specs give Claude Code and Cursor the brand at the start of every session. A pre-commit hook then audits each diff, and a check catches components that have no spec.
Every commit
Colour, type, spacing and components checked against the token list
Component with no spec
The spec check mattered most. Without it, the docs would always trail the code.

Read from the source
Swatches read the token file at runtime, so the docs match what ships.
One colour, one job
The AI token marks Curator output, match scores and availability. Nothing else.
Read from the source
Swatches read the token file at runtime, so the docs match what ships.
One colour, one job
The AI token marks Curator output, match scores and availability. Nothing else.
Step 03
The first version looked like AI output.
V1's strategy was right and its taste was wrong. Cream, champagne gold, a soft serif and lots of air is what a model reaches for when you say “elegant” and “wedding.” I'd built a system that stopped Claude inventing tokens, then shipped the palette Claude would have picked anyway.
V2 changed values only: cooler stone, near-black ink, lavender in place of gold, and lime for the AI signal. The token names stayed and no component code changed. V1 still ships behind a toggle.
| Token | V1 | V2 | Role (unchanged) |
|---|---|---|---|
| --color-ivory | #faf6f0 | #f5f6f4 | Page background |
| --color-espresso | #1e1510 | #0c1013 | Ink, primary buttons |
| --color-gold | #b8944e | #b3a3d4 | Accent: fills and icons |
| --color-slate | #4a6b5a | #8dc63f | AI Curator, match, availability |
V1: the default aesthetic

V2: after the iteration

Same page, components and token names. Only the values differ. Both ship, one toggle apart.
Step 04
The docs render the real system.
Every swatch, type step, shadow and component on the live showcase imports the code the app runs and reads the same token file. At Komodo, the docs were a separate artifact kept by whoever had deploy access, and they were often wrong.
Token file
Read at runtime
The app
Every component reads it
The showcase
Swatches, type, shadows, components, rendered live
Spec file (.md)
One concern per file
Claude Code, Cursor
Read it as a briefing
The documentation
The same file, not a copy

Thirteen named type steps, each set in real product copy.

Input, textarea and select, with every state spec'd in the file the component ships from.

Elevation instead of borders, from resting card to modal. A build partner will otherwise quietly break a rule like this.
Reflection
What I learned.
I now judge a design system by how quickly its users can make a correct decision. When one of those users is a language model, “correct” has to be machine-checkable.
I built the hook last. It should have been one of the first things, because I spent hours hand-reviewing diffs for stray hex values. I'd also version from day one. Freezing V1 before starting V2 is the only reason the before/after above exists.
The limit matters most. DSYS stopped the build partner inventing tokens. It couldn't stop me shipping the build partner's taste. A system enforces consistency and has no opinion on whether the result is any good. Catching that is still my job. The system let me act on it in an afternoon instead of a quarter.




