Button.stories.tsxProps, variants, interactive controls
design-system.htmlVisual tokens, component gallery, brand voice
Button.agent.jsonSemantic categories, governance rules, intent mapping
TypeScript gives the agent the shape of a component. Storybook gives a developer the feel. Neither tells an AI agent when to use it, what rules to follow, or how to resolve a user's intent to the right variant. That's what the agent file adds.
Four things a React component doesn't have
Each addition comes from a specific finding at IDS 2026. Each one closes a gap between what the agent knows and what it needs.
semantic_category
"variant": {
"type": "union",
"values": ["primary", "secondary", "tertiary", "ghost"],
"semantic_category": "visual_hierarchy",
"usage_rules": [
"Use 'primary' for the single most important action per section",
"Maximum one primary button per visible viewport"
]
}A normal React button has a type definition. An agent-readable button tells the LLM what the prop controls semantically — not just that it accepts a string, but that it governs visual hierarchy. Diana Wolosin proved this single addition closes an 18-point accuracy gap.
governance
"governance": {
"trust_level": "verified",
"rules": [
"Never hardcode hex values — the variant system handles all colour",
"Maximum one primary button per visible viewport section",
"Button text must be verb-first: 'Book a Chat', not 'Chat Booking'"
],
"antipatterns": [
"Do not wrap Button in an <a> tag — use the href prop instead",
"Do not use className to override variant colours"
]
}TypeScript tells the agent what a button can do. Governance tells it what a button should do. Romina Kavcic introduced trust levels as programmable signals — a 'verified' component can be used without human review. The antipatterns array is enforceable: an agent that reads this will not wrap a Button in an anchor tag, even if the prompt asks it to.
maps_to_intent
"knowledge_graph": {
"maps_to_intent": {
"call_to_action": { "variant": "primary", "size": "md" },
"schedule_meeting": { "variant": "primary", "size": "lg",
"href": "https://cal.com/lincmitch" },
"supporting_action": { "variant": "secondary", "size": "md" },
"navigation": { "variant": "tertiary" }
}
}A normal button component requires the developer to know which variant to use. An agent-readable button lets the LLM resolve intent directly to props. 'I need a call to action' resolves to variant='primary' without guessing. Jesse Gardner built this pattern as an MCP server at NYS. At portfolio scale, flat JSON achieves the same routing.
tokens
"tokens": {
"primary": {
"background": "linear-gradient(135deg, #2563eb, #8b5cf6)",
"text": "#ffffff",
"shadow": "0 0 20px rgba(37, 99, 235, 0.25)",
"hover": "filter: brightness(1.1)"
},
"secondary": {
"background": "transparent",
"text": "#b4c5ff",
"border": "1px solid rgba(255, 255, 255, 0.1)"
}
}The agent doesn't need to parse Tailwind classes or trace CSS custom properties through a stylesheet. The token block gives it resolved values directly — what each variant actually looks like. Jan Six's colocation principle: Button.tsx, Button.stories.tsx, and Button.agent.json sit in the same folder. Three files, three audiences, zero drift.
Why JSON, not Markdown
Diana Wolosin benchmarked 8 metadata configurations across 4,389 AI-generated prototypes at Indeed. JSON with semantic annotations won on every metric.
Source: Diana Wolosin, “Machine-Readable Design Systems for MCP and LLMs” — Into Design Systems 2026
Three files. Three audiences.
src/components/ui/ Button.tsx → code Button.stories.tsx → stories Button.agent.json → agent context
CLAUDE.md routes agents to these files. The *.agent.json glob means a future MCP server can index every agent file in the repo without configuration. At portfolio scale, the flat file is enough. At enterprise scale, you wrap it in a server. The content is the same — the delivery mechanism changes.
The design system is the N layer. The agent files are how N becomes consumable.