← Portfolio
WRITING ENGINE SHIPPED

copywriter.

Four Claude Code skills that write specific, proof-backed copy instead of generic AI copy, each gated by a deterministic linter that blocks AI slop before it ships.

CLAUDE CODE SKILL·UPD JUL 2026

01 · THE PROBLEM

Ask a model to write good copy and it hands back the statistical average of every piece of copy it has ever seen, which is exactly what generic AI copy sounds like: the same seamless platforms, the same unlocked potentials, the same reframe where it's "not about X, it's about Y." A better adjective in the prompt cannot fix that, because the problem was never the adjective. It's the input and the process. I wanted a system where the quality comes from what actually goes in, not from asking nicer.

02 · HOW IT WORKS

copywriter is four Claude Code skills, /copy-website, /copy-resume, /copy-email, and /copy-marketing, that all run the same five-pass engine: lock the context (who the author actually is, what the reader needs), draft framework-first from real swipe examples, critique the draft as the skeptical reader who will actually read it, gate it against a hard quality bar, then deliver. Every draft fuses three inputs that are never the model's imagination: a distilled voice profile, a local file of proof the author actually has (numbers, projects, pre-approved claims), and a swipe corpus of real, sourced writing whose structure gets borrowed, never whose words. A slot with nothing real behind it gets a [VERIFY] placeholder. It never gets an invented number.

03 · ENGINEERING DECISIONS

A regex grades the draft, not the model

The same model that wrote a slop pattern cannot be trusted to grade itself for it, so the mechanical half of the gate is a small, dependency-free Python linter with no model in the loop. It hard-blocks em dashes, the spaced-hyphen substitute models reach for the moment the em dash is banned, negative-parallelism reframes, a fixed list of dead AI vocabulary and dead phrases, and any unresolved proof placeholder. A delivery without a clean run of that linter is treated as invalid, full stop.

Proof discipline outranks voice

When the rules collide, the order is fixed: proof discipline first, then reader relevance, then structure, then voice. The voice pass is explicitly barred from polishing away a hedge that keeps a claim honest. "Targeting this month" does not get to become "shipping this month" just because the second one reads more confidently. A sentence that sounds better but says something untrue is a bug, not a style win.

Four hard blocks the gate cannot waive

Every draft is scored against a twelve-test quality bar and the score has to print with evidence, since a PASS with no supporting line counts as a FAIL. Four of those tests hard-block regardless of anything else looking good: the swap test (would this hero fit any competitor's name pasted over it), the proof test, the no-leak test, and the lint-clean test. Revisions are capped at three passes; past that the draft says the blocker is upstream, thin proof or a weak offer, instead of polishing a draft that structurally cannot clear the bar.

One source of truth, fanned out on install

Claude Code installs each skill as its own top-level directory, and a skill can't reliably reach a sibling skill's files through a relative path once installed. So the voice file, the forbidden list, and the linter are edited in exactly one shared location, and an install script copies them into each of the four skills' own reference folders and rebuilds each skill's swipe corpus from scratch on every run. Edit the shared source once; all four skills update, and nothing dropped from the source lingers in an installed copy.

04 · WHERE IT STANDS

The engine, the voice model, the forbidden list, the quality gate, and the linter are built and in use, and all four surface skills install standalone with install.sh. The swipe corpus is rebuilt as verbatim, sourced quotes rather than paraphrase, split per surface so ad-copy moves never bleed into a resume bullet. What is not finished is the proof file itself: collecting a first real testimonial and closing the remaining [VERIFY] and [FILL] gaps in personal proof material is the highest-leverage work left, because copy quality here is capped by proof, not by prose, and that is the one input a linter can never generate for you.

05 · STACK

Claude Code skills Python (stdlib only) regex-based deterministic linter Markdown knowledge files per-surface swipe corpus install.sh fan-out

TRY IT — BREAK THE LINTER

Below is a real, faithful port of copywriter's own deterministic linter, the same regex checks from its lint.py, running entirely in your browser. Edit the sentence and watch it get flagged live. Write your way to a clean pass; that's the whole test.

Sample sentence run through the linter: "In today's digital world, our seamless platform empowers you to unlock your potential - it's not just software, it's a game-changer for your business."

LINT FAILED: 8 violations. Copy does not ship until clean.

dead filler phrase: "in today's digital world" fills space, not meaning.
dead AI vocabulary (×4): "seamless," "empowers," "unlock," "game-changer" are flat, inflated words standing in for plain ones.
spaced-hyphen dash substitute: "l - i" is the same slop rhythm as an em dash, banned for the same reason.
negative-parallelism reframe: "it's not just software," should delete everything before the positive claim.
"not just X, it's Y": "not just software, it's" should state the positive claim straight.

Turn on JavaScript to edit the sentence yourself and watch the flags update live.