Run: agents do the routine work, people make the decisions

A design system is no longer a library you publish. It is a service you run. Run keeps the system current with agents that work under your rules: they read the system, check their own work, propose what is missing and record why. People set how far they may go.

Any agent can read your system

Loom's MCP server gives AI coding agents your system, not a guess at it. Any agent that speaks MCP, on any model, can use it. Working

The server has 17 tools:

  • search_system: find components, tokens and patterns, with a confidence level and an honest "no strong match".
  • get_entity: read a full component contract, with the exact import.
  • get_tokens: read token values and roles.
  • get_guidelines: read guidance, or learn that it is missing.
  • get_rules: list every rule, who enforces it, and its exceptions.
  • get_design_md: get the whole system as one DESIGN.md file, generated from the same records.
  • check_composition: check a draft before it is written.
  • audit_code: find drift in existing files.
  • propose_change: open a draft for review, labelled as AI-generated.
  • intake_need: decide whether a need is reuse, extend or new.
  • list_unmet_needs: see what agents asked for and could not find.
  • get_flow: read a governed flow (onboarding, payment and the like), its locked steps and whether it is signed off.
  • search_illustrations and get_illustration: find an approved illustration or icon, with its alt-text guidance.
  • search_content and get_content: find the approved wording for a label or message, with tone, length and plural forms.
  • get_localisation: see which languages are required and which strings are still unreviewed.

It also serves four resources (the system overview, all tokens, the DESIGN.md file, one contract per component) and one prompt that walks an agent through building on the system.

Recording of real output

A recorded session: a scripted agent against Loom Base, our own design system (MIT), with real server output. The replay types each call as the agent sent it and shows each result after its recorded latency, shortened for the page. Server output is in English.

