Tracking drift

Design systems don't fail loudly. They leak — a hex value here, a one-off padding there — and six months later the "system" is a suggestion. Nobody notices, because nothing measures it.

tostada diff measures it. Give it two exports and it tells you what moved.

Drift reports are produced as part of a Tostada engagement, not by a command you run. The open @tostada-ui/format package regenerates artifacts; comparing two of them and judging what drifted is auditing, and auditing is the product. What follows describes what the report tells you.

You get a report you can read in two minutes: which tokens drifted, which families were rebound, which rules were edited. Add --out report.md to write it to a file, or --json report.json for the complete machine-readable version.

Catching what never touched the library

The more interesting half. A team can leave every token alone and still drift, one hardcoded colour at a time — and only a look at the code sees that.

Drift reports are produced as part of a Tostada engagement, not by a command you run. The open @tostada-ui/format package regenerates artifacts; comparing two of them and judging what drifted is auditing, and auditing is the product. What follows describes what the report tells you.

Pass a scan report and the drift report gains a Codebase regressions section: every hardcoded value in the code that your library already defines, with the file and line where it was written. Not "your codebase has 84 hardcoded colours" — src/components/Button.tsx:12, and the token it should have used.

An unchanged library is not a clean bill of health. If nothing moved in the system but the code walked away from it, the report says so rather than reporting no drift.

What a clean report looks like

If nothing changed, you get one page saying so, naming both snapshots and the categories checked. That is deliberate: "no drift since the engagement" is a result worth having in writing, and a reader should be able to tell a thorough pass from a shallow one.

What it deliberately does not do

Every one of these is a decision, not a gap. A drift report is something you forward to people, and a confident wrong answer costs more than a missing one.

  • It never guesses at renames. A token renamed between two exports appears as one removal and one addition. Guessing which removal pairs with which addition would be a heuristic presented as a fact.
  • It matches values exactly. #fff and #ffffff are the same colour and are matched — that is spelling, not approximation. But a value one digit away from a token is not reported as a regression, because accusing a team of drift they did not cause is worse than missing one they did.
  • It does not treat 1rem and 16px as equal. That is only true if the root font size is 16px, which is a fact about a codebase this report has not read.
  • It never compares what it cannot see. If one export does not record colour families, the report has a "Not compared" section saying so, rather than silently counting that as unchanged.

Every approximation the run actually made is listed at the bottom of each report, under Method & approximations. That section is generated from what happened, so it is worth reading rather than boilerplate to skip.

Which file to compare

The tostada.json snapshot in your export bundle is the one to keep — it carries everything, including colour families, palettes and sizing.

A design-system.json also works, but it does not record those three, so a comparison between two of them is silent about part of the system. The report tells you which part.

Archive the snapshot at the end of an engagement. That is your baseline, and everything on this page is comparing against it.

Using it in CI

By default diff exits 0 whether or not it finds drift — drift is information, not a build failure, and a tool that broke the build on every design change would be switched off within a week.

If you do want a gate:

Drift reports are produced as part of a Tostada engagement, not by a command you run. The open @tostada-ui/format package regenerates artifacts; comparing two of them and judging what drifted is auditing, and auditing is the product. What follows describes what the report tells you.

That exits 1 when anything moved, which is useful for catching a bundle that was regenerated but never committed.