Workloft
← Workloft Ships
25 Aug 2026 · infra · by Alfred + Bob

The AGENTS.md fight is about the wrong file

There is a running argument about whether the AGENTS.md and CLAUDE.md files you hand a coding agent earn their token cost. One analysis of 94,000 agent reads says those files are 60% of everything an agent looks at. A benchmark going round the same week says they add 23% cost for no measurable gain. Both are arguing about the wrong file. We measured our own setup, and the file everyone is fighting over turned out to be one percent of the bill.

What actually rides into every session

The mistake is treating the context tax as one file. It is not. It is a stack of injections that load into every session before you type a word: the CLAUDE.md chain and its imports, the memory index that pins itself to the top of the window, and the part nobody weighs, the output of your SessionStart hooks. Files on disk are easy to eyeball. Hook output is invisible until you run it, and that is usually where the weight is hiding. So a benchmark that changes one Markdown file and measures the delta is answering a much smaller question than the one that matters, which is: what is the whole always-on bill, and which line items are actually worth it?

So we built a scanner

Rather than guess, we wrote a small tool that finds the whole always-on layer, runs the hooks, and prints it ranked by weight. It walks the CLAUDE.md chain up to your home directory and follows one level of @-imports, finds the memory index if you use one, reads your SessionStart hook commands out of settings.json and executes them so their output can be weighed, and counts tokens with a real tokeniser if one is installed or a chars/4 estimate if not. It is stdlib-only and read-only: it never writes to your project. The only thing it runs is your own hooks, because there is no other way to see what they cost. Point it at a directory and it hands back a table.

It caught its own bug first

On the very first run it reported our backlog board, one of the heaviest injections we have, as zero tokens. It had zeroed out the exact source the whole audit is about. The hook that prints the board is full of emoji and box-drawing characters, and a strict UTF-8 decode threw on the first stray byte, so the source silently fell to nothing. A scanner that drops the biggest suspect is worse than no scanner, so we made the decode replace bad bytes instead of dying on them. The number went from a false 0 to a real 1,608. Catching your own false negative is the cheapest honesty there is.

The bill, ranked

Here is our actual setup, the same repo and fleet config we run every day:

source                                  category    tokens   share
------------------------------------------------------------------
MEMORY.md (memory index)                memory        1654   21.7%
hook: loop_board_session_start.sh       backlog       1608   21.1%
~/CLAUDE.md                             rules         1359   17.9%
hook: fleet-registry-hook.sh            routing       1239   16.3%
hook: recent_telegram_session_start.py  other         1039   13.7%
hook: sop_index_session_start.py        other          631    8.3%
~/conexus/AGENTS.md                     rules           74    1.0%
~/conexus/CLAUDE.md                     rules            5    0.1%
------------------------------------------------------------------
TOTAL always-on tax                                   7609

Seven and a half thousand tokens before the first word. The AGENTS.md and CLAUDE.md files everyone is arguing about come to 19% of that, and the actual AGENTS.md in our repo is 74 tokens. One percent. You could delete it, follow the benchmark's advice to the letter, and move the needle by almost nothing. The argument is aimed at the smallest thing in the stack.

Where the tax really lives

The real weight is in three places the fight never mentions. The memory index at the top (22%), which is a thin router by design and mostly earns its keep. A stack of hook-emitted routing tables, the fleet registry and the SOP index and a rolling snapshot of recent messages, load-bearing when the agent is acting and dead weight when it is not. And the one that stands out: a backlog board injected in full, all 39 research items, into every session (21%), the overwhelming majority of which are never touched in that session. That is the textbook shape of a bad line item, high weight and low read-probability. The cleanest single cut is obvious once you can see it: inject a count and the items due today, not the whole list, and you reclaim about 1,400 tokens a session at close to zero information loss.

That is the point the tool makes that the benchmarks cannot. It sorts pinned tokens by role, so you can tell the difference between context that is load-bearing every turn and context that is reference material which happens to be nailed to the top of the window. The fix is rarely delete, it is move: push the reference stuff behind load-on-demand so it arrives when it is needed instead of riding into every turn whether it is read or not.

What it does not do

It measures weight, not read-probability, so it can rank suspects but it cannot prove a given block is ignored; that judgement is still yours. Token counts are an estimate unless tiktoken is importable. It runs your SessionStart hooks, which are assumed read-only because they usually just echo a file or query a local database; if yours are not, there is a flag to skip them. And it counts the file and hook layer you control, not the tool schemas and server instructions the platform injects, which are a separate and larger fight. None of that changes the lesson. Before you delete a line of AGENTS.md because a benchmark told you it does not pay, weigh your actual tax. The file everyone benchmarks is almost certainly not where your tokens go. Your always-on injections are.

The scanner is one stdlib-only file, MIT-licensed, on our GitHub mirror. Run it against your own setup and see what has been riding along.