---
title: "Astryx — AI affordances"
description: "Astryx is Meta’s design system, open-sourced on 18 June 2026 after eight years inside the company, where it grew to power over 13,000 apps. It is the clearest case in…"
url: "https://state-of-ai-in-design-systems.netlify.app/systems/astryx.md"
canonical: "https://state-of-ai-in-design-systems.netlify.app/systems/astryx"
type: "design-system-record"
json: "https://state-of-ai-in-design-systems.netlify.app/systems/astryx.json"
id: "astryx"
category: "design-system"
ai_maturity: "ai-native"
affordance_count: 10
technique_count: 9
data_collected: "2026-07-26/28"
generated: "2026-07-28T17:08:05Z"
report: "State of AI in Design Systems — July 2026"
author: "Kaelig Deloumeau-Prigent"
license: "CC-BY-4.0"
citation: "Deloumeau-Prigent, K. (2026). State of AI in Design Systems. https://state-of-ai-in-design-systems.netlify.app/systems/astryx.md"
---

> Snapshot of 2026-07-28. Every claim below links to the source URL it was taken from. Check the source before citing.

# Astryx — AI affordances

Meta · design-system · MIT · AI maturity: **ai-native** (AI consumption is a design goal, with dedicated surfaces and staff behind it). 10 affordances, 9 coercion techniques.

- Docs: https://astryx.atmeta.com
- Repo: https://github.com/facebook/astryx
- This record as JSON: https://state-of-ai-in-design-systems.netlify.app/systems/astryx.json
- This record on the site: https://state-of-ai-in-design-systems.netlify.app/systems/astryx

## Summary

Astryx is Meta’s design system, open-sourced on 18 June 2026 after eight years inside the company, where it grew to power over 13,000 apps. It is the clearest case in this study of a system rebuilt because of AI rather than adapted to it, and the team says so: “AI changed the economics of building UIs… we wanted to modernize on the latest browser technology, open up far more customization, and make the system AI-fluent by design rather than retrofitting it.” The architecture follows from that. The CLI is the source of truth and the docs site is a consumer of it, which is why `llms.txt` tells agents to stop crawling and run `npx @astryxdesign/cli` instead. Every command speaks a typed JSON envelope with append-only error codes an agent can branch on, and a `--dense` mode keeps the answers inside a context window. A hosted MCP server answers two tools that return real prop tables and compilable template source. What separates it is measurement. A nightly benchmark scores it against shadcn/Tailwind and raw HTML across six dimensions, and the 91-row ledger is public on the repo wiki with the losses left in. Over those 91 nights the shadcn baseline won 50, Astryx 19, Astryx-plus-Tailwind 9, and 13 were ties.

## Maintenance

- Actively maintained: yes
- Last release: v0.1.9 — 2026-07-27 (npm `@astryxdesign/core` 0.1.9 published 2026-07-27T19:20Z); prior: v0.1.8 (2026-07-23), v0.1.7 (2026-07-21), v0.1.6 (2026-07-15)
- Activity: Public since 18 June 2026 and moving fast. Nine releases in 31 days at a median gap of four days, 153 commits in the most recent full week against a 10-week peak of 226, and 16 changesets already pending on `main` the day after v0.1.9 shipped. 10,994 stars, roughly 69 contributors, 194 open issues and 163 open PRs against 3,245 closed. Ten stable packages version in lockstep through a changesets `fixed` group and publish from CI by npm trusted publishing over OIDC with `--provenance`, so there is no long-lived npm token in the pipeline. Still 0.1.x and labelled Beta, with no 1.0 date published.

## AI affordances (10)

### @astryxdesign/cli — the machine interface, and the source of truth

Type: `cli-scaffolding` (CLI scaffolding) · Official · Audience: both

Astryx inverts the usual arrangement: the CLI is the canonical docs and the website is downstream of it. Sixteen top-level commands (`init`, `build`, `search`, `docs`, `component`, `hook`, `template`, `layout`, `theme`, `swizzle`, `upgrade`, `discover`, `doctor`, `validate-integration`, `manifest`, plus an undocumented `blog`). `component Button` returns 20,128 bytes of markdown covering anatomy, do/don’t guidance, 19 typed props, theming variables and 96 related block templates. Global `--dense` and `--detail full|compact|brief` exist purely to manage context windows. `doctor` and `validate-integration` document their exit codes as “safe as a CI gate”. Eighteen fully-qualified command paths, counting subcommands like `theme build` and `layout expand`, also emit `{apiVersion, type, data}` envelopes under a global `--json`, gated by an allowlist checked before any side effect so a programmatic caller never gets partial state plus an error. Failures carry a stable `code` and Levenshtein `suggestions`; `astryx manifest --json` is a 23KB self-description of every command, flag and response type, and `@astryxdesign/cli/json` ships an `isError()` type guard.

