UpSkill Agentic Design System

This is the second chapter of UpSkill. Part 1 designed the foundations; Part 2 turns them into a working system in code, where AI agents operate under the same governance as everything else: machine-readable, checked by scripts and humans, and built to run inside a fixed AI usage budget.

Part 1: UpSkill Design Foundations

Role

Senior Product Designer

Main Goal

Agentic design system

Pipeline health dashboard DAG view
Challenge

Trustworthy AI output at solo scale

LLMs generating UI without a machine-readable system fabricate token names, drift from brand, and lose context between sessions. A design system only constrains AI output if the AI can actually read it: prose documentation and screenshots do not stop a model from inventing a plausible-sounding color token that does not exist, or reaching for a component that was never built. Every layer of this system (tokens, components, layout, governance) is written as data a machine can parse and a script can check, while staying readable for people.

The personal constraint is just as real. One person maintains the whole system: the token pipeline, 27 components, the documentation, and governance, on a consumer AI plan with one shared usage window. Every agent workflow, from scaffolding a component to reviewing a pull request, draws from the same budget, so there is no team to split the work across and no API invoices to absorb a wasteful architecture. The system had to be governed and cheap to run at the same time, or it would not run at all.

Objectives

  • Make every part of the system readable by machines as well as people
  • Keep AI involvement governed: agents propose, checks and humans decide
  • Fit all automation inside a fixed, shared LLM usage budget
  • Support two brands, two themes, and three breakpoints from one token source
Approach

Five decisions that shaped the system

1. Machine-readable by contract

Every component ships a JSON metadata file, validated against a JSON Schema in CI, next to its code, styles, and stories. A layout grammar maps structural levels (Page, Header, Section, Container, Column, Component, Footer) one to one onto HTML landmarks, and a script validates that mapping deterministically instead of relying on a reviewer to notice a mismatch. The choice of JSON over prose is not a style preference: an Indeed benchmark across 1,056 prompts and 8 MCP configurations found that JSON metadata cuts LLM token cost by roughly 80% compared to Markdown, at equal or better accuracy. That number is the actual reason component contracts are machine-readable data instead of a well-written README, and it puts this system on the same path the design systems field is moving toward: components as data rather than components with documentation attached.

2. Nine agentic moments, not an agent mesh

I rejected the always-on multi-agent pattern: a router spawning parallel workers on every task. AI in this system only runs as nine developer-triggered moments (component scaffold, token deprecation pass, Figma variable audit, layout generation, docs sync, adversarial review, and learning extraction among them), and none of them watch anything continuously. Ending a session ends the loop. Exactly two subagents exist, and the reviewer is read-only by tool grant, not by instruction: its tool access is Read, Grep, and Glob, no Edit, no Write, so "reviewer reports, never fixes" is enforced at the permission layer rather than a rule someone has to remember under time pressure. Reviews route their findings back into component metadata and token conventions through an extract-learnings step, so a problem found once does not get rediscovered by the next review.

3. Context economics as an architecture constraint

The system runs on a seat-based consumer plan, where all agents share one rolling weekly usage window instead of a per-token budget, so context has to be treated like money. Agents never call Airtable, Figma, or GitHub live; scripts freeze external state into committed JSON snapshots that agents read instead, which keeps runs reproducible, immune to rate limits, and small in context. The always-loaded instruction file, CLAUDE.md, is capped at 200 lines by a CI gate after it once grew to 289 lines and instruction-following measurably degraded. Everything else loads through a five-rung ladder, from always-on rules down to on-demand snapshots, so only what a task needs enters context. I also evaluated a costed proposal for a parallel agent swarm and rejected it: on this plan, parallelism does not save money, it multiplies how fast the shared usage window drains without improving the outcome.

4. Measured, not assumed

Before feeding cross-component pattern data into generation tasks, I built a harness to test whether it actually helps, with an honest-outcome rule pre-registered in the results file: if the data does not help, say so and do not ship it. The result did not match the intuition that more context always helps. Pattern context roughly halved rule violations in layout and composition tasks but made component scaffolds worse (violations rose from 11 to 17), so it ships only for the task types where it measured positive, an overall 13% reduction in violations. Accessibility runs on the same discipline: a manual audit found 12 failing contrast pairs in light theme and 6 in dark, which led to token-level contrast math running in CI over the built CSS on every change. Waiver ledgers are only allowed to shrink, never grow, and the accessibility backlog is now empty.

5. Multi-brand from one source

