2026-08-14·3 min read

Rules for the version of me who's in a hurry

field-notesmetawritingtooling

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.