Agent consumption
The canonical reference for what each agent surface contains lives at Agents. This page is the how-to: the call shapes, the validation step, the version-pinning policy, and the routing pattern for surfacing Matter's voice rules to a downstream model.
Three surfaces, three jobs
Each surface answers a different question, and the right agent code fetches a different one for each.
| Surface | URL | Question it answers |
|---|---|---|
| Structured manifest | /design-system.json | "What is token --foo? Which components exist?" |
| JSON Schema | /design-system.schema.json | "Did the manifest match the contract I built against?" |
| Flat-text bundle | /llms-design.txt | "Inject the whole corpus into my system prompt." |
All three are served from https://design.mattermode.com. CORS is open; responses cache for an hour. The manifest and the bundle regenerate on every build of apps/design; the schema regenerates only when the payload shape changes.
When to use which
Reach for the manifest when the agent needs a deterministic value lookup — a token, a component import path, a voice rule. Parse once, query in-memory, never inline string-match the source MDX.
Reach for the schema at agent boot, once, alongside the first manifest fetch. Validate before reading. A schema-validated manifest lets every downstream call assume shape — there's no defensive if (manifest?.tokens?.colors) once validation passes.
Reach for the bundle when the agent is composing a system prompt for a downstream model. The bundle is concatenated MDX with light per-page framing — no JSON parsing, no schema check. Drop it in alongside the model's instructions, then let the model reason against the corpus.
A typical agent fetches the manifest and the schema once on boot, validates, holds the manifest in memory, and re-fetches only when the user signals a version mismatch. The bundle is fetched on-demand by whichever subsystem composes prompts.
Worked example — fetch, validate, look up
The complete flow for an agent that resolves a Matter token reference into its concrete CSS variable and value. Uses Ajv for validation; any JSON Schema draft 2020-12 validator works.
import Ajv2020 from "ajv/dist/2020";
const SITE = "https://design.mattermode.com";
// 1. Fetch both surfaces in parallel.
const [manifest, schema] = await Promise.all([
fetch(`${SITE}/design-system.json`).then((r) => r.json()),
fetch(`${SITE}/design-system.schema.json`).then((r) => r.json()),
]);
// 2. Validate. If the manifest doesn't match, the upstream contract has
// shifted — fail closed rather than guess.
const ajv = new Ajv2020({ strict: false });
const validate = ajv.compile(schema);
if (!validate(manifest)) {
throw new Error(
`manifest failed validation against ${manifest.version}: ` +
JSON.stringify(validate.errors, null, 2)
);
}
// 3. Look up a token. Manifest is an in-memory object — no further fetches.
const orange = manifest.tokens.colors.find(
(c) => c.css_var === "--color-matter-orange"
);
// → { name: "matterOrange", css_var: "--color-matter-orange",
// value: "#F89866", source: "brand",
// ts_path: "packages/brand/src/tokens/index.ts#colors.matterOrange",
// group: "Brand" }
console.log(`Resolved ${orange.name} → ${orange.value} (${orange.source})`);Three properties of this flow are load-bearing.
- Parallel fetch. Manifest and schema are independent — fetch them on the same tick, not sequentially.
- Validate before reading. Validation is the contract. Downstream code reads
manifest.tokens.colorsas if it's always present, because the schema guarantees it is. - In-memory lookup. Once parsed, the manifest is a few hundred KB of structured data — never re-fetch per query.
Version pinning
The manifest carries a version field that mirrors packages/tokens/package.json#version (currently 2.3.0). Pin your agent against it.
const MIN_VERSION = "2.3.0";
if (semverLt(manifest.version, MIN_VERSION)) {
throw new Error(
`Matter design system at ${manifest.version}, agent requires ≥ ${MIN_VERSION}`
);
}The version follows semver. Patch bumps add tokens or fix documentation — agents pinned to a minor band stay compatible. Minor bumps may add new token kinds or new component categories — re-validate against the schema, but existing lookups stay correct. Major bumps are reserved for renames or removals — agents must re-test.
On version mismatch, fail closed. Reaching for a token that no longer exists, or trusting a component shape that's been renamed, will produce wrong UI rather than missing UI. The wrong UI is harder to detect.
System-prompt injection
The flat-text bundle is the single artefact for "give the downstream model full design context." It's regenerated on every build from the same source the human site renders from — the corpus stays in sync without a per-agent ETL.
const bundle = await fetch(`${SITE}/llms-design.txt`).then((r) => r.text());
const systemPrompt = [
`You are an agent generating Matter-branded UI.`,
`The full Matter design system is included below as canonical context.`,
`Honour every voice rule. Quote tokens by CSS variable name.`,
``,
bundle,
].join("\n");The bundle is the corpus, not a summary. Don't paraphrase it before injection — the rules are precise, and paraphrase loses precision. If the bundle is too long for the model's context, prefer fetching /api/raw/<slug> for the relevant pages over summarising — the per-page raw MDX is the same canonical source, scoped narrower.
Voice rules, machine-readable
The voice contract — the rules that govern every line of copy Matter ships — surfaces under voice.rules[] in the manifest. Every rule is a structured object an agent can route on, not a paragraph it has to interpret.
const rules = manifest.voice.rules;
// → [
// { id: "no-competitor-comparisons", scope: "global",
// summary: "Never compare Matter to other products by name." },
// { id: "sentence-case-ui", scope: "ui",
// summary: "Sentence case for every UI surface." },
// { id: "two-word-title-case-buttons", scope: "buttons",
// summary: "Two-word Title Case for buttons." },
// …
// ]
function lintCopy(text, scope) {
return rules
.filter((r) => r.scope === scope || r.scope === "global")
.map((rule) => ({ rule: rule.id, pass: runRule(rule.id, text) }));
}An agent that generates UI copy can run the rules against its own output before returning. An agent that reviews copy can return rule-by-rule findings. The contract is the same; the direction reverses.
MCP, when available
The same surfaces are exposed as MCP tools, available via MCP if Matter's MCP server is connected:
mcp.design.getToken— bycss_varorname, returns the same row shape as the manifest.mcp.design.listComponents— returns the components array.
The MCP tools are a convenience layer over the HTTP surfaces — semantically identical, with the agent's existing transport. An agent built against the manifest works without MCP; an agent built against MCP works without re-fetching the manifest. Pick whichever transport the host already speaks.
version.Cross-references
- The reference shape for each surface lives at Agents.
- Voice rules in long form: Voice & casing.
- The full token catalogue: Tokens.