copywriting · git:20260909.1c2e4ab · 2026-09-09 · sha256 ce426497d0bc3a30

copywriting git:20260909.1c2e4abA

Immutable. This exact content is served forever at /api/v1/blob/ce426497d0bc3a30.

---
description: "Write or rewrite any text a user reads (interface strings, errors, empty states, landing and pricing pages, posts, changelogs, store listings, ads, email): apply when asked to write copy, rewrite a headline or CTA, fix microcopy, or when a draft reads machine-made"
alwaysApply: false
---

# copywriting — write it in the product's own voice

`brand-voice` decides how the product speaks. This is the pass that writes
in it. The two are not interchangeable: defining a voice mid-sentence to
finish a button is how a product ends up with six voices.

## First action, every time

Read the pack: `docs/brand/voice.md`, `terminology.md`, and the
`channels.md` record for the surface being written. **No pack? Stop and run
`/brand-init`.** Guessing the voice and being wrong costs more than the
pause.

**Never write to `docs/brand/`.** A term missing from the dictionary, or a
number with no row in `facts.md`, is **reported** — never invented to finish
the sentence. Adding it is `brand-voice`'s decision, not this pass's.

## Rules that hold in every voice

- **Every figure comes from `facts.md`.** No sourced fact, no number. Never
  fabricate a statistic, a quote, or an expert.
- **One action keeps one name** across button, confirmation, toast, history,
  notification and accessible name. Search `strings.md` before naming one.
- **No humor, exclamation marks or emoji** on error, destructive confirm,
  billing or paywall surfaces — including in a playful voice.
- **Errors say what happened and how to recover**, in the user's words, and
  never blame the user.
- **A register is a delta on the voice axes**, never a crossing of the
  invariants recorded in `voice.md`.
- **Every new interface string gets a `strings.md` row**: key, `file:line`,
  and the scenario it serves. A string with no scenario is a candidate for
  deletion, not translation.
- **Claims reach a consequence.** "AI-powered" is a mechanism; what the user
  stops doing is the copy.

## The any-other-SaaS test

Could this sentence sit unchanged on a competitor's page? Then it says
nothing. Rewrite it until it could not.

Machine-made tells to strip: tricolons that add nothing, "seamless /
effortless / unlock / elevate / robust", em-dash cadence in every paragraph,
"it's not just X, it's Y", hedges stacked two deep, and a closing sentence
that summarizes what was just said.

## Localization

A locale is not a translation of the English: the length coefficient, the
address form, and the dead idioms are recorded per locale. A locale that
lags the primary says so rather than pretending to be current.

## Check

```bash
python3 docs/brand/lint.py
```

Exit 0 clean **or warnings only**, 1 warnings under `--strict`, 2 any error. That is the policy `docs/ux/lint.py` has always had, and one pack cannot hold two opposite meanings for a warning: this linter returned 1 on warnings alone until 2026-08-20, so 13 of its 39 codes turned a build red while printing `0 error(s), 1 warning(s)`. Clean means *checkable*, not *good* —
tone drift, unproven claims and a voice that overshot its declared failure
mode are judged by `/ux-audit copy`.