Hooks that trim test and log output before Claude reads it
A hook can remove the passing lines from test output, and the lines without errors from a log, before Claude reads them. A hook is a command that Claude Code runs by itself at a fixed point, and a hook on the PreToolUse event can rewrite a terminal command before it runs. Anthropic's documentation, read on 4 October 2026, gives a working example that keeps only the failing lines of a test run. This page reproduces that example, shows how to check it with `/hooks` and a debug log, and lists what the filter can hide, such as a failure that is reported with an unexpected word. It also covers code intelligence plugins and subagents.
Published October 4, 2026. Editorial.
Key takeaways
- Anthropic's documentation, read on 4 October 2026, says a hook that returns only the lines containing ERROR from a 10,000-line log reduces context from tens of thousands of tokens to hundreds.
- A `PreToolUse` hook can change a command before it runs by returning a field named `updatedInput`, which replaces the entire input of the tool.
- Anthropic's example script keeps the lines that contain FAIL, ERROR or error:, the five lines after each, and at most 100 lines in total.
- Running `/hooks` shows whether the hook is listed under `PreToolUse`, and a debug log shows a `modified tool input keys` line when the hook rewrites the command.
- Anthropic states that one go-to-definition call from a code intelligence plugin can replace a text search followed by reading several files.
Claude Code is Anthropic's coding tool. You type a request, and an AI model reads files, runs commands and edits code for you. The work is counted in tokens. A token is a piece of text that the model processes, and every request you send is measured in tokens.
When Claude runs your tests or opens a log file, the full output goes to the model, and much of that output can be lines that report no problem. A hook can remove those lines first. This page calls that trimming the output: the hook removes the lines nobody needs before the model reads them. A hook is a command that you write and that Claude Code runs by itself at a fixed point in its work, for example before every terminal command.
This page belongs to the guide on how to reduce Claude Code token usage. It shows the example hook from Anthropic's documentation, read on 4 October 2026, explains how to check that it works, and names what the filter can hide.
Why to shorten command output
The context window is the text the model can read in one request. It holds your instructions, every earlier message and the result of every command Claude has run. Anthropic's documentation, read on 4 October 2026, says that Claude Code sends your full conversation with every request [1]. In an invented example, a test run that prints 500 lines is sent once when it happens and again with each later request in that session. The page on where Claude Code tokens go shows the full list of what is sent.
Anthropic's cost page describes the saving with its own example: "Instead of Claude reading a 10,000-line log file to find errors, a hook can grep for ERROR and return only matching lines, reducing context from tens of thousands of tokens to hundreds." [1] To grep is to search a text and keep only the lines that contain a given word. The figures in that sentence are Anthropic's illustration of the idea, and Anthropic publishes no measurement with them.
What a hook is, and where a PreToolUse hook runs
Anthropic's hooks guide, read on 4 October 2026, defines hooks as "user-defined shell commands" that Claude Code runs at specific points [2]. A shell command is a command for the terminal. The guide gives the reason to use one: certain actions then always happen, and you no longer depend on the model choosing to do them [2].
Each point is called an event. A tool is an action the model can ask Claude Code to perform, such as running a terminal command or reading a file. The event named PreToolUse happens before a tool call runs [2]. For terminal commands, the tool is named Bash.
The hooks reference lists what a PreToolUse hook can decide about a tool call: allow it, deny it, ask the user to confirm it, or postpone it. The hook can also change the tool's input before the tool runs, through a field named updatedInput [3].
Changing the input is the option that saves tokens. The hook receives the command Claude is about to run, and it returns a different command. Claude Code runs the new command, and only the output of the new command reaches the model.
The exchange uses JSON, a plain text format for structured data. Claude Code passes the details of the tool call to the hook as JSON, and for a terminal command the field tool_input.command holds the command. The hook prints a JSON answer [2]. The reference adds one rule about updatedInput: it "replaces the entire input object, so include unchanged fields alongside modified ones" [3].
Anthropic's example: a hook that filters test output
Anthropic's cost page gives this hook as its example. It has two parts: a setting and a script [1].
Part one: the setting. Add this to your settings.json file. It tells Claude Code to run the script before every Bash command [1].
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/filter-test-output.sh"
}
]
}
]
}
}
The hooks guide says where the setting can be placed. A hook in ~/.claude/settings.json applies to all your projects and stays on your computer. A hook in .claude/settings.json inside a project applies to that project and can be shared with the team through the project's files [2].
Part two: the script. Anthropic's instructions are to create the folder with mkdir -p ~/.claude/hooks, save the script as ~/.claude/hooks/filter-test-output.sh, and make it runnable with chmod +x ~/.claude/hooks/filter-test-output.sh [1].
The script below is Anthropic's, reproduced exactly.
#!/bin/bash
input=$(cat)
cmd=$(echo "$input" | jq -r '.tool_input.command')
# If running tests, filter to show only failures
if [[ "$cmd" =~ ^(npm test|pytest|go test) ]]; then
filtered_cmd="$cmd 2>&1 | grep -A 5 -E '(FAIL|ERROR|error:)' | head -100"
echo "$input" | jq --arg filtered "$filtered_cmd" \
'{hookSpecificOutput: {hookEventName: "PreToolUse", permissionDecision: "allow", updatedInput: (.tool_input + {command: $filtered})}}'
else
echo "{}"
fi
Anthropic describes the script in one sentence: it "checks if the command is a test runner and modifies it to show only failures" [1]. Line by line, in our own reading of the code, it does this:
- It reads the JSON that Claude Code sends and takes out the command Claude is about to run. The program
jqdoes the reading.jqis a separate program for working with JSON. - It tests whether the command begins with
npm test,pytestorgo test. Anthropic's description calls these test runners, which are commands that run tests. - If the command is one of those, it builds a longer command. The new command runs the tests, keeps each line that contains
FAIL,ERRORorerror:together with the five lines after it, and keeps at most the first 100 lines of the result. - It prints a JSON answer with two instructions.
permissionDecision: "allow"approves the command.updatedInputholds the original input with the command replaced by the longer one. - For any other command it prints
{}, an empty answer, and the command runs unchanged.
How to check that the hook works
Anthropic gives two checks, both on the cost page read on 4 October 2026 [1].
First, run /hooks in Claude Code. This opens a list of all configured hooks, grouped by event [2]. The new hook should appear under PreToolUse.
Second, start Claude Code with claude --debug-file ./claude-debug.txt and ask Claude to run npm test. This start option writes a detailed log to the file you name [3]. When the hook rewrites the command, the log contains a line with the words modified tool input keys, which lists command and the other input fields of the Bash tool [1].
The hooks guide adds three fixes for common faults [2]:
- The hook does not appear in
/hooks. Edits to a settings file are normally detected automatically. If the hook has not appeared after a few seconds, restart the session. Check also that the JSON is valid, because trailing commas and comments are not allowed. - You see "jq: command not found". Install
jq, or write the script in Python or Node.js. - The script does not run at all. Make it runnable with
chmod +x.
You can also test the script by itself, outside Claude Code. The guide's method is to send the script a sample of the JSON yourself and read what it prints [2]. For this hook, a sample with npm test as the command should print a JSON answer that contains the longer command, and a sample with ls should print {}.
What the filter can hide
A filter removes text, and removed text can matter. Read this section before you install the hook. The first four points are our own reading of Anthropic's script, and the last two come from the hooks documentation.
A failure that uses other words. The filter keeps a line only if it contains FAIL, ERROR or error:. A test tool that reports a problem with a different word, such as "failed" in lowercase letters or a word in another language, produces no matching line. Claude then receives empty output.
A pass and a missed failure look the same. When every test passes, no line matches, and Claude also receives empty output. Claude cannot distinguish these two cases from the output. Check what your own test tool prints for one failing test before you rely on the three words in the script.
Long failures are cut. The filter keeps five lines after each matching line and stops at 100 lines in total. The later lines of a long error report can be removed, and a long list of failures is cut at line 100.
Some test commands are skipped. The script matches only commands that begin with npm test, pytest or go test. A command that starts with something else, such as cd app && npm test, runs with its full output. Nothing is hidden in that case, and nothing is saved. Change the list of commands to match the ones your project uses.
The hook approves the command. The script returns permissionDecision: "allow". The hooks guide says this value skips the interactive permission prompt, while the deny rules and ask rules in your settings still apply [2]. A test command that you would normally be asked to approve now runs without the question.
Two hooks that rewrite the same tool conflict. The hooks guide says that when more than one PreToolUse hook returns updatedInput, the last one to finish takes effect, and the order is not fixed because hooks run at the same time. Its advice is to avoid having more than one hook modify the same tool's input [2].
Other ways to keep long output away from the model
Anthropic's documentation, read on 4 October 2026, gives four other ways to do this job.
Code intelligence plugins. A plugin is an add-on package for Claude Code. A code intelligence plugin connects Claude Code to a language server, the same type of program that gives a code editor its "go to definition" feature [4]. Anthropic's cost page says: "A single 'go to definition' call replaces what might otherwise be a grep followed by reading multiple candidate files." [1] With the plugin, Claude also receives the errors the language server reports after each edit, such as a wrong type or a missing import, without running a compiler, the program that checks and builds the code [4]. Anthropic's page has a table of 13 rows of languages, among them Python, Go, Rust, Java, and TypeScript with JavaScript. You install the language server program first and the plugin second, for example with /plugin install typescript-lsp@claude-plugins-official [4]. The page says these plugins work in terminal sessions, and that Claude Code does not start them in cloud sessions [4].
Subagents. A subagent is a second copy of Claude that works on one task in its own separate context window and sends back a summary. Anthropic's subagents page says that running tests, fetching documentation or processing log files can be delegated to one, so that the long output stays in the subagent's context and only the relevant summary returns to your conversation [5]. The cost page adds that the subagent's own requests still count towards your usage [1].
A hook that runs after the tool. The event named PostToolUse happens after a tool call succeeds. A hook on it can return a field named updatedToolOutput, which replaces the tool's output before it is sent to Claude [2][3]. This lets a script shorten a result after the command has run, in place of rewriting the command before it runs.
A skill. A skill is a packaged set of instructions that loads when it is used. The cost page suggests a skill that describes how the project is organised, so that Claude gets this information immediately and reads fewer files to learn it [1]. CLAUDE.md is the instruction file that Claude reads at the start of each session, and the page on how long CLAUDE.md should be explains when a skill is the better place for instructions.
What to shorten, and with which tool
Each row comes from Anthropic's documentation, read on 4 October 2026 [1][3][4][5].
| What fills the context | Tool | What it does |
|---|---|---|
| Output of a test run | PreToolUse hook that rewrites the command |
Passes on only the lines that report a failure |
| A long log file | Hook that searches for ERROR |
Returns only the matching lines. Anthropic's illustration is a reduction from tens of thousands of tokens to hundreds |
| Searching for where a function is defined | Code intelligence plugin | One "go to definition" call in place of a text search and several file reads |
| Errors that an edit introduces, such as a wrong type | Code intelligence plugin | The language server reports them after each edit, with no compiler run |
| Running tests, fetching documentation or processing log files | Subagent | The long output stays in the subagent's context, and a summary returns |
| The result of a tool that has already run | PostToolUse hook with updatedToolOutput |
Replaces the output before Claude sees it |
| Reading many files to learn the project | Skill that describes the project | Claude gets the description immediately |
Our position
Install the test filter if your test runs are long and your failures are short. Before you do, run one failing test yourself and confirm that its output contains one of the words the script looks for. If it does not, change the words. A filter that hides a failure costs more than the tokens it saves, because Claude may then report success on code that is broken.
If your language has a code intelligence plugin, install it first. It has no filter that can be set wrongly, and Anthropic states that it reduces unnecessary file reads when Claude explores code it has not seen before [1]. The page on how to write a request that reads fewer files covers the same aim through the wording of the request.
Use a subagent when the output is long and you need a judgement about it, such as "which of these failures share a cause". Use a hook when a fixed rule is enough.
Reveneau is an AI software development consultancy. All of its code is written by AI, and every change must pass an eval suite, a set of automated tests written from the specification, before release. Token use is therefore a running cost of every Reveneau build, and the test result decides whether a change is released. Reveneau recommends that a filter on test output always keeps the full text of a failure. The guide on eval-driven development covers that way of working. Reveneau is independent of Anthropic, and every figure on this page is Anthropic's own statement about its own product.
Common questions
What is a hook in Claude Code?
A hook in Claude Code is a command that you write and that Claude Code runs by itself at a fixed point in its work. Anthropic's hooks guide, read on 4 October 2026, says hooks make certain actions always happen, so they no longer depend on the model choosing to do them. Each fixed point is called an event. The `PreToolUse` event, for example, happens before a tool call runs.
What is a PreToolUse hook?
A PreToolUse hook is a hook that runs before Claude Code performs a tool call, such as a terminal command. Anthropic's hooks reference, read on 4 October 2026, says it can allow the call, deny it, ask the user to confirm it, or postpone it, and that it can change the tool's input through a field named `updatedInput`. Changing the input is how a hook filters test output.
How does a hook reduce token usage in Claude Code?
A hook reduces token usage in Claude Code by removing lines from command output before the model reads them. Anthropic's cost documentation, read on 4 October 2026, gives the example of a 10,000-line log file: a hook that returns only the lines containing ERROR reduces the context from tens of thousands of tokens to hundreds. Those figures are Anthropic's own illustration, published without a measurement.
Where do I put the hook that filters test output?
Put the hook in a `settings.json` file and its script at `~/.claude/hooks/filter-test-output.sh`, as Anthropic's cost documentation, read on 4 October 2026, shows. The hooks guide says a hook in `~/.claude/settings.json` applies to all your projects, and a hook in `.claude/settings.json` inside a project applies to that project and can be shared with the team. Make the script runnable with `chmod +x`.
How do I check that a Claude Code hook is running?
Run `/hooks` and check that the hook appears under its event, which is `PreToolUse` for the test filter. Anthropic's documentation, read on 4 October 2026, gives a second check: start Claude Code with `claude --debug-file ./claude-debug.txt` and ask Claude to run `npm test`. When the hook rewrites the command, the log file contains a line with the words `modified tool input keys`.
What does updatedInput do in a PreToolUse hook?
`updatedInput` in a PreToolUse hook changes the input of a tool before the tool runs. Anthropic's hooks reference, read on 4 October 2026, says it replaces the entire input object, so the hook must include the unchanged fields beside the changed ones. Claude Code checks its permission rules against the input the hook returns. In the test filter, `updatedInput` holds the rewritten command.
Can a filter hook hide a failing test from Claude?
Yes, a filter hook can hide a failing test when the failure text lacks every word the filter looks for. The script in Anthropic's documentation, read on 4 October 2026, keeps only lines containing FAIL, ERROR or error:, plus five lines after each. A failure reported with a different word produces empty output, the same as a run where every test passes. Check the output of one failing test first.
Does the test filter hook skip the permission prompt?
Yes. The test filter hook returns `permissionDecision: "allow"`, which skips the interactive permission prompt for the test commands it rewrites. Anthropic's hooks guide, read on 4 October 2026, says the deny rules and ask rules in your settings still apply after a hook returns allow. For every other command, the script prints an empty answer and the normal permission steps apply.
Why does my hook fail with jq: command not found?
The hook fails with that message because the script uses a program named `jq` to read JSON, and `jq` is missing from your computer. Anthropic's hooks guide, read on 4 October 2026, gives two fixes: install `jq`, or use Python or Node.js to read the JSON. The same guide says to make a script runnable with `chmod +x` when it does not run at all.
What is a code intelligence plugin in Claude Code?
A code intelligence plugin in Claude Code connects Claude to a language server for one programming language, the same type of program a code editor uses. Anthropic's documentation, read on 4 October 2026, says Claude then finds definitions by name in place of a text search, and receives errors after each edit. Anthropic's cost page says one go-to-definition call can replace a text search followed by several file reads.
Should I use a hook or a subagent for long test output?
Use a hook when a fixed rule can select the lines you need, and a subagent when the output needs judgement. Anthropic's documentation, read on 4 October 2026, says a subagent keeps long test output in its own context and returns only a summary, and that the subagent's own requests still count towards your usage. A hook of the command type runs a script on your computer and sends no request to the model.
Can two hooks rewrite the same command?
Two hooks can both return a rewritten command, and only one of the rewrites takes effect. Anthropic's hooks guide, read on 4 October 2026, says that when several PreToolUse hooks return `updatedInput`, the last one to finish is used, and the order is not fixed because hooks run in parallel. The guide advises against having more than one hook change the same tool's input.
References
- Anthropic, Manage costs effectively (code.claude.com), read 4 October 2026
- Anthropic, Automate actions with hooks (code.claude.com), read 4 October 2026
- Anthropic, Hooks reference (code.claude.com), read 4 October 2026
- Anthropic, Code intelligence plugins (code.claude.com), read 4 October 2026
- Anthropic, Create custom subagents (code.claude.com), read 4 October 2026
More in Setup
How long should CLAUDE.md be? What to keep and what to move into skills
A CLAUDE.md file should be under 200 lines. That is the target in Anthropic's documentation for Claude Code, read on 4 October 2026, and the reason is cost: CLAUDE.md loads at the start of every session and is then sent with every request, so each line is counted on every request, including requests that have no use for it. Keep the facts that every session needs, such as build commands and conventions. Move step-by-step procedures into skills, which load when they are used, and move instructions for one folder into path rules, which load when Claude opens a matching file. This page shows where to put each type of instruction.
MCP servers or command-line tools: what each adds to every message
An MCP server, a program that connects Claude Code to an outside service, adds its tool names and its instructions to every message. A command-line tool adds nothing until Claude runs it. That is the default behaviour in Anthropic's documentation, read on 4 October 2026: a feature named tool search holds back the full definition of each MCP tool until Claude needs it. When tool search is off, every definition loads at the start of the session and is sent with every request. Anthropic advises command-line tools such as `gh` and `aws` where they exist, because they add no tool listing. This page compares the two and shows how to check what your servers add.