Arely Rivera, home
All case studies

AI-native Design Engineering + Design Systems R&D

Building a five-layer design framework for AI coding agents

How I turned design judgement into code, tested it across React and Rails, and reduced how many interface decisions depend on a non-deterministic model.

Role
Lead Product Designer
Onion co-creator
Collaboration
Alicia Rojas(opens in a new tab)
Senior Software Engineer
Onion co-creator
Scope
Design Engineering
Design Systems
Applied AI
Stack and tools
React · Tailwind · shadcn/Radix
Rails 8 · Tailwind v4 · ViewComponent · Stimulus
Claude · Codex
Validation
React + Rails
Claude + Codex
41 agent runs
Status
Preparing for public release
Download as Markdown

The Onion Design Framework is a five-layer method for building code-native design systems for AI coding agents.It moves repeatable decisions into tokens, primitives, and composed patterns, while leaving contextual decisions to written guidance and human judgement.

My role

Role and collaboration

I was the Lead Product Designer and co-creator of the Onion Design Framework.

The work began when I asked whether we could extract a design system from a Rails codebase itself instead of translating one from Figma. I partnered with Alicia Rojas, a Senior Software Engineer, to test that idea in working code.

Our responsibilities were different, but intentionally connected:

The first Rails branch, split by author. One person built the track; the other drove.
The trackThe driving
WhoAliciaArely
WhatHarness commitInterface overhaul
Lines5696,771
ShareEngineering guardrails94% of the branch's additions

Alicia built the engineering track around the work: branch protection rules, CI, Bash hooks, and permission settings. I drove inside those boundaries, using Claude to design and ship the interface changes directly in the Rails codebase.

The split is the story. One person built the track. The other drove.

From the experiment to the framework

Together, Alicia and I co-created the initial framework structure, its five layers, and the protected workflow. After the original experiment, I continued developing Onion independently: I built the first complete reference implementation in React, translated the methodology back into Rails, and designed the experiments used to evaluate it.

From How a defect travels inward onward, the work was mine: the inward-fix method, enforcement rings, React and Rails reference implementations, fidelity tests, analysis, and subsequent findings were my responsibility.

Engineering continued to own backend architecture, data modelling, security, and permissions. My role was to determine how far design could safely travel into code — and which decisions could become structural, which still required interpretation, and which continued to need human judgement.

The shift

The design system's reader changed

Design systems were built primarily for people to interpret and use.

A designer could read the guidelines, inspect a component, and ask a question when something was unclear. A developer could compare an example with the existing interface, compose the implementation, and rely on human review before the work shipped.

AI coding agents changed that relationship. The agent does not only read the design system. It uses the system to generate the screen.

When a decision remains open, the agent resolves it during generation. It may invent a value, ignore an existing pattern, or interpret a written rule differently from the team. By the time a person reviews the work, those decisions are already inside the code.

The design system could no longer be only a resource that described the interface. It needed to become part of the environment in which the agent built it.

Your design system's main reader is no longer a person. It is an agent, and it generates the screen.

The workflow before and after

Two cards: a traditional design system is a system people interpret; the Onion Design Framework is an environment the agent builds inside
The same comparison as text, so it can be read, quoted, and searched rather than only looked at.
Traditional design systemOnion Design Framework
A system people interpretAn environment the agent builds inside
Guidelines, tokens, components and toolsTokens, primitives, patterns, rules and gates
Designers and developers interpret, compose and implementThe agent generates with structural constraints and written guidance
People build and review the screenPeople evaluate the generated experience and evolve the system

The original problem

Figma spoke design. The codebase spoke Rails.

When I started experimenting with the Figma MCP in Claude, I wanted to know whether Claude could use our existing Figma design system to help me design directly in code.

The first results looked promising. Claude could access the visual language in Figma and generate interfaces that appeared consistent with it.

But Figma and the Rails codebase did not describe the interface in the same way.

