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, stable for LLMs, 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. Each component ships a schema-validated contract covering variants, states, tokens, accessibility, and composition, with token paths checked against the built output. Agents read and cite that contract instead of inferring intent from code.
Fixed component set. A small, closed list where a three-question test gates every addition, so agents 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, built by Style Dictionary into CSS and JS; components
consume the built output, never the source.
Deterministic split. 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 context costs money and crowds the model's memory; too little makes it guess. For this large repo it was needed to carefully engineer and automate the context the LLM gets. See the context layers
CLAUDE.md. The one file loaded into every
Claude session: only the rules that always apply, plus a commands reference table. An automated CI check keeps it under 200 lines so it never bloats.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 adversarial-review agent, 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, inside a predictable pipeline. The real product isn't the components; it is a prepared set of context any agent can act on correctly and cheaply. That is what lets one person hold team-scale rigor.