- Docs: https://astryx.atmeta.com/docs/cli

- Code: https://github.com/facebook/astryx/blob/main/packages/cli/cli/index.mjs

Notes: `component` and `hook` need `@astryxdesign/core` installed in the project; without it the command exits 1 with `Error: Could not find @astryxdesign/core package`. Only `search`, `docs` and `blog` work from a bare `npx`. The error codes come with a stability promise the docs state plainly: “The code field is a stable, machine-readable identifier. Branch on it, never on the human-readable error string... Codes are append-only: once shipped, a code’s meaning never changes and a code is never removed.”

```text
It is the tool an agent uses to build with Astryx or as we like to think of it the interface for the machine.

…

Agents live in the terminal now. Give one a good tool and it uses it well. But most tools we hand agents are not good enough. So we made a call that the CLI is the docs. That is where every doc, example, and reference starts. The docs site you are reading is a consumer of the CLI and not the other way around. The CLI is the source of truth. An agent always reads the exact source we wrote and maintain. There is no second copy to fall out of sync. Nothing goes stale.
```

Source: https://astryx.atmeta.com/blog/the-astryx-cli

### Hosted MCP server at astryx.atmeta.com/mcp

Type: `mcp-server` (MCP server) · Official · Audience: consumers

A remote streamable-HTTP server (protocol 2025-06-18, `serverInfo` reports `astryx` 2.0.0) built on `mcp-handler` and zod, running as a Next.js route in the docs app. Stateless and unauthenticated: no session id is issued and `tools/list` answers without an `initialize` handshake. Exactly two tools, `search(query, limit)` and `get(name, section)`. They return content rather than links — `get("Button")` is a 10KB typed prop table, `get("settings")` returns the template’s actual source. The keyword index is derived from the same component `.doc.mjs` files that produce the human docs, so the machine surface cannot drift from them.

- Docs: https://astryx.atmeta.com/docs/cli

- Code: https://github.com/facebook/astryx/blob/main/apps/docsite/src/app/mcp/route.ts

Notes: Neither tool description contains coercion language of the kind Primer, Polaris or shadcn use. The strongest instruction in the whole surface is a parenthetical: “recommended for large topics like \”theme\” to avoid context overload”. The published config block on /docs/cli still keys the server `"xds"`, the name it carried before the June rename.

```javascript
/**
 * @file MCP Server route handler — hybrid v2 (search + get).
 *
 * Two tools:
 *   - search(): curated brief results with keyword-based resolution and scoring
 *   - get(): full component/topic/template details with examples
 *
 * Key features:
 *   - Keyword index derived from component .doc.mjs `keywords` fields
 *   - Compound component awareness (Table → sorting/selection hooks)
 *   - Context budget control (~1.5K tokens per brief result)
 *   - Showcase examples included in get() responses
 *
 * Transport: Streamable HTTP (via mcp-handler)
 */
```

Source: https://github.com/facebook/astryx/blob/main/apps/docsite/src/app/mcp/route.ts

### Generated agent context (`astryx init --features agents`)

Type: `agents-md` (AGENTS.md) · Official · Audience: consumers

Rather than publishing a rules file for people to copy, the CLI writes one into the consumer’s repo, generated from the installed package version so it matches the API actually present. Targets are picked per tool: `AGENTS.md` by default (“the tool-agnostic standard most agents read”), `.claude/CLAUDE.md` for Claude Code, and `--agent all` for every one. The preset list is ordered so the first existing file wins and the last entry is the default, which means `--agent cursor` only updates a `.cursorrules` that is already there and otherwise writes AGENTS.md. The docs page says it produces `.cursorrules`; in a clean project it does not. Content is a three-step discovery workflow, a rules block, a component count and a CLI reference, written between `` markers so it can be regenerated in place. The styling rule branches on whether the project runs StyleX, Tailwind or plain CSS, so it never recommends a path that is not compiled in that repo.

- Docs: https://astryx.atmeta.com/docs/working-with-ai

- Code: https://github.com/facebook/astryx/blob/main/packages/cli/lib/agent-docs/agent-docs.mjs

Notes: There is no URL at which this file can be read: it exists only after a consumer runs the CLI, so the snippet reproduces generated output and the link points at the generator that emits it. The styling rule shown is the StyleX branch; a Tailwind or plain-CSS project gets a different one. Astryx’s own repo has no AGENTS.md for the same reason. The file is small, about 2.4KB: it carries a component count taken from the installed package rather than an allow-list, and delegates the enumeration to `astryx component --list`.

