Appearance
A design system agents can read
An agent needs a checkbox. It fetches a 20 kilobyte stylesheet, scans hundreds of selectors, guesses which tokens are public, and writes custom CSS anyway. The browser needed the stylesheet. The agent needed one labelled example and three rules.
A design system for generated apps has two interfaces. Browsers load versioned CSS, JavaScript, fonts, and examples. Agents query a compact specification by section and name. Mixing those jobs wastes context and encourages unsupported styles.
This follows the browser-testing contract in Browser tests for generated apps. Checks become more useful when generated pages start from known, tested components.
Concept map
text
release source -> immutable browser assets
-> validated specification
-> query tool -> agentThe source can be complex. The release contract must be small, named, and stable.
Terminology
Release is one immutable version of all design assets and its specification.
Browser asset is CSS, JavaScript, a font, an example module, or another file loaded by the app.
Agent contract is structured documentation exposed through bounded queries.
Class index is a list of supported classes with one-line purposes.
Component entry describes native markup, states, and accessibility rules for one control.
Behavior entry documents optional JavaScript needed when HTML and CSS are not enough.
Integrity metadata records hashes and byte sizes for release files.
Current release is the default for new apps. Older releases remain available at their exact URLs.
Build two outputs from one source
The release builder should produce immutable assets such as:
text
/design/1.5.0/mini.css
/design/1.5.0/mini.js
/design/1.5.0/fonts/body.woff2
/design/1.5.0/spec.json
/design/1.5.0/examples/settings.htmlThe browser imports exact URLs. No latest alias belongs in generated source. The specification names the same URLs, versions, classes, tokens, components, behaviors, examples, accessibility rules, and audit thresholds.
Validate the specification during the build. Check that documented classes exist in CSS, named behaviors are exported by JavaScript, example files exist, and every asset has size and integrity metadata. A stale spec is more dangerous than no spec because the agent will produce plausible but invalid code.
Once released, never change bytes at an existing version. Fixes require a patch release. Long-lived generated apps may keep old URLs in caches, service workers, and published source. Replacing an old file can change an app without a new app revision or deployment.
Query the contract
An agent tool should answer focused questions:
json
{"section": "components", "name": "checkbox"}The result might include:
html
<label>
<input type="checkbox" name="alerts">
Email me when the report is ready
</label>It should also say that the label row is the touch target, the input keeps native checked state, and no custom class is required.
A start query can return:
- Exact CSS and optional JavaScript URLs.
- The current version and integrity values.
- A class index with one-line descriptions.
- Available component, layout, behavior, and recipe names.
- Core rules for viewport, focus, reduced motion, and colour use.
Keep start small enough to read once per build. Detailed entries come through later queries. Unknown names should return nearest matches and the relevant index. An error saying only "unknown component" causes another search round.
Why agents should not read raw CSS
Raw CSS is an implementation artifact, not an agent interface.
First, it is expensive. A stylesheet includes resets, compatibility rules, media queries, fallbacks, and internal selectors that do not help with one component.
Second, CSS does not explain intent. A selector can show that a row has min-height: 44px; it does not say that the row, rather than the 22-pixel checkbox, is the intended touch target.
Third, agents may treat internal tokens as public. They copy a variable used once in a fallback, then later lint or release changes break the app.
Fourth, source order hides the supported combinations. A spec can say that tabs require one named behavior, while a list needs no JavaScript.
Finally, letting agents read raw assets rewards brute-force context use. A queryable contract makes the cheapest action the correct one.
Static checks should reinforce the boundary. Reject unknown --mini-* token references. Warn when apps redefine body fonts, add a second accent system, or implement effects already owned by the design release. Tell the agent which query returns the supported option.
Prefer native markup
Native HTML is a good component API for generated static apps. Labels, inputs, selects, textareas, details, progress, dialog, and buttons already carry browser behavior and accessibility semantics.
Add classes for layout and composition: stacks, clusters, panels, action rows, rich lists, metrics, sticky headers, sheets, screen stacks, and empty states. Use optional JavaScript only for behavior the platform does not provide consistently, such as roving tab focus, keyed list movement, or retained navigation stacks.
Behavior modules should be explicit and idempotent. Importing them should have no side effects. An initializer should return a controller with a repeatable destroy() method.
This keeps generated code short. Prebuilt asset lines cost nothing in the model's output, while copied control CSS and focus code cost tokens and create defects.
Budgets keep releases honest
Set gzip ceilings for CSS, JavaScript, and fonts. The exact numbers depend on the product, but the build should fail when a release crosses them.
Record actual byte counts in the manifest. Separate budgets prevent a small script from hiding inside one large aggregate. Examples and specs need their own practical response limits because they enter agent context.
One accent hue can derive a full colour ramp. One tested type pairing can remove per-app font work. A small glass treatment can be available for fixed chrome while falling back to opaque surfaces under reduced transparency or missing browser support. The point is controlled reuse, not visual novelty.
Decisions and rejected alternatives
Publish exact versions. A floating URL silently changes existing apps.
Expose structured queries. Raw CSS reads consume context and reveal unsupported internals.
Use native HTML as the default component layer. A custom component runtime adds bundle weight and more generated glue.
Add optional JavaScript by named behavior. A global script that scans the whole document creates hidden coupling.
Keep old releases immutable. Forced migration turns design work into a fleet-wide risk.
Enforce token validity. A misspelled variable that falls back to an arbitrary value should fail static checks.
Test examples in browsers. Documentation markup that never renders is not a contract.
Failure modes
The spec lists a class absent from CSS. Cross-check class names during the release build.
A patch overwrites an old version. Generate content hashes and refuse changed bytes under existing paths.
The agent imports JavaScript for CSS-only controls. Mark each entry's runtime requirement.
Examples violate production content security policy. Use external modules instead of inline initialization when the target policy blocks inline scripts.
Font loading changes layout. Ship metric-matched fallbacks and test both loaded and fallback states.
Unknown queries throw without help. Return nearest names.
The design tool returns the entire spec. Index first, detail on demand.
Apps invent custom tokens. Lint undefined names and point back to the token query.
Field checklist
- Does every app import an exact design version?
- Are old release bytes immutable?
- Does one validated spec describe all public assets and names?
- Can an agent query one component, layout, token, behavior, or recipe?
- Does the start response include a compact class index?
- Do unknown names return useful suggestions?
- Are CSS, JavaScript, font, and prompt-response sizes budgeted?
- Do release tests render every example at phone and desktop sizes?
- Are native controls preferred where possible?
- Are JavaScript behaviors explicit, idempotent, and removable?
- Does lint reject undefined public tokens?
- Does guidance tell agents not to read raw CSS?
A readable design system supplies the pieces. Generated apps still need rules for arranging those pieces on small screens and moving between views. Mobile navigation and motion covers those interaction mechanics.