Framework · Design systems · 2026

A design system AI can build from

A framework for design systems that AI tools build from: a contract for every component,
checks that score every screen, and triage for new parts.

Role
Product designer and builder, alone
For
AI tools that build UI, and the people who review them
What I did
  • Tokens
  • Components
  • Templates
  • Contracts
  • Rules
  • Checks
  • Triage
The framework as one flow: tokens, components and templates, contracts and rules, the AI builds, checks score the screen, and the screen ships while new parts go to triage
  1. Tokens, components and templates
  2. Contracts and rules
  3. AI builds
  4. Checks
  5. Ships, and new parts go to triage

01

The scenario in 2026

In 2026, anyone can be a builder: designers, PMs and developers build screens with AI tools. So how does a product stay consistent when everyone builds it? That is the challenge: a design system that works for everyone, people and AI tools alike.

An AI tool draws a plausible table in seconds. Give it a component library and it still guesses: which component fits the job, how far apart things sit, when a part is new. Nothing in the library answers that, so screens drift, and nobody sees it without opening the code.

The framework adds what a library leaves out. The next five chapters follow its steps, as in the diagram at the top.

02

Tokens, components and templates

Figma and code

The system is in code and in Figma, with the same names for tokens and components. The code is React and TypeScript, and AI tools build from it: each file answers one question and nothing is written twice. Figma's MCP server connects the two through those components: a screen the AI builds in code opens in Figma with the same components, and the AI can read a change made in Figma and bring it to the code.

A designer can refine a screen or a component in Figma, and the refinement comes back to the code in a pull request, where the harness checks it like any other change. A refined component goes to triage, where the design system owner decides.

AGENTS.md         what an AI reads first, in order
tokens.css        the values: colour, type, spacing
components.css    the components' styles, built only from tokens
src/components/   one React component per contract, with typed props
src/templates/    whole screens built from components: list, detail, form
contracts/        one contract per component: what it is, when to use it,
                  what never to do
rules.md          the rules between components: spacing, titles, colour, layout
decision-map.md   an index of the contracts by job, built from them
harness/          the checks that score every screen

Tokens hold the values, components are built from them, templates put components together into whole screens, each component has a contract, the rules cover whole screens, and the decision map points to the right component for a job. AGENTS.md comes in chapter 04 and the harness in chapter 05.

Semantic tokens

Tokens are the only place raw values live, and each name says what the value is for, not how it looks:

/* Colour */
--surface: #ffffff;
--text: #3d3d3d;
--critical: #b3261e;

/* Spacing: eight steps */
--s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px;
--s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

/* Type: five sizes, no more */
--type-title: 600 24px/32px var(--font);
--type-body: 400 14px/22px var(--font);

A screen asks for “critical”, not “red”, and for “title”, not “24px”. The AI picks a value by its job, and a value changes in one place, without renaming anything: every screen follows.

The names are each organisation’s choice: “critical” or “error”, one layer of tokens or several. The framework doesn’t pick the names. It makes sure the AI uses the ones the system has.

Templates

Templates are whole screens built from components: a list page, a detail page and a form page. Each has a contract like a component, and a screen starts from the one that fits its job. If none fits, the AI builds the screen from layout components and says which template came closest, so the screen reaches triage as a possible template.

03

Contracts and rules

Contracts

A component's code says how it looks. Its contract says when to use it, and what never to do with it, because an AI can't infer that. Every contract has the same parts: what it is, markup, variants, use for, never, where it lives, and the checks that enforce it.

# Menu button
One "⋯" button that opens a list of actions.

## Use for
- Several actions on one row or object

## Never
- A row of three or more buttons in a table cell
- A button with a chevron that pretends to be a menu

## Lives in
Table cells, card headers, page header actions.

## Checked by
MENU-01

It says the ⋯ button is for rows with several actions, and names two mistakes to avoid. The last line says which check tests it.

Rules

