Claude Code burns ~15–20% of your tokens on a 3-word status line Flamerix AI released no-agent-summary.js, an MIT-licensed Bun preload that disables Claude Code's background agent-summary feature, which sends each background agent's full transcript to a model roughly every 30 seconds to generate a 3-5 word status line. Using OpenTelemetry data from Claude Code's api_request events, the team measured that agent_summary accounted for 16.4% of Claude Code spend and 19.7% of API requests, with 96% of that spend on Opus, and reported the share fell to 0% after the hook was installed. The hook works by wrapping setTimeout/setInterval and returning an inert handle when a callback's source text contains a summarizer anchor, since the module ships as precompiled Bun bytecode. Claude Code burns ~15–20% of your tokens on a 3-word status line. Here's how to turn it off by Flamerix AI https://flamerix.ai · MIT License Tested on Linux, Claude Code 2.1.257–2.1.312 see Tested versions . The binary is not modified BUN OPTIONS=--preload . An update can silently undo it, so see Verify. TL;DR sh curl -fsSL https://gist.githubusercontent.com/flamerix-ai/c3905705cc4205e5de3011fa2e74efce/raw/no-agent-summary.js -o ~/.local/share/no-agent-summary.js claude daemon stop --any BUN OPTIONS="${BUN OPTIONS:+$BUN OPTIONS }--preload $HOME/.local/share/no-agent-summary.js" claude To make it permanent for every Claude Code process, see Install install . The problem Every ~30 seconds, for every background agent, Claude Code sends that agent's entire transcript to the agent's own model usually Opus and asks it to "describe your most recent action in 3-5 words". The answer only updates the agent's status line in the agents panel; it never reaches the model or your conversation. There is no setting that turns it off, and since 2.1.232 August 2026 it has been on by default. The anomaly was detected by DRIM https://flamerix.ai in Claude Code's OpenTelemetry export: grouping claude code.api request events by query source showed agent summary costing more than the main conversation itself . | query source = agent summary | week before the hook | 2 days after | |---|---|---| | share of all Claude Code spend | 16.4 % main conversation: 15.7 % | 0 % | | share of all API requests | 19.7 % , about 1 in 5 | 0 % | | part of that spend on Opus | 96 % | — | | input tokens per output token | ≈ 9,000 : 1 | — | Spend here means Claude Code's own per-request estimate cost usd , not an invoice: on a subscription, what you lose is rate-limit headroom. We are not the only ones who measured it: 86879 https://github.com/anthropics/claude-code/issues/86879 collects four independent measurements of 18–26 %. The fix how it works no-agent-summary.js is a Bun preload ~80 lines of code . It wraps setTimeout / setInterval ; when a callback's source text contains a summarizer anchor e.g. the AgentSummary Timer fired log line , it returns an inert handle instead of arming the timer. Every other timer passes through untouched. In the OpenTelemetry export the suppressed requests are claude code.api request events with query source = agent summary . Why a timer hook rather than something simpler: the module ships as precompiled Bun bytecode, so editing its JS text inside the binary changes nothing, and the API client does not go through a wrapped globalThis.fetch . But Function.prototype.toString still returns a callback's source even when it runs from bytecode, so the timer can be recognised by a string inside it. The inert timer uses exactly 2³¹−1 ms: Node and Bun treat a larger delay as 1 ms, so an "infinite" delay would fire at once. Install 1. Put no-agent-summary.js somewhere stable; note its absolute path. 2. Set BUN OPTIONS globally so every Claude Code process gets it. One of: sh ~/.profile, ~/.bashrc, ~/.zshrc export BUN OPTIONS="${BUN OPTIONS:+$BUN OPTIONS }--preload /abs/path/no-agent-summary.js" fish ~/.config/fish/config.fish set -gx BUN OPTIONS "--preload /abs/path/no-agent-summary.js" ini ~/.config/environment.d/50-no-agent-summary.conf systemd user env; also reaches user services and timers; applies when the user manager next starts, usually next login BUN OPTIONS=--preload /abs/path/no-agent-summary.js Or a wrapper named claude earlier on PATH the case keeps it idempotent when one Claude Code process starts another : sh /bin/sh HOOK=/abs/path/no-agent-summary.js case " ${BUN OPTIONS-} " in " --preload $HOOK " ;; export BUN OPTIONS="${BUN OPTIONS:+$BUN OPTIONS }--preload $HOOK" ;; esac : "${CC AGENT SUMMARY LOG:=${XDG RUNTIME DIR:-/tmp}/no-agent-summary.log}" export CC AGENT SUMMARY LOG exec /path/to/the/real/claude "$@" 3. Restart the daemon and every already-running session, then start Claude Code from an environment that has BUN OPTIONS : sh claude daemon stop --any Env | variable | values | effect | |---|---|---| | CC AGENT SUMMARY MODE | off default , pass | off suppresses the summary timer. pass is the A/B control: loads and logs, arms every timer untouched. Any other value warns on stderr and acts as off . | | CC AGENT SUMMARY LOG | file path, optional | Appends preload active mode=… bun=… hooked=… on load, one line per matched timer first 20 , and an exit count. | | CC AGENT SUMMARY MARKER | file path, optional | Overwritten on load with the preload active … line. | Nuances - Restart the daemon after install. The daemon, pty host and pre-warmed bg-spare sessions inherit the environment of the client that started the daemon, so a daemon started before BUN OPTIONS was set keeps spawning unhooked sessions. Hence claude daemon stop --any . - Headless runs need it too: claude -p , cron, CI, editor integrations. - Platform: Linux tested, macOS and Windows untested. On Windows the /$bunfs/ gate most likely never installs the hook. - A/B: CC AGENT SUMMARY MODE=pass loads the hook but arms every timer; the summaries come back, which shows the off result is the hook's doing. - Background processes: daemon, pty host and bg-spare must carry --preload in their environment /proc/