ctsheehan.com / writing
Context engineering

I deleted 71% of my agent instructions

Every rule you write for a coding agent gets read on every single request, forever. Most of mine were correcting for a model that no longer exists. Here is the rubric I used to work out which ones, what came out, and what I kept.

Agent setups only ever grow. Something goes wrong, you write a rule so it does not go wrong again, and the rule stays there forever. Nobody schedules time to delete one. There is no linter for it and no test that fails when a rule goes stale, so the pile just accumulates, quietly, for as long as you keep using the thing.

I measured mine last week. Across six repos there were 63,572 words of always-on instructions, and my worst single session was loading 25,112 of them, about 33,000 tokens, before it read one line of my actual code. Rules, gotchas, conventions and advice, read in full on every request, most of it written months ago for models that have since been replaced twice.

The six repos are now down to 18,200 words in total, and that worst session to about 8,200. Nothing broke. Here is how, and more usefully, here is what turned out to be in there.

Part 01

The idea is older than the tooling, and it is called ablation

This started with Boris Cherny, who created Claude Code, on the Y Combinator Startup Podcast in July. He said that when Opus 5 shipped they deleted 80% of Claude Code's own system prompt, and the reason is the interesting part:

"A lot of the stuff in the system prompt was correcting for these behaviors that the model should have known, but it didn't. Now, Opus 5 just does it."

Boris Cherny, Y Combinator Startup Podcast, 28 July 2026

They test this with an ablation, which is the research habit of deleting everything and then adding it back one line at a time to measure what each line is actually worth. He mentions an undocumented environment variable that strips every system prompt including the tool prompts, which they run specifically to answer the question "is this prompt useful?" His finding, stated plainly:

"The model is actually a little bit more intelligent without these prompts."

Then he gave the version of the advice that applies to everyone who is a user of these tools rather than a builder of them: every six months, delete your CLAUDE.md. Delete your skills. Delete your hooks. See what the model does.

The thing that makes this land is the asymmetry nobody prices in. We treat an instruction as free upside: worst case the model ignores it. But an always-on instruction is not free, it is rent. You pay it on every request, in context that could have held your actual code, and you pay it in attention, because a model reading 80,000 tokens of accumulated house rules is a model with less room to think about the problem in front of it. Past some threshold the pile starts crowding out the parts that still matter.

Part 02

Measure before you cut, because the number is worse than you think

Nobody knows their own footprint. Mine was three times what I would have guessed, and it was not concentrated where I expected. Fifty lines of shell answers it:

measure-footprint.sh
$ ./measure-footprint.sh ~/code/some-project
== Project: ~/code/some-project ==
project CLAUDE.md                                  1110 words
project .claude/rules/*.md (all auto-load)        15959 words
== Global (loads in EVERY session) ==
global ~/.claude/CLAUDE.md                         3210 words
global ~/.claude/rules/*.md                        2706 words
skill frontmatter descriptions (always-on)         2127 words
-----------------------------------------------------------
TOTAL always-on                     25112 words (~32646 tokens)

Before any of your code is read. Three of those five lines were invisible to me until I counted them.

Two things catch people out here. The first is that the whole rules directory loads whether or not your main config file imports it, so the import list you are maintaining is decoration and the real number is wc -w on the directory.

The second is skills, and this one is genuinely sneaky. A skill is lazy: its body sits on disk until the skill triggers, which is exactly what you want. But its description is not lazy, because the model has to see every description in order to know which skill to reach for. So descriptions are always-on, and if you have written them as thorough paragraphs (I had, twenty-seven times over) you have quietly built a second always-on config file out of metadata. Trimming those to trigger phrases and pushing the detail down into the lazy body costs nothing and buys real room.

Part 03

The rubric: four buckets, and one question that settles most lines

"Delete it all and see" is correct advice and slightly terrifying advice, because some of that pile is load-bearing. What made this tractable was sorting every block into four buckets, and the sorting is almost mechanical once you have the right question. For every line: could the model know this without being told? If yes, it goes. If no, it stays.

KEEPThings the model cannot possibly know

Where the credentials live. Project and account IDs. Hostnames, ports, test phone numbers, the magic OTP your staging environment accepts. Tenant mappings. Real tooling bugs and their workarounds, but only the ones that still reproduce. Safety rails around operations you cannot undo. None of this is guessable from the code, so all of it earns its rent. Compress it, do not cut it.

CUTInstructions correcting behavior the model already has

"Research before implementing." "Prefer libraries over hand-rolling." "Do not over-engineer." "Verify your work." "Explore the codebase first." Every one of these was worth writing in 2025 and every one is now a model telling itself something it was going to do anyway. Same for the dated war stories: if the rule survives, one line states it, and the three-paragraph story of the afternoon you discovered it does not need to ride along on every request forever.

ARCHIVEEverything you are afraid to lose

This is the bucket that makes the whole exercise safe. Old gotchas move, verbatim, into a file that is not auto-loaded. Nothing is destroyed, it just stops being read on every request. The day the model actually stumbles on something you cut, you restore exactly one line from the archive. Without this bucket you will be conservative and cut nothing, which is how the pile got there in the first place.

MERGEThe same thing said in four places

Overlapping files on one topic collapse into one. Reference data that has been living in an always-on rules file (decision logs, inventories, profiles) moves into docs behind a pointer that says what lives where and when to read it. The pointer is fifteen lines and replaces thousands.

The one rule that overrides the rubric: a guardrail has to load before the mistake it prevents. If the failure mode is silent or destructive, that rule stays always-on no matter how obvious it looks, because a lazily-loaded guardrail never fires in time. Everything else can go and be earned back.

Part 04

What was actually in there

Six repos: two product codebases, an ops repo, a data pipeline, a documentation-heavy private repo, and the global config that loads into all of them.

before after product web app 17,069 → 3,573 -79% ops + automation 17,016 → 3,084 -82% mobile app 12,789 → 3,458 -73% global config 8,043 → 4,672 -42% data pipeline 5,261 → 2,429 -54% docs repo 3,394 → 984 -71% total 63,572 words in, 18,200 out -71%
swipe the chart sideways →
One pass, six repos, nothing broke. The global config cut least in percentage terms and matters most, because it loads into every session in every repo.

The categories, roughly in order of how much they cost me:

  1. Stale gotchas. The biggest single file was 10,096 words of workarounds, and its own header said it should only ever hold the current month. It was holding three. A policy nobody enforces is a policy nobody has.
  2. Advice for a model that no longer exists. Whole sections of engineering guidance that modern models simply follow unprompted.
  3. Reference data filed as rules. Six files of personal and project reference material, about 8,000 words, loading on every single request because they happened to live in the rules directory. They are now docs behind a fifteen-line pointer.
  4. The same rule in three places. Global config, project config, and a skill, all stating it slightly differently, which is worse than stating it once because now they can drift apart.
  5. Dead references. Instructions naming scripts, files and flags that no longer exist. The instruction survived its subject by months.
  6. Overlapping files. Five separate testing documents in one repo, 2,383 always-on words, now one file of 464.

The find that actually changed my mind about the exercise was none of those. One repo had a rules file from a rebuild that shipped back in June, and it still carried the instruction never modify this file, which had been correct during the migration and was now simply wrong. Any agent picking up work in that area was being told to avoid the exact file it needed to edit. That is the real cost of an un-audited instruction pile: not the tokens, but the confident, specific, obsolete directive sitting in the middle of them.

Stale instructions do not decay into noise. They decay into confident, wrong instructions, and the model has no way to know which is which.

Part 05

Running it as a fleet, with a verifier that can veto

I ran this as a workflow rather than by hand, three stages per repo, each repo flowing through independently: an analysis agent that classifies every block against the rubric and writes a plan, an implementation agent that executes the plan on a branch, and a verify agent whose only job is to try to catch the other two.

The verify stage is the reason I was willing to let agents delete things. It re-reads the plan's KEEP list, then checks the merged result to confirm those specific items survived, scans the whole diff for anything that looks like a credential, and confirms nothing outside the intended paths was touched. It has the authority to stop the merge. That is what makes an aggressive cut safe: not the agent being careful, but a second agent being paid to assume the first one was not.

It earned its keep immediately. In one repo the analysis plan had drafted a replacement table of fixture values, and the verify agent checked them against the actual source file and found one that did not exist. The plan had faithfully copied a value from documentation that had drifted from the code, which is precisely the failure mode this whole exercise exists to fix, reproduced live during the fix.

The other thing worth stealing: every PR body carries the before and after word count per file, plus a list of the riskier deletion candidates that were deliberately not taken. The counts make the change reviewable in ten seconds instead of by reading a 9,000 line diff, and the deferred list means the next pass starts from a real inventory rather than from scratch.

Part 06

What to watch out for

01Branching from main will silently revert your uncommitted work

Two of my repos had substantial uncommitted changes in the working copy, including edits to the very files being ablated. An agent that branches from the remote, rewrites those files and merges has just reverted work that was never committed, and the revert looks exactly like part of the intended cleanup. Check which target files are dirty first, and base those edits on the live file rather than the remote one. This is the one that would have actually cost me something.

02Deleting a section leaves dangling pointers in other repos

My global config pointed at a section of a project config for the detail. The project section was cut, correctly, and the pointer became a reference to nothing. Cross-repo references are invisible to a single-repo pass, so grep for the section name everywhere before you cut it, and expect a small follow-up.

03The archive is the feature, not the deletion

Every entry that came out of an always-on file went into an archive file in the same repo, verbatim, in the same commit. This is what let me be aggressive: the cost of being wrong about any single line is one restored line, not a lost lesson. Teams that skip the archive step end up cutting only the things they are already sure about, which are the things that were not costing them anything.

04You cannot A/B this, and pretending otherwise wastes time

There is no clean experiment here. You cut, you use it for a couple of weeks, and you notice whether the model starts stumbling on something specific. Only then do you restore that one entry. That is unsatisfying if you want a dashboard, but it is the same empirical loop the people building these harnesses describe using themselves, and the alternative is guessing which instructions matter, which is how a pile like this reaches 63,000 words across six repos.

Where to start

If you have never audited yours

Three steps, in this order.

Count it. Do not skip to cutting, because the number is the thing that makes you willing to cut. Include your global config and your skill descriptions, which are the two people forget.

Sort with the one question. Could the model know this without being told? Environment facts stay, advice goes, war stories get archived. When you are unsure, the default is cut, because you can restore in one line and you cannot un-spend the context.

Then leave it alone and use it. Add an instruction back only when you catch the model repeatedly failing at the same specific thing. Every line you add back should be able to name the failure it prevents.

I put the rubric, the measurement script and the multi-repo workflow in a repo, generic enough to run against any setup:

If your team's setup has been growing for a year and nobody has ever deleted anything from it, that is the normal case, and it is worth an afternoon. Happy to compare notes, email me.

Get in touch
chris@ctsheehan.com
← Back to ctsheehan.com