Contracts can't say how components sit together, so the screen rules do: surfaces, titles, type, geometry, spacing, colour, elevation, states, motion and layout. Every answer is a number, a token or a named component. “Generous spacing” fails; “24 between sections, 16 inside a card, 8 between buttons” passes.

04

AI builds

What the AI reads first

Every AI coding tool starts at AGENTS.md, a file in the root of the repository. It says what to read, in order: the rules, the decision map, then the contract of each component the screen uses.

The AI reads only what the screen needs. In the test in chapter 07, a screen uses 6 to 13 components, so the AI reads 18 to 22 KB, about 5,000 tokens. The whole system, every contract included, is 34 KB. Each contract is under 2 KB, so a new component adds little to what the AI reads.

The decision map

The decision map holds the contracts' “use for” and “never” lines, sorted by job. It is built from the contracts each time they change, so the two never disagree and nobody edits the map by hand.

The jobUseNeverChecked by
Several actions on one rowMenu buttonA row of three or more buttons, or a button with a chevronThe harness
Filter one listToggle groupTabsA person
A count in the navNumeralA badgeThe harness
A statusBadgeColoured textThe harness

The last column says who checks each line: the harness, shown in the next chapter, or a person, while that line has no check yet.

Only what the system has

Four rules decide which components a screen may use, and each can pass or fail:

- CMP-01 Build only with components that have a contract.
- CMP-02 No new variants. A contract lists every variant there is.
- CMP-03 If no component fits the job, you may build one, and the build
  continues. Label its root data-new="name" with data-job and data-why.
  If it starts from a component, add data-base="that component".
  All its classes start with x-. In React, the root is a NewPart.
- CMP-04 Never restyle a component, with a style attribute or a style
  block. If it needs to look different, build the new look under CMP-03,
  with data-base.

Only components with a contract, no new variants, no restyling. If nothing fits, or a component needs to change, the AI may build a new part, as long as it labels it.

The types enforce part of this before any check runs. A component takes no className or style, and its props list only the variants its contract has, so a restyle through props or a variant that doesn't exist doesn't compile.

New parts

Forbidding new parts only hides them, so the rules give them one way in. When no component fits the job, the AI builds the part and labels it with a name, its job, and why no component fit. The rules also list the components the system doesn't have yet, such as a textarea, so the AI knows not to look for them. In React, a new part is a NewPart: its job and why are required, so a new part with no label doesn't compile. A labelled part looks like this, as an AI wrote it:

<NewPart
  name="message-field"
  base="field"
  className="x-message"
  job="Let the reviewer write a multi-line message to the driver"
  why="The field contract has only one-line inputs and selects; textarea is listed as not built">

The AI needed a message box with several lines, and the system has no textarea. It built one and labelled it, so the textarea reaches triage instead of staying hidden in one screen.

This part is also a refinement: a component the AI started from and changed on purpose, here the field. Its label names that component, so triage can decide whether the component changes.

05

Checks

The harness

The harness runs on every pull request. It opens each screen in a headless browser, at desktop and phone widths, and runs the checks. The score is the share of checks that apply and pass. Each check is a few lines:

// MENU-01 several row actions go in a menu button
const crowded = cells.filter(td =>
  td.querySelectorAll('button').length > 2 && !td.querySelector('.menu-button'));
set('MENU-01', cells.length > 0, crowded.length === 0,
  `${crowded.length} cells with 3+ buttons`);

It finds every table cell with three or more buttons and no menu button. A screen with no table skips this check.

When a check fails

A failed check names the rule, what broke, and where the rule lives:

MENU-01 (3 cells with 3+ buttons)  ← contracts/menu-button.md

Here, three table cells had three or more buttons, and the rule comes from the Menu button contract. Every rule a machine can test gets a check like this one, so a bigger system has more checks; a person checks the rest until a check exists.

The harness doesn't change the screen. The AI fixes it in the same pull request, and the harness runs again. The screen ships only when every check passes, so an error never reaches triage.