```text
WORKFLOW — discover, don't guess. Before writing UI:
1. `astryx build "<idea>"` — START HERE: returns a kit (closest [page] + [block]s + [component]s). No args = full playbook.
2. `astryx template <name> [--skeleton]` — scaffold the [page]/[block]s it named, or study their layout. Templates are reference code.
3. `astryx component <Name>` — props + examples for every component you use.

RULES:
- No <div> — components do all layout/spacing. Full page → AppShell; sidebar nav → SideNav.
- Frame first: pick the shell (AppShell / Layout+LayoutPanel) and budget regions in px BEFORE
  writing content (`astryx docs layout`).
- Dense data = rows (Table, List/Item) edge-to-edge — never Card-wrapped list items. Card =
  dashboard widgets, galleries, settings groups only.
- Status → StatusDot/Token; Badge only for counts and enumerated states, never decoration.
- Custom styling: component props first; else the xstyle prop / StyleX tokens
  (@astryxdesign/core/theme/tokens.stylex). No raw hex/px.
- Tokens for every value (`astryx docs tokens`). Brand/accent via `astryx theme` — never
  override --color-* in :root.
- SELF-CHECK before you finish: re-read the file and replace any className=, style={{…}}, raw
  <div>/<span> layout, imported .css/@apply, or hardcoded #hex/px with the component or the
  xstyle prop + a token.
```

Source: https://github.com/facebook/astryx/blob/main/packages/cli/lib/agent-docs/agent-docs.mjs

### Public nightly vibe-test ledger

Type: `other` (Other) · Official · Audience: builders

A nightly benchmark scores agent-written UI on four targets: Astryx, Astryx plus Tailwind, a shadcn/Tailwind baseline, and raw HTML. Each run appends one row to a public wiki page. 91 rows from 2026-03-20 to 2026-07-28, plus a second table breaking Astryx across five of them for 32 nights. Six dimensions are scored: Correctness, Accessibility, Code Quality, Efficiency and Maintainability by static analysis, and Design by a vision model against designer-reviewed reference images. The losses are left in. Across the 91 nights the baseline wins 50, Astryx 19, Astryx plus Tailwind 9, and 13 are ties, and the most recent row is a loss (Astryx 95, Baseline 96). Each row links its source run issue. The stated purpose is regression detection against a competitor, not marketing.

- Docs: https://github.com/facebook/astryx/wiki/Vibe-Test-Scores

- Code: https://github.com/facebook/astryx/wiki/Vibe-Evaluation

Notes: The harness lives at `internal/vibe-tests/` with 62 designer-reviewed reference images across 55 prompt ids, a vision-model design judge, and a README stating “Known Accepted Asymmetries… they slightly favor baseline, making Astryx wins more credible”. Per-run output is committed to `vibe-test/nightly-*` branches and rendered reports are served at facebook.github.io/astryx/reports/, but nothing on astryx.atmeta.com links to any of it, and the explainer post is drafted on a branch and unpublished (/blog/vibe-tests is a 404).

```text
The nightly evaluation answers: **is Astryx measurably better than the alternatives?** If baseline (shadcn/Tailwind) consistently outscores Astryx, something is regressing — stale docs, growing API complexity, or conventions that fight mental models.

…

- **Decisions/element** — How many styling decisions the LLM had to make per UI element. Astryx typically scores ~1.7 vs ~2.3 for raw Tailwind. Lower is better — it means the system is absorbing complexity.
- **Semantic ratio** — What percentage of styling uses semantic tokens vs raw values. Higher means more maintainable, more themeable.
- **Escape hatches** — Did the LLM drop out of the design system to raw CSS/HTML? Where and why?
```

Source: https://github.com/facebook/astryx/wiki/Vibe-Evaluation

### /docs/working-with-ai

Type: `ai-docs-page` (AI docs page) · Official · Audience: consumers

The one docs page addressed to people setting up an agent. It gives a prompt to paste (“Install @astryxdesign/cli and run `npx @astryxdesign/cli init --features agents`…”), documents the per-tool file targets, and carries a three-question self-test for whether the setup took. The framing is unusually empirical: the three questions “have a 0% pass rate without docs; models confidently guess wrong on all of them”. It also names a failure mode observed in the wild, agents invoking the CLI through the wrong `node_modules` path, and prescribes an npm script alias to prevent it.

- Docs: https://astryx.atmeta.com/docs/working-with-ai

### astryx.atmeta.com/llms.txt

Type: `llms-txt` (llms.txt) · Official · Audience: consumers

