We Cut Agent Instructions by 76%
We cut always-loaded agent instructions by about 76% without deleting knowledge, by moving guidance to the narrowest layer agents reliably find before it applies.
Founder / CEO
Bottom Line
- Our root instruction file went from 36,914 bytes to 8,890 (75.9% smaller) and the Claude Code default payload from 38,684 bytes to 9,638 (75.1%), measured with a deterministic script.
- The goal was to minimize default context, not knowledge: detail moved to patterns, checklists, skills and deterministic gates, each with exactly one canonical owner.
- An always-on test decides what stays in the root file, and a router table plus a route audit keep moved guidance findable.
- A byte budget enforced in CI forces a conscious decision to grow the root file; it has been raised in small steps since, and the file is now larger than at the audit.
- Token counts are a ceil(bytes / 4) proxy, and this post measures default context size, not task success.
Every byte in an always-loaded instruction file is paid for on every task, including the ones it has nothing to do with. We audited ours and cut the agent instructions loaded into the context window by roughly 76%, from 36,914 bytes to 8,890 in the root instruction file, without deleting the knowledge that was in them. The knowledge moved to places agents reach only when it applies.
This post is the measured version of a story we told in the overview of our agent guardrails. It covers the rule we used to decide what stays, the numbers, the checks that keep moved guidance discoverable, and what we did not measure. It is one part of how we run agents safely, which the hub post lays out in full.
How the waste started
Our first approach to agent documentation was consolidation. We gathered project knowledge into instruction files and let hooks and prompts inject large documentation blobs into every session. It felt responsible: the agent had everything. In practice the agent re-read rules for database migrations while editing a Twig template, then still missed the specific pattern for the change it was making.
The first fix was on-demand retrieval. We split monolithic backend and frontend guidance into focused pattern documents and checklists, and exposed them through a project MCP server that agents query by name. An agent writing a new entity asks for the entity pattern. An agent finishing a migration asks for the migration-safety checklist. When the server is unavailable, the root file names the same documents in a docs folder as a fallback, so the route works with and without the tool.
That removed the injected blobs, but the root file kept growing anyway. Commands, thresholds and procedures drifted back into it one reasonable sentence at a time. The audit was the second pass, and this time we wrote down the rule that decides what is allowed to stay.
Minimize context, not knowledge
The principle in our instruction architecture document is one sentence: minimize default context, not knowledge. Guidance belongs in the narrowest layer that agents can reliably discover before it applies. The document assigns each layer a job and a list of things that do not belong there.
| Layer | Holds | Does not hold |
|---|---|---|
| Root instruction file | Universal invariants and a concise router | Detailed commands, examples, thresholds, work-type procedures |
| Patterns and checklists | Conventions and completion criteria for one work type | Host mechanics, unrelated domains |
| Skills | Repeatable workflows with ordered actions | General reference, or rules that apply without the workflow |
| Reference docs | Explanation, examples, troubleshooting | A requirement with no route from the layers above |
| Deterministic tooling and CI | Formatting, static checks, thresholds | Judgment that needs product or security reasoning |
| Host files | Behavior unique to one host | Shared coding rules copied from the root file |
The table matters less than the last column. Most of the bloat we found was text sitting in a layer whose "does not hold" cell described it exactly: a threshold in prose that a gate already enforces, or a command sequence that a skill already owns.
The always-on test
A rule earns a place in the root file only if at least one of four things is true.
- It must constrain the agent before the task type is known.
- Missing it could cause irreversible, security-sensitive, financial, compliance, environment, or collaboration harm.
- It is a near-universal architectural boundary that should shape most designs.
- The relevant host cannot reliably load a narrower instruction source.
Even a rule that passes keeps only its invariant in the root, with detail routed to its owner. The document is explicit that importance is not the criterion: a migration rule can be critical and still belong in the migration pattern, as long as the root reliably sends every migration there. That sentence ended most of the arguments. "But this one is important" is not a reason to load it on every task.
What survived in the root file: the rule against committing or pushing without an explicit ask, the environment and runtime invariants, the root-cause rule, worktree isolation, the independent-trader boundary, universal architecture constraints, the task router, quality routing, and mandatory browser verification. The isolation rule is a good example: one line in the root, with the detailed steps living in a skill.
A router table instead of detail
The replacement for the removed detail is a task router table in the root file. Each row names a kind of work and the guidance to load before starting: a pattern, a checklist, a skill, or a reference document. The row for a new controller points at the controller pattern and the new-controller checklist. The row for a migration points at the migration pattern, the safety checklist and the safety tooling.
A router is only useful if it is true, so two audit scripts enforce it. The first parses the table and fails when a row has no deterministic discovery route, when a routed path does not exist, when a named pattern or checklist has no backing document, or when a shared skill has no exact path in any row. That last check is the orphan guard: a skill nobody routes to is effectively deleted knowledge. The second checks the skills themselves: the declared name must equal the directory name, the canonical tree must hold real files only, and each host-specific link must point at its canonical skill. It also pins safety settings, such as the one that stops a model from invoking a skill on its own, to their exact values, because flipping one is a smaller diff than deleting it.
The rule we hold ourselves to is in the architecture document: do not fix duplication by deleting the only discoverable copy. Move it, route it, and test the route.
The numbers
Measurements come from a script that reports bytes, words and lines for each always-loaded file, and runs against the working tree or any git ref. Estimated tokens are the byte count divided by four, rounded up. That is a deterministic proxy so before and after compare on the same scale. It is not a model tokenizer, and a real tokenizer will give different absolute counts. The script excludes conditional path-scoped instructions, invoked skills, MCP responses and host wrappers, because those are not default context.
| Always-on file | Before (bytes / proxy tokens) | After | Reduction |
|---|---|---|---|
| Root instruction file | 36,914 / 9,229 | 8,890 / 2,223 | 75.9% |
| Claude Code instruction file | 1,770 / 443 | 748 / 187 | 57.7% |
| Copilot review instructions | 19,863 / 4,966 | 5,937 / 1,485 | 70.1% |
What a host actually loads is a combination of files. Cursor, Codex and the Copilot coding agent read only the root file, so their payload fell 75.9%. Claude Code reads the root file plus its own host-specific file: 38,684 bytes (9,671 proxy tokens) before, 9,638 bytes (2,410 proxy tokens) after, a 75.1% cut. Copilot code review reads its own file and fell 70.1%.
Two honesty notes. First, we checked for other auto-loaded files and found none: no additional nested root-level instruction files and no Cursor rule files existed, and the review agent's four path-scoped instruction files are conditional, so they are not counted. The audit skill tells future auditors to re-check for newly introduced auto-loaded files before comparing totals. Second, the numbers are a snapshot from the audit. The root file has grown since, as the next section explains.
Canonical owners for every requirement
Cutting 28,000 bytes from one file is easy if you are willing to lose things. The audit did not allow that. For every section removed, it records where the detail now lives:
- Environment providers, setup stages and remediation went to the environment skill and its pattern.
- The browser tool sequence, authentication and failure handling went to the browser verification skill and pattern.
- File, branch and full quality scope, coverage, mutation, complexity and static analysis commands went to the targeted-quality-checks pattern and the patterns it names.
- Postgres migration rules went to the migration pattern, its checklist, and the deterministic migration-safety gate.
- Pull request procedure went to the pull request skill and the pull request workflow document.
- Full review methodology and examples went to the review rubrics, with file-type detail in path-scoped instruction files.
The same mapping makes the opposite mistake visible. When we find a requirement written in two places, one of them is wrong the next time it changes. Picking a single owner and routing to it from everywhere else is cheaper than keeping copies in sync, and the router audit makes the route testable. Rules that are mechanical went to a gate instead: a threshold in prose is a smell when a tool can enforce the number.
A budget that forces a decision
Cutting once does not help if the file regrows. A budget check compares each always-on file with a ceiling stored in a small checked-in file, and CI fails on overage. When we audited, the ceilings were 9,500 bytes for the root file, 800 for the host-specific file and 6,000 for the review instructions.
The budget is deliberately not a forever limit. The architecture document calls it a responsibility brake and says raising it is allowed when a real invariant or router line needs room. The condition is process: you edit the budget in the same pull request, keep the addition tight, and explain why in the summary. Budgets are ceilings, not targets, and spending headroom is discouraged.
We tested that process for real. When we added guidance for request-only CI (the subject of a later post in this series), the root file needed more room than the ceiling allowed, so that pull request raised the budget. It has been raised in a few small steps since, and the root file is now about 10,300 bytes against a 10,320-byte ceiling. That is larger than the 8,890 we measured at the audit, and still far below the 36,914 we started from. We would rather have that visible, argued growth than none of it being noticed. The gate does not prevent growth. It prevents silent growth, and every raise is a diff someone has to read.
What we did not measure
The reduction numbers are about default context size. They say nothing about whether agents behave better, and a smaller file proves nothing by itself, so the audit skill says token reduction is never sufficient evidence.
The audit did run an effectiveness comparison: six existing tasks, three runs each, 18 samples at a 0.8 pass threshold, before and after. All 18 passed in both cases. Five focused regression tasks covering migration safety, browser verification, compliance, worktree isolation and pre-pull-request verification added 15 more samples, which also all passed. Optimized total: 33 of 33. Be careful reading that. A baseline that already scores 100% leaves no room to show improvement, so this evaluation can detect a regression but cannot prove a gain. The runs also used one agent provider, and an earlier harness had to be replaced because it hardcoded an executable we did not have.
We also did not measure task success rate in production, wall-clock time, or what the token proxy costs in dollars. Task success, including how we turn real misses into failing fixtures before touching any documentation, is covered in the post on regression tests for agent instructions. CI runs only the deterministic checks and scores checked-in fixtures; live agents never run in CI, and the full local pack runs periodically on a developer machine.
Lessons
- Measure with a script you can rerun. A byte count at any git ref, with a stated proxy for tokens, beats an estimate in a pull request description.
- Write down the test for the root file. "Is it important?" admits everything. "Must it constrain the agent before the task type is known?" does not.
- Give every requirement one owner. Route from other layers instead of copying, and test the route so moved guidance cannot become orphaned.
- Treat growth as a decision. A budget enforced in CI that you can raise in the same pull request turns silent drift into a reviewed change.
- Do not claim more than you measured. We showed smaller default context and no regression on a fixed task pack, not better agent outcomes.
The routing approach has a cost we accepted: an agent that skips the router misses guidance that used to be handed to it. That is why the skip-the-router answer is one of the negative fixtures we score, and why we treat a missed route as a defect in the router rather than a reason to paste the detail back into the root file.