AI agents now render user interfaces at runtime: A2UI surfaces, MCP App views, generative components. The catalogs those agents draw from are hand-written JSON with no designer in the loop, and a surface can be perfectly schema-valid while quietly off-brand. glph is the brand layer for that new surface: a model handles the fuzzy edges, and a deterministic rules engine carries every guarantee.
color-not-tokenevery color must resolve to a catalog token; fixes snap to the nearest token by CIE deltaEspacing-off-gridspacing must sit on the brand grid; fixes snap to the nearest grid steptype-not-in-scalefont sizes must belong to the type scalecontrast-too-lowtext must meet WCAG contrast against its background; fixes pick the nearest passing tokencomponent-not-allowedcomponents outside the agent allowlist are flagged, never silently correctedThe catalog does not have to belong to the brand. A person's experience profile is a second rule set the same engine applies after the brand pass, on the brand-corrected tree, so it has the last word on presentation: type floor, contrast floor, line-height floor, density floor, reduced motion. It never touches the component allowlist, variants, or structure; those stay with the brand. Fixes reach for the brand's own tokens and scales first: a 18px floor on a 14px button becomes 20px, the smallest brand step that clears it, and a 7:1 floor the brand's blue cannot meet moves the button to the nearest brand pair that does.
type-below-floortext smaller than your floor; fixes snap up to the smallest brand type step at or above itcontrast-below-floortext under your contrast floor; fixes keep the background and move the text to a passing brand token, else the nearest passing brand pair, else black on whiteline-height-below-floorline height under your floorspacing-below-floorpadding under your density floor; fixes snap up to the brand spacing scalemotion-not-reducedautoplay or animation while your profile asks for reduced motion; fixes switch it offThree built-in profiles ship in the studio (low vision, dyslexia-friendly, reduced motion) and export as a JSON file you own. Import it back, or write your own, and the studio and the API both accept it under the same strict guard: an unknown rule or an out-of-range value is an error that names the field, never a silently dropped preference.
The enforcement path is pure math: WCAG contrast ratios, color distance, grid arithmetic, set membership. Same input, same output, every run; the public test suite pins it, including an end-to-end case where a raw A2UI wire stream produces the exact same five violations every time. That is the difference between glph and asking a model to review your UI: a guarantee, not an opinion.
POST an A2UI server-to-client stream to /api/check. Optionally include your own catalog; without one the demo catalog answers. Add "profile": "low-vision" (or dyslexia-friendly, reduced-motion, or your own rules) and the response gains an experience block: your verdict, your fixes, and a finalTree that honors both layers. GET the same URL for usage and a ready-to-POST sample.
curl -s -X POST /api/check -H "content-type: application/json" -d '{
"messages": [{
"version": "v0.9.1",
"updateComponents": { "surfaceId": "s", "components": [{
"id": "root", "component": "Button", "variant": "primary",
"background": "#3B82F6", "textColor": "#9CA3AF",
"paddingX": "13px", "fontSize": "13px"
}]}
}]
}'{
"ok": true,
"valid": false,
"summary": { "total": 4, "errors": 4, "byRule": { "color-not-token": 1, ... } },
"violations": [ ... found, expected, autoFix ... ],
"correctedTree": { ... the same surface, on brand ... }
}glph does not re-implement A2UI schema validation or catalog negotiation (the protocol already does both), does not render surfaces, and does not ask a model to judge taste. The wedge is the brand layer: designer-grade authoring over the catalog, and a deterministic guarantee over everything an agent emits against it.