A 1,180-byte file that refuses to be an index. Instead of listing docs URLs it tells the agent to stop reading the site and run the CLI, then lists five commands and warns that bare `npx astryx` resolves to an unrelated package. It is the only llms.txt in this study whose purpose is to redirect traffic off the website. There is no llms-full.txt and no markdown twin of any docs page; individual blog posts do have `.txt` mirrors.

- Docs: https://astryx.atmeta.com/llms.txt

Notes: It never mentions the MCP server. The two machine channels are documented in different places and do not reference each other.

```text
Everything on this docs site (component docs, props, variants, tokens, page
templates, and design rules) is also available through the Astryx CLI, in a
form built for agents to read. Instead of crawling these pages, use the CLI to
learn about Astryx directly. Some examples:

    npx @astryxdesign/cli search "<what you're looking for>"   # search components, hooks, docs, templates
    npx @astryxdesign/cli docs                                 # list reference docs, then: docs <topic>
    npx @astryxdesign/cli component <Name>                     # props, variants, examples for one component
    npx @astryxdesign/cli component --list                     # every component
    npx @astryxdesign/cli blog                                 # read the Astryx blog

Use the scoped name @astryxdesign/cli. Bare "npx astryx" resolves to an
unrelated package until the CLI is installed as a dependency.
```

Source: https://astryx.atmeta.com/llms.txt

### Root CLAUDE.md that hands maintainers the consumer CLI

Type: `claude-md` (CLAUDE.md) · Official · Audience: builders

7,737 bytes, and most of its imperative force sits in two generated blocks. The `ASTRYX-CLI` block gives maintainers a sub-500ms bootstrap sequence of the same commands consumers run, with rules attached: “always run bootstrap on each branch — docs reflect the branch’s actual API” and “always run `$ASTRYX component  --dense` before modifying a component”. The `STYLEX-CAPS` block is a pipe-delimited capability table ending in a VERIFY command. The effect is a loop: the people who maintain the machine interface are required to use it, so it cannot rot quietly.

- Code: https://github.com/facebook/astryx/blob/main/CLAUDE.md

Notes: The two generated blocks appear to be mirrored into the file by hand: `scan.mjs` writes `CAPABILITIES.md` and `capabilities.json`, and no CI job regenerates or drift-checks the copy inside CLAUDE.md.

```text
Astryx CLI|Run from repo root. Load agent docs before any component work.
ASTRYX="node packages/cli/bin/astryx.mjs"
BOOTSTRAP (run every branch, <500ms):
$ASTRYX help # discover all commands and options
$ASTRYX docs # list available doc topics
$ASTRYX docs principles --dense # design rules, anti-patterns, xstyle, tokens
$ASTRYX docs tokens --dense # spacing, color, radius, typography, shadow
$ASTRYX component --list # all components grouped by category
$ASTRYX template --list # available page templates
…
RULE: always run bootstrap on each branch — docs reflect the branch's actual API
RULE: always run $ASTRYX component <Name> --dense before modifying a component
RULE: after @astryxdesign/core bump, always run $ASTRYX upgrade --apply
```

Source: https://github.com/facebook/astryx/blob/main/CLAUDE.md

### .github/copilot-instructions.md plus four path-scoped instruction files

Type: `copilot-instructions` (Copilot instructions) · Official · Audience: builders

A 12KB repo-wide review policy for the Copilot reviewer, plus `applyTo`-scoped files for `packages/**` (35KB, the largest agent file in the repo), the docs site, CLI templates, and blog posts. The policy is written as severity rules rather than advice, and it tells the reviewer explicitly not to discount a finding because the trigger is unlikely or because a lint rule was already suppressed. Committed assistant fingerprints in any text are a blocking finding, alongside internal identifiers and @meta.com addresses.

- Code: https://github.com/facebook/astryx/blob/main/.github/copilot-instructions.md

Notes: The AI reviewer is advisory by design. `.github/REVIEW_GATE.md` states “Detection is **path-based and deterministic** (no LLM in the enforcement path)”, and a 29KB labeler workflow does the actual gating.

```text
## Blocking criteria — score the failure, not its likelihood

A finding's severity is set by **what breaks if it ships**, not by how likely
the trigger is, who wrote it, or whether a linter already flagged it. A rare
path to data loss is still a blocker; a lint-suppressed hardcode is still a
blocker. Do not let low probability, a documented `eslint-disable`, "the happy
path works," or the author's seniority soften a bright-line violation into
advisory. Score the failure first; use likelihood only to prioritize the fix,
never to decide whether it blocks.

…

**🔴 Always blocking:**

- **Hardcoded colors.** Every color is either a token — `var(--color-*)` — or
  **derived from tokens** via `color-mix()` / `light-dark()` / `calc()` whose
  inputs are vars. **No raw hex/rgb/hsl anywhere**, including as an argument to
  `light-dark()` or `color-mix()`, behind a `const`, or under an
  `eslint-disable`. "No suitable token exists" is **not** an exception
```

