Selected work

Case study · Design systems

A design system AI can read.

Thirteen products, thirteen front end stacks, and a component library nobody could reuse. We rebuilt it on unstyled primitives and served it through an MCP server, so developers and their AI tools pull the real component instead of reading a spec and guessing.

Role
Head of design, hands on the system
Scope
13 products, one design function
Built on
MUI Base, tokens, MCP server
Status
In adoption

01 · The situation

Thirteen stacks, one library nobody reused.

The GRC portfolio grew by acquisition and by age. Thirteen products, each with its own front end stack, its own release train, and its own idea of what a button is. One design function covers all of them.

A design system existed on paper. The failure was not the components. It was the delivery mechanism: a spec that a developer reads, interprets, and reimplements in whatever framework their product runs. Every reimplementation is a fork, and every fork drifts. We were correcting drift slower than we were creating it.

The usual fix is a styled component library. That fix assumes every consumer shares a framework. Ours did not, and never would.

Before: how a component reached production

Old path

  1. DesignComponent designed once
  2. SpecWritten up in documentation
  3. ReadDeveloper interprets the spec
  4. ReimplementPer stack, thirteen times
  5. DriftEach copy ages separately

The gap: the spec is a description of a component, not the component. Anything a human has to retype, a human will retype differently.

02 · What I took on, and what I left alone

A system that ships beats a system that looks right.

The tempting goal was visual consistency across all thirteen products. I did not chase it. A system with no adoption mechanism is shelfware, however good it looks, and unifying pixels across thirteen release trains would have consumed the whole effort before a single team adopted anything.

Took on

  • Behaviour and accessibilityThe parts that are expensive to get right and identical everywhere.
  • TokensOne source for colour, spacing, type and radius.
  • DistributionGetting the real component into the codebase, which is where every previous attempt failed.

Deliberately left alone

  • Pixel parity across productsThirteen products on different release trains cannot converge at once, and forcing it would have stalled adoption.
  • Rewriting legacy screensNew and changed surfaces adopt first. Old screens migrate when they are touched anyway.
  • One framework for everythingA migration nobody asked for and no roadmap had room for.

03 · The call

Unstyled primitives, served as a tool.

Two decisions carry this project. Build on unstyled primitives so the system is portable by construction, and distribute it through an MCP server so the component arrives in the codebase rather than in a document.

The second one is the part that is genuinely new. Developers increasingly write code with an AI assistant sitting next to them. That assistant is a consumer of the design system, and it had no way to read ours. Serving the system over MCP makes the assistant a first class consumer: it queries the real component and its rules, so the code it suggests is the system rather than an approximation of it.

Decision
Build on MUI Base, unstyled.
Because
Thirteen stacks cannot share styled components, but they can share behaviour, state handling and accessibility, which is the expensive part.
Rejected
A fully styled React library, which would have served the React products and stranded the rest.
Cost
Every consuming team writes its own theme layer, so the first adoption in each stack is slower.
Decision
Serve the system through an MCP server.
Because
A spec has to be read and retyped. A tool call returns the component and its constraints directly, to a developer or to the assistant writing alongside them.
Rejected
Better documentation. We had already tried that. Documentation quality was never the bottleneck, the retyping was.
Cost
The system now has runtime surface to maintain, not just a package to publish.
Decision
Tokens as the contract, components as the convenience.
Because
A product that cannot adopt a component this quarter can still adopt the tokens, so it moves toward the system instead of away from it.
Rejected
All or nothing adoption, which in a thirteen product portfolio means nothing.
Cost
Partial adoption is harder to measure and easier for a team to declare finished too early.

04 · How it works

One source, many consumers.

Operating model

Source of truth

TokensColour, type, spacing, radius
MUI Base primitivesBehaviour, state, accessibility
Usage rulesWhen to use what, and when not to

Distribution

MCP serverServes components and their rules on request
Token packagesFor teams adopting styling first

Consumers

13 product stacksEach themes the primitives it pulls
AI coding toolsQuery the real component instead of guessing
DesignersSame names in Figma and in code

The AI assistant is a first class consumer, not an afterthought. That is the difference between a system that survives the way software is written now and one that quietly drifts.

After: how a component reaches production now

New path

  1. DesignComponent designed once
  2. PublishPrimitive and tokens, one source
  3. PullDeveloper or AI tool requests it over MCP
  4. ThemeStack applies its own skin

What changed: the reimplementation step is gone. Nobody retypes a component from a description, so there is nothing to drift from.

05 · The hard tradeoff

Portability cost us polish, up front.

Unstyled primitives mean the system ships no opinion about how anything looks. Each team writes a theme layer before it sees value, which is real friction at exactly the moment adoption is most fragile. We accepted that because the alternative served three products and abandoned ten.

Options considered
Three approaches to serving components across thirteen product stacks
Option Stacks served Drift risk Cost per team Call
Styled React library Only the React products Low where adopted, unchanged everywhere else Low to start Rejected
Per stack forks of one design All thirteen High, thirteen copies aging apart Low each, unbounded in total Rejected
Unstyled primitives, served over MCP All thirteen, plus AI tools Low, one source and no retyping Higher first adoption, a theme layer per stack Chosen

06 · Where it landed

What is proven, and what is not.

Measured

Adoption is still rolling out across the portfolio, so there is no defensible before and after number yet. Rather than publish a figure I cannot show the method for, this stays empty until the first full quarter of adoption data lands.

Observed

The reimplementation step is gone for teams that have adopted. A component pulled over MCP is the component, so the class of bug where a product's button behaves differently from the system's button no longer starts.

Design and engineering now argue about the same object. Previously a disagreement about a component was really a disagreement about whose interpretation of a spec was correct.

Too early to claim

Whether portability actually reduces total maintenance across thirteen stacks, or just relocates it into thirteen theme layers. The honest answer arrives after the second or third product adopts, not the first.

Whether AI assisted development materially improves output quality when the assistant can read the system. It is the bet behind the MCP work and it is not yet settled.

Let's talk.

Open to Head of Design roles. If you are building a design function, or rebuilding one, let's talk through what it would take.