HAND-BUILT MENUDECISION MAPTHE JOBUSENEVERSEVERALACTIONS ONONE ROWMENUBUTTONA BUTTONWITH ACHEVRONFILTERONE LISTTOGGLEGROUPTABSA COUNTIN THE NAVNUMERALA BADGETHE SCREEN PASSES EVERY CHECK

Checks on the tokens

The harness also checks the tokens. A screen or a component may name only tokens that exist: a token name an AI invents, such as “color-primary”, shows no error in the browser, and the value is just missing. Every text must reach a contrast of 4.5:1 against what is behind it, the WCAG minimum, on every screen and in every component. And each variant keeps one word in the code, the contract and Figma, so “primary” never becomes “main” in one of them.

06

Ships, and new parts go to triage

Once every check passes, the screen ships with its new parts labelled, and they go to triage. In this flow, the build doesn't wait for triage to decide. That depends on how the company is organised: some teams hold the screen until triage decides.

Where each part lives

The system lives in the code repository and in Figma, with the same names in both. The repository also holds AGENTS.md, the contracts, the rules, the decision map and the harness. An AI builds a screen and opens a pull request, the harness checks it there, and errors are fixed before it ships. Each new part goes to a triage list in the tracker the team already uses, such as Jira, Linear, Notion or Shortcut. The design system owner works through the list, and each decision goes into the contracts, the design system in Figma, and the code.

THE SYSTEMFIGMATOKENSCOMPONENTSTHE SAME NAMESAS IN CODEREPOSITORYTOKENSCOMPONENTSCONTRACTS AND RULESAGENTS.MD AND THE DECISION MAPTHE HARNESSAN AI BUILDSA SCREENPULL REQUESTTHE HARNESS RUNS THE CHECKSA SCORE FOR THE SCREENERRORS, FIXED HERETHE NEW PARTSTHE SCREEN SHIPSNEWPARTSTRIAGE LISTEACH NEW PARTTHE SCREEN IT IS ONWHO MADE ITHOW OFTEN IT REPEATSTHE DESIGN SYSTEMOWNER DECIDESTHE DECISION GOESINTO CONTRACTS, FIGMA AND CODE

What reaches triage

Only new parts reach triage: a part for a job no component does, or a refinement of a component, each labelled with its name, its job, and why no component fit or what it changes. The triage list adds the screen it is on, who made it and how often it repeats. Errors never reach triage. A value that isn't a token, a restyled component, or a part built outside the system with no label fails its check, inside a new part too, and is fixed in the pull request.

How triage decides

The design system owner looks at each part and picks the first decision that fits:

DecisionWhenWhat changes
Replaced by one that existsA component already does the job, as it isThe screen switches to that component. The contracts get a line for this job, so the next build uses it.
Updates the componentIt refines a component, and the change is worth keepingThe change goes into that component's contract, Figma and code. Every screen with the part switches back to the component.
Becomes a componentThe same part reached triage more than onceIt gets a contract and goes into Figma and code, with the same name. Every screen with the part switches to it.
Waits until it appears againIt reached triage onceThe screen keeps the labelled part. If it reaches triage again, it becomes a component.
THE SCREEN SHIPSPULL REQUESTERRORS FIXEDTRIAGENEW PARTS ONLYREPLACED BYONE THAT EXISTSUPDATES THECOMPONENTBECOMES ACOMPONENTWAITS UNTIL ITAPPEARS AGAININTO THE SYSTEMCONTRACTS, FIGMA AND CODETHE NEXT BUILDUSES IT

Triage in the public kit

The framework is also published as a public kit on GitHub, ai-ready-design-system, and triage runs there on every pull request. Each new part the AI labels opens one item in the triage list, here GitHub Issues. The signature part appeared on two screens, so its item shows a picture of it, both screens, who made each one, and the four decisions for the design system owner. Another tracker needs only another sender. See the triage list.

What a new component gets

A new component gets a contract like every other: what it is, its markup and variants, “use for” and “never” lines, and the check that tests it, or a person's review until one exists. The decision map is rebuilt from the contracts, so the next build finds the component by its job.