Source: https://github.com/facebook/astryx/blob/main/.github/copilot-instructions.md

### Graded template gallery as the exemplar corpus

Type: `registry` (Registry) · Official · Audience: consumers

Page and block templates, reachable by `astryx template` and by `astryx build ""`, which ranks them deterministically with no model and no network call and returns a composition kit. They are held to a published 100-point rubric where Astryx Component Purity is scored by counting raw HTML tags, and every gallery template must grade B or better. This is the concrete expression of the team’s stated strategy: fix what the model copies rather than arguing with it.

- Docs: https://github.com/facebook/astryx/wiki/Contributing-Templates

```text
Arguably what an LLM does best is copy. We all know it is much worse at coming up with original ideas... The answer was almost too simple. It was copying our bad examples. Garbage in, garbage out. The old saying still holds. That is why we wrote a grading rubric for templates. It scores every template the same way every time. Nothing sloppy slips through and a room full of designers can hold one bar. We fixed what the agent was copying and the output followed.

…

Instead of fighting the copycat we lean into it. We make good things. We put them where the agent will find them. And we let it copy.
```

Source: https://astryx.atmeta.com/blog/astryx-cli-build-command

### Claude Code slash commands (.claude/commands/)

Type: `other` (Other) · Official · Audience: builders

Two invocable maintainer workflows, `/create-component ` and `/create-theme `, each taking `$ARGUMENTS`. The component one is the whole contribution path in one file: seven files to create across `packages/core`, `apps/storybook` and the CLI’s showcase blocks, a required `isShowcase: true` marker, an export wired into `index.ts`, `node scripts/sync-exports.js`, then `pnpm build && pnpm test && pnpm lint` as the gate. It carries conventions in the same voice the consumer rules use: “Compose, don’t rebuild”, “displayName — always set it”, “all `:hover` in `@media (hover: hover)`“, “Spacing/elevation tokens — never raw px or boxShadow strings”. Notably it routes rather than instructs: the actual protocol lives on three GitHub wiki pages and the in-repo file keeps only a quick reference, so the resident context stays small.

- Code: https://github.com/facebook/astryx/blob/main/.claude/commands/create-component.md

Notes: `.claude/skills/` holds two more maintainer documents, on authoring component docs and on writing the compressed `docsDense` strings the CLI’s `--dense` mode serves. Both are plain markdown with no frontmatter, so they are context files rather than registered skills, and nothing loads or gates on them.

```text
Follow the full component lifecycle documented on the Astryx wiki:

- **Lifecycle Overview**: https://github.com/facebook/astryx/wiki/Component-Lifecycle
- **Specification Protocol**: https://github.com/facebook/astryx/wiki/Component-Specification-Protocol
- **Build Protocol**: https://github.com/facebook/astryx/wiki/Component-Build-Protocol

### Quick reference

- Read the spec thoroughly — it's the contract
- Study sibling components in the same family for patterns
- Create files in `packages/core/src/{ComponentName}/`:
  - `{ComponentName}.tsx` — main component
  - `{ComponentName}.test.tsx` — unit tests
  - `{ComponentName}.doc.mjs` — typed docs (ComponentDoc)
  …
- Run `node scripts/sync-exports.js` to update package.json exports
- Run `pnpm build && pnpm test && pnpm lint`

### Key conventions

- **Compose, don't rebuild** — use existing Astryx components (Field, Icon, etc.)
- **displayName** — always set it
- **:hover guards** — all `:hover` in `@media (hover: hover)`
- **Spacing/elevation tokens** — never raw px or boxShadow strings
```

Source: https://github.com/facebook/astryx/blob/main/.claude/commands/create-component.md

## Coercion techniques (9)

### The CLI is the docs, and the website is downstream

Category: `tool-gating` (Tool-gating) · all 21 in this category: https://state-of-ai-in-design-systems.netlify.app/techniques/tool-gating.md

Every doc, prop table and example originates in the CLI; the docs site and the MCP server read from the same `.doc.mjs` sources. Because there is no second copy, an agent that runs the CLI is reading the branch’s actual API rather than a rendering of it. llms.txt exists to push agents onto that channel.

```text
So we made a call that the CLI is the docs. That is where every doc, example, and reference starts. The docs site you are reading is a consumer of the CLI and not the other way around. The CLI is the source of truth. An agent always reads the exact source we wrote and maintain. There is no second copy to fall out of sync. Nothing goes stale.
```

