Claude Code burns ~15–20% of your tokens on a 3-word status line

Hacker News by 9 min read 507x views
Claude Code burns ~15–20% of your tokens on a 3-word status line

Share Post

Claude Code burns ~15-20% of your tokens on a 3-word position line: a Bun preload that turns agent_summary off · by Flamerix AI, flamerix.ai · MIT

by 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.

curl -fsSL https://gist.githubusercontent.com/flamerix-ai/c3905705cc4205e5de3011fa2e74efce/raw/no-agent-summary.js -o ~/.local/share/no-agent-summary.js claude daemon halt --any BUN_OPTIONS="${BUN_OPTIONS:+$BUN_OPTIONS }--preload $HOME/.local/share/no-agent-summary.js" claude

To create it imperishable for all Claude Code process, see Install.

Every ~30 seconds, for all backdrop agent, Claude Code sends that agent's entire transcript to the agent's own example (usually Opus) and asks it to "describe your most recent action in 3-5 words". The answer lone updates the agent's position row in the agents panel; it never reaches the example or your conversation. There is no environment 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 chief 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 %, concerning 1 in 5 0 %
part of that expend on Opus 96 % —
input tokens per output token ≈ 9,000 : 1 —

Spend current method Claude Code's own per-request evaluation (cost_usd), not an invoice: on a subscription, what you endure is rate-limit headroom. We are not the lone ones who measured it: #86879 collects four independent measurements of 18–26 %.

no-agent-summary.js is a Bun preload (~80 lines of code). It wraps setTimeout/setInterval; when a callback's origin content contains a summarizer anchor (e.g. the [AgentSummary] Timer fired log line), it returns an inert grip alternatively of arming the timer. Every another timer passes through untouched. In the OpenTelemetry export the suppressed requests are claude_code.api_request events alongside query_source = agent_summary.

Why a timer hook fairly than item simpler: the component ships as precompiled Bun bytecode, so editing its JS content inner the binary changes nothing, and the API client does not go through a wrapped globalThis.fetch. But Function.prototype.toString motionless returns a callback's source even whenever it runs from bytecode, so the timer can be recognised by a cord inner it. The inert timer uses exactly 2³¹−1 ms: Node and Bun treat a larger postpone as 1 ms, so an "infinite" delay would blaze at once.

  1. Put no-agent-summary.js location stable; note its absolute path.

  2. Set BUN_OPTIONS globally so all Claude Code procedure gets it. One of:

    # ~/.profile, ~/.bashrc, ~/.zshrc export BUN_OPTIONS="${BUN_OPTIONS:+$BUN_OPTIONS }--preload /abs/path/no-agent-summary.js"
    # ~/.config/fish/config.fish set -gx BUN_OPTIONS "--preload /abs/path/no-agent-summary.js"
    # ~/.config/environment.d/50-no-agent-summary.conf (systemd person env; additionally reaches # person services and timers; applies whenever the person director next starts, normally next login) BUN_OPTIONS=--preload /abs/path/no-agent-summary.js

    Or a wrap named claude before on PATH (the case keeps it idempotent whenever one Claude Code procedure starts another):

    #!/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 all already-running session, afterward commencement Claude Code from an environment that has BUN_OPTIONS:

variable values effect
CC_AGENT_SUMMARY_MODE off (default), pass off suppresses the summary timer. continue is the A/B control: loads and logs, arms all timer untouched. Any another value warns on stderr and acts as off.
CC_AGENT_SUMMARY_LOG file path, optional Appends preload energetic mode=… bun=… hooked=… on load, one row per matched timer (first 20), and an exit count.
CC_AGENT_SUMMARY_MARKER file path, optional Overwritten on burden alongside the preload energetic … line.
  • Restart the daemon following install. The daemon, pty presenter and pre-warmed bg-spare sessions inherit the surroundings of the client that started the daemon, so a daemon started before BUN_OPTIONS was set keeps spawning unhooked sessions. Hence claude daemon halt --any.
  • Headless runs need it too: claude -p, cron, CI, publishing company integrations.
  • Platform: Linux tested, macOS and Windows untested. On Windows the /$bunfs/ entrance most likely never installs the hook.
  • A/B: CC_AGENT_SUMMARY_MODE=pass loads the hook but arms all timer; the summaries arrive back, which shows the off outcome is the hook's doing.
  • Background processes: daemon, pty presenter and bg-spare must transport --preload in their surroundings (/proc/<pid>/environ on Linux); if not, restart the daemon.

Verify (after all update)

  1. Preload loads:

    BUN_OPTIONS="--preload $HOME/.local/share/no-agent-summary.js" CC_AGENT_SUMMARY_LOG=/tmp/nas.log claude --version && cat /tmp/nas.log

    Expect preload energetic mode=off …. No line: BUN_OPTIONS did not attain the process, or the path is not absolute.

  2. Timer suppressed: alongside the identical BUN_OPTIONS and CC_AGENT_SUMMARY_LOG=/tmp/nas.log, run a backdrop subagent for a infinitesimal or two. The log shows summary timer #1 suppressed (setTimeout, delay=30000) and the agent's panel position stops updating. If you export OpenTelemetry, query_source = agent_summary should remain at zero; this is the lone inspect that catches all nonaccomplishment mode.