Agent session · recorded session

  1. Agent

    I need a destructive "delete workspace" action with a confirmation. What does the system have?

  2. Loom · search_system · 145 ms→ search_system({"query":"delete confirm danger","kind":"component","limit":5})

    20 results for "delete confirm danger" (lexical ranking). Top: Dialog (dialog, 0.8, beta), ConfirmAction (confirm-action, 0.46, beta), ToastRegion (toast-region, 0.41, beta), Tag (tag, 0.27, beta), Alert (alert, 0.25, beta)

    • Dialog (dialog, strong, confidence 0.8) — import { Dialog } from "@loom/base/native";• ConfirmAction (confirm-action, partial, confidence 0.46) — import { ConfirmAction } from "@loom/base/native";• ToastRegion (toast-region, partial, confidence 0.41) — import { ToastRegion } from "@loom/base/native";
  3. Loom · get_entity · 34 ms→ get_entity({"id":"Button"})

    Button: Starts an action in the current view: save, publish, open a dialog, run a check.

  4. Agent

    Here is my first draft. It reaches for an MUI Modal, guesses a variant prop, uses two primary buttons and hard-codes a colour and a margin.

  5. Loom · check_composition · 48 ms→ check_composition({"tsx":"import { Card, Button, Heading, Text } from \"@loom/base/native\";\nim…"})

    Off-system: 3 errors, 2 warnings across 6 nodes.

    - [warning] Text has style set: overriding a system component's styling is drift from its contract. → Customise through the component's slots, variants or overridable tokens wit…- [error] Button has no "variant" prop. → Did you mean "tone" ("primary" | "secondary" | "quiet" | "danger")? primary: the one main action in a view; secondary: other actions; q…- [error] <Modal> is not part of Loom Base (imported from "@mui/material"). → Closest system components: AILabel (ai-label), Dialog (dialog), Drawer (drawer). If none fits, draf…
  6. Loom · check_composition · 5 ms→ check_composition({"tsx":"import { Card, Button, Text, Stack, ConfirmAction } from \"@loom/bas…"})

    On-system: 0 errors, 0 warnings across 5 nodes.

    components: Card, Stack, Text, Button, ConfirmAction
  7. Loom · audit_code · 117 ms→ audit_code({"files":[{"path":"src/settings/SettingsPage.tsx","source":"import React from \"react\";\nimport { Button as MuiButton, Dialog…

    Drift found: 11 errors, 11 warnings — 7 colours, 9 dimensions, 1 non-system import, 1 re-implemented component.

    ✗ src/settings/settings.css:2 Hard-coded colour #fffdf8 (background). → Use var(--base-color-palette-cotton-0) ().✗ src/settings/settings.css:5 Hard-coded dimension 16px (padding). → Use var(--base-space-scale-6) (16px).✗ src/settings/settings.css:5 Hard-coded dimension 20px (padding). → Use var(--base-space-scale-7) (20px).
  8. Loom · get_guidelines · 11 ms→ get_guidelines({"topic":"illustration"})

    Guidelines for illustration: missing. 0 sections. Missing: Loom Base has no dedicated illustration guideline. Do not invent one: follow existing foundations, and use propose_change (kind "guideline") to draft it for review.

    missing: Loom Base has no dedicated illustration guideline. Do not invent one: follow existing foundations, and use propose_change (kind "guideline") to draft it for review.
  9. Agent

    Research uploads need a drag-and-drop file area. Nothing in the system does that, so I will draft a proposal rather than ship a one-off.

  10. Loom · propose_change · 399 ms→ propose_change({"kind":"component","title":"FileDropzone","need":"Researchers attach interview recordings and notes to a journey. Set…","…

    Draft component-filedropzone-6af1d4b4 written to drafts/component-filedropzone-6af1d4b4.json (status: proposed, labelled AI-generated, not yet human-reviewed). Intake: extend. 7 existing alternatives listed; impact: 5 declared dependents.

    impact: 5 declared dependents (partial graph)status: proposed; system source modified: false
  11. Loom · check_composition · 69 ms→ check_composition({"tsx":"import { Modal } from \"@mui/material\";\nimport { Button } from \"@loo…"})

    Off-system: 4 errors, 5 warnings across 6 nodes.

    - [warning] Raw <h1> used where the system provides Heading. → import { Heading } from "@loom/base/native";- [error] Button has no "variant" prop. → Did you mean "tone" ("primary" | "secondary" | "quiet" | "danger")? primary: the one main action in a view; secondary: other actions; q…- [error] Button has no "variant" prop. → Did you mean "tone" ("primary" | "secondary" | "quiet" | "danger")? primary: the one main action in a view; secondary: other actions; q…
  12. Agent

    The booking flow needs a date range picker. Does the system have one?

  13. Loom · search_system · 17 ms→ search_system({"query":"date range picker for booking","kind":"component","limit":5})

    No component matches "date range picker". Closest partial matches: ComboBox (combo-box, partial match, confidence 0.24, beta: covers "picker" but not "date range"); FormField (form-field, partial match, confidence 0.24, beta: covers "picker" but not "date range"); LooseThreads (loose-threads, partial match, confidence 0.24, beta: covers "picker" but not "date range"). Logged as an unmet need. If this is a real gap, draft it with propose_change instead of building it off-system.

    • ComboBox — partial match: covers "picker" but not "date range"• FormField — partial match: covers "picker" but not "date range"• LooseThreads — partial match: covers "picker" but not "date range"
  14. Loom · search_system · 14 ms→ search_system({"query":"show an error when payment fails","kind":"component","limit":3})

    51 results for "show an error when payment fails" (lexical ranking). Top: ErrorSummary (error-summary, 0.93, beta), AIStatus (ai-status, 0.74, beta), Alert (alert, 0.74, beta)

    • ErrorSummary (error-summary, strong, confidence 0.93) — import { ErrorSummary } from "@loom/base/native";• AIStatus (ai-status, strong, confidence 0.74) — import { AIStatus } from "@loom/base/native";• Alert (alert, strong, confidence 0.74) — import { Alert } from "@loom/base/native";
  15. Loom · list_unmet_needs · 5 ms→ list_unmet_needs({})

    1 unmet need from 1 request; 0 over the threshold (3 requests from 2+ requesters in 30 days). "date range picker" x1.

    • "date range picker": 1 request(s), 1 requester(s) — Below threshold: needs 2 more request(s) and 1 more client(s) or team(s) within 30 days.

Checks that tell the agent exactly what to fix

check_composition flags raw colours and spacing, rebuilt components, unlabelled form controls, two primary actions in one region, style overrides on system components and pattern rule breaks, and says what to use instead. Working

One draft, checked twice

Recorded server output

Off-system: 3 errors, 2 warnings across 6 nodes.

  • [warning] Text has style set: overriding a system component's styling is drift from its contract. → Customise through the component's slots, variants or overridable tokens wit…
  • [error] Button has no "variant" prop. → Did you mean "tone" ("primary" | "secondary" | "quiet" | "danger")? primary: the one main action in a view; secondary: other actions; q…
  • [error] <Modal> is not part of Loom Base (imported from "@mui/material"). → Closest system components: AILabel (ai-label), Dialog (dialog), Drawer (drawer). If none fits, draf…

On-system: 0 errors, 0 warnings across 5 nodes.

  • components: Card, Stack, Text, Button, ConfirmAction

The agent fixed what the check named, then checked again before handing the work over.

From the recorded agent session on Loom Base, our own design system (data/mcp-demo.json), read when this page is built.

In a live test on 25 October 2026, the server caught 6 of 9 issues on a new billing page. We fixed the three it missed the same day and added tests for them.

Autonomy is set per area, by its owner

The owner of each area chooses how much agents may do, from observing only to merging routine changes when every check passes. The four modes are shown below.

In every mode, every change is a pull request, required checks must pass, a hard-deny list keeps some actions for people only, every change can be undone and is recorded, and an organisation-wide cap applies. When a change touches two areas, the stricter mode applies.

Autonomy is set for each area, by its owner

The modes work like the permission modes of a coding agent such as Claude Code, with allow and deny rules on top.

Concept
  1. Observe

    Loom reports what it sees. Nothing changes.

  2. Suggest default

    Loom drafts changes. A person approves each one.

  3. Auto with guardrails

    Routine changes merge when every check passes. Anything else waits for a person.

  4. Full

    Changes merge when the required checks pass, with no review: the owner accepts that risk in writing. Any person can revert a change with one click afterwards.

Today the mode per area is a record, and the stricter-mode rule is enforced. Partial What does not work yet: agents acting on their own under these modes, opening, merging and reverting pull requests. Until then, every change waits for a person. Pilots do not use Full.

Sensors watch for drift between design, code and the contracts

Sensors will compare what exists with your rules: checks on every pull request, scheduled scans, a Figma watcher and agent telemetry. A difference becomes a draft, never a silent edit. Concept

What works today: drift checks you run on demand, through the audit, audit_code and the rules command, which ends with an error code when an error remains, so it can run in CI. Partial A packaged CI step is planned. Concept

Changes arrive as pull requests

Loom has one way to open a change in GitHub, GitLab and Azure DevOps: a labelled draft pull request with its provenance. Partial What does not work yet: it has been tested against simulated git hosts, not yet on a client repository.

Migration pull requests with before and after screenshots are a concept. Concept

Every agent action is labelled and logged

Drafts written by agents carry a machine-readable label: AI-generated, the model and provider when reported, the time, and that no person has reviewed them yet. Working Pull requests Loom opens carry the loom:agent-generated label and a disclosure; the run fails if the label is missing. Partial What does not work yet: this has been tested against simulated git hosts, not yet on a real repository.

Every Loom tool call is written to a run log: which tool, how long it took, token counts and a cost estimate. You can cap a run by calls, tokens or estimated cost, and Loom refuses further calls once a cap is reached. Working

Figma and Storybook are fed from the same source

In one Figma Professional file, Loom pushed tokens as variables (one mode so far), generated a partial component library and read the file back to compare it with code. Working Storybook stories are generated from contracts. Partial

People can ask the system in plain language

Designers, writers and product managers ask in plain language and get answers from the system's own rules, with the source of each answer. An early version searches the rules and quotes them; it does not write answers yet. Concept

What we are building next

These are concepts. We share them because they show where a governed system can go.

  • Accessibility passport: a living test record for every component, exportable as evidence for compliance work under the European Accessibility Act. Concept
  • Contract tests for agents: the same tasks and checks for different models, so you can choose a model on evidence. Concept
  • Migration simulator: before you approve a change, see every screen it would affect. Concept

Agents do the routine work. People decide what the routine is.

Questions

Which models can we use? Your own, with your own keys. Any agent that speaks MCP can already use the server, whichever model it runs on. For agents that Loom runs for you, provider setup for Anthropic Claude, OpenAI and OpenAI-compatible gateways is in development.

Does Loom call a model itself? Loom's current tools do not. They are checks that give the same answer whichever model produced the result.

Where does the MCP server run? On your machines today. Over a network it requires a secret token on every request and refuses to start without one.

Can an agent change our system without anyone noticing? No. Every change is a labelled pull request, recorded on the timeline. In Full mode, any person can revert with one click.

Start with a conversation about your system.

We read your system, show you what we found, and agree with your team what to fix first.