Source: https://astryx.atmeta.com/blog/the-astryx-cli

### Fix the exemplars instead of the prompt

Category: `exemplars` (Exemplars) · all 11 in this category: https://state-of-ai-in-design-systems.netlify.app/techniques/exemplars.md

The team traced bad agent output to bad templates rather than to bad prompting, then wrote a 100-point grading rubric so every template in the gallery scores B or above. Component purity is scored by literally counting raw HTML tags: zero tags earns the full 30 points, 21 or more earns none. Exemplars ship at three sizes, page, block and component example, so retrieval can match the request.

```text
Quality rubric for grading templates. Use this to evaluate any template (page or block)
against the guidelines above. Every template in the gallery should score **B or above**.

### Grade Scale

| Grade | Score | Meaning |
|-------|-------|---------|
| **A** | 90–100 | Exemplary. Copy-paste ready. No excuses needed. |
| **B** | 75–89 | Good. Minor issues a reviewer would flag but approve. |
| **C** | 60–74 | Needs work. Would get "request changes" in review. |
| **D** | 40–59 | Poor. Significant rewrites needed. |
| **F** | 0–39 | Failing. Actively teaches bad patterns. |
```

Source: https://github.com/facebook/astryx/wiki/Contributing-Templates

### A self-check pass measured to cut escapes fourfold

Category: `validation-loop` (Validation loop) · all 30 in this category: https://state-of-ai-in-design-systems.netlify.app/techniques/validation-loop.md

The generated agent file ends by making the model re-read its own output and replace any `className=`, inline style, raw layout element, imported CSS or hardcoded value. The rule is there because it was tested: the code comment beside it records that rules alone still leave raw CSS in 11-13% of runs on complex UIs, and that the re-read pass cuts that roughly fourfold at negligible token cost. It is also the arm that won a three-way trial: a control that appends nothing, a one-paragraph re-read, and a four-step mandatory audit opening “STOP — MANDATORY SELF-AUDIT”. The cheap middle arm shipped, not the forceful one. `doctor` and `validate-integration` give the same loop a CI-safe exit code.

```javascript
// Self-check — post-generation pass. Validated via vibe tests (internal/vibe-tests/
// prompt-purity-test): on complex multi-step UIs the rules above alone still leave raw
// CSS in ~11-13% of runs; a re-read-and-fix pass cuts that ~4x at negligible token cost.
// The fix names the sanctioned escape hatch for the configured system.
```

Source: https://github.com/facebook/astryx/blob/main/packages/cli/lib/agent-docs/agent-docs.mjs

### Context budgeting as a flag, not a docs strategy

Category: `curated-context` (Curated context) · all 22 in this category: https://state-of-ai-in-design-systems.netlify.app/techniques/curated-context.md

Where other systems slice llms.txt by concern, Astryx puts the budget control in the tool. `--dense` rewrites prose rather than dropping structure, `--detail` offers full, compact and brief, and the MCP server guards against context bombs in code: topics over 4,000 characters come back as an overview plus a section list and a hint to request one section. Brief search results are budgeted at about 1.5K tokens each.

```javascript
          // Full topic — guard against context bombs
          const fullJson = JSON.stringify(doc);
          if (fullJson.length > MAX_TOPIC_BRIEF_CHARS) {
            const overview = doc.sections[0];
            return {
              content: [
                {
                  type: 'text' as const,
                  text: JSON.stringify(
                    {
                      topic: doc.topic,
                      title: doc.title,
                      description: doc.description,
                      overview: overview,
                      sections: doc.sections.map(s => s.title),
                      hint: `This topic is large (${doc.sections.length} sections). Use get("${doc.topic}", { section: "..." }) for specific sections to avoid context overload.`,
                    },
                  ),
                },
              ],
            };
          }
```

Source: https://github.com/facebook/astryx/blob/main/apps/docsite/src/app/mcp/route.ts

### Negative rules that name the component to use instead

Category: `prohibition` (Prohibition) · all 26 in this category: https://state-of-ai-in-design-systems.netlify.app/techniques/prohibition.md

The generated rules are prohibitions with a destination attached: “No  — components do all layout/spacing. Full page → AppShell; sidebar nav → SideNav”, “never Card-wrapped list items”, “Badge only for counts and enumerated states, never decoration”. The anti-patterns list served by `astryx docs principles` does the same, including the hallucination this study sees repeatedly: “❌ Inventing props. Read component docs first”. The register is prohibition and imperative throughout; there is no “must” and no “always” in the shipped rules.