Matching is by source text: an anchor must sit inner the recall passed to the timer. If an update breaks that, the hook matches nothing and summaries silently arrive back. Ways it can happen:

  • the log row or query-source id is renamed;
  • the recall is passed via fn.bind(...) (no origin in toString) or another wrapper;
  • the strings move to a shared changeless exterior the callback;
  • the timer moves to an unwrapped API (timers/promises, a scheduler loop).

So re-run Verify following all update.

  • We run it under all Claude Code procedure on our device (2.1.301). Since afterward there have been zero agent_summary requests, and no another flank query grew to obtain its place.
  • Subagents, backdrop agents, forked skills and backdrop sessions run normally; lone the summary fork is skipped.
  • Visible change: the per-agent panel position stops updating; SDK task_progress has no summary.
  • Overhead: one Function.prototype.toString per distinct timer callback, cached in a WeakMap. claude --version: ~10 ms → ~17 ms (one measurement).

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.

version published sha256 static summary forks in a ~2.5-min delegate run: no hook / hook continue / hook off notes
2.1.312 2026-10-27 4f4178ce41d8 OK 5 / 5 / 0 latest on 2026-10-28; interactive: 6 no hook, 0 off
2.1.310 2026-10-23 b73676430af1 OK 5 / 5 / 0
2.1.308 2026-10-22 356733f185fa OK 5 / 6 / 0 stable on 2026-10-28; the continue run's delegate took 9 steps alternatively of 8
2.1.301 2026-10-15 bc1aad9982c7 OK 5 / 5 / 0 same alongside before hook builds; interactive off additionally 0; in regular use since 2026-10-26, 0 agent_summary requests in telemetry
2.1.280 2026-09-22 1e08503dbdf3 OK 1 / 1 / 0 (timer fired 11 / 11 / 0) interactive: -p cannot allow summaries on this version. The delegate sat at a approval prompt, so afterward timers skipped the unchanged transcript
2.1.257 2026-09-01 9a64bda9d872 OK 1 / 1 / 0 (timer fired 11 / 11 / 0) same as 2.1.280

5 / 5 / 0 = the fork happens on this version, merely loading the hook changes nothing, and off removes it.

Why there is no environment for this

  • The documented toggle lone turns it on. The SDK choice agentProgressSummaries defaults to false, but in the bundle it is one term of an OR, and all code way that writes it sets true. So false changes nothing, and the undocumented CLAUDE_CODE_AGENT_PROGRESS_SUMMARIES can lone allow summaries too.
  • The duration belongs to the server. It comes from a per-model-family server emblem and is clamped to 30–240 s. The default is already the minimum, and no value disables the timer.
  • The apparent env vars miss. DISABLE_NON_ESSENTIAL_MODEL_CALLS, which several packagers set, does not happen in the binary at all. CLAUDE_CODE_FORK_SUBAGENT=0 and CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 do halt it, but lone by taking fork subagents or background agents alongside it.
  • The immediate cache makes it cheaper, not cheap. About 98 % of these calls re-read the transcript from cache; the ~2 % that hit a chilly cache transport complete a third of its cost.
  • Cost tools that peruse transcripts don't see it. These requests are not written to the session logs on disk (#104358); only the OpenTelemetry export shows them. The docs division on backdrop token use doesn't catalog it either, during Agent View's row summaries are documented as a Haiku-class example refreshing every few minutes.
  • A cheaper type already exists, switched off. 2.1.310 ships a abbreviated mode: concerning 2k tokens of notes alternatively of the complete transcript, optionally written by a smaller model. The default is motionless the complete transcript, and lone server flags can alter it.
version (published) what changed
2.1.32 (Feb 5) the code archetypal appears; deceased in community builds
2.1.72 (Mar 9) reachable as an SDK opt-in
2.1.117 (Apr 21) reachable in the interactive CLI rearward the fork entrance or a server rollout
≤ 2.1.220 (Jul 24) forked skills are continually summarized
2.1.232 (Aug 13) on by default for interactive backdrop agents
2.1.300 (Oct 14) interval becomes server-tunable, 30–240 s
2.1.310 (Oct 23) the cheaper abbreviated manner lands, switched off

In our telemetry its weekly portion of expend went from 3.5–7 % in July (the fork entrance was already open for us) to 7.3 % and afterward 11.8 % in the week we picked up 2.1.233, and to concerning 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 defeat or account action arising from its use. Changing a client's runtime behavior may battle alongside the conditions of the assistance you use it with; checking that is on you.

"Claude" and "Claude Code" are trademarks of Anthropic, PBC. This project is autonomous and is not affiliated with, sponsored or endorsed by Anthropic.

Other Article Hacker News
↑
Close Right Ads
Close Left Ads