For agents
Context ships with the code. A rule in prose is advice; a rule in a hook, a type or a lint check is enforced (DECISIONS.md #16). This page is what Claude reads, and how it gets there.
The plugin
A Claude Code plugin with a skill, hooks, a reviewer agent and MCP config. The CLI installs it; it can also be added from the marketplace.
claude plugin marketplace add Cristian-pineda/MACAW-Design-System
claude plugin install macaw- using-macaw skill: generated reference files for every component and token, loaded on demand.
- Hooks: lint after every edit, and run the project's verify script before a turn ends.
- macaw-reviewer agent: a fresh-context review for label association, heading order, one primary action and aria-label on icon-only buttons.
- MCP config: connects the
macawserver below.
The CLAUDE.md block
init writes this block into the consumer's CLAUDE.md. It stays short and points at the skill.
<!-- macaw:start -->
# MACAW design system
- UI comes from @macaw-ds/ui only (Icon from @macaw-ds/icons). Never write a component that exists there; read the `using-macaw` skill first.
- Colours, spacing, type, radius, shadow, motion: MACAW token utilities only (bg-action-primary, p-4, text-body-md, rounded-control). Never hex, never px, never bg-[...], never Tailwind's default palette.
- Never pass className or style to a MACAW component. Variants are typed props. If a variant is missing, stop and propose it; do not work around it.
- Every string goes through <Text>. Money, counts and dates use <Text numeric>. Every <Input> has a visible label.
- Light and dark are token modes; never branch on theme in component code.
- Run the project's verify script (pnpm verify or npm run verify) before reporting done and show the output.
- If a request needs something not in the system, stop and say `not-in-system: <what>` instead of improvising.
- Details live in the using-macaw skill; the component manifests are the contract. Ask the macaw MCP server (`validate`) when unsure.
<!-- macaw:end -->The CLI
One door for humans and agents alike.
npx @macaw-ds/cli init # packages, stylesheets, plugin, CLAUDE.md block
npx @macaw-ds/cli add button # wires the import, prints the starter snippet
npx @macaw-ds/cli add button --eject # copies the source in; recorded in .macaw/ejected.json
npx @macaw-ds/cli diff # (0.2) what ejected copies are behindMCP tools
@macaw-ds/mcp exposes the generated registry over four tools.
| Tool | Returns |
|---|---|
| list_components | Every component at the installed version with its status, category and purpose. Ask this before writing a component that might exist. |
| get_component | The full manifest for one component: props, rules, accessibility contract, tokens used, examples and the starter snippet. |
| get_tokens | The token metadata with light and dark values, so colour, space and type decisions resolve to real utilities. |
| validate | Lints a JSX snippet with the consumer rules and reports className on MACAW components, raw values and not-in-system components. |
The manifest is the contract
Every component carries a schema-validated manifest. One source feeds the playground, the props table, the registry, the skill and the MCP tools.
The JSON schema is published at /schema/manifest.schema.json. A manifest declares props (with the control each one gets), a11y (role, keyboard, name computation, notes), tokens, rules, dos and donts, examples and a bundle budget.
{
"name": "Button",
"slug": "button",
"purpose": "Triggers an action. Not navigation; for links use asChild with an anchor.",
"props": {
"variant": { "type": "enum", "values": ["primary", "secondary", "ghost", "destructive"], "default": "primary", "required": false, "description": "…" }
},
"a11y": { "role": "button", "keyboard": ["Tab: focus", "Enter, Space: activate"], "name": "From the visible label (children)", "notes": [] },
"rules": ["One primary button per view."],
"budget": { "gzip": 4000 }
}Each manifest is also served as JSON at /r/<slug>.json in shadcn registry format, which is what add --eject and npx shadcn add read.