| name | copy |
| description | Produces a COPY.md (UI microcopy — labels, errors, empty states, tooltips, onboarding — each with surface, action, a 3-5 word voice, and a character budget); primes the editorial + accessibility gates. Use to write in-product microcopy from the brief. |
copy
The microcopy producer of the content domain — it writes a COPY.md: in-product UI strings (labels, errors,
empty states, tooltips, onboarding), each declaring its surface, the action it serves, a voice in
3-5 words, and a character budget. The bar is the two failure modes microcopy dies on: it never blames
the user, and an error or empty state always names a recovery — no dead-end "Something went wrong". It
binds the pack's microcopy sub_target and verifies by Review (a human/grader judges clarity, voice, and
recovery — prose is not auto-asserted). It writes the strings; it does not set the brand voice
(content-brief) or write prose (long-form).
What this does / does not do
Does: resolve the microcopy sub_target, write a COPY.md of per-surface entries (surface + action + copy +
voice + character budget/count + recovery for errors), grounded in the brief's voice + audience, and a
receipt. Does not: set the brand voice / audience (that is content-brief, via VOICE.md/BRIEF.md), write
long-form prose (long-form), write campaign/marketing copy (marketing-copy), or issue the gate verdict
(the editorial/accessibility gates do — this primes them).
When NOT to use
- The work is deciding the brand voice / audience / structure — that is
content-brief (this consumes it).
- The work is long-form prose (blog/article/landing/tutorial) — that is
long-form; microcopy is short
in-product UI text.
- The work is campaign/positioning copy — that is
marketing-copy; microcopy is product UI, not marketing.
- A current
COPY.md still fits and nothing changed — edit the strings; do not rewrite the deck.
Reference Routing
| Situation | Reference |
|---|
| The COPY.md contract template | references/copy-template.md |
| Per-sub_target must-declares · overlay · vocabulary | ../acceptance/sub-targets.md · ../acceptance/overlay.md · ../vocabulary.md |
| The upstream content contract (voice / audience) | BRIEF.md / VOICE.md (from content-brief) |
Inputs
- The surfaces needing copy — the UI states (labels, errors, empty states, tooltips, onboarding) and their
character constraints.
BRIEF.md / VOICE.md if present — the audience + the voice the strings must match.
- The content domain pack (
../vocabulary.md, ../acceptance/) + state/intake.json.
How to do it
- List the surfaces: enumerate the UI states that need copy, each with the action it serves (what the
user is trying to do there) and its character budget (from the UI constraint).
- Set the voice: carry the 3-5 word voice from
VOICE.md/BRIEF.md (or state it if absent); every
string is written to it. Voice decided before bulk writing (the content ordering rule).
- Write each string to its job: say the one thing the surface needs, within budget. Lead with the user's
action, not the system's. Plain language — the reading level the audience actually uses (accessibility).
- Make errors recoverable: every error/empty state states what happened in plain terms AND the next
action to recover. Never blame the user; never a dead-end ("Something went wrong" with no path).
- Record budget + count: each entry carries its character budget and the actual count, so an over-budget
string is caught here, not in the UI.
- Write
COPY.md from references/copy-template.md; note that it verifies by Review.
Gate (before marking complete)
A gate failure is fixed before lock, not waived — these mirror the editorial/accessibility gates.
Output
- COPY.md at the product root (or
content/COPY.md) — persistence: Spec-Anchored. Per surface:
surface type · the action it serves · the copy · the voice · character budget + count · recovery (errors).
- receipt (
<workspace>/receipts/copy-receipt-<ts>.json): base schema + sub_target, surfaces,
voice, over_budget (count), errors_with_recovery, copy_path, gate_checks. persistence:
Spec-Anchored.
Proactive Triggers
- A blame-the-user string ("you entered an invalid …"): rewrite to state the issue + the fix without
fault; microcopy guides, it does not scold.
- A dead-end error ("Something went wrong"): add what happened + the next action; an error with no
recovery is the microcopy failure mode.
- An over-budget string: tighten it to the surface's character budget, or the UI truncates it.
- A string off the declared voice: bring it to voice, or the deck reads as written by three different
people.
Completion Criteria
Done when: a COPY.md exists with per-surface entries each declaring surface + action + voice + character
budget/count, no blame and a recovery on every error/empty state, all strings within budget and in plain
language; a copy receipt records the gate checks. Verified by Review.
Not done if: an entry lacks its surface/action/voice/budget; a string blames the user or dead-ends; a
string is over budget; or strings drift off the declared voice.
Next step: the editorial + accessibility gates judge the deck (Review); the strings land in the UI;
localization handles i18n; content-brief is the upstream voice contract.
Related Skills
- content-brief: sets the audience, voice, and structure the copy is written to. content-brief decides;
copy writes the strings. Run content-brief first when the voice is the gap.
- long-form: blog/article/landing prose. copy is short in-product UI text; long-form is the article —
different lengths, different jobs.
- localization: translates the strings copy writes into other locales. copy is the source strings;
localization is the i18n.