Rules for the version of me who's in a hurry
I write rules down so I stop deciding the same thing twice. Not to be systematic about it. Because the second time I decide something, I’m usually tired, halfway through a draft, and pleased with what I’ve just made, which is the worst possible condition for judgment.
A knowledge graph of this repo put a number on how often I do this. I asked it
which file sits on the most paths between parts of the graph that otherwise
don’t touch, and the answer was docs/writing-guidelines.md, with the highest
betweenness in the graph at 0.0345. It bridges the writing side of the site and
the app-security side of a different project. The link is one sentence I wrote
in July, saying the same discipline lives in Perpetūra as a CI linter and in
SkinAtlas as a canonical style doc. I hadn’t noticed the habit until something
counted it.
The rules get written cold
docs/writing-guidelines.md names banned moves: significance inflation, the
reflexive rule of three, fancy copulas where “is” would do. I wrote it on a
quiet afternoon with a list of AI writing tells open beside me, which is the
only time you can think clearly about your own tics. It has caught me once, a
heading in an early note that used a word from the list and got rewritten
before it shipped.
SkinAtlas has a version with no linter anywhere near it. A pull request on July 5 added a few sentences to three system prompts, no model swap and no new feature. One of them: draw on a user’s history by relevance, not wholesale. The app reads a photo of your face and remembers months of your skin journal, and in the middle of building that, asked what the copilot should do, I would have said “be helpful” and moved on. Sitting down separately to decide how a copilot should treat someone’s history is a different question with a different answer, and the answer only survives because it lives in a file the model reads every time.
The disclosure rule in CLAUDE.md is the clearest case. It sets out what can
be said publicly about unreleased work, an infrastructure-versus-story-content
split with specific terms on the wrong side of the line. The moment I’m about
to publish something is the worst moment to decide what’s safe to publish,
because that’s exactly when I’m most excited about the work. So the rule was
written cold and gets consulted hot.
Enforcement keeps the file honest
A rule nobody runs rots into decoration. That’s the whole argument for the mechanical layer, and it’s a smaller argument than it looks.
Yesterday’s commit 6ca46e7 wired scripts/check-text.mjs into npm run check. It flags zero-width spaces, bidi controls, soft hyphens and stray BOMs,
the characters that survive a copy-paste and then quietly break grep and diffs
while being invisible in review. A no-break space between two digits is left
alone, because “16 416” is a thousands separator and not junk. That exemption
is the interesting part: even the mechanical rule needed a judgment call
written into it.
Perpetūra’s prose-check.js runs the same way in CI. Em-dashes outside
interrupted dialogue and American spellings fail the build; softer patterns
warn and leave the call to a person. The linter’s own docs are honest about the
limit. It catches mechanics, not judgment.
Proof it earns its place: a draft of this note put a zero-width space inside the sentence explaining zero-width spaces. It got caught before the file was written.
The rule that can’t be run
No script can read a paragraph and decide whether it gave something away. The disclosure rule can’t be linted, so in Perpetūra it’s enforced by shape instead: the public build runs off an allowlist script, and the story bible, the outlines and everything else that could spoil a reader never reach the server. The other rules are checkers that read a file and fail a build. This one is a gate, and it decides what exists on the far side at all.
The site copy has no gate. It’s enforced by being read, every time, by me, and that’s the honest end of the pattern. The file isn’t there to make me consistent. It’s there so the version of me who’s in a hurry at midnight doesn’t get a vote on something I already thought through properly.