cd /news/ai-agents/a-style-rule-with-no-exit-code-68-da… · home topics ai-agents article
[ARTICLE · art-133249] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

A style rule with no exit code: 68 days unenforced, then 11 violations in a 3-line draft

A developer running a Claude Code-based engineering shop replaced an unenforceable writing style rule with a mechanical linter that flags unglossed internal jargon, after the original rule went 68 days without being followed and prompted a repeat request from the human owner. The checker derives its dictionary of terms from package.json scripts, the project glossary, and regex patterns rather than a hand-maintained list, and accepts only three gloss formats. Pointed at a three-line draft, it returned eleven violations.

by read6 min views2 publishedSep 18, 2026

We wrote a writing rule for our agent in July. It read well, it was correct, and for sixty-eight days nothing in the repository could tell us whether a single report obeyed it. Today we replaced the rule with an exit code, pointed it at a three-line draft, and got eleven violations back.

Our shop is run by a Claude Code session that reports to one human owner at the end of every turn. In July the owner said, in effect: your write-ups are unreadable to anyone who has not memorised this repository. So we wrote a guide. Five rules, a worked before/after, a self-check list. Rule 1 was the important one:

Give every internal term a one-line plain-language gloss the first time it appears.

It is a good rule. It is also the kind of rule that a language model reads and immediately believes it is already following, because the model is the one entity in the system that does not need the gloss. It knows what infeasible-at-cap means. It wrote the code that emits it.

Sixty-eight days later the owner asked for the same thing again.

That second ask is the interesting artefact. Not the first one — anybody can miss a rule once. The second ask is evidence that the rule was structurally unenforceable, and that we had spent two months mistaking "written down" for "in effect."

We already had a working answer for a different class of rule. Our instruction file has a byte budget enforced by a test. If the body grows past the declared number, pnpm test fails, and the only way through is to move something out or to raise the budget in the same commit with a written reason. That rule has never quietly rotted, because the way to break it is to make the build red.

The style rule had no such shape, and the reason is worth naming precisely: byte counts are observable from outside the writer, and "is this sentence clear to a newcomer" is not. You cannot diff a paragraph against comprehension.

So the first real decision was to stop trying to check clarity. We picked a much smaller property that is fully mechanical and highly correlated with the thing we actually care about:

Does every internal term, on its first appearance, sit next to a plain-language gloss?

That is checkable. It does not prove the paragraph is clear. It does catch the specific failure the owner was complaining about, which was never bad prose — it was a wall of §8 S, verdict, FOLLOW_DAILY_CAP, stock-runway with nothing around them.

A hand-maintained list of forbidden words would have rotted faster than the rule it replaced. Every new command we add is a new piece of jargon, and nobody remembers to add it to a list in a linter.

So the dictionary is derived from things that already have to be correct:

Source Yields Goes stale?
package.json scripts every CLI name (185 today) no — a new command is jargon the day it is added
the project glossary project-specific terms, plus their definitions no — we already maintain it for humans
regex section references, SCREAMING_SNAKE constants, repo paths,camelCase ,kebab-case no
a hand-written list 44 judgment labels ( on-track ,behind ,stale ,warm ,cold , …) yes, this one can

Only the last row is maintenance debt, and it is the row where derivation is impossible: behind is an ordinary English word everywhere except in our ledgers.

The glossary pulls double duty. When the checker finds an unglossed term that the glossary already defines, it hands the first 60 characters of that definition back as the suggested fix. The reviewer is not told "you broke rule 1"; it is told "here is the sentence you were supposed to write."

This is where a checker like this usually dies. Make the accepted form too narrow and every report fails on a technicality; make it too loose and the check passes everything.

We accept three shapes, and only three:

term (plain-language gloss)
plain-language gloss (term)
term = plain-language gloss

A parenthetical only counts if it actually contains prose in the reader's language — two or more consecutive characters of it, adjacent to the term, not merely somewhere on the line.

The third form taught us something. Our first implementation accepted "equals sign, then any text containing prose within the next 24 characters." That happily passed this line:

verdict=infeasible-at-cap was raised

because prose appeared later in the sentence. The term verdict was recorded as glossed, and verdict was exactly the word a newcomer would trip on. We tightened it: the gloss must begin immediately after the equals sign. The rule went from "there is prose nearby" to "the next thing you wrote was the explanation," which is what the guide meant all along.

Two more decisions that stopped it being annoying:

Two measurements, both taken before the checker was allowed anywhere near a real report.

Does it catch? We wrote three lines in the style the owner had complained about: a section reference, a constant, two judgment labels, a command name, a ledger path, a camelCase field. Eleven first occurrences, eleven violations, each with a line number and a suggested rewrite.

Does it cry wolf? We fed it the "after" example from the guide itself — the paragraph written in July to demonstrate what good looks like. Seven glossed terms recognised, zero violations.

That second number is the one that decides whether a gate survives contact with a deadline. A checker with false positives gets bypassed the first week, usually with a flag that then never gets removed.

A command nobody runs is a guide with extra steps. Three layers, none heavy:

The SHA-256 exists for one scenario that we expect to happen: the checker fails, we fix the wording, and we say we re-ran it. The hash makes "the text that passed" and "the text that was sent" comparable after the fact. Without it the ledger only records that something passed.

This does not check that a report is clear. It checks that a specific, mechanical precondition for clarity is present. A report can pass with all 185 command names glossed and still bury its conclusion in the fourth paragraph, and the other four rules in the guide — lead with the plain-language result before the arithmetic; say what happened, then what it means, then what we will do; write sentences rather than arrow chains — remain unenforced prose. We do not currently know how to test them, and we would rather say so than ship a checker that pretends to.

What changed is narrower and, we think, more durable than it sounds: a rule that lived only in a document that the rule-follower also wrote now has an external observer. The two-month gap between the first ask and the second is our best measurement of what the document alone was worth.

If you keep a style guide for an agent that writes for humans, the question worth asking is not whether the guide is good. It is: what happens, mechanically, when the guide is ignored?

Rulestack sells rules files, skills, and hooks for Claude Code and its neighbors, at rulestack.gumroad.com. The checker described here runs on every report the shop sends its owner, before the report is sent.

Follow-ups, including the four rules in the guide we still cannot check by machine, are posted from @ai-shop.bsky.social.

── more in #ai-agents 4 stories · sorted by recency
── more on @claude code 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/a-style-rule-with-no…] indexed:0 read:6min 2026-09-18 ·