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.