Tokens resolve through four ordered layers: primitives, brand, theme, and device, each referencing only the layer before it. Two brands, UpSkill and Horizon, and two themes switch at runtime through data-brand and data-theme attributes, and three breakpoints come from the device layer. A single Style Dictionary build is the only bridge between the token source and anything a component can reference: components never import raw JSON, only the generated CSS custom properties, so brand and theme swapping cannot be bypassed at a single call site. The token pipeline also carries a reversal worth stating plainly: the original plan had Figma own primitives as the source of truth, but the Variables REST API is Enterprise-only on this plan, so no automated sync from Figma into code was possible. Code became the source of truth instead and Figma became the downstream mirror, and the old decision was not deleted, it was recorded as a superseded ADR.

Four token layers with Style Dictionary build as the single bridge
Four token layers, one build bridge
Same showcase screen in UpSkill and Horizon brands
Runtime brand and theme switching
Component metadata JSON beside the rendered component in Storybook
Metadata beside the rendered component
The nine agentic moments
Nine agentic moments
Airtable governance table with human vs code owned columns
Governance ownership per column
Pull request with token-diff bot comment and green CI gates
CI gates on a pull request
Solution

One governed pipeline from token to component

The verified component loop

/add-component walks the same path every time. A sensing script snapshots the current state of the repo, the main session scaffolds the new component from its schema plus Figma context, and deterministic gates check metadata, types, the build, and accessibility before anything moves forward. A human approves a visual checkpoint, then a fresh, read-only subagent reviews the diff adversarially with no memory of how it was built, and only after that does a pull request open. AI does the labor of drafting and iterating; scripts and humans hold every gate that decides whether the result ships. The reviewer's independence is structural, not requested: it starts cold and reads only the diff and a frozen snapshot, so its verdict carries none of the motivated reasoning of the session that wrote the code.

Pattern accuracy harness results by task type
Eval harness results, shipped only where they help

Governance without meetings

Airtable is the governance surface, but ownership runs per column, never per table. Token status and deprecation are human-authored in Airtable and pulled to code, because a deprecation decision is a judgment call. Component maturity is derived from code and pushed to Airtable on merge. Terminal pipeline states set by a human, done or todo, are never overwritten: the sync script checks what is already in Airtable before writing and skips the write if a human already closed it out, the "don't downgrade done" guard. Deprecation state is also mirrored into the token source itself, so the committed code, not the Airtable base, stays the durable record if the two ever disagree. Twenty ADRs apply the identical rule to decisions across the system: nothing is silently rewritten, a reversal is amended or superseded in the open, so the reasoning behind a changed decision stays on record instead of living only in one maintainer's memory.

Everything observable

The live showcase, hosted on GitHub Pages, includes a pipeline health dashboard that renders the whole system as a dependency graph, built from the same frozen snapshots everything else reads from. Real generated pages, a homepage, a course overview, and a user settings screen, prove the components actually compose into working layouts rather than existing only as isolated examples. Storybook documents every component and token set, with brand and theme toolbars so a reviewer can switch UpSkill to Horizon, or light to dark, and watch the same component adapt without touching code. Nothing in either view is assembled separately for this case study: the dashboard and the showcase pages are generated from the same committed state that CI checks and that the sync scripts read, so what a visitor sees is the system the pipeline enforces, not a separate presentation layer.

View live showcase View GitHub repo

Impact

A team-scale system, one maintainer

The numbers below describe a system sized for a team but run by one person. Every component ships with schema-validated metadata, its own stories, and accessibility coverage; every brand and theme combination renders from a single token source instead of a forked file per variant; every architectural reversal is recorded rather than erased. None of this is asserted: each line is measured against the repo's own CI gates, test suites, or harness results.

  • 27 production components and 2 hooks, each with schema-validated metadata, stories, and accessibility coverage
  • 2 brands x 2 themes x 3 breakpoints rendered from one token source
  • 20 ADRs recording every reversal and amendment in the open
  • 54/54 screenshot baselines passing at 0.000% diff after the latest refactor
  • Accessibility backlog empty, with contrast checked mathematically in CI over the built CSS
  • Pattern harness: 13% violation reduction overall, shipped only for the task types where it measured positive
  • Instruction file capped at 200 lines by CI; all automation running inside one consumer-plan usage window

None of this required a systems team: governance, quality, and multi-brand consistency held because the system itself is machine-readable and checks its own work.

Result

Screens

Pipeline health dashboard, full view
Pipeline health dashboard
Generated showcase pages across breakpoints
Generated showcase pages
Storybook with brand and theme toolbar visible
Storybook with brand and theme toolbar