Figma knew the colours, typography, components, and layouts. Rails knew which shared partial appeared across dozens of views, which form-builder constant controlled every label, how themes were assigned to individual pages, and which implementation patterns the codebase already depended on.

The design system in Figma: colour ramps, a font system, and a page for every component.
The code after the first layer: application.css, holding the same colours and fonts as plain values.

The agent could see how the interface was supposed to look, but it could not see all the decisions required to build safely inside the codebase. Whenever the two sources did not align, it had to translate, infer, or invent.

The problem was not that we lacked a design system. The system the agent could read was not the system the code executed.

That changed the question:

Could we extract the design system from the codebase itself — and turn it into an environment both people and AI agents could build from?

An earlier consumer product whose screens were largely agent-built: the design decisions were made by a person, the markup mostly was not.

It worked. But it was a small surface with a forgiving stack, and I wanted to know what held up on something harder — a more complex product, and less of me in the loop.

The first experiment

I brought that question to Alicia.

Instead of importing the Figma system into Rails, we started extracting the design decisions that already existed in the code. We identified reusable values and patterns, built a protected workflow around the repository, and experimented with propagating one design change across multiple screens.

These tools reduce handoff and improve reuse. When several valid paths remain, the human or agent still chooses how to compose them.

The experiment placed the agent, extracted decisions, existing code and enforcement inside the same working environment.

The design-to-code path as the tools ship it: two sets of sources, a bridge between them, and interpretation left to whoever builds the screen.
Where the experiment moved the agent: codebase, extracted decisions, components and guardrails inside one protected environment, with the human at review and merge.

The result was one Rails pull request:

Lines added
+7,158
Lines deleted
−1,920
Files touched
153
The pull request the first experiment produced. The size of the diff and the size of the change are not the same number: most of what landed is a catalog no user is ever served.
MeasureValue
Lines added7,158
Lines deleted1,920
Files touched153
Dev-only catalog64% of the lines added, never served to a user
New production markup102 lines
Harness in production68 lines
CI checks4, all green
Review1, by an engineer
Commits2, by two authors

What ships as the harness is the part worth naming, because it is the part that is small:

  • 46 lines of tokens and base styles.
  • One 12-line partial, with 50 call sites.
  • A 10-line contract in CLAUDE.md.

Two commits, two authors. Alicia's is the harness commit, at 569 lines. The additions are mine: 6,771 of them, about 94% of everything the branch added, and almost all of it the catalog.

The harness made a change of that size safe enough to merge, and the new structure substantially reduced what the agent invented. Across the affected views, hard-coded hex values fell from 119 to 24. The agent introduced no new arbitrary spacing and no invented components.

But four defects still escaped.

The four defects, grouped by what could have caught them. The split is the finding: two were mechanically detectable and two were valid against the tokens and still wrong on screen.
Checkable in the diffVisible only in the rendered experience
24 hard-coded hex values remained. A check could have caught them, but that check did not exist yet.Every form label became smaller. The change was token-compliant and CI remained green.
A duplicate canonical tag reached the new page. It rendered as nothing and was found in an SEO audit.One page rendered white navigation over a white background. Only a person looking at the page caught it.

The experiment worked, but not in the way a perfect demo would have worked. It proved that an agent could ship a large design change inside a protected Rails codebase. It also exposed the boundary between engineering safety and design fidelity.

Some decisions could be checked mechanically. Others were technically valid and still wrong for the experience.

That changed the question again:

If the agent could build inside the codebase, where should each design decision live so the repeatable ones no longer depended on interpretation?

The hypothesis

Reduce the decision surface, not the model's variability

The first experiment showed that documentation, components, and green CI were not enough to guarantee a correct experience.

An LLM is non-deterministic. More documentation or a longer prompt cannot guarantee that it will make the same decision every time. But many interface decisions do not need to remain model decisions.

A colour can become a token. A recurring interaction can become a primitive. A solved layout can become a composed pattern. Only the decisions that depend on the context of a specific screen should remain open to interpretation.

Our hypothesis was:

