Design System Contracts

How it works · foundations 1

The model — truth between surfaces

Every design system team eventually argues about where the canonical source of truth lives: the canvas library or the code library. Both answers are wrong in the same way.

Whichever side is declared canonical, the other side becomes a hand-maintained copy that drifts. Developers outnumber designers, so code accumulates decisions design never signed off on; design files freeze into snapshots of intent that stop being true. Eroded trust is why design reviews devolve into archaeology — is the file right, or is prod right? — and why every design system team ends up with a human whose actual job is reconciliation.

The position this spec takes: the source of truth is neither surface. It's a machine-readable contract that sits between them. A contract is a small, versioned JSON document capturing everything both sides must agree on: the component's API (props, types, enum vocabularies, defaults), its anatomy, its bindings to design tokens (never raw values), its slots, its semantics, its declared events. The canvas library and the code library are both renderers of that contract — generated from it on the first pass, validated against it forever after.

Workflow diagram: the contract sits between the design surface and the code surface. Generation flows outward from the contract to both surfaces; changes on either surface flow back into the contract as promotions, and the contract regenerates the other side. A three-way differ verifies all of it continuously. Surfaces never sync side-to-side.Workflow diagram: the contract sits between the design surface and the code surface. Generation flows outward from the contract to both surfaces; changes on either surface flow back into the contract as promotions, and the contract regenerates the other side. A three-way differ verifies all of it continuously. Surfaces never sync side-to-side.

Generation is a party trick; the diagnosis is the product

Lots of tools generate code or draw components once. The contract model is generative first, diagnostic forever: after the first pass, a three-way differ continuously compares the contract, the code, and the canvas, and classifies every difference:

FindingMeaningRemedy
aheada surface has something the contract doesn'tthe differ emits a proposed contract patch — a human reviews and promotes it
behindthe contract has something the surface doesn'tregenerate that surface
mismatchboth define it, values disagreecontract is canonical: adopt (patch contract) or enforce (regenerate)

Fluidity, not enforcement

The bridge would be worthless if it only policed. Real teams evolve their systems from both ends — an engineer adds a loading prop because the product needed it; a designer adjusts a surface color because the old one failed in context. Both of those are good changes that started on the "wrong" side. So the loop is built around promotion: when a surface runs ahead of the contract, that difference becomes a reviewable proposal to the contract. Accept it, and the contract version bumps and regenerates the other side. Reject it, and the surface is flagged as drift to be reverted. Either way there is exactly one arbiter, and it's a diffable, reviewable, version-controlled file. (The full lifecycle, replayed step by step →)

Why the style mapping lives in the contract

A subtle failure mode in contract-first proposals: if the contract declares variant: primary | secondary but a handwritten "resolver" maps those values to styles, drift hasn't been eliminated — it's moved into the resolver. So here, the contract's anatomy binds each named part directly to design token references, and the CSS Module is generated from those bindings. There is no handwritten style layer to drift. The generator fails the build if a binding references a token that doesn't exist — contract and tokens cannot silently disagree. (When those token names actually turn into pixels — at generate time on the code side, as bound variables on the canvas — is its own page: How styles are applied →)

And the reason that's growing: AI generation

In the reference repo's A/B evaluation, an ungoverned agent building screens scored 69/100 adherence with 90 violations — invented props, hard-coded colors, restyled components. The same model constrained by the compiled contract catalog scored 100/100 with zero violations, and when it hit a real gap in the system, it reported the gap instead of faking around it. The gap became a contract proposal, the proposal became a version bump, and the score went back to 100. The contract isn't just how design and code stay aligned — it's how generation stays honest. (Full write-up with the judge internals: docs/10 — Honest Generation.)

A proven playbook, one level up

At the token layer, the DTCG format — which this spec consumes for every token reference — proved that a neutral, Git-versioned, machine-readable artifact can govern both a design tool and a codebase at once. This spec runs that playbook one level up, at the component-API layer: the same properties (diffable, reviewable, tool-agnostic), applied to props, anatomy, and composition instead of color and spacing.