Auditing the Token Layer
Porter's design system was built by hand, before AI was in the workflow, and the token layer showed it: names the export mangled, values that had drifted between Figma and code, components wired straight to raw colours. I built a small linter to turn 'these tokens feel messy' into a countable, reproducible audit, then packaged the fixes as phases the team could actually say yes to.
- role
- Senior Product Designer: audit, tooling & governance (hands-on, not the DS owner)
- stack
- Design tokens · Tooling · AI-assisted · Governance
- status
- in progress
How I got here
I'm a product designer at Porter, and most of my work now sits at the seam between design and AI: getting our design data into a shape that tooling, and eventually designers themselves, can operate on without a developer in the loop.
Our design system was built the careful, manual way, before any of us had AI in the workflow. It works. But a worry I'd raised earlier, that the token names didn't follow a rule you could actually write down, got parked at the time, because the system was nearly finished.
It came back because it blocks everything downstream I want to build. My AI workflows need tokens that are clean and machine-readable: a name a script can parse, a value that means one thing. If the token layer can't be trusted, nothing built on top of it can be either. So I picked the audit back up, not to redesign the system, but to make it trustworthy.
One constraint framed the whole thing: I don't own the design system. I couldn't walk in and say "this is wrong, here's something new." The team had earned their way to today's state. My job was to find the truth, then package it as something a busy team could say yes to.
How I thought about it
Two rules kept me honest.
First: derive, don't invent. I wasn't going to impose a naming convention I liked. I reverse-engineered the pattern the system already followed and measured it against its own implicit rule. Where I proposed a change, I had to name the concrete thing that breaks if we don't make it. No "this is tidier."
Second: audit for the ideal, propose in phases. I let myself map the perfect end-state privately, but everything I'd hand over got ordered by effort and by how easy it would be to accept. Lead with what's objectively broken in code (a dropped font, a value that drifted) because fixing those costs nobody any pride and builds trust. Raise the structural, opinionated stuff only after that.
What I actually did
The audit runs on tooling I built for it. I ingested the six-file token export, 698
tokens, into a workspace and wrote a small zero-dependency Node CLI to interrogate it.
Four commands: inventory (count what's there), graph (resolve every reference to find
dangling refs, orphans, and components that skip a tier), lint (score every name against
the derived grammar and emit each deviation), and suggest (generate a conformant name).
The linter and the generator share one name-checker, so the tool can never suggest a name
it would reject: spec, audit, and generator all run off a single source of truth.
That turned "these names feel messy" into a countable, reproducible result.
Then I went to the source. Using AI to read the Figma files live, I built a full map from each Figma variable to its exported JSON, and found the real story: the names in Figma were clean. The mess was the export pipeline mangling them on the way out (welding two levels of hierarchy into one segment, dropping group prefixes) and drifting. Three representations of the same token disagreed: Figma itself (the truth), Figma's own dev-mode CSS (faithful), and the JSON developers actually build from (mangled and stale).
The graph command surfaced the structural finding: components referenced raw colour
values directly and never passed through the meaning layer that should sit in between, so
a role couldn't be changed in one place, and a theme could never reach a component. It also
caught a set of text styles referencing a font that the export had dropped entirely.
The part I'm most glad I did: I didn't trust my own findings. I ran a 16-agent adversarial pass to cross-check each claim against the actual files, and it caught me being wrong, killing a "drift" claim of mine that didn't survive the export. For the target state, a separate 5-agent web sweep grounded my recommendations in how mature systems (Material 3, Spectrum, the W3C token spec) actually handle theming and fonts, so the ideal wasn't something I invented.
Out of all this came the naming grammar I set out to produce: one rule for delimiters, a scalable path-segment target, and a per-tier spec: the machine-readable contract the whole thing exists for.
Where it landed
Still in progress. The design system's owner reviewed the findings, agreed the gaps were real (the system was hand-built pre-AI, so the cleanup was legitimate) and asked me to write it up as a formal proposal.
I'm working through it tier by tier, packaging every recommendation the way the doctrine demands: an effort tag, a concrete example of what breaks without it, and a way to see it. The deliverable underneath is the thing I actually care about: a machine-readable token layer that lets designers own the system end-to-end, drift-free, without waiting on a developer. This audit is the foundation that makes that safe.