How do you prevent AI-generated UI from drifting from a design system?

Short answer

You prevent drift at two points. Before the agent writes, give it the system that actually exists in your code: the tokens, the components and the rules, not an aspirational document. After it writes, check the change against that system: raw values that equal a token, near-misses, duplicated components, one-off overrides. Prompts alone do not hold; a check you can run does.

Why AI-generated UI drifts

Agents optimise for code that works and looks right in isolation. A hex value that renders the right purple passes every visual check, so nothing stops it. Over many changes those values accumulate: in the Lunary scan, 22 hard-coded colours exactly equal a declared token and are written 436 times in total, and 78 more sit perceptually close to one.

Before: give the agent the real system

Documentation that describes the system you intended is less useful than a description of the one you have. Reconstruct it from code: which tokens are declared, in which themes and modes, which are used and which are dead, which components exist and which names collide.

Keep the hand-over short and specific. A list of tokens with their roles, a list of components with their purpose, and a few rules (never write a raw colour when a token exists) are more effective than long prose.

After: check the change

Run the same analysis on the code after the agent has written it. Exact drift is deterministic: a raw value that is string-identical to a token is a finding with no judgement involved, so it can be fixed or rejected in review. Near-matches are inferences and should be reviewed by a person.

Terminal
saer scan .
# open .saer/report.html

What Saer does about this

Today
  • Colour drift detection in the beta: exact drift, near-matches with their distance, dead and conflicting declarations.
  • Typography and foundation drift (spacing, radius, shadows, z-index, breakpoints, borders, opacity, motion): in the beta.
  • Component duplicates and overrides: in the beta.
  • A self-check an agent calls through MCP, saer_check_changes, which judges only the lines it wrote: in the beta.
Not yet
  • CI Guard, a pull request check that fails on new drift: planned.

Every capability and its state: what Saer checks.

See it on your own codebase.

Request early access