I banned the em dash from my AI's voice
At the end of August I was reviewing a weekly digest my pipeline had drafted, and there it was again: the em dash, thirteen times in one issue. I have never written one in my life, and I had been striking them out of the machine’s drafts by hand for weeks. That evening I banned it, and not just from the digest. Anything published as my voice, essays, digests and their titles, the manual and its excerpts, bios, replies. Part of the reason is that I hate the thing. The rest is that the em dash is the most recognised tell of machine prose in 2026, and I run a voice engine whose entire job is to make text sound like me rather than like the model. A tell the engine lets through is a bug in the engine.
The rule is one line. The enforcement is where the work went, into three places that cannot drift apart.
The engine carries the ban. hyphos, the open-source tool I wrote to rewrite drafts in my own voice, already had a banned-words rule. Its built-in list ships empty, because which words a writer avoids is personal, not a model-ism; the personal overlay carries the list. An em dash cannot be a banned word though. The rule matched on word boundaries, and a dash is not a word, so it could never fire. The rule class gained a token mode: literal marks matched without boundaries, flagged and never rewritten, because the replacement is a decision per instance.
{
"id": "banned-words",
"kind": "banned",
"words": [],
"tokens": ["\u2014", "\u2013"],
"tests": [
{ "in": "a \u2014 b", "flags": 1 },
{ "in": "a \u2014 b \u2013 c", "flags": 2 }
]
}
Shown escaped, because not even the rule’s own example gets to print the glyph on this site.
Building that surfaced a second bug worth telling. A rule whose compiled pattern can match the empty string, a missing field, an empty word entry, a zero-width regex, fired at every position in the text and reported the text’s length plus one as the hit count. My model-ism score had equalled the character count for a day, and I had read it as “very bad” instead of “broken”. Such rules are inert now, and the self-test pins the class.
The site refuses the character. One shell script is the single place the check lives. The build gate runs it over all content before anything uploads, the digest tooling runs it over a draft, and the voice step runs it over whatever the engine hands back. Fenced code is exempt, because a fence depicts another text’s format rather than speaking for the site; the one essay that quotes a decision-record heading keeps the dash the record actually carries. Everything outside a fence is scanned, front matter included, because titles and descriptions are published text too.
$ bin/no-dash-check.sh src/content
src/content/patterns/claims-and-locks.md:3: description: "..."
no-dash-check: 1 line(s) carry an em-dash (banned on this site)
$ echo $?
1
The drafting rule changed too. The weekly digest is written by a model on a headless rail, and its prompt now forbids the character outright. The first issue drafted under the new prompt came back clean.
Then the replacement itself. The ban says per instance, never a blanket swap, and that turned out to be the real editorial work: 72 rewrites across the six manual chapters, 24 across two excerpts, 13 in the digest issue that started it, 8 on the site. A colon where the dash introduced an expansion, a comma for a parenthetical, a semicolon for a turn, a new sentence where the dash was hiding two thoughts. The dash had been doing four jobs at once, and the prose got better when each job got its own mark.
- The em dash was doing four jobs. The writing improved when each job got its own mark.
The gate proved itself within a day, and against me. On the first of September a description line on one page carried a single dash, and every deploy for the next twenty-four hours refused: eight runs, three hours apart, each naming the same file and line. Nothing shipped, which is the point of a gate. And the refusal named the file, the line and the fix, which is the difference between a gate and a trap. I replaced one character and the next run went out.
Why does a punctuation mark deserve a build gate? Because the alternative is a note to remember, and a note to remember is enforced by nobody at 03:00, when the pipeline drafts and deploys without me. Style rulings target the engine. The engine ships tests. The site holds the line. I get to have taste without having to remember it.
I never used the em dash. Now nothing with my name on it can either.