2 September 2026
Your Design Tokens Need to Be Machine-Readable Before Your Agents Are
Agents do not read Figma. They read JSON and CSS custom properties. Here is how I structure NIL DS tokens so Cursor can actually use them.
Loading…
2 September 2026
Agents do not read Figma. They read JSON and CSS custom properties. Here is how I structure NIL DS tokens so Cursor can actually use them.
Loading…
Passing a Figma link to a coding agent and expecting brand-consistent UI is like handing a junior dev a screenshot with no spec. They will guess. They will invent #F4F5F7 because something similar lived in a legacy file. They will pick padding: 18px because it looked balanced in the moment.
That is not an intelligence problem. It is a data problem. Agents parse text — JSON, CSS variables, type definitions — not layout hierarchy on a canvas.
When I orchestrate UI work in Cursor, the agent searches the repo for patterns it can copy without improvisation:
tokens.json, generated CSS)--nil-*)Figma is still where I think visually. It is not the source of truth for build agents. The source of truth lives in files the model can grep.
Full three-tier token systems (primitive → semantic → component) are the north star. NIL DS v0.1 ships the spine: primitive values, semantic aliases, components that only read --nil-*.
Primitive — raw material. Names describe what, not where:
"spacing": {
"xs": { "value": "4px" },
"md": { "value": "16px" },
"lg": { "value": "24px" }
},
"color": {
"accent": { "value": "#1752eb", "note": "Locked brand accent" }
}
Semantic — purpose. References primitives. Theme-aware where it matters:
"spacing-md": { "ref": "primitive.spacing.md" },
"light": {
"color-bg": { "ref": "primitive.color.neutral-900" },
"color-accent": { "ref": "primitive.color.accent" }
}
Component — in v0, this lives in the component layer and registry.json, not a third token file. A Panel reads --nil-color-surface and --nil-spacing-md. It never touches --nil-primitive-*.
That split is deliberate. Version zero does not need a Figma sync pipeline. It needs a file an agent can open and treat as law.
--nil-* namespaceAgents pattern-match on names. Inconsistent naming is how you get drift.
NIL uses a closed prefix:
--nil-primitive-* — raw values (build pipeline only)--nil-* — what components and pages consumeExamples from generated CSS:
--nil-primitive-spacing-md: 16px;
--nil-spacing-md: var(--nil-primitive-spacing-md);
--nil-color-bg: #f3f2ee;
--nil-color-accent: #1752eb;
When I prompt for a settings panel, the agent can search for --nil-color-surface instead of guessing a background. The namespace tells it category and role before it reads the value.
Being agent-ready is not:
Being agent-ready is:
For NIL, the v0 distribution method is copy-paste: tokens.json → npm run tokens:build → import tokens.css in the consumer. TetherLog and the portfolio site wire it the same way. The delivery mechanism can mature later. The architecture cannot wait.
Without tokens, the feedback loop is visual — slow, subjective, easy to ship plausible garbage.
With tokens, the loop is mechanical:
--nil-spacing-* and kit primitivesAGENTS.md / lintThe agent is not applying design taste. It is navigating a state machine you defined.
I am building NIL DS as the proof stack for this — brutalist CLI lineage, IBM Plex, accent #1752eb, showroom in Vite. Private repo for now; the patterns are what I audit and ship under Keel AX when teams need agent-ready UI infrastructure.
If your agents keep inventing spacing and colours, check the spine before you blame the model. Machine-readable tokens first. Agents second.