Your design system says one thing, your product ships another. Compare tokens from any design tool (Figma, Sketch, Penpot), live sites & apps, or codebases — get conflicts, confidence scores, and WCAG drift checks. CLI + library + MCP server.

Your design system says one thing. Your product ships another. This shows you exactly where.

npx token-reconciler ./design-tokens.json https://yourproduct.com

Give it any two sources — a design-tool export (Figma, Sketch, Penpot, Tokens Studio…), a live site or web-app URL, a codebase token file — and it prints a real drift report. Site URLs are scanned live (extraction is delegated to the open-source Dembrandt extractor), so there is nothing to set up and nothing staged: the report is your actual design system, as it exists right now.

No arguments? npx token-reconciler opens a guided start that walks you through it.

The problem

A design system never lives in one place. There's the Figma file, the shipped CSS, and the codebase — three copies of the same decisions. Over time they quietly stop agreeing: a developer hardcodes Tailwind's blue instead of the brand indigo, Figma gets a new gray that never ships, a heading goes out 700 where the type scale says 600. No single tool notices, because each tool only sees its own copy.

By 2026 the extraction side of this is solved — good open-source tools pull tokens out of live sites, and Figma exports Variables — all speaking the same DTCG format (the W3C Design Tokens Community Group standard: one agreed JSON shape for design tokens, so every tool can read every other tool's output). What was missing is the step after: comparing those files and knowing which differences matter. That's what this tool does.

What you get

Running a comparison produces a report with three sections:

  • Conflicts — the same token defined differently in two sources, sorted by a 0–1 confidence score for how much the difference matters. Scoring is type-aware: colors are compared perceptually (OKLab), not as strings — so #FFFFFF vs rgb(255,255,255) is not a conflict, while two grays one shade apart is. Dimensions and durations are unit-normalized (1rem = 16px, 0.3s = 300ms), and DTCG aliases are resolved before comparing, so {color.base.indigo.500} vs its raw value agree.
  • Unmatched tokens — designed but never shipped, or shipped but never designed. Not conflicts yet; usually where the next one comes from.
  • A suggested resolution per conflict — from a deliberately simple default resolver (mostRecentWins), with its reasoning stated. Smarter resolution is pluggable.
  • Accessibility analysis, current and next standard — text-role color tokens are paired against background-role tokens and checked against WCAG 2.2 AA (4.5:1 — the current W3C standard, and the level EU EAA / ADA rules bind to), with AAA and an informative APCA reading (the WCAG 3.0 draft algorithm) per pair. The unique part: because this tool sees multiple sources, it can tell you when drift changed accessibility — the same pairing passes AA in Figma but fails on the shipped site. A generic audit can't say that; a reconciler can.

Here's a fragment of a real run (two production sites, scanned live):

### typography.style.text-heading-1
Confidence: 0.97 🔴 · type: typography

| Source        | Value                                                    |
|---------------|----------------------------------------------------------|
| wildchild.ai  | { fontFamily: Geist, fontSize: 48px, fontWeight: 400 … } |
| humano.ai     | { fontFamily: Inter, fontSize: 12px, fontWeight: 700 … } |

### color.palette.palette-3
Confidence: 0.94 🔴 · type: color
| wildchild.ai  | #7a7a7a |
| humano.ai     | #888888 |

How to use it

Compare your design system against your product (the main event):

  1. Export your design system's tokens to DTCG JSON from whatever tool holds it — Figma (Community plugins like "Design Tokens (W3C)" or DesignBridge), Penpot (native DTCG export), Sketch, or Tokens Studio.
  2. Run:
npx token-reconciler ./design-tokens.json https://yourproduct.com

Compare any two sources — every argument can be a .json file path, a URL to a token file, or a site URL to scan:

npx token-reconciler https://yoursite.com https://staging.yoursite.com
npx token-reconciler design-system.tokens.json codebase-scan.tokens.json

Guided mode — if you're not sure where to start:

npx token-reconciler

In CI — the exit code is the drift gate (0 clean, 1 high-confidence conflicts, 2 input error):

npx token-reconciler reconcile figma.tokens.json site.tokens.json --threshold 0.7 --out report.md

Useful flags: --json (JSON report), --out <file>, --names a,b, --kinds figma-variables,live-site, --threshold <0..1>, --no-fail. See examples/ci-usage.md for a full GitHub Actions setup and examples/dembrandt-vs-figma.md for a worked walkthrough.

Beyond marketing sites: SaaS, web apps, and mobile apps

Design systems live mostly in products, not public websites. Every kind of product connects — the source just differs:

Logged-in SaaS / web apps. They're still web — the scanner just needs your session. Grab your cookie from the browser's dev tools (Application → Cookies) and pass it through:

npx token-reconciler ./design-tokens.json https://app.yourproduct.com --cookie "session=abc123"

--header "Authorization: Bearer …" works too, for token-authenticated apps. Scan the screens that matter by pointing at their URLs directly.

Mobile apps (iOS / Android / React Native / Flutter). There's no URL to scan — but a mobile app's design tokens live in its codebase, which is even better than scanning: Android Compose/XML themes, iOS asset catalogs, React Native theme files. If you use Style Dictionary or Tokens Studio, your source token JSON is already DTCG-compatible — feed it in directly:

npx token-reconciler ./design-tokens.json ./mobile-app/tokens/theme.tokens.json

That codebase-as-source path is also the most precise one for web apps, when you'd rather compare intended code tokens than scanned computed styles.

All three at once. The tool takes 2+ sources — so one run can answer "does Figma, the web app, and the mobile theme agree?":

npx token-reconciler design-tokens.json https://app.yourproduct.com android/tokens.json

Use it from an AI agent (MCP)

claude mcp add token-reconciler -- npx -y token-reconciler-mcp

Three tools: reconcile(sources) runs a comparison and returns the scored report; get_conflicts(runId) retrieves a past run; explain_conflict(runId, tokenPath) breaks one conflict down completely — raw and resolved values per source, alias chains, and every confidence factor with its weight and reasoning. Pairs naturally with extractor MCP servers: an agent can scan a site with Dembrandt and reconcile against a Figma export in one conversation.

Use it as a library

import { reconcileSources } from "token-reconciler";

const report = await reconcileSources([
  { name: "Design system", kind: "design-tool", document: "./design.tokens.json" },
  { name: "Live site", kind: "live-site", document: "./site.tokens.json" },
]);

for (const conflict of report.conflicts) {
  console.log(conflict.path, conflict.confidence.score, conflict.confidence.factors);
}

document accepts a file path, an http(s) URL, or an already-parsed DTCG object. If a source carries an extraction timestamp in $extensions (Dembrandt does), it's picked up automatically.

How confidence scoring works

Every conflict's score is built from three documented factors — the full breakdown ships in every report, never a black box:

Factor Weight What it measures
valueDelta 0.6 Type-aware distance. Perceptual (OKLab) for colors, relative-numeric for dimensions/durations, field-averaged for composites. Mid-range deltas score highest — tiny ones are usually rounding noise; huge ones often mean two different tokens share a name.
nameMatch 0.25 The same token path exists in both sources.
typeAgreement 0.15 Both sources agree on the token's $type.

The score tops out around 0.97 by design: it's a heuristic, and a heuristic claiming 1.00 would be lying.

Plugging in your own resolver

Detecting conflicts is this library's job; deciding the winner is pluggable. One deliberately simple resolver ships (mostRecentWins — newest extraction wins; abstains without timestamps). Writing your own is one function:

import type { Resolver } from "token-reconciler";

const designWins: Resolver = (conflict) => {
  const design = conflict.sightings.find((s) => s.sourceKind === "design-tool");
  if (!design) return { decision: "unresolved", reasoning: "no design-tool source" };
  return {
    decision: "resolved",
    winner: design.sourceName,
    value: design.token.resolvedValue,
    reasoning: "design file is the declared source of truth",
  };
};

Every resolution carries a reasoning string, always. Provenance is the point.

Scope — what this deliberately does not do

  • No extraction engine of its own. Site scanning is delegated to Dembrandt; Figma export belongs to Figma plugins. This tool starts where extractors stop.
  • No invented schema. Standard DTCG in, standard DTCG concepts out.
  • No pretend judgment. The default resolver is honest about being dumb. Real judgment — knowing your system's intent — is a different product.

Works great with

  • Dembrandt — live site → DTCG tokens; powers this tool's URL scanning.
  • designlang — live site → tokens + layout + a11y data (GitHub).
  • uiscanner — URL → token teardown via MCP.
  • DesignBridge — Figma design system → structured DESIGN.md + tokens.
  • W3C DTCG format — the interchange format that makes all of this composable.

Development

npm install
npm run build   # tsc → dist/
npm test        # vitest — includes an end-to-end MCP client/server test

License

Apache-2.0. Use it, fork it, build products on it.

Built by wildchild.ai

MCP Server · Populars

MCP Server · New

    weed33834

    🛡️ AgentSeed

    AgentSeed - anti-hallucination guardrails for AI coding agents: hybrid Skill + MCP plugin (Agent Plugins 1.0.0) that forces spec-driven development and verifies code before it is marked done.

    Community weed33834
    geolens-io

    GeoLens

    Self-hosted geospatial data catalog with semantic search (pgvector), OGC/STAC APIs, and map builder. Built on FastAPI, PostGIS, React, and MapLibre.

    Community geolens-io
    leonardosepulvedat

    MCP n8n Server

    Complete n8n API integration for Claude Desktop and Cursor - 100 workflow templates with intelligent matching

    Community leonardosepulvedat
    maximhq

    Bifrost AI Gateway

    The Fastest LLM Gateway with built in OTel observability and MCP gateway

    Community maximhq
    crisnahine

    rails-ai-context

    45 MCP tools that give AI coding agents ground truth about your Rails app: schema, models, routes, controllers, views, jobs, conventions. Works with Claude Code, Cursor, GitHub Copilot, OpenCode and Codex CLI. MCP or CLI, in-Gemfile or standalone, and it still answers when the app can't boot.

    Community crisnahine