File format
A skill file and an agent-profile file are both plain markdown with a --- block at the top: the block holds the
settings, everything below it is the instructions.
---
id: brand-audit
name: Brand audit
---
Everything down here is what the agent reads.The block is optional. A file with no --- at all is all instructions, and everything takes its default — which is
a perfectly good skill.
The settings block
It looks like YAML and is deliberately a much smaller thing: one key: value per line, starting in the first
column. Values can be
-
plain text —
name: Brand audit -
trueorfalse—readOnly: true -
a number —
maxRounds: 6 -
a list, written either way:
tools: [find_nodes, get_node]tools: - find_nodes - get_node
Quotes around a value are optional and are stripped. Blank lines and # comments are ignored. Anything else — a
line that isn't key: value, an indented key, a tab, a key set twice, a block that is never closed — is reported
as an error with the line number, rather than being half-understood.
Unknown fields are an error. If you write whenUse: instead of whenToUse:, the file will refuse to load and
tell you so. That is on purpose: a setting that is quietly ignored is much harder to notice than a file that says
what's wrong with it.
A skill
A skill is a sheet of instructions the agent pulls in when a job matches it. The agent only ever sees the name,
description and whenToUse up front — that is how it decides — and reads the body only once it has decided to
follow the skill. So write whenToUse as the sentence you'd use to recognise the job, and put the actual steps in
the body.
Put the file in skills/.
---
id: brand-audit
name: Brand audit
description: Check a page against the brand palette and type scale.
whenToUse: The user asks whether a design is on-brand, or to fix off-brand colors.
tools:
- get_document_outline
- find_nodes
- get_node
- get_styles
- set_fills
---
Audit the current page against the brand, then report before changing anything.
1. Read `get_document_outline` to see what's on the page.
2. Collect every fill and stroke color with `find_nodes` and `get_node`.
3. Compare each one against the brand palette:
- ink `#12131A`
- paper `#FFFDF7`
- signal `#FF4A1C`
- muted `#8A8F98`
4. Anything within ~4% of a brand color is a near-miss and should be snapped to it with `set_fills`.
Anything further away is a deliberate choice — list it, don't change it.
5. Finish with a short list: what you snapped, and what you left alone and why.Skill fields
| Field | Required | Default | What it does |
|---|---|---|---|
id | the file name | How the skill is referred to. Lower-case letters, digits and -; anything else is folded to -. Matching a built-in's id replaces it. | |
name | the id | What the panel and the agent's skill list show. | |
description | empty | One sentence on what the skill is for. The agent sees this before it opens the skill. | |
whenToUse | empty | One sentence on when it applies. This is the line the agent matches a request against — it's the most important field in the file. | |
tools | all tools | Narrows the tools the agent may call while following this skill. See tool names. | |
| the body | ✓ | The instructions. Up to 20,000 characters. |
A skill with an empty body is an error: there is nothing to follow.
An agent profile
A profile is a persona the main agent hands a self-contained job to. The child starts with a clean slate — it never sees your conversation — does its job, and hands back one summary. So the body should describe a job, not a personality, and should say what the summary must contain.
Put the file in agents/.
---
id: spacing-critic
name: Spacing critic
description: Measures the gaps in a layout and reports the ones that break the rhythm.
whenToUse: A layout feels off and you want the spacing checked before anything is moved.
model: inherit
readOnly: true
tools: [get_document_outline, find_nodes, get_node, measure]
maxRounds: 10
---
You measure spacing. You never change anything.
1. Use `get_document_outline`, then `find_nodes` to get every visible layer in the frame you were given.
2. With `measure` and `get_node`, collect the vertical gap between each pair of stacked siblings and the
padding inside each container.
3. Work out the dominant step (usually the most common gap, often 4 or 8).
4. Report only what breaks it. For each one give the node id, the gap you measured, and the nearest value on
the step.
Your summary is the only thing that comes back, so make it a list of `nodeId — 13px, should be 12px` lines and
nothing else. No preamble, no offer to fix them.Profile fields
| Field | Required | Default | What it does |
|---|---|---|---|
id | the file name | How the agent refers to the profile when it delegates. Matching a built-in's id replaces it. | |
name | the id | What the panel shows. | |
description | empty | One sentence on what the persona does. | |
whenToUse | empty | One sentence on when to delegate to it. The agent matches against this. | |
model | inherit | inherit uses whatever model your chat is on. Otherwise a model id, to pin a cheap model to a cheap job. | |
readOnly | false | true means it can look but never change the document. It can only tighten — see what a file can't do. | |
tools | all tools | Narrows the tools the child may call. See tool names. | |
maxRounds | 8 | How many model turns the child gets before it has to report back. 1–24. | |
| the body | ✓ | The child's instructions. Up to 20,000 characters. |
Read-only profiles with no model set are run on a fast model automatically, because a survey is tool calls and a
paragraph rather than hard thinking. Pin a model when that isn't the trade you want.
Field spellings
whenToUse, readOnly and maxRounds also accept when-to-use / when_to_use, readonly / read-only /
read_only, and max-rounds / max_rounds. tools also accepts a comma-separated string
(tools: find_nodes, get_node), so a definition copied from another tool usually works unchanged.