If every design decision lived in the innermost layer capable of enforcing it, the agent would have fewer opportunities to invent — and its output would be more likely to belong to the design system.

This was not an attempt to make the LLM deterministic. It was an attempt to make fewer interface decisions depend on its non-determinism.

The operating rule became: a fix belongs in the innermost layer it can possibly live in — not the layer where the defect was noticed.

The question we needed to test was simple: could an agent with no prior context generate a system-consistent screen from a minimal prompt if the framework had already made the repeatable decisions for it?

The framework

Five layers, built from the inside out

Onion organises design decisions by how enforceable they are. The inner layers remove repeatable decisions from the agent. The outer layers handle the context that code alone cannot decide.

Every layer reads the one inside it. The outer layer — the screen — is the one we can throw away and generate again.

The Onion Design Framework: five nested layers, numbered from 1 at the centre out to 5, under the line “a five-layer framework that turns design decisions into structures AI agents can follow”
The five layers as text — the diagram's rings are numbered, not labelled, and this is where the numbers get their names.
LayerWhat lives thereWhat it prevents
1. TokensRaw values for colour, spacing, typography, radius, elevation and motionInvented values and visual drift
2. PrimitivesBase components such as Button, Input, Card, Dialog and TableRe-deriving behaviour, accessibility and states on every screen
3. Composed patternsSolved interface structures such as PageHeader, DetailPanel and TopBarRebuilding recurring layouts and interactions from scratch
4. Written rulesContextual decisions that no token or component can forceApplying valid components in the wrong interface context
5. ScreensThe assembled experienceNothing — the screen is where the system is tested, not where repeatable fixes should live

How a defect travels inward

Defining the five layers gave the framework its structure. I then developed the operating discipline for deciding how a defect should move through them.

When something looks wrong on a generated screen, I ask these questions in order:

  • Is a token wrong or being misused?
  • Can a primitive fix the problem once for every screen?
  • Can a composed pattern absorb the decision?
  • Only if none of those can solve it: what written rule is missing, and why can the inner layers not enforce it?

If a generated screen uses an incorrect button state, fixing that single screen is the weakest intervention. Fixing the primitive means the correction travels to every existing screen and every screen generated later.

The enforcement rings

The five layers organise decisions. Four enforcement rings make the inner decisions difficult to bypass:

The four rings, from the component outward to CI.
RingRole
1. A primitive that refusesThe component rejects invalid composition — for example, an icon-only button without an accessible name.
2. The editor gateA hook checks each relevant write and returns the exact line and reason when it finds a violation.
3. The local gateFast, deterministic checks verify tokens, text rules and theme parity before work leaves the machine.
4. CIThe same checks run where skipping them is no longer an option, including runtime accessibility checks.

In the Rails implementation, a primitive refuses by raising a rendering exception before it can produce invalid markup. For example, this simplified guard inside ButtonComponent rejects an icon-only button without an accessible name:

if icon_only? && aria_label.blank?
  raise ArgumentError,
    "An icon-only ButtonComponent needs an aria-label—its glyph is not a name."
end
Simplified from the Rails component guard. The exception is raised before invalid markup can render, so the agent receives the reason and the required correction immediately rather than shipping an inaccessible button.

The agent receives the reason and required correction immediately. It cannot continue by silently rendering an inaccessible version of the component.

The rule itself appears once, but it can be enforced at multiple points. That matters because a slow or noisy check eventually gets ignored, and a rule duplicated across tools eventually drifts.

The framework is not a document the agent is expected to remember. It is a system that decides which choices the agent is allowed to make freely.

From React to Rails

First, I formalised the method in React

The first complete implementation of Onion used React, Tailwind and shadcn/Radix. It served as a reference environment for testing how agents interpreted the layers.

The method as the agent reads it: five layers, innermost first, each one naming the files it lives in and the fixes that belong to it.

Before building the system, I tested three ways of presenting the same tokens and rules to three cold agents:

