A DESIGN.md is not a design system

What a shortcut at TurboTax taught me, and how it became Rift's theme importer.

Early to mid 2026, my team at TurboTax built a TurboTax connector for Claude: an MCP app that runs inside Claude.

At the time, Claude didn’t offer a design system for this. There was a Figma kit, guidelines and tokens, but no components or contracts to pull from. So every MCP app was custom underneath, styled by hand to look like Claude.

My engineers rebuilt every element from scratch. To speed things up, we dropped a DESIGN.md into our tooling. That’s a markdown file describing a product’s look: colours, type and radii up top, prose underneath. It got us closer to Claude’s look and feel, fast.

But it wasn’t a system. It was the same hand-coding, just quicker. Change the accent and you went hunting for every place it lived. It was great for prototyping, and it was quick and dirty.

That stuck with me.

A system that was only mine

Rift started as my personal design system. It had one theme, now called Tide, in light and dark, with every token picked for my portfolio.

I ended up enjoying the system more than the portfolio. It grew tests, accessibility checks, docs, and validators that fail the build when anything drifts. Eventually it deserved its own repo and its own npm package. My portfolio now installs it like any other consumer would.

But the style was mine: my colours, my fonts, my shapes. What would rift look like if it were truly themeable?

Themes are an architecture problem

At Intuit I saw how a design system at scale serves many brands from one set of components. It comes down to the token structure, and rift already used the same three tiers:

  1. Primitives: raw values, like a specific teal.

  2. Semantic tokens: roles like “the action colour” that point at primitives.

  3. Component CSS: reads only the roles.

Re-point the roles and every component follows. So I built themes end to end, from primitives through semantics. Eleven ship today, each a generated stylesheet that one data-brand attribute switches on. Then I built a playground with levers for colour, radius, density, type, tracking and more.

It works, but making a theme still means dialling every lever yourself. And I kept thinking about that DESIGN.md.

Drop a file, get a theme

Now you can drop a DESIGN.md, or an image, on the playground and get a theme you can actually ship.

The difference from TurboTax is where the values go. There, they went into component code. Here, they go onto the levers. Components never see the file. They read the same semantic tokens as always, now pointing somewhere new.

Under the hood

  • Local. The file is read in your browser and never uploaded. The only network request is a Google Font, if the file names one.

  • Careful parsing. Front matter is read as a strict subset of YAML. Anything fancier is skipped, not evaluated. With no front matter, it reads the prose instead.

  • Fitted, not assigned. For each lever, the importer sweeps the whole range, compares each output to the file, and keeps the closest. It’s the same code path as dragging the lever yourself.

  • Read where people write it. I built it against fifteen real brand files. The action colour comes from the primary button’s fill, not from colors.primary. A corner that’s half the button’s height is a pill.

  • Kept, then checked. Colours the file states are kept, then bent by fixed rules where they’d break a contract: button labels hold 4.5:1 contrast in every state, dark mode still works, and accents stay off the action hue. An image’s palette comes from median-cut quantisation of its pixels instead.

  • Nothing added. No new tokens, no skipped tiers.

  • Transparent. The same file always gives the same theme. A match report shows each lever, each bend, and what rift couldn’t take.

  • A real export. You get one AGENTS.md built on rift’s agent starter, with the theme’s CSS. That CSS is written by the same function as the built-in themes, and a build check keeps the two in sync. Hand the file to a coding agent and it builds on the real components.

Approximation vs. system

At TurboTax, the DESIGN.md got us closer to a look. It couldn’t keep that look consistent as things changed, and that was never the file’s job.

The file describes the look. The system keeps it consistent. Put them together and a description becomes something you can ship.

Try it at rift-ds.com/playground. If you don’t have a DESIGN.md handy, there are three example files under “Try it”.