Skip to content

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.

SurfaceURLQuestion 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.colors as 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 — by css_var or name, 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.

Fetch the manifest and schema in parallel on boot, validate once, hold the result in memory. Pin against version.
Don't string-match the bundle for a token value. The manifest gives you a typed lookup; the bundle is for prompt injection.

Cross-references

  • The reference shape for each surface lives at Agents.
  • Voice rules in long form: Voice & casing.
  • The full token catalogue: Tokens.

On this page