Three document formats, same tokens, same task, three cold agents. The most detailed one lost.
VariantFormatResult
A. Strict schemaA rigid specification and terse checklistCleanest and least expensive
B. README styleTokens plus short human-readable do-and-don't guidanceTied on correctness, with slightly more context cost
C. Lint-annotatedEvery token paired with its failure mode and fixThe only variant to invent a value, miss part of a touch target and cost the most

The most detailed document should have won. It did not.

The test showed that machine-readable constraints and human-readable reasoning should remain separate layers. Dense explanations did not strengthen the schema; they buried it.

I then built roughly 50 React components and used cold-agent fidelity tests to expose gaps. Those runs found missing toast guidance, undocumented patterns, and placeholder code inside catalog examples. The agent copied the placeholder faithfully — because the usage example, not the component source, was what it treated as the instruction.

The fix was not another reminder. I created a deterministic placeholder scan that failed the build.

The catalog those runs were tested against: primitives, foundations and the accessibility floors, each documented beside the component it governs.

Then, I translated the methodology to Rails

To learn whether Onion described a methodology or merely a React implementation, I rebuilt it in a separate Rails 8 application created specifically for measurement.

What each layer became on the second stack. The component layer got more expensive; the reasoning transferred unchanged.
React implementationRails implementation
CSS tokensTailwind v4 tokens with automatic theme-parity checks
shadcn/Radix primitives61 ViewComponents plus native platform behaviour and Stimulus
Radix accessibility behaviourNative dialog, Popover API, real form controls and browser-based accessibility gates
README principlesUsage rules attached to the component catalog
Build-time placeholder scanEditor hook, local verification and CI
React composed patternsThe same PageHeader, DetailPanel and TopBar patterns rebuilt in Rails

The change of stack made the component layer more expensive because Rails did not have Radix underneath it. But the values, reasoning, composed patterns, and layer boundaries transferred.

The Rails version made several ideas measurable that React had only stated. It included 131 colour tokens present in both light and dark themes, 61 component files, and four enforcement rings verified against deliberate defects.

Onion survived the stack change because its layers describe design decisions, not implementation contexts.

Validation

Forty-one runs, one deliberately minimal prompt

I evaluated Onion through 41 agent runs across React and Rails:

The 41 runs, by environment and purpose. Every count here is a denominator for a claim made below it.
EnvironmentRunsPurpose
React3Compare document structures using the same tokens and task
React2Expose gaps in the design system through cold-agent fidelity tests
Rails5Test structural and written constraints in the first measurement round
Rails10Compare sharpened prose with an optional composed component
Rails17Test six successive attempts to correct the same cards-first behaviour with Claude
Rails1Run the same screen task with the design system accessible but without the harness
Rails3Repeat the same screen task with the harness through Codex's orchestrated workflow
Total41Claude and Codex across two stacks

For the Rails experiments, every run started from an isolated copy of the repository with a seeded database. Agents had no shared conversation history. I recorded the model before launching each run and kept the prompt constant within each comparison.

How the runs were fanned out. Each subagent starts cold from the repository and the framework — no conversation history, no memory of another run, and no knowledge that the other agents exist.

The prompt did not mention Onion, cards, tables, tokens, components, or layout. Its public wording is domain-anonymised while preserving the original scope and level of detail:

Build the records page for this app. Someone using it needs to see the records, edit one, and delete one.

If the prompt had repeated the rules, I would only have measured instruction following. I wanted to know what a builder with no prior context could recover from the environment itself.

The decision I intended the framework to carry

I also wanted a decision the agent would not arrive at on its own. A list of records has an obvious answer — a table — and an agent reaching for it proves nothing about the environment, because it is what many builders would reach for by default.

The intended design decision was less obvious: the collection should open as product cards, with the table available as another view of those same records. The prompt never said that. I believed Layer 4 did.

The product tile, documented with the behaviour around it: the whole tile is clickable, and the active ring — not a re-read of every title — tells you which record is open.
The collection decision lived in Layer 4, the written-rules layer for contextual choices that a token or component cannot force on its own.

