Build your own token filter when your waste sits in a few noisy commands on one agent and you are willing to measure. Adopt an open-source token optimizer when the waste is spread across file reads, tool manifests and long sessions, or across several agents. The filter itself is easy; keeping it from costing more than it saves is the real job.
I build Tokenade, a free, open-source optimizer, so weigh my view accordingly. I also ran DIY filters for months before writing it, and some of what follows is a list of my own mistakes.
Facts about Claude Code below come from Anthropic's documentation, read 2026-10-15. The only Tokenade figure quoted is the published THOL result, explained on the methodology page.
The options at a glance
| Option | What it is | Entry cost | Best for |
|---|---|---|---|
| CLAUDE.md rules | Written instructions like "pipe test output through tail" | Free, minutes | Nudging habits, no guarantees |
| Shell filters | grep, head, tail wrappers around noisy commands | Free, an afternoon | One or two known noisy commands |
| Hooks | PreToolUse / PostToolUse scripts that rewrite calls or trim results | Free, a weekend | One agent, predictable tools |
| MCP proxy | A server that sits between the agent and its tools | Free, weeks | Teams with an infra owner |
| Open-source optimizer | A packaged tool covering commands, reads, search and MCP | Free, setup time | Several agents, long sessions |
Build or adopt: the short answer
Build if your problem is narrow and you will measure it. Adopt an existing tool if it is broad or you will not. A twenty-line hook that keeps only the failures from npm test is a good piece of engineering. A homegrown system that tries to cover commands, file reads, search and MCP across three agents is a second product you now maintain.
The deciding question is not "can I write this?" You can. It is "will I notice when it starts costing me money?" Most DIY filters fail quietly, and the failure looks like a normal session with a slightly higher bill.
What building your own actually involves
A DIY token filter is usually four layers, added one at a time as each previous one proves insufficient.
1. Rules in CLAUDE.md. "Never cat a whole log, pipe it through tail -50." Cheap, and the agent often listens. But Anthropic is explicit that Claude "treats them as context, not enforced configuration" and points to a PreToolUse hook when you need a guarantee (memory docs). Every rule is also re-sent each turn, so a long rulebook becomes a cost of its own.
2. Shell wrappers. A test script that runs the suite and prints the summary plus failing tests. This works well when you know the command in advance. It does nothing when the agent improvises a command you did not wrap, which it does constantly.
3. Hooks. This is where real DIY filters live. updatedInput on PreToolUse rewrites a call before it runs; updatedToolOutput on PostToolUse replaces the result before Claude reads it (hooks reference). I mapped every event and its cost in Claude Code hooks: which add tokens, which cut them.
4. An MCP proxy. The ambitious version: a server between the agent and its tools that compresses results, dedupes reads, maybe adds search. At this point you are building an optimizer, with no users but yourself to find its bugs.
Claude Code already has defaults you should know before writing anything. A successful Bash result goes inline up to roughly 30,000 characters; past that, Claude gets a file path and a 2,000-character preview. A failing command gets roughly 10,000 characters as a head-and-tail excerpt (tools reference, output limits). The BASH_MAX_OUTPUT_LENGTH variable moves that ceiling (environment variables).
So the crudest DIY move, lowering that variable, is a one-line change. It is also blunt: it cuts every command at the same place, whether the useful line is at the top or the bottom.
Where DIY genuinely works
DIY is the right call more often than tool authors like me admit. These are the cases where I would tell a friend to write the filter and skip installing anything:
- One or two commands dominate your noise. A monorepo whose test runner prints 4,000 lines of passing tests. A filter that keeps the summary and failures pays back the same day.
- You use one agent and rarely upgrade it. The hook format is stable enough within one tool, and you will notice when it changes.
- Your sessions are short. On a ten-turn session, a stray log costs little. The compounding that makes filtering valuable needs length.
- You need a hard policy, not savings. Blocking
caton.envor capping a known-huge command is a gate, and a gate is exactly what hooks are for. - You enjoy it and you measure. If you read your transcript before and after, you will catch your own regressions. That habit is what separates a working DIY filter from a placebo.
The technique behind most of these is old and well understood; output filtering for command logs covers the verdict-plus-error pattern in detail.
The hidden costs of a homemade filter
The costs below do not show up when you write the filter. They show up three weeks later, in a bill that went up instead of down.
The agent re-runs what you cut
A filter that drops the byte the model needed makes the model fetch it again. You trim a stack trace to its last ten lines; the useful frame was line twelve. The agent re-runs the command with 2>&1 | grep, or reads the log file directly, going around your filter. Now you paid for the trimmed output, the re-run and the full output.
This is the most common failure mode I see on the open THOL benchmark, which describes it plainly: when compaction drops the bytes the model actually needed, "the model simply re-runs the command — often bypassing the tool" (THOL leaderboard, read 2026-10-15). A lossy filter needs a way for the agent to recover the full output without re-executing anything.
Your filter breaks the cache
Prompt caching only pays when the start of the request is byte-identical to the previous one. Anthropic's caching docs list what invalidates it: changing tool definitions, for instance, invalidates the entire cache (prompt caching). A cache read is billed at a fraction of fresh input, so losing it is expensive.
A DIY MCP proxy that toggles tools on and off mid-session, or a hook that rewrites earlier history, can turn a cheap cached prefix into a full-price re-read on every turn. THOL observed exactly this with a history-rewriting proxy: the few tokens its compression saved were dwarfed by the cache it broke. More on the mechanism in prompt caching and your input bill.
Standing overhead you forgot about
Every rule, tool description and injected reminder is paid on every turn. A CLAUDE.md section explaining your filters, an MCP server exposing six helper tools, a UserPromptSubmit hook that prints a reminder: each is small, and each is re-sent until the session ends.
If the agent rarely uses the tool, its description is pure loss. THOL names this standing cost as one of the main reasons tools that look good in isolation fail end to end.
Maintenance across agents and versions
Your filter is written against one agent's interface, and that interface moves. Claude Code's hooks reference keeps adding events and fields; output limits and defaults change between releases. If you also use Codex, Cursor or Copilot, each has its own extension surface, and your hook does not run there at all.
Failures are silent. The reference notes that a PreToolUse command hook which times out "doesn't block the tool call", and that a mistyped script path leaves a gate disabled with only a non-blocking notice. Your filter can be off for a week and nothing tells you.
No end-to-end measurement
The number you can see is what your filter removed, not what the session cost. Counting bytes before and after a filter is easy. Knowing whether the whole session got cheaper, after re-runs, cache misses and extra turns, requires paired sessions on the same task with and without it.
Almost nobody running a DIY filter does that, and it is the only test that counts. Start with how to measure agent token usage before trusting any filter, mine included.
When adopting an open-source tool makes sense
Adopting makes sense when the cost of keeping a filter correct exceeds the time it takes to install and evaluate an existing tool. In practice that happens in these situations:
- Your tokens are mostly file reads, not commands. Hooks on Bash do not touch the agent's built-in read and search tools unless you write separate logic for each. Skeleton compression for file reads is a different technique from log filtering, with its own edge cases.
- You use more than one agent. Rewriting the same filter for each agent's hook format, and again after each update, is the maintenance tax at its worst.
- Your sessions are long. That is where the compounding lives, and also where re-runs and cache breaks hurt most.
- You want a measured result rather than a feeling. A packaged tool should show you what it did, and ideally be measured end to end against a control.
On that last point, my own number: on long sessions, Tokenade cuts session cost by 39% compared with plain Claude Code, on the THOL benchmark (methodology). I maintain that benchmark, so the protocol and raw data are published for you to check.
What a packaged tool gives you is the parts that are tedious to build: folded output stored locally so the agent can recover the exact bytes with tokenade expand-ref instead of re-running the command, compression that keeps the cached prefix stable, and the same coverage across Claude Code, Codex, Cursor, Copilot and Windsurf.
Compaction runs on the computer where you work, with no telemetry. Tokenade is free and open source (MIT/Apache-2.0), with no account, so adopting it costs setup time, not money. And because the source is public, you keep the main advantage of building: you can read exactly what it does to your output, or fork it.
How I compared the two
I judged both routes on what reaches the invoice, not on how much text a filter removes. Five questions:
- Does it cover the channels where your tokens actually are (commands, reads, search, MCP)?
- When it cuts too much, can the agent recover without re-running?
- Does it keep the cached prefix byte-identical?
- Does it survive agent updates and a second agent?
- Is there a session-level, before-and-after measurement?
| Dimension | DIY filter | Open-source optimizer |
|---|---|---|
| Upfront cost | Your time to write it | Install and setup time |
| Coverage | Whatever you wrote | Commands, reads, search, MCP |
| Recovery of cut output | Usually none: agent re-runs | Built in, if the tool is designed for it |
| Cache safety | Up to you | Should be a design goal; check it |
| Multi-agent support | One hook format per agent | Shipped by the maintainers |
| Measurement | Bytes removed, at best | Session-level, if published |
| Control | Total | Settings, plus the source to read or fork |
Which one should you choose?
- Solo dev, one agent, one noisy test suite: build a
PostToolUsehook. Keep failures and the summary line. - You need a guardrail, not savings: build it. A
PreToolUsegate is the right tool. - Heavy daily user, long sessions, mostly file reads: adopt an existing optimizer, or at least try one for a week.
- Several agents in the same week: adopt one. Maintaining four filter variants is not a hobby.
- You are not measuring yet: do neither. Measure one week first, then decide.
FAQ
Is a homemade Claude Code hook enough to reduce token usage?
For a narrow problem, yes. A PostToolUse hook returning updatedToolOutput with only failures and the summary line can cut a noisy test log to a fraction. It will not touch file reads, search or MCP manifests, and it only runs on Claude Code. Measure total session input before and after, not the size of one trimmed result.
Why would a filter increase my bill?
Three ways. It drops a line the model needed, so the agent re-runs the command and pays twice. It changes something early in the context, so the cached prefix is lost and the history is re-read at full price. Or it adds instructions and tool descriptions that are re-sent every turn. All three are invisible if you only count bytes removed.
Can I just lower BASH_MAX_OUTPUT_LENGTH?
You can, and it is the cheapest experiment there is. Claude Code inlines successful Bash output up to roughly 30,000 characters by default and saves larger results to a file with a 2,000-character preview. Lowering the limit cuts every command at the same point, so a useful line near the end may move into a file the agent then has to read.
Should I write rules in CLAUDE.md instead of hooks?
Use CLAUDE.md for habits and hooks for guarantees. Anthropic's documentation says Claude treats CLAUDE.md as context rather than enforced configuration, and recommends a PreToolUse hook when an action must be blocked regardless. Rules also cost tokens on every turn, so keep them short.
Is Tokenade open source?
Yes. Tokenade is open source under MIT OR Apache-2.0, and the code is on GitHub. Compaction runs locally on the computer where you work and there is no telemetry, so your code and logs are not sent anywhere. If you need to inspect every line of your filter, you can read Tokenade's or build your own.
See also:
- Claude Code hooks: which add tokens, which cut them: the event-by-event cost map for DIY filters
- Output filtering for command logs: the verdict-plus-error technique
- Skeleton compression for file reads: the channel most DIY filters miss
- How to measure agent token usage: the before-and-after test any filter needs
- Best Claude Code token optimizers: if you decide to adopt, the ranked field
Cut your AI agent's token bill.
Ranked #1 on the Token-Harness Optimizer Leaderboard. Zero config.
Tokenade cuts the token bill of AI agents: one install, zero config, and it trims what your agent sends to the model.