← Back to work step by step

How to write a SKILL.md for your design system

29 August 2026 · 8 min read

Pick one component. Write its rules so an agent can act on them. Ship that before you touch anything else.

This is the practical version. Seven steps, one component, about an hour.

At the end you have a valid SKILL.md for your button. You also get an honest read on what your documentation was missing.

If you want the format itself explained first, that is in what is SKILL.md. The wider case is in agent-ready design systems.

1. One component

Start with the button. Not the system.

Three reasons. Every product has one. Every agent will try to build one. And it carries far more rules than it looks like it does. Variants, sizes, states, labels, icons, focus, loading.

A whole design system is a multi-week project. One button is an hour, and the hour teaches you the shape of the weeks.

Make a directory now. Call it design-system-button/ and put an empty SKILL.md inside it. The directory name is load-bearing. The spec requires the name field to match the parent directory name.

Artifact: a directory with an empty file in it.

2. The description

Write the description before you write the body.

Skills load progressively. The name and description sit in context at startup for every installed skill, roughly 100 tokens each. The body only loads after the agent decides to activate the skill.

So the description is not a summary. It is a trigger.

Two things go in it. What the skill does, and when to use it. Use the words a real task will contain. Button. CTA. Submit. Action. The spec allows 1,024 characters. Most good ones use 200 to 300.

Button guidelines. fails. It tells an agent nothing about when it applies.

Artifact: one sentence you would bet a build on.

3. Rules that resolve

Now the body. Write rules that resolve to a value or a decision.

Primary buttons use color.action.primary is actionable. An agent can check its own output against it.

Buttons should feel confident is not. An agent reads that, produces something, and cannot tell you whether it complied.

The test is simple. Could a script check this? If yes, it survives translation. If no, sharpen it until it can, or leave it out.

Most of your current documentation will fail that test. That is the finding, not the failure.

Tables carry this better than prose. One row per variant. One column per token. Every cell a name, never a hex value.

Artifact: variant, size and state tables where every cell is a token.

4. The do-nots

Write down what the agent must never do.

Design system docs describe the happy path. They tell you what a primary button is. They rarely tell you the rules that stop an agent guessing.

That a view gets one primary. That a control which changes the URL is a link, not a button. That removing the focus ring is not a styling choice.

Humans absorb those from context. Agents do not have your context.

The failure mode of an agent is doing something nobody thought to forbid. Every do-not you write is a failure you have already seen, from a designer, an engineer, or a model. Go and find them in your review comments.

Artifact: 8 to 12 do-nots, each one a thing that actually went wrong.

5. The gate

Give the agent a checklist to run against its own output.

This step changes results more than any other. Without it the agent reads the rules, writes the code, and returns. With it the agent reads the rules, writes the code, checks each rule, and fixes what it broke.

Keep every item binary. Passes or fails. Nothing that requires taste.

Then add the line most people leave out. Tell the agent what to do when it cannot pass. Naming the conflict and stopping beats guessing.

Artifact: a numbered gate at the end of the file.

6. The validator

Run it.

pip install skills-ref
skills-ref validate ./design-system-button

It checks frontmatter and naming, not your rules. name is 1 to 64 characters, lowercase, hyphens only, and it must match the directory name. No leading or trailing hyphen, no double hyphen. description is 1 to 1,024 characters and non-empty. Everything else is optional.

Two soft limits are worth holding to. Keep the body under 500 lines. Keep it under 5,000 tokens, because the whole file loads the moment the skill activates. Anything longer belongs in references/.

Artifact: a file that passes.

7. The test

Now run it against the agent your team actually uses.

This is the step everyone skips. It is also where the real information is.

Give it three tasks. A plain one: build a primary button. An ambiguous one: build the button for deleting an account. A trap: build a button that takes the user to the pricing page.

Watch what it does. The third should produce a link. If it produces a button, your rule was either unclear or buried too deep in the file.

Then fix the file and run the same three again. Two or three rounds is normal.

Every failure is a missing rule, a vague rule, or a rule the agent could not find. All three are yours to fix.

Artifact: a short list of what you changed and why.

The file

