Claude Code regularly sends each background agent’s transcript to its model
Instantly share code, notes, and snippets.
by Flamerix AI · MIT License
Tested on Linux, Claude Code 2.1.257–2.1.312; macOS reported working by others (see Tested versions). The binary is not modified (BUN_OPTIONS=—preload). An update can silently undo it, so see Verify.
Every ~30 seconds, Claude Code re-sends each background agent’s full transcript to the model just to fill that agent’s status line in the agents panel. no-agent-summary.js is a Bun —preload that stops that timer without modifying the Claude Code binary.
To make it permanent for every Claude Code process, see Install.
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 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.
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 collects four independent measurements of 18–26 %.
no-agent-summary.js is a Bun preload (~70 lines of code). It wraps only the global setTimeout, the one the summary timer is armed through; 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.
The hook installs only inside Claude Code: Bun.main must be /$bunfs/root/cli (the compiled entry, the same on every row below) and process.execPath must be a Claude Code install. Any other bun, or a compiled Bun binary with another entry name, loads the file and does nothing.
macOS and Windows are not measured; the hook installs there only if they produce these same shapes, and Verify step 1 tells you. One known pass-through: a foreign binary built with bun build —compile —outfile cli and renamed claude; there, only timers whose callback carries an anchor change.
Put no-agent-summary.js somewhere stable; note its absolute path.
Set BUN_OPTIONS globally so every Claude Code process gets it. Write
—preload=
Or a wrapper named claude earlier on PATH (the case keeps it idempotent when one Claude Code process starts another, and also recognises the v2 space form):
Restart the daemon and every already-running session, then start Claude Code from an environment that has BUN_OPTIONS:
Expect preload active mode=off …. No line: BUN_OPTIONS did not reach the process, or the path is not absolute.
Timer suppressed: with the same BUN_OPTIONS and CC_AGENT_SUMMARY_LOG=/tmp/nas.log, run a background subagent for a minute or two. The log shows summary timer #1 suppressed (setTimeout, delay=30000) and the agent’s panel status stops updating. If you export OpenTelemetry, query_source = agent_summary should stay at zero; this is the only check that catches every failure mode.
Matching is by source text: an anchor must sit inside the callback passed to the timer. If an update breaks that, the hook matches nothing and summaries silently come back. Ways it can happen:
So re-run Verify after every update.
Linux x64 binary from npm @anthropic-ai/claude-code-linux-x64 (its sha256 equals the native installer’s manifest.json checksum). Static: the extracted bundle’s summary timer callback carries a hook anchor. Live: claude -p —model haiku with CLAUDE_CODE_AGENT_PROGRESS_SUMMARIES=1, one subagent doing 8 steps of ~20 s, counting [AgentSummary] Forking in —debug-file.
The two v3 rows are this script, re-run on 2026-10-29. The rows below them were measured with v2.
5 / 5 / 0 = the fork happens on this version, merely loading the hook changes nothing, and off removes it.
On claude -p: headless runs don’t arm the summary timer by default. Our live tests set CLAUDE_CODE_AGENT_PROGRESS_SUMMARIES=1 for that reason. The default-on overhead is in interactive sessions with background agents.
In our telemetry its weekly share of spend went from 3.5–7 % in July (the fork gate was already open for us) to 7.3 % and then 11.8 % in the week we picked up 2.1.233, and to about 16 % by mid-October.
MIT © 2026 Flamerix AI. Provided as is, without warranty of any kind; you use it at your own risk. Flamerix AI is not liable for any damage, data loss or account action arising from its use. Changing a client’s runtime behaviour may conflict with the terms of the service you use it with; checking that is on you.
“Claude” and “Claude Code” are trademarks of Anthropic, PBC. This project is independent and is not affiliated with, sponsored or endorsed by Anthropic.
Heads up on the global BUN_OPTIONS install. With a space, —preload /path, every bun subcommand breaks: on bun 1.4.3 bun install, add, test, build and x all fail with Script not found “install” and so on. It’s bun’s parser, any value flag before the subcommand does it, e.g. bun —define x:1 install. —preload=/path works for both bun and Claude Code.
I also gated install() on Bun.main === ”/$bunfs/root/cli” plus execPath being a Claude Code install, so other compiled Bun binaries don’t get their timers wrapped. Got the same 5/5/0 on 2.1.308 your way.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Interesting find, do you happen to know if this is still the case over ACP/Claude Agent SDK?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
@Bedz01 thank you, both points were right and both are in v3.
—preload=
Claude-Code-only gate: taken as you described it, Bun.main === ”/$bunfs/root/cli” plus an execPath check. We measured execPath per install channel on Linux (claude —version):
The gate admits exactly these; a compiled Bun binary with another entry name is left alone.
Also new: a second load of the file in one process is a no-op. Bun already loads one path once, even when BUN_OPTIONS names it in both forms; the guard covers two different paths (an old and a new copy) during an upgrade.
What remains: a foreign binary built with —outfile cli and renamed claude looks the same on both signals; there only anchor-carrying timers would change. macOS and Windows are still unmeasured.
Thanks also for the independent 5/5/0 on 2.1.308. You’re credited in the script header and the changelog.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
@samwatkinson Mostly no, with one exception. In the 2.1.301 bundle (2.1.310 has the same call sites), a background Agent-tool agent is summarized only in interactive mode, unless the host opts in with the SDK option agentProgressSummaries: true or the env var CLAUDE_CODE_AGENT_PROGRESS_SUMMARIES.
Both can only turn summaries on, never off. The exception is fork subagents (subagent_type: “fork”) and forked skills (context: fork): those are summarized unconditionally, SDK included. In SDK mode the summary also arrives as a task_progress stream-json event. With summaries enabled, our -p run forked 5 times without the hook and 0 times with it in off, so the preload works there too, provided BUN_OPTIONS=—preload=… reaches the claude process the SDK spawns.
Not checked: whether a given ACP adapter sets agentProgressSummaries, and whether versions after 2.1.301 changed the non-interactive default.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Does this also apply to desktop app?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
We don’t have data for the desktop app and haven’t tested it there. If you check it and can share what you find, that would be much appreciated!
Sorry, something went wrong.
There was an error while loading. Please reload this page.
I looked at the source of Claude Desktop app, and it has the same feature. I did not proxy the API calls to verify that it runs. I’m not a JS wizard, so my solution is to set the model’s mode to short “tengu_groovy_ember”: {“mode”: “short”} (Code name for Opus) in the server config and set the file to read only attrib +R “%USERPROFILE%.claude.json” (on Windows).
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Wow very surprising! /s
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Great find, thank you for sharing. You mentioned Windows hasn’t been measured yet, so I gave it a try.
Syntax is a b**ch After fixing the gate, I got:
@Bedz01’s, thanks for the tip. Will be switching to —preload= @Genbox, if you’re making .claude.json read-only to stop these summaries, this might be another option to try. I got zero summaries with “off” in the Windows test above, while “slow” reduced the frequency.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Windows desktop app: the Code tab uses its own bundled copy of Claude Code (2.1.309 in app 4.4212) (not terminal)
Quick checking with the same test against the bundled binary gives indeed 5 / 5 / 0
Correct me if I’m wrong, but Cowork mode runs in its own VM, so it shouldn’t be able to reach the hook. Would love to hear your thoughts. Especially from you tuxes out there
Used same installer as before: claude-summary-tuner
Sorry, something went wrong.
There was an error while loading. Please reload this page.