At this point in the experiment, I treated the cards-first behaviour as a test of whether the agent could recover that decision from the environment. A later audit showed that this assumption was itself part of the bug.

Experiment 1: structural consistency worked

In the first five Rails runs, the agent-authored code produced zero real violations across 30 pre-registered checks after adjudication. The agents reused existing components, avoided raw CSS literals, preserved the type scale, and included feedback for committed actions.

Two runs even discovered that the application shell was missing the region required to render toasts and repaired the baseline itself.

That was encouraging, but incomplete. All five agents still chose a familiar records-management pattern: a table, a row menu, and a modal. None opened on cards or used the pushing detail panel I expected from the framework.

One run's products page, generated from the prompt with no human involved: a table with a row menu.
Another agent, same prompt, same environment, no shared history: a table again, differing only in how each row is dressed.

The system was producing consistent code without necessarily producing the intended interaction behaviour.

Experiment 2: prose versus structure

I sharpened the rules and created a CollectionBrowser component that packaged the intended cards, table switcher, and detail panel into a single call.

Ten new agents received the improved rules. Five also had the composed component. My prediction was that the structural arm would make the intended pattern nearly automatic.

The result inverted the prediction:

  • The application shell appeared in 10 of 10 runs.
  • The cards-first behaviour appeared in 1 of 10 runs — and that run belonged to the prose-only arm.
  • The optional composed component was used in 0 of 5 runs that had it available.
Experiment 2, same result: a table. The view switcher sits in the top corner — the cards view was one click away, and no run opened on it.

The component worked if an agent selected it. Nothing forced the selection.

An optional component is still documentation. Real structure is the constraint an agent cannot route around.

Experiment 3: the failure survived six interventions

I tested six possible explanations. I rewrote the prose more imperatively, moved guidance closer to the component, removed a misleading table example, made cards as cheap to build as tables, and made the table component demand an explicit reason for bypassing the intended pattern.

The output remained remarkably stable. Across 17 Claude runs, every agent built a table, a row menu, and a modal.

The transcripts showed that the relevant design-system material was being found. Seven of ten comparison agents had the detail-panel guidance in context, and all ten opened the relevant catalog and table component.

At the time, I interpreted that as evidence that the agent could read a rule and still route around it. The escape hatch seemed to reinforce that interpretation because agents produced circular justifications for the table they had already chosen.

That interpretation turned out to be incomplete.

I had been treating the output as a compliance failure without first checking whether the Layer 4 rule actually expressed the decision I thought it did.

Experiment 4: the defect was a sentence

The Claude-versus-Codex comparison initially looked like a reader problem. The same screen task run three times through Codex produced cards, a pushing detail panel, and no modal, while the earlier Claude runs had repeatedly converged on a table-and-modal pattern.

But while investigating that discrepancy, a Claude agent inspected the Layer 4 rule itself and surfaced a more fundamental problem.

The rule said:

“When a record has a photo, cards are the default and the table is the alternative.”

That sentence did not encode the decision I thought I was testing.

It made cards conditional on a record having a photo. It did not say that the collection should open as cards. It also did not explain the relationship between the two representations.

Claude had not necessarily been refusing the rule. It had a literal, valid path through it.

The irony matters: Claude had written the original sentence, and another Claude agent later exposed the ambiguity in it.

I rewrote Layer 4 as:

“A record list opens as cards, and the table is those same records seen another way.”

That version expressed the interaction directly. Cards became the initial representation of the collection; the table became an alternative view of the same records.

From that correction forward, every subsequent recorded run opened with cards.

This changes how the earlier experiments should be read. The 17 table results are still real observations, but they are not clean evidence that the agent “read the rule and ignored it.” The specification itself was part of the failure.

The Codex comparison still matters, but it cannot be used as a clean Claude-versus-Codex result because the reader architecture also differed. What it did was create the discrepancy that forced a closer audit of the system.

The failure was not only in the generated screen. It was in the sentence that was supposed to govern it.

And the fix followed the Onion rule exactly: the defect appeared in Layer 5, but the correction belonged in Layer 4.

