← Back to Writing

The rules my coding agents work under, and why each exists

About this artifact

essayon-the-recordmaintained

method · since 2026

For about three months, a guard meant to block em dashes in anything my agents wrote never fired once. It was installed and registered, and it looked alive. The guard decoded its input in the wrong text encoding, and every probe I ran against it fed it an escaped form of the character instead of the literal one. The real character never matched, and no probe ever exercised the path where it should have.

Every preference I have configured for my coding agents traces back to a failure like that one. I run several agents across my repositories: a supervising model that plans and reviews, cheaper models that make edits, and a set of hooks and checks around all of them.

Five decisions stay with me regardless of the checks#

New recurring spend, publishing, switches that make something public, personal data, and changes to scoring logic. Any agent that reaches one of these stops and asks, at every tier, however green the checks are. It does not spend a consultation with a stronger model trying to reason its way past the question.

The reason is that each of these is hard to undo or keeps costing after the change lands: a monthly bill, a post that readers have already seen, data that cannot be unshared. A passing test suite says the code does what it claims. It cannot say whether I want it to happen.

If a hook can block it, the hook blocks it#

A rule written in an instruction file is a request the model weighs against everything else in its context. A hook that exits with an error is not weighed. So wherever a mechanism can block an action, such as a guard that refuses force pushes, the hook does the enforcing and the written rule only explains why.

The em dash guard added the second half of this rule. A guard counts as live only after I have watched it fail on a planted example, fed the same literal input it will see in real use, in the same encoding. A probe built for the test's convenience can pass forever while the production path stays dead. A check I have never seen fail is indistinguishable from a check that does nothing.

Done means a check someone else can rerun#

Agents report success fluently, and a report is not evidence. "Done" means a check another person or agent can rerun and get the same answer. Each claim in a completion report is mapped to its evidence, to where that evidence stops, and to the gap that remains. A test against a mocked database shows the logic is right; it does not show a row was written. A green pipeline shows the steps passed; it does not show the page loads.

So the last check happens from the user's seat: load the URL, run the command, read the rendered page. Green logs are not health.

The strongest model judges, cheaper models type#

The most capable model I have plans the work, writes briefs, reviews diffs and makes every acceptance call. Cheaper models make the edits, and every one of them stops at a pull request. None merges or deploys. Judgment is where the expensive model earns its cost; the edits are where the volume is.

A brief is good when it removes the need for judgment. It names the goal, the exact files, the command that verifies the change, what is out of scope, and an instruction to come back with a question rather than guess. If I cannot write that brief yet, the work is still in planning, and handing it to a cheaper model only moves the guessing somewhere I am not looking.

Every statement has one home#

What an agent must see before an irreversible act stays in the instructions that load into every session. Procedures live in commands that load when invoked. Each agent's role and limits live in its own definition. History and background live in reference files read on demand.

Two copies of a rule drift apart, and an agent has no way to tell which one is current. So a hand-kept copy of a rule is treated as a defect, even when it was made for convenience.

Changes to the rules ship like code#

A change to an instruction file changes the behavior of every agent at once, which makes it the widest blast radius in the setup. It goes through a pull request, a reviewer that did not write it, tests that pin the text that must not disappear, and the same merge gate as any product change.

Lead with the result, and push back first#

Agents lead with the result and skip the preamble. On design questions they challenge the premise before building; on implementation that already has a spec, they execute without reopening it. An agent that accepts a weak premise will build it carefully, and that costs more to unwind than an early objection.

What rewriting all of it showed#

On November 10 and 11 I rewrote the set: the always-loaded rules, thirteen agent definitions and thirteen commands, in four pull requests. Each merged only after an independent review and a full local test run.

I set out to cut the always-loaded rules by more than half. They shrank by 10%, from 22,937 characters to 20,552. Review kept restoring lines I had cut, and they turned out to be obligations someone needed to see. The large saving came from somewhere else: one repository's instruction file went from 766 lines to 124 by moving 29 numbered lessons into their own file without renumbering them.

The new one-page summary of the rules, which I called a constitution, opened with a sentence saying every rule answers to it. Read literally, that ranked it above the list of decisions that stay with me. Two independent reviews missed it, and the third caught it. The page now says it ranks nothing and that the rule file wins.

The merge gate also blocked the rewrite itself. A full test pass existed, but its record had been written to the wrong folder, so the gate did not count it until the run was repeated properly.

A horizontal bar for 110 guards, a long green section labeled 104 fired on a planted failure and a short red section labeled 6 did not, captioned that the six went on the fix list.

The same night, a guard drill planted a failure in front of each of 110 guards. 104 fired. Six did not, and they are on the fix list now.

Related:

Questions this post answers

Which decisions should never be delegated to a coding agent?
In my setup, five: new recurring spend, publishing, switches that make a surface public, anything touching personal data, and changes to scoring logic. Each is either hard to reverse or carries a cost that keeps accruing. A passing test suite says the code does what it claims; it cannot say whether I want the result, so every agent stops and asks.
How do you know a guard hook for an AI agent is actually working?
Plant an example it must reject, using the literal input it will see in production, and watch it fail. A probe that feeds a convenient substitute, such as an escaped character, can pass while the real input slips through. In my last drill, 104 of 110 guards fired on their planted failures; the other six went on a fix list.