I build software with LLM coding agents doing most of the typing. That
changes what a coding standard is for. A human team needs standards so
people can read each other's code. An agent team needs standards
because an agent will do exactly what makes the current task look
finished, and nothing else.
What agents get wrong, reliably
These are not occasional slips. Every one of them happened often
enough in my repositories that it now has a rule and a check.
Copying instead of sharing. It is quicker to paste a function and
change one value than to find the existing one and add a parameter.
Swallowing errors. A failing test goes green fastest when the
error is caught and turned into null, [] or a default.
Weak tests.expect(result).toBeDefined() passes for almost any
bug. So does a test that sets a value and reads it back.
Widening the exceptions. A check fails, and the agent adds the
file to the ignore list. The check still runs and now proves less.
Keeping dead code. An export "might be useful later", or exists
only because a test imports it.
Building the easy half. The types and helpers land, and the
hard behaviour is left for "a later pull request".
Fixing the wrong thing. A flaky runner or a broken tool gets a
retry loop or a workaround, and the real problem is buried.
Narrating. Comments that repeat the code, commit messages that
tell a story, and documentation that hedges every sentence.
The four layers
Each rule that matters gets as many of these layers as it can carry.
A written rule with its reason. It lives in AGENTS.md or a
document AGENTS.md links to. The reason matters, because the
preferences are "defaults, not laws", and an agent can only bend a
rule sensibly if it knows what the rule is for.
A mechanical check. If a machine can judge the rule, a script
judges it in precommit and in CI. Agents do not argue with a red
check the way they argue with a sentence.
A ratchet. Most checks start on a codebase that already breaks
them. The existing breaks go into a baseline that can only shrink,
so the check is strict for new code from day one.
A test of the test. Coverage proves the tests run every line.
Mutation testing proves they would notice if a line changed. Model
checking proves the state machines are safe for every run, not
only the runs someone thought to write down.
Principles that run through everything
Fail loudly. Never default away a missing value. A crash with a
clear message is cheaper than a wrong answer that looks right.
One source of truth. Declare a thing once, as data, and derive
everything else from it. Two copies of a fact will drift.
Lists that only shrink. Every exception list, baseline and
registry is a ratchet. Adding to one is an owner decision, never a
side effect of making a check pass.
The code is the authority once it exists. A plan governs work
that is not built yet. After that, check every claim against the
real source and tests.
Hardest first. Build the part most likely to change the design
first, so the easy parts are built on the right shape.
The trap to avoid
Checks are not a substitute for design
Mutation testing can show that an assertion is weak. It cannot show
that a state, a race or a provider failure was never designed. That is
why the behaviour contract
comes before any code, and why a human approves it.
The checks keep a good design good. They do not make a bad design
good.
Design first, then check
Plan the states, failures, retries and races. Then let the machines hold the line.
Where to start if you want to copy this
You do not need all of it. In my experience the order of value for
effort is roughly:
A single AGENTS.md with pre-decided answers. Costs an afternoon.
A strict linter config, run read-only in CI.
Copy-paste detection at 0%, with a low token threshold.
Ratchets on anything that starts dirty.
100% coverage, with an exclusion list that only shrinks.
Weak-assertion checks on test files.
Mutation testing on the files a branch changes.
Acceptance specs in plain language for the user journeys.
Nightly runs against real sandboxes for anything that talks to
a third party.
State machines and model checking for anything that moves
money or cannot be allowed to lose data.
The last few cost real effort. They earn it in code where a bug costs
someone money.