Same prompt. Same repo. The harness changed what the agent could recover.

After correcting the Layer 4 rule, I ran a direct four-run comparison using the same products-page prompt and the same base repository.

One run had access to the repository and could inspect the design system, but did not have the harness. The other three ran with the harness and the design system available.

The results were visually consistent within each condition.

The four-run comparison, as text. The variable is the harness, not the prompt, the repository, or the design system.
Design system accessible, no harnessDesign system + harness
The agent produced a generic products table with default-looking edit and delete actions.The agents produced the application shell, product cards, governed states, and a dedicated non-modal detail panel.
Without the harness: a generic products table, with edit and delete as default browser links.
With it: the application shell, product cards with governed states, summary counts, and a detail panel that pushes instead of covering the collection.

Same prompt. Same repo. Same design system. Different operating environment.

Making the design system available was not the same as making it operational.

This is the visual comparison I would use as the payoff of the validation section, not as proof of a universal causal effect. It shows what happened in these four runs: access to the repository alone did not produce the same interface as an environment in which the design system had been made discoverable, actionable, and checkable through the harness.

The experiment also had to test its own specification

The measurement system failed more than once. One regex flagged correct component usage. Another scorer defined compliance through a component available to only one experimental arm, making a correct alternative look like failure.

I kept the original scores, recorded the adjudications separately, and rewrote later conditions around observable behaviour instead of a preferred implementation.

The Layer 4 discovery was the same kind of failure at a different level. I had been scoring “table” as evidence against the agent while assuming that the specification unambiguously required “cards.” It did not.

That means the experiment was testing two things at once:

  • whether the agent could recover and follow the design system;
  • whether the design system had expressed the intended decision clearly enough to be followed.

Every generated screen became evidence about both the reader and the system being read.

That is not a footnote to Onion. It is one of the strongest findings: an agent can expose ambiguity in the design system itself, but the experiment has to be willing to revise its own interpretation when that happens.

Results and limits

What Onion improved

Onion gave me a repeatable way to move design decisions out of prompts and individual screens and into the code environment.

  • Hard-coded hex values across the affected views fell from 119 to 24 in the original Rails experiment.
  • The Rails implementation maintained 131 colour tokens in both light and dark themes through an automatic parity check.
  • The methodology transferred from React to a system of 61 Rails component files without changing its five-layer model.
  • The first five measured Rails runs produced zero real violations across 30 structural checks after adjudication.
  • Cold agents reused components, preserved governed values, and found missing infrastructure without being told the name of the framework.
  • An optional composed component was not enough to guarantee selection: it was used in 0 of 5 runs where it was available.
  • A repeated cards-versus-table failure exposed a defect in the Layer 4 wording rather than only a failure in the generated screen.
  • After Layer 4 was rewritten from a photo-conditioned rule to an explicit cards-first interaction, every subsequent recorded run opened with cards.
  • In the direct four-run comparison, the no-harness run produced the generic table shown above, while the three harnessed runs produced the system-shaped cards/detail-panel experience.

The most important result was not that Onion made every output identical. It was that it made inconsistency diagnosable.

The question stopped being only “why did the agent make the wrong screen?” and became:

  • Is a governed value missing?
  • Can a primitive prevent the defect?
  • Can a composed pattern absorb the decision?
  • Is the written rule missing, ambiguous, or expressing the wrong reasoning?
  • Is the remaining judgement something only a person reviewing the experience can decide?

The cards-first failure is the clearest example. The defect appeared on the screen, but the most useful correction lived in Layer 4.

What Onion could not guarantee

The experiments also set clear boundaries around the framework.

  • It did not produce identical executions.
  • It did not guarantee that an agent would discover or choose an optional component.
  • It did not guarantee that a written rule would express the intended decision correctly; the specification itself can be ambiguous or wrong.
  • It did not make every model or orchestration strategy behave the same way.
  • Structural enforcement can prevent known invalid choices, but it cannot decide whether the underlying design decision is good.
  • It cannot determine whether the team framed the right user problem.
  • It does not supply taste, design strategy, user research, or final experience review.
  • A design system can make a bad decision repeatable just as efficiently as a good one.

