AGENTS.md is infrastructure

Checked 22 Sep 2026 · By Luke Czak

ArticleUnderstanding AIFree to read

Two engines reading two different copies of the same rules drift apart silently, with no error to catch it. One real file and a pointer is the only shape that stays correct.

I run agents from more than one vendor against the same codebase, and each vendor’s CLI looks for its own configuration file by convention — one reads a file named after itself, another reads a differently named one. The obvious move, the first time you hit this, is to write the rules twice: once in each file, adjusted slightly for each engine’s expectations.

That obvious move is wrong, and it took a real instance of drift to see why. I updated a standing rule in one file after a mistake, moved on, and did not touch the other file. Weeks later, an agent running on the second engine broke the exact rule I had already fixed — not because it ignored the rule, but because the copy of the rules it was actually reading had never been told about it. The failure was silent. Nothing errored. The rule simply did not exist from that engine’s point of view.

What made the drift especially hard to catch is that both files still looked complete on their own. Read either one in isolation and it reads as a full, sensible rulebook — there is no missing section, no obvious gap, because the gap is not inside either file, it is between them. Skimming the second file for correctness gives no way to know a rule exists elsewhere that this file should also carry, because nothing in the file says so.

The fix is not discipline. "Remember to update both files" is a promise that survives until the day you are tired or in a hurry, which is most days eventually. The fix is removing the second copy entirely. One file holds the actual rules. The other file is not a copy — it is a pointer, a single line telling its engine to go read the real one.

This only works if the pointer mechanism is one the engine actually honours rather than one you are hoping it honours, and the two ways of building it are not equivalent even though they look interchangeable on a good day. A soft include depends on the reading tool resolving a reference correctly at load time, and it can be dropped by a tool that changes how it resolves references, or that hits a path it cannot follow — the file naming the reference still looks fine, and the rules are simply absent from context with nothing to catch it. That is worse than duplication, because it fails exactly like success does. A filesystem symlink fails differently: if it is broken, the file does not open at all, and a file that does not open is loud in exactly the way a silently unresolved reference is not. I have moved to that kind of link wherever the tooling supports it, because I would rather have a pointer whose failure mode is an error than one whose failure mode is indistinguishable from working.

The same logic scales past two engines. Rules meant to apply everywhere live in one real file, and every project- or account-specific version is a pointer back to it. Rules specific to one project live in that project’s real file, with its own pointer from whatever the local engine expects. The result is that there is exactly one place to edit a rule, no matter how many engines or how many repositories are meant to obey it.

What made this click for me as infrastructure rather than configuration is that configuration is the kind of thing you are allowed to let drift a little — a stale setting mostly means a slightly wrong default somewhere low-stakes. A rules file that is out of sync is not a slightly wrong default. It is an agent operating on a rulebook you believe you updated and did not. That is the same class of bug as two services reading two different copies of a schema, and you do not fix that by promising to keep them in sync by hand. You fix it by making sure there was only ever one copy to begin with.

Comments (0)

Sign in to comment.