```text
RULES:
- No <div> — components do all layout/spacing. Full page → AppShell; sidebar nav → SideNav.
…
- Dense data = rows (Table, List/Item) edge-to-edge — never Card-wrapped list items. Card =
  dashboard widgets, galleries, settings groups only.
- Status → StatusDot/Token; Badge only for counts and enumerated states, never decoration.
- Tokens for every value (`astryx docs tokens`). Brand/accent via `astryx theme` — never
  override --color-* in :root.
```

Source: https://github.com/facebook/astryx/blob/main/packages/cli/lib/agent-docs/agent-docs.mjs

### A typed, versioned interface agents can program against

Category: `other` (Other) · all 4 in this category: https://state-of-ai-in-design-systems.netlify.app/techniques/other.md

`{apiVersion, type, data}` envelopes across 18 commands, component data carrying name, TypeScript union type, default and required flag per prop, do/don’t guidance encoded as a boolean rather than prose, error codes promised to be append-only, and a capability manifest that describes the whole tool in one call. The manifest’s own header says it exists so an agent can discover the surface “without scraping `--help`“. Nothing else in this study offers agents a stability promise like it.

```json
Every command supports --json for machine-readable output. Responses are typed envelopes:

{"type": "component.detail", "data": {"name": "Button", ...}}

Errors:

{
  "error": "No component named \"Buttn\"",
  "code": "ERR_UNKNOWN_COMPONENT",
  "suggestions": [{"name": "Button", "reason": "similar name"}]
}
```

Source: https://astryx.atmeta.com/docs/cli

### Instruction files written into the consumer's repo, per tool

Category: `instruction-files` (Instruction files) · all 10 in this category: https://state-of-ai-in-design-systems.netlify.app/techniques/instruction-files.md

Astryx does not ask consumers to copy a rules file. `init --features agents` generates one from the installed version and writes it to the file the consumer’s tool actually reads, defaulting to AGENTS.md and injecting into an existing CLAUDE.md rather than overwriting it. Because it is generated per install, the component index and CLI reference inside it match the version in the project.

```javascript
/**
 * Agent tool presets — maps tool names to their file search paths.
 * Order matters: first existing file wins, last entry is the default (created if none exist).
 */
const AGENT_PRESETS = {
  claude: [CLAUDE_MD, CLAUDE_DIR_MD],
  cursor: [CURSOR_RULES, AGENTS_MD],
  codex: [AGENTS_MD],
  hermes: [HERMES_DOT_MD, HERMES_MD, AGENTS_MD],
};
```

Source: https://github.com/facebook/astryx/blob/main/packages/cli/lib/agent-docs/agent-docs.mjs

### Tokens or nothing, enforced on both sides of the repo boundary

Category: `token-enforcement` (Token enforcement) · all 14 in this category: https://state-of-ai-in-design-systems.netlify.app/techniques/token-enforcement.md

Consumers get “Tokens for every value” and “never override --color-* in :root” in their generated agent file. Contributors get the same rule as a blocking review criterion, written to close the usual escapes: no raw hex, rgb or hsl anywhere, including inside `light-dark()` or `color-mix()`, behind a `const`, or under an `eslint-disable`, and “no suitable token exists” is explicitly not an exception.

```text
- **Tokens, not raw values** — every visual value references a token; a raw
  color/space/radius/shadow in core is fixed by using the right token, never by
  swapping one raw value for another.
- **Spacing (relationship hierarchy)** — 4px grid; gaps step up with grouping
  (`label→input < fields < groups < sections`); flag monotonous spacing,
  inverted nesting (child gap wider than parent), off-grid values, nested cards.
```

Source: https://github.com/facebook/astryx/blob/main/.github/instructions/packages.instructions.md

### API naming settled by measuring what models reach for

Category: `other` (Other) · all 4 in this category: https://state-of-ai-in-design-systems.netlify.app/techniques/other.md

Astryx arbitrates API decisions by writing two versions of a component’s docs, throwing the same prompts at both, and shipping whichever one models use correctly. Issue #477 asked whether Selector should take `items` or `options`; PR #479 renamed it the same day. The decisive arm was neither documented variant but a no-docs condition measuring the model’s untutored prior. The shipped `Selector.doc.mjs` declares `options` and no `items` remains. Elsewhere agents are the audience for the design system; here they are an input to designing it.

```text
Renames the XDSSelector `items` prop to `options` based on vibe test results from #477.

## Vibe Test Results

Ran 8 prompts × 3 variants (24 sub-agents):
- **`items` (with docs)**: 1/8 confusion (about StyleX, not naming)
- **`options` (with docs)**: 0/8 confusion
- **No docs (LLM guesses)**: chose `options` 5/8 times, `items` 0/8 times

`options` aligns with HTML `<select>`/`<option>` semantics and matches Ant Design,
Chakra, MUI, and React Select conventions.
```

