Patagonia's AI Agent
Conversational B2C interface shaped by the brand's personality and values.
This is the second chapter of UpSkill. A fully coded component library that generates production-ready components, with AI running as infrastructure: machine-readable, low-drift, and token-efficient.
Senior Product Designer
Agentic design system
AI generates UI fast, but the result only looks fine on the surface; by default it's expensive to run and unreliable. At scale it drifts: invented components, misused tokens.
The real challenge is guiding the LLM to understand design intent and stay aware of the system's state, without 24/7 orchestration or costly live MCP calls.
Three early plans failed. Figma as the source of truth fell to an enterprise-locked feature, so code became the source and Figma a mirror. Parallel agents fell for draining a shared monthly allowance and hitting limits. Constant MCP calls to Figma and Airtable fell too, slow, rate-limited, and inconsistent. A deeper reengineering was needed.
Metadata schema. JSON metadata schemas: a machine-readable semantic layer for component build and layout composition, guiding agents on a predictable path matching design intent.
Fixed component set. A small, closed list where a three-question test gates every addition, so agents discover and compose from known parts rather than inventing new ones.
Four-layer tokens. Every value resolves through
primitives → brand → theme → device, later layers overriding earlier
ones. Tokens are DTCG JSON, the open design-token standard, compiled by Style Dictionary into CSS and JS; components
consume the built output, never the source.
Plumbing first, AI on top. Most of the system is plumbing: GitHub Actions, npm scripts, and REST calls move state between tokens, components, Airtable, and CI with no model involved. Only jobs a script cannot do, like generating or reviewing a component, use one of nine Claude commands.
Every task gets exactly the context it needs. Too much costs money and crowds the model's memory; too little makes it guess. The fix was context engineering: externalizing the system's semantics, what things mean, how work is done, why it is this way, and what is true right now, into four layers an agent reads on demand, instead of inferring them from code or watching the repo live. See context layers
CLAUDE.md is
the one file in every session: only the rules that always apply, plus a
commands reference table, held under 200 lines by an automated CI check.
The detailed rules, the nine commands, and their step-by-step skills load
on demand. Because they ship with the repo rather than living in
someone's head, every developer and every agent runs the same task the
same way.What loads is earned, not assumed. An eval harness scores candidate context by whether the output correctly cites the component contract and stays within the fixed set, keeping reference material in a prompt only if it measurably raises that score. That is how the system learned that details on how components fit together help when building a full page but hurt a single one, so only the layout task loads them.
add-component loop runs a fixed sequence: sense the
current state from the snapshots, scaffold the component, run automated checks (lint,
accessibility, typecheck), pause for a visual review in Storybook (the component
workshop and live docs), hand it to a separate reviewer agent, adversarial by
design: no memory of how the component was built, so it has no reason to go easy
on it, then bundle fixes into a pull request. A second loop builds full page layouts the same way,
citing the component contract for every choice.
Additional loops self optimize the system. A bug found in review routes back into the component's schema metadata, so the next build already knows the fix. A documentation loop catches stale docs, rewrites only the outdated parts, and checks the result with a fresh agent before it ships.
Airtable is the governance layer: a live inventory of every token and component. For each component it tracks two things, how finished the code is and whether I signed off, with a safeguard so automation can never downgrade something I marked done. I read it through command-line status views built on the same snapshots the agents use.
"patterns": [...],
"antiPatterns": [...],
"accessibility": [...],
"composition": [...],
"tokens": [...]
"patterns": [
{
"name": "course-curriculum",
"description": "A list of course modules, each expandable to reveal a description.",
"tree": "Accordion > [AccordionItem(title, subtitle), AccordionItem(title, subtitle), ...]"
},
{
"name": "faq-list",
"description": "A set of frequently asked questions where each answer is hidden by default.",
"tree": "Accordion > [AccordionItem(title='Question?') > Text(answer), ...]"
}
]
Gives the agent accepted composition patterns and usage examples.
"antiPatterns": [
{
"scenario": "Nesting Accordion inside another Accordion",
"reason": "Deep nesting creates a confusing mental model and breaks the heading hierarchy.",
"alternative": "Flatten the information architecture or use a sub-section heading and Text"
},
{
"scenario": "Passing both the open prop (controlled) and defaultOpen prop simultaneously to AccordionItem",
"reason": "The component cannot resolve two competing sources of truth. The controlled open prop silently wins over defaultOpen; a DEV-only console.warn is emitted, but the initial state discrepancy still occurs at runtime.",
"alternative": "Use open + onOpenChange for fully controlled mode, or defaultOpen alone for uncontrolled mode. Never supply both."
}
]
Stops the agent from repeating documented mistakes.
"keyboardInteractions": [
{
"key": "Enter",
"action": "Toggles the focused accordion item open or closed"
},
{
"key": "Space",
"action": "Toggles the focused accordion item open or closed"
},
{
"key": "Tab",
"action": "Moves focus sequentially through any focusable content within an open panel, then to the next accordion trigger. Focusable descendants inside a collapsed panel are skipped — the panel's inert DOM property is set while closed, so Tab cannot land on them even though they remain in the DOM for aria-controls."
}
]
Fixes ARIA and keyboard behavior the agent can't infer on its own.
"composition": {
"composedOf": ["Icon", "Text"],
"accepts": ["AccordionItem"],
"containedBy": ["Box", "Stack", "Card"]
}
Tells the agent what's valid to nest and wrap.
Most products bolt AI on top as a chat assistant; here it runs underneath. The infrastructure is the context itself: centralized, shared, and discoverable knowledge, so agents work from the same facts instead of guessing. CI keeps it from drifting, review findings feed back into the rules, and sign-off keeps a human in the loop. That's what lets one person hold team-scale rigor, and scale to more people or agents without redesigning the system.