The four-run no-harness/harness comparison is strong visual evidence for this repository and task, but it is still a small comparison, not a replicated effect-size study across models and environments. The study can show what changed in those runs, how decisions propagated through Onion, and how the framework responded when its own rule was defective. It cannot claim that every future agent will make the same choice.

Likewise, the fact that every recorded run after the Layer 4 rewrite opened with cards is strong evidence that the corrected rule mattered in this environment. It is not proof that prose alone guarantees compliance.

Onion reduces the surface on which the agent improvises. It does not eliminate improvisation — and it does not turn consistency into quality.

Repeatable is not the same as good.

What changed

The repetitive process became replaceable. The designer did not.

I began this work by asking whether AI could help me design directly in code. I ended it with a different understanding of what design needs to become when code can be generated on demand.

The repetitive parts of interface production no longer need me every time. Known patterns can be assembled, tokens can be applied, and familiar states can be generated from the system.

That gives design more room to move toward the decisions that should not be automated blindly.

What moved and what did not. The right column is the job, not the leftovers.
AI made easierStill requires design judgement
Assemble the interfaceUnderstand users
Apply known patternsFrame the right problem
Maintain governed valuesDecide what the intended behaviour actually is
Follow existing decisionsApply taste
Propagate a component or rule fixDecide when the system should change
Generate another screenEvaluate the complete rendered experience

The Layer 4 defect changed this conclusion in an important way.

It would be too simple to say that the agent can generate screens while the designer alone catches the reasoning problems. A Claude agent was the one that surfaced the defective sentence. The agent helped audit the design system.

But finding an ambiguity is not the same as owning the design intent.

The sentence said that cards were the default when a record has a photo. The system could identify that this condition did not necessarily imply “open the collection as cards.” The design judgement was deciding what the interaction should actually mean:

A record list opens as cards, and the table is those same records seen another way.

That distinction matters.

The valuable human work is not manually producing every repeatable interface decision. It is deciding which behaviour should exist, expressing that reasoning in the right layer, evaluating whether the resulting experience is good, and changing the system when new evidence says it should evolve.

The design system became something the agent can audit

I no longer treat a design system as a finished library waiting for people or agents to obey it.

It is a living system. Every generated screen tests it.

When an agent repeatedly produces an unexpected result, there are now at least two questions:

Why did the agent produce this?

Did the system actually say what we thought it said?

In this case, the second question changed the interpretation of the first three experiments.

The AI was not only a consumer of the design system. It became one of the instruments for auditing it. It could surface ambiguity, compare the literal rule with the rendered result, and point to the sentence that did not encode the intended behaviour.

Human judgement still owns a different layer of responsibility: user needs, product intent, taste, trade-offs, and the decision about what the system should become next.

That is a more useful division of labour than “AI builds, designer fixes.”

The repetitive process? Yes, increasingly replaceable. Design judgement? Still the thing that decides what should become repeatable.

Public framework

Onion is becoming a public resource

This case study explains how Onion was created. A framework page is being written to state the method on its own terms, for anyone who wants to use it beyond this project.

Together with the research log, it will cover:

  • The five-layer method and the rule for moving fixes inward.
  • A practical audit for deciding where an existing design decision belongs.
  • Reference implementations in React and Rails.
  • Examples of primitives that refuse invalid composition.
  • Templates for written rules, local gates, and CI checks.
  • A protocol for running cold-agent fidelity tests.
  • The complete research log, including model details, contaminated runs, corrections, and open control arms.

Onion was co-created by Arely Rivera and Alicia Rojas. I independently developed the inward-fix discipline, enforcement rings, cross-stack reference implementations, and experimental research that followed. It remains a living framework: each new implementation, stack, and model is another test of which decisions can become structural and which still require people.

Keep reading

Looking for a lead product designer or design engineer?