[Blog] Design tokens save LLM tokens: what building iOS/Mac apps with AI agents taught me about SwiftUI theming

Design tokens save LLM tokens: what building iOS/Mac apps with AI agents taught me about SwiftUI theming

I've been leaning on AI coding agents (Claude Code, mostly) for a good chunk of my SwiftUI work this year, and I noticed something that took me a while to name properly: the same word — token — shows up in two completely unrelated places in that workflow, and they turn out not to be unrelated at all.

There's the "token" in a design system: a named value like spacing.md or color.accent that stands in for a raw literal. And there's the "token" on your Anthropic or OpenAI bill: the unit an LLM reads and writes text in, and the thing you're paying for. I'd always treated those as a coincidence of vocabulary. Building a few apps almost entirely through an agent changed my mind — a design system built around the first kind of token measurably reduces how many of the second kind you burn.

The failure mode

Here's the pattern I kept hitting. I'd have an agent scaffold a screen, and it would do the obvious thing: write out Color(.systemBackground), .padding(16), .cornerRadius(12), literal values wherever a value was needed. Fine, it compiles, it looks right.

Then the design changes. A radius needs to go from 12 to 8 app-wide, or a client wants a second visual theme, or dark mode needs different shadow treatment than the naive system default. Now the agent has to go find every place it wrote that literal, re-read the surrounding context to make sure it's editing the right instance, and regenerate the styling code across N files. That's not free — it's output tokens spent reproducing code that already existed, plus input tokens spent re-reading files to relocate literals it already had every reason to reference by name the first time.

It's the same failure mode as hardcoding magic numbers in any codebase, except the cost isn't just future-developer time — it's a metered API call every time an agent has to rediscover and rewrite what should've been a single source of truth.

The fix isn't new, just underused with agents

None of this is a novel idea to anyone who's used a real design system before: route every visual decision — color, spacing, radius, shadow, type — through a token, and make components accept a style rather than hardcoding one, the same pattern SwiftUI itself uses for ButtonStyle.

// Before — literal values scattered across every view that needs them
Text("Ship it")
    .font(.system(size: 15, weight: .medium))
    .padding(.horizontal, 16)
    .padding(.vertical, 10)
    .background(Color(red: 0.31, green: 0.27, blue: 0.9))
    .cornerRadius(8)

// After — everything resolves through the environment's active theme
Text("Ship it")
    .dfTextStyle(.buttonLabel)
    .dfPadding(.md)
    .dfBackground(.accent)
    .dfCornerRadius(.button)

The second version isn't shorter because it's clever — it's shorter because the actual visual decision was already made once, elsewhere, and lives in one place. What changes when I applied this deliberately with an agent in the loop:

  • Fewer output tokens on iteration. Changing a radius or swapping a theme is a one-line change to the token definition, not a find-and-replace across every screen. The agent doesn't have to regenerate styling code it already wrote correctly the first time.
  • Fewer input tokens on orientation. A small, named, documented vocabulary (.md, .accent, .button) is something an agent can reference directly instead of re-reading five files to infer "what does this app usually do for corner radius." Convention lookup gets cheap when the convention has a name.
  • Runtime theme switching becomes a modifier, not a refactor. If components already read from tokens, swapping a whole visual identity — light/dark, brand A/brand B, an accessibility high-contrast variant — is one call at the app root instead of a multi-file change the agent has to plan and execute.

What I've been using

I extracted the token/style-swapping layer I use for this into a small open-source package, DesignFoundation — MIT licensed, Swift 6 strict concurrency audited, iOS and macOS. It's the same pattern above: token-based theming, components that take a style parameter instead of a hardcoded value, plus a few presets and Liquid Glass support if you're targeting that. Docs are here if you want to see the actual API rather than my paraphrase of it.

If you want the same token system but with full pre-built screens instead of primitives, there's a paid add-on (DesignFoundationPro) built on top of it — not the point of this post, just mentioning it exists for anyone who asks.

Curious whether others working with AI agents on SwiftUI codebases have hit the same regenerated-boilerplate problem, and what you've done about it — token systems aren't the only fix, just the one that worked for me.