Building Parsimony, an Agentic Design System
A cross-site design system built to be used by agents as much as by people: one source of truth, from DTCG tokens through framework-agnostic components to an MCP server an agent can read and lint against before it writes any UI.
Most design systems are documentation a person has to read. Parsimony is data an agent can query, build against, and lint itself with before it ships any UI.
Interfaces are increasingly assembled by agents, and design systems were never written for that reader. Most of my own work now happens through AI agents, so I built a system whose rules a machine can read, build against, and self-check.
Parsimony is a design system with an API for agents. One source of truth runs from DTCG tokens, through framework-agnostic Web Components, to an MCP server an agent can query and lint against before it writes any UI. It's also a sequel: OTKit was this discipline built for people, with docs humans read and governance by hand. Parsimony inverts it.
Browse the live token catalog: this site consumes the system it documents.
The Problem
Design systems are written for people: docs sites, Figma libraries, "use this, not that." But the thing building my UI now is an agent, and an agent doesn't read your docs site. The problem was never missing tokens. It was that nothing in the system was readable by a machine.
The Architecture
Primitives hold values. Semantics name roles. Components render decisions. UI code never touches a hex. That's the whole layer model; the rest is enforcement. One repo, one direction of flow, so tokens and components version together and a token rename is a breaking change by design.
- Author. DTCG tokens: primitives → semantic roles. Brands re-point the roles.
- Build. Style Dictionary compiles every brand to CSS. A gate rejects hex, primitive refs, and dangling aliases — a bad rename fails the build, not production.
- Components. 27 framework-agnostic Lit web components. Code Connect mappings are authored for 22 and held to each component's real prop unions by a build gate — unpublished, because Code Connect needs a Figma Enterprise plan.
- Artifact. Hand-authored metadata + generated manifest merge into one design-system.json.
- Interfaces. Humans read Figma and docs; agents read an MCP server.
- Consumers. Every site pulls from one source, as an installable package.
One Source of Truth, Four Brands
Decision-engine flips to a light enterprise theme with a blue primary; dot-art goes pure black for photos; dot-blog bumps the reading size. None of it forks a component — each brand is a small override file.
Components as Contracts
Each component ships its own rulebook: the tokens it may touch, the rules that bind it, the ARIA pattern it implements. The spec and what the agent reads are the same file — prop descriptions come from the code's JSDoc, so the contract can't drift from the implementation. Docs generate from that same metadata: mechanical sections regenerate, hand-written prose is preserved, and CI fails the build if a change leaves its docs stale.
check_usage: Governance, Moved Upstream
Design-system checks usually happen after the fact. check_usage moves them earlier: hand the system a snippet before the code ships, get back every violation. The same rules run in three places — this check, the build gate, the drift scan — so the answer an agent gets here is the one the build enforces later.
- Ln 2:10no-hexHardcoded hex "#4ade6e" — use a semantic var(--color-*) token, never a raw color.
- Ln 3:19no-primitivePrimitive token "--primitive-color-green-500" — UI must reference the semantic layer, not primitives.
- Ln 4:3hardcoded-sizeHardcoded font-size — use a --font-* token or a semantic font shorthand.
- Ln 5:3hardcoded-weightHardcoded font-weight — use a --font-weight-* token (display/title 300, body/label 400, strong 500).
- Ln 6:3font-familyUnapproved font-family — use var(--font-family-sans|serif|mono). Approved: Space Grotesk, Spectral, JetBrains Mono.
Governance, Measured
"Agents follow the system better when the system is data" was an assertion until I measured it. Twenty realistic UI prompts, two arms, a fresh agent per run. The governed arm got the compiled context packs; the ungoverned arm got "Use the design system." Every output scored by the same rule set that gates the build — no hand grading.
Neither arm invented a token that doesn't exist — the failure mode was drift, not fabrication. The one dirty governed run exposed two gaps in the packs; both became issues the next day. The eval is committed and re-runnable, so the number gets measured again as the system grows.
The Contract Caught a Shipped Bug
The newest layer of the contract is anatomy: each component declares which foreground token sits on which background token, in every state. Contrast stops being a convention the system hopes holds and becomes a pairing the gate checks against what actually renders.
The first pass found a real defect. The badge's accent variants had shipped unreadable under the light enterprise brand — as low as 1.39:1 — because the brand re-tinted the fills without re-tinting the text. The gate had those pairings on an exclusion list, so nothing ever looked. Anatomy named the pair the badge actually renders, and the gate failed it immediately. The fix took one evening: three brand-side overrides, the exclusion list deleted, a patch release rolled to all three consumer sites the same day.
A docs site promises. A contract catches.
Decisions & Tradeoffs
Distribution: public npm over GitHub Packages
GitHub Packages needs a login even for public installs — a token just to download tokens. Public npm needs none, and tokens are CSS that ships to the browser anyway.
The agent interface: MCP over docs or a REST API
Docs don't work; a REST API needs a server, a login, discovery. MCP is what agents already speak — the session writing the code can just ask. The cost: it's new, and mine runs locally.
Components: Web Components over React
Lit is clunkier inside React — the real cost. But one version works everywhere instead of three synchronized buttons. One source beats the smoother React-only version.
Honest Status
Part of the work was deciding what to leave unbuilt. Shipped: a two-layer token architecture across four brands; 27 Lit components with build-gated Code Connect bindings; an MCP server with 17 tools; one rule set behind every checker, so the gates can't disagree; weekly automated drift and parity audits; and WCAG AA verified across every intended pairing, in every brand.
Deferred on purpose: publishing the component library and MCP server to npm (the token package ships today), migrating the remaining sites onto it, auto-fixing drift rather than just filing it, and generating Figma and component code from the contract — the committed end state.
Self-assessment is cheap, so the system is also graded against Brad Frost's ten-station design-system inspection. First pass: 71. Three re-inspections closed the gaps.
Still open: one borderline 4.38:1 pairing, and the two process stations unscored until they've run long enough to judge — re-score in October.
Reflection
Every system I'd built before made things clear to people. This one asks what a system looks like when its main reader is a machine. The answer is structure: tokens as data, components that carry their own rules, a system an agent can query. A component library tells you what exists. This one also tells an agent what it's allowed to use.