Source: https://github.com/facebook/astryx/pull/479

## Platform integrations (2)

### Storybook (addon-mcp, manifests, AI docs)

A published Storybook: 1,571 stories across about 170 story files, built from `apps/storybook` in the monorepo. The package is private and excluded from releases by a changesets `ignore` rule, so it ships as a site rather than as something a consumer installs.

Link: https://facebook.github.io/astryx/storybook/

### Figma (Dev Mode MCP server, Code Connect, Figma Make)

No official Figma library, and no Figma Code Connect: the string does not appear anywhere in the repo’s 4,484 tree entries. The gap is deliberate rather than overlooked. Issue #569 proposed a Figma plugin for theme sync with a full design and was closed in March with “Tabling this for now.” The two Astryx Figma libraries on the community site both describe themselves as unofficial. Design-to-code grounding is the one machine channel Astryx has not built.

Link: https://github.com/facebook/astryx/issues/569

## Building the system vs. consuming it

### For consumers (agents building UIs with Astryx)

Two parallel machine channels: a CLI that is the canonical source of docs, props and templates, and a hosted MCP server that answers search and get. A third channel writes rules into the consumer’s own repo, generated per install so it matches their version and their styling system. Coercion is mostly structural rather than verbal, and the one measured intervention, a self-check re-read pass, is in the shipped file.

### For builders (the Astryx team using AI on the system itself)

Maintainers are pointed at the consumer CLI by the root CLAUDE.md, with rules requiring a bootstrap on every branch and a `component --dense` read before editing a component. Review runs on a 12KB Copilot policy plus four path-scoped instruction files, though the enforcement gate is deliberately deterministic and model-free. The distinctive part is arbitration: conventions are settled by putting competing approaches in front of people and models and measuring, with the nightly ledger catching regressions in how usable the system is.

## Gaps

Not confirmed, or found wanting: 1) The invitation to stop crawling has a floor. `component` and `hook` need `@astryxdesign/core` installed, so a bare `npx` gets only `search`, `docs` and `blog`, and no hosted props manifest exists at any guessable path (/manifest.json, /components.json, /api/components.json all 404). Press coverage describing a fetchable JSON manifest is describing an npm-only artifact. Typed props are served, but only inside the Next.js RSC flight payload, so an HTML-only agent fetching a component page gets navigation and nothing else while /docs pages read fine. 2) `astryx init --features agents --agent cursor` is documented as writing `.cursorrules` and does not; in a clean project it writes AGENTS.md instead. 3) `component --list --json` on 0.1.9 leaks two prop-description strings, one untranslated Chinese, into its group keys, so an agent iterating categories gets two garbage entries. 4) Whether the eval harness scores as target-neutrally as its README claims was not assessed; the five scoring functions were not audited. 5) The per-arm results of the prompt-purity trial are not published. Only the aggregate reaches the open repo, as a source comment, so the effect size can be read but not checked.

## Sources (15)

- https://astryx.atmeta.com/llms.txt

- https://astryx.atmeta.com/docs/cli

- https://astryx.atmeta.com/docs/working-with-ai

- https://astryx.atmeta.com/blog/how-astryx-works

- https://astryx.atmeta.com/blog/the-astryx-cli

- https://astryx.atmeta.com/blog/astryx-cli-build-command

- https://github.com/facebook/astryx/blob/main/CLAUDE.md

- https://github.com/facebook/astryx/blob/main/.github/copilot-instructions.md

- https://github.com/facebook/astryx/blob/main/apps/docsite/src/app/mcp/route.ts

- https://github.com/facebook/astryx/blob/main/packages/cli/lib/agent-docs/agent-docs.mjs

- https://github.com/facebook/astryx/blob/main/.claude/commands/create-component.md

- https://github.com/facebook/astryx/wiki/Vibe-Test-Scores

- https://github.com/facebook/astryx/wiki/Vibe-Evaluation

- https://github.com/facebook/astryx/pull/479

- https://github.com/facebook/astryx/blob/main/internal/vibe-tests/prompt-purity-test/variants/C-strong.md

---

Generated 2026-07-28T17:08:05Z from the State of AI in Design Systems — July 2026 dataset. Index of every machine-readable file: https://state-of-ai-in-design-systems.netlify.app/llms.txt. JSON, SQLite and the MCP endpoint: https://state-of-ai-in-design-systems.netlify.app/ai.md. Kaelig Deloumeau-Prigent, CC BY 4.0.