07

Testing it

I tested the framework on a design system for a delivery operations product, and published the test as a kit anyone can reuse: ai-ready-design-system.

An AI built a new feature, proof of delivery, three times with components only and three times with the framework. Each screen was built by a new AI agent that never saw the harness or the other condition. The feature needs parts the system doesn't have, such as a photo, a signature and a file upload.

Built withUnlabelled class namesLabelled new parts
Components only1760
Framework116

With components only, the AI built what the system lacks and labelled none of it, so nobody would know what's missing. With the framework, it labelled 16 new parts with their job and why no component fit, so the design system owner can decide what each one becomes. The harness flagged the 1 class name left with no label, to be fixed in the pull request.

Before the framework had templates, the same test left 8 class names with no label and 28 labelled parts: most of the difference was layout the AI had to improvise.

The test is small. It doesn’t go deep: it shows how the framework works.

08

For large teams

The test covers how I work: alone, with AI tools that may make new parts. In a team, making components is the designers' job, so the roles change and the rules stay. This chapter is a plan; I haven't run it with a team.

QuestionAlone, how I workLarge team
Who builds screensAI tools, with meDesigners and PMs, with AI tools
Who makes new partsMe, and the AI, which labels what it makesDesigners, who explore them
When nothing fits during a buildThe AI builds the part and labels it, the build continues, and the part goes to triageThe same
Who decides what enters the systemMe, in triageThe design system owner, in triage
Who updates Figma, code and contractsMeThe design system owner

Exploration still works

Building only with components that have a contract doesn't stop designers from exploring, or from refining a component in Figma when a screen needs it. An explored part, a refined component and an improvised part get the same label and go to the same triage list. Between working alone and in a team, the rules differ in one line: who may make a new part.

The triage list

In a team, the triage list collects new parts from everyone who builds screens, with who made each one and on which screen. When a part becomes a component, the list shows every screen to update.

What a team sets

A team brings its own tokens, components, contracts and rules. What stays the same is how they work together.

PartWhat a team setsWhat stays the same
Tokens and variantsThe names and the valuesEvery name a screen uses exists, with one word in code, contract and Figma
Contracts and rulesWhat they sayEach one is written as a value, and the checks test it
ChecksWhich rules get a check firstA failed check names the rule, and is fixed in the same pull request
TriageThe tracker and who decidesOnly new parts reach triage, each with a label

09

What I learned

Put “when” and “never” next to each component

A library shows how a component looks. An AI also needs to know when to use it and what never to do with it, in the same place, and each check points back to it.

Write every rule as a value

An AI applies “24” the same way every time; “generous” makes it guess.

Test the system on a new feature

A new feature needs parts the system doesn't have, and that is where the difference shows. With components only, the AI built them in its own way and labelled none; with the framework, each one reached triage with a label.

Give new parts one way in

Forbidding new parts only hides them. With a label, a new part becomes a decision for the system; without one, it becomes a copy in one screen.

Every change goes through the same gate

The screens built from components only looked finished; only the checks showed the parts outside the system. Every change reaches the code in a pull request, whether an AI built it or a designer refined it in Figma, and the harness checks each one the same way.

An AI does what its files say

Both builds had the same components and the same brief. The only difference was what the AI read: the rules and the contracts. So the files hold the rules as they are today, each written as something to do.

10

Where I applied it

The framework has seven parts: tokens, components, templates, contracts, rules, checks and triage. It started at an AI platform, where I was the only designer and AI tools built most new screens. Now I use it in my own projects.

AI platform

An investment platform in private capital markets, and where the framework started, in 2026. Designers and PMs built screens with its design system. It lived only inside Claude Code, not in the code repository: moving it there was a refactoring job that hadn't been prioritized yet. Read the AI platform case.

Mesa Jurídica

A legal product for in-house legal teams in Brazil. Read the Mesa Jurídica case.

Lune

An iOS and Android app for moon rituals. Read the Lune case.

This website

My portfolio.

Next case

02 / 07