Here is the whole thing. The token names are placeholders. Swap them for yours and it is real.

---
name: design-system-button
description: Build, review and fix buttons using this design system's button rules. Covers the four variants, three sizes, six states, token names, label writing and focus behaviour. Use whenever a task creates, edits or reviews a button, CTA, submit control, or a link styled as a button, in React, HTML or Figma.
license: MIT
metadata:
  owner: design-systems
  version: "1.0"
---

# Button

A button triggers an action in place. Anything that changes the URL is a link.

## Variants

| Variant | Background | Label colour | Use for |
|---|---|---|---|
| `primary` | `color.action.primary` | `color.text.on-action` | The one action the screen exists for |
| `secondary` | `color.surface.raised` | `color.text.primary` | Supporting actions beside a primary |
| `ghost` | transparent | `color.action.primary` | Tertiary actions in dense UI |
| `destructive` | `color.action.danger` | `color.text.on-action` | Delete, remove, revoke |

`secondary` carries a 1px border in `color.border.default`. No other variant
has a border.

## Sizes

| Size | Height | Horizontal padding | Label type |
|---|---|---|---|
| `sm` | `size.control.sm` | `space.3` | `type.label.sm` |
| `md` | `size.control.md` | `space.4` | `type.label.md` |
| `lg` | `size.control.lg` | `space.5` | `type.label.lg` |

Radius is `radius.control` at every size. Default size is `md`.

## States

| State | Rule |
|---|---|
| default | Variant tokens as listed above |
| hover | Background steps to the `.hover` token on the same ramp |
| active | Background steps to the `.active` token on the same ramp |
| focus-visible | 2px outline in `color.focus.ring`, 2px offset, always present |
| disabled | `opacity.disabled`, cursor `not-allowed`, no hover change |
| loading | Width held, label swaps to a spinner, `aria-busy="true"` set, accessible name unchanged |

## Labels

Sentence case. Verb first. Three words or fewer.

Name the outcome, not the mechanism. `Save changes` is right. `Submit` and `OK`
are not.

## Do not

1. Do not invent a variant. There are four. If none fit, stop and ask.
2. Do not use a raw hex, rgb, or pixel value. Every value resolves to a token.
3. Do not place two `primary` buttons in one view.
4. Do not remove or override the focus ring, including `outline: none` with no replacement.
5. Do not use a button for navigation. If it changes the URL, render a link.
6. Do not add a shadow, gradient, or transform. Elevation is not a button property here.
7. Do not set `width: 100%` except in a modal footer below 480px.
8. Do not ship an icon-only button without an accessible name.
9. Do not animate anything except `background-color` and `border-color`, at `motion.fast`.
10. Do not put `destructive` in the default submit slot of a form.
11. Do not nest an interactive element inside a button.

## Quality gate

Before returning, check every line and report the result.

1. Every colour, spacing, radius and type value is a token name, not a literal.
2. The variant is one of the four.
3. Focus-visible styling is present and unmodified.
4. The label is sentence case, verb first, three words or fewer.
5. Any icon-only button has an accessible name.
6. The view holds at most one `primary`.
7. No rule under "Do not" is broken.

Fix anything that fails, then run the list again.

If a check cannot pass without breaking another rule, name the two rules that
conflict and stop. Do not choose.

## References

Resolved token values are in [references/tokens.md](references/tokens.md).

That file is about 90 lines. The spec's ceiling is 500. There is room for a second component before you need to split anything out.

Judgment

You cannot generate this from a token export.

An export gives you values. It does not give you the rules.

It cannot tell you that a view gets one primary button. It cannot tell you the destructive variant never sits in the default submit slot. Those rules live in people's heads and in old review comments.

Deciding which of them survive translation is the work.

Some are real constraints, and they become do-nots. Some are preferences nobody ever enforced, and writing them down makes them binding for the first time. Some turn out to be wrong, and you only find that reading them back.

That last one is worth the hour by itself.

Do one component. Test it against your own agent. Then decide whether the next twenty are worth doing.

If your design system needs to work with agents, say hello.

Format constraints checked against the Agent Skills specification on 29 August 2026. Back to work