Enforce Your DESIGN.md in React Native and Expo With Live Style Inspection
A DESIGN.md file holds your design system in a form your AI coding agent can read: the colors, type scale, spacing, and corner radii your app is supposed to use, plus the rules for using them. The agent reads it before it builds a screen. Reading the rules doesn't mean the screen follows them, though. Your agent can only enforce your design system if it can check what the running app actually rendered.
Ceraph lets it do that check. Ceraph is an MCP server that lets your AI coding agent drive and test a React Native or Expo app on iOS devices and simulators, plus Android devices and emulators. One option on its snapshot tool returns render-time styles from the running app. Your agent gets the render-time color, font, spacing, and radius values each matched element received, and can check them against your DESIGN.md before it calls the work done.
What DESIGN.md is
DESIGN.md is an open format from Google Labs for describing a visual identity to coding agents. It's Apache-2.0 licensed and currently marked alpha, and its specification is also documented on Stitch. A file has two parts:
- YAML front matter with the tokens. These are the normative values, grouped as
colors,typography,spacing,rounded, andcomponents. Tokens can point at each other with references such as{colors.primary}. - A Markdown body with the rationale. Sections such as Overview, Colors, Typography, Layout, Shapes, Components, and Do's and Don'ts explain how to apply the tokens.
The format ships with a linter (npx @google/design.md lint DESIGN.md) that checks the file itself, for problems like broken token references, orphaned tokens, and contrast ratios. That covers the spec. Whether your app follows the spec is a separate question, and you can only answer it by looking at the app.
Why design token drift hides from a code review
Reading the code isn't enough to enforce a design system in React Native, because the value that reaches the screen is often decided outside the line you're reviewing:
- Hardcoded values. A
#FF5722typed into oneStyleSheetlooks like a brand color but isn't the token. - Wrong variant. A shared
Buttonrenders its secondary radius because the screen passed the wrong prop. - Theme resolution. A themed value resolves through hooks and context, so the source shows a lookup, not a color.
- Overrides. A
styleprop spread late in the array quietly beats the token the component meant to use.
Each of these looks plausible in a diff, and each is obvious in the rendered output. That's where Ceraph lets your agent check.
Live style inspection with includeStyles
ceraph_snapshot is the agent's structured view of the current screen: each element's role, label, on-screen bounds, and a stable ref to act on. When you pass includeStyles: true, the snapshot also carries bounded render-time styles for the visible elements it can uniquely match, covering:
- Color: text color, background color, border colors
- Typography: font family, size, weight, style, line height, letter spacing
- Spacing: margin, padding, and gap
- Shape: border widths and corner radii
- Layout and size: flex settings, alignment, width, and height
The snapshot also reports style-coverage metadata: how many elements were eligible, how many came back styled, how many were ambiguous, and the overall ratio. The agent can see what it didn't inspect, so a partial snapshot doesn't pass as a full audit. Nested Text reports the typography and color it inherits from its parent Text, marked as inherited, so a body style set once on a paragraph is checked on every span inside it. Platform defaults aren't style props, which is why the coverage numbers and the screenshot matter. Ceraph's guidance tells the agent to pair the styled snapshot with a screen_screenshot. The numbers show what rendered, and the screenshot shows how it looks.
Ceraph doesn't parse your DESIGN.md. Your agent reads the spec and Ceraph supplies the evidence. Your design system stays in your repo and in your words. Google's format, a hand-written token table, or a Figma export all work, because the comparison happens in the agent that already reads your project.
Walkthrough: catching drift on a paywall screen
Say your DESIGN.md includes:
---
name: Acme
colors:
primary: "#1A1A2E"
accent: "#FF6B35"
typography:
body:
fontFamily: Inter
fontSize: 16px
lineHeight: 24px
rounded:
md: 12px
components:
button-primary:
backgroundColor: "{colors.accent}"
rounded: "{rounded.md}"
---
You ask your agent to build a paywall screen with an Upgrade button.
- Build and bring up. The agent writes the screen, calls
ceraph_startto get the app running, and opens the paywall withscreen_open_url. - Snapshot with styles. It calls
ceraph_snapshot({ includeStyles: true }). The Upgrade button reports a background of#FF5722and a border radius of8. The body text, which sets its typography directly, reports Inter at 16 with a line height of 24, which matches. - Compare against the spec. The agent checks the button against
button-primary: the background should resolve to{colors.accent}(#FF6B35) and the radius to{rounded.md}(12). Both drifted. A hex value copied from an old mock and a radius left over from a default. - Fix at the source. It swaps both values for your theme's tokens. It doesn't patch in new literals.
- Confirm on the running app. A fresh
ceraph_snapshot({ includeStyles: true })shows#FF6B35and12. Ascreen_screenshotconfirms the button looks right, and the coverage metadata shows the elements it checked.
Steps 2 through 5 run inside the same conversation, so the drift is fixed before the screen reaches review.
A prompt you can paste
Put this in your agent's project instructions, or add it to any UI request:
Before finishing any UI change, open the affected screen with Ceraph, call
ceraph_snapshotwithincludeStyles: true, and check every styled element against DESIGN.md: colors, typography, spacing, and radii. Fix mismatches at the token source, re-snapshot to confirm, attach a screenshot, and report the style coverage.
Run on every visual change, this makes your design system something the agent verifies on the running app before it finishes. Your coding agent already reads DESIGN.md, and Ceraph shows it the styles the running app rendered with.
Ready to try it on your own app? Get started here.