a Bun preload that turns agent_summary off · by Flamerix AI, flamerix.ai · MIT · GitHub


by Flamerix AI · MIT License

Tested on Linux, Claude Code 2.1.257–2.1.312 (see Tested variations). The binary isn’t modified (BUN_OPTIONS=--preload). An replace can silently undo it, so see Verify.

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

To make it everlasting for each Claude Code course of, see Install.

Every ~30 seconds, for each background agent, Claude Code sends that agent’s complete
transcript
to the agent’s personal mannequin (normally Opus) and asks it to “describe your most up-to-date
motion in 3-5 phrases”. The reply solely updates the agent’s standing line within the brokers panel; it
by no means reaches the mannequin or your dialog. There is not any 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 occasions by query_source confirmed agent_summary costing greater than the principle dialog itself.

query_source = agent_summary week earlier than the hook 2 days after
share of all Claude Code spend 16.4 % (principal dialog: 15.7 %) 0 %
share of all API requests 19.7 %, about 1 in 5 0 %
a part of that spend on Opus 96 % —
enter tokens per output token ≈ 9,000 : 1 —

Spend right here means Claude Code’s personal per-request estimate (cost_usd), not an bill: on a
subscription, what you lose is rate-limit headroom. We are usually not the one ones who measured it:
#86879 collects 4 unbiased
measurements of 18–26 %.

no-agent-summary.js is a Bun preload (~80 strains of code). It wraps setTimeout/setInterval;
when a callback’s supply textual content accommodates a summarizer anchor (e.g. the [AgentSummary] Timer fired
log line), it returns an inert deal with as an alternative of arming the timer. Every different timer passes
by untouched. In the OpenTelemetry export the suppressed requests are
claude_code.api_request occasions with query_source = agent_summary.

Why a timer hook moderately than one thing easier: the module ships as precompiled Bun bytecode, so
modifying its JS textual content contained in the binary modifications nothing, and the API consumer doesn’t undergo a
wrapped worldThis.fetch. But Function.prototype.toString nonetheless returns a callback’s supply
even when it runs from bytecode, so the timer will be recognised by a string inside it. The inert
timer makes use of precisely 2³¹−1 ms: Node and Bun deal with a bigger delay as 1 ms, so an “infinite” delay
would fireplace directly.

  1. Put no-agent-summary.js someplace steady; word its absolute path.

  2. Set BUN_OPTIONS globally so each Claude Code course of will get 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/setting.d/50-no-agent-summary.conf (systemd consumer env; additionally reaches
    # consumer companies and timers; applies when the consumer supervisor subsequent begins, normally subsequent login)
    BUN_OPTIONS=--preload /abs/path/no-agent-summary.js

    Or a wrapper named claude earlier on PATH (the case retains it idempotent when one Claude
    Code course of begins one other):

    #!/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/actual/claude "$@"
  3. Restart the daemon and each already-running session, then begin Claude Code from an
    setting that has BUN_OPTIONS:

variable values impact
CC_AGENT_SUMMARY_MODE off (default), go off suppresses the abstract timer. go is the A/B management: masses and logs, arms each timer untouched. Any different worth warns on stderr and acts as off.
CC_AGENT_SUMMARY_LOG file path, non-compulsory Appends preload energetic mode=… bun=… hooked=… on load, one line per matched timer (first 20), and an exit rely.
CC_AGENT_SUMMARY_MARKER file path, non-compulsory Overwritten on load with the preload energetic … line.

  • Restart the daemon after set up. The daemon, pty host and pre-warmed bg-spare classes
    inherit the setting of the consumer that began the daemon, so a daemon began earlier than
    BUN_OPTIONS was set retains spawning unhooked classes. Hence claude daemon cease --any.
  • Headless runs want it too: claude -p, cron, CI, editor integrations.
  • Platform: Linux examined, macOS and Windows untested. On Windows the /$bunfs/ gate most
    seemingly by no means installs the hook.
  • A/B: CC_AGENT_SUMMARY_MODE=go masses the hook however arms each timer; the summaries come again, which reveals the off result’s the hook’s doing.
  • Background processes: daemon, pty host and bg-spare should carry --preload of their setting (/proc//environ on Linux); if not, restart the daemon.

Verify (after each replace)

  1. Preload masses:

    BUN_OPTIONS="--preload $HOME/.native/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 didn’t attain the method, or the
    path isn’t absolute.

  2. Timer suppressed: with the identical BUN_OPTIONS and CC_AGENT_SUMMARY_LOG=/tmp/nas.log, run
    a background subagent for a minute or two. The log reveals
    abstract timer #1 suppressed (setTimeout, delay=30000) and the agent’s panel standing stops
    updating. If you export OpenTelemetry, query_source = agent_summary ought to keep at zero; this
    is the one verify that catches each failure mode.

Matching is by supply textual content: an anchor should sit contained in the callback handed to the timer. If an
replace breaks that, the hook matches nothing and summaries silently come again. Ways it may possibly occur:

  • the log line or query-source id is renamed;
  • the callback is handed by way of fn.bind(...) (no supply in toString) or one other wrapper;
  • the strings transfer to a shared fixed exterior the callback;
  • the timer strikes to an unwrapped API (timers/guarantees, a scheduler loop).

So re-run Verify after each replace.

  • We run it below each Claude Code course of on our machine (2.1.301). Since then there have been
    zero agent_summary requests, and no different aspect question grew to take its place.
  • Subagents, background brokers, forked abilities and background classes run usually; solely the
    abstract fork is skipped.
  • Visible change: the per-agent panel standing stops updating; SDK task_progress has no abstract.
  • 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 abstract 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.

model revealed sha256 static abstract forks in a ~2.5-min agent run: no hook / hook go / hook off notes
2.1.312 2026-10-27 4f4178ce41d8 OK 5 / 5 / 0 newest 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 steady on 2026-10-28; the go run’s agent took 9 steps as an alternative of 8
2.1.301 2026-10-15 bc1aad9982c7 OK 5 / 5 / 0 identical with earlier hook builds; interactive off additionally 0; in each day 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 can’t allow summaries on this model. The agent sat at a permission immediate, so later timers skipped the unchanged transcript
2.1.257 2026-09-01 9a64bda9d872 OK 1 / 1 / 0 (timer fired 11 / 11 / 0) identical as 2.1.280

5 / 5 / 0 = the fork occurs on this model, merely loading the hook modifications nothing, and off
removes it.

Why there isn’t any setting for this

  • The documented swap solely turns it on. The SDK possibility agentProgressSummaries defaults to
    false, however within the bundle it’s one time period of an OR, and each code path that writes it units
    true. So false modifications nothing, and the undocumented CLAUDE_CODE_AGENT_PROGRESS_SUMMARIES
    can solely allow summaries too.
  • The interval belongs to the server. It comes from a per-model-family server flag and is
    clamped to 30–240 s. The default is already the minimal, and no worth disables the timer.
  • The apparent env vars miss. DISABLE_NON_ESSENTIAL_MODEL_CALLS, which some packagers set,
    doesn’t happen within the binary in any respect. CLAUDE_CODE_FORK_SUBAGENT=0 and
    CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 do cease it, however solely by taking fork subagents or
    background brokers with it.
  • The immediate cache makes it cheaper, not low-cost. About 98 % of those calls re-read the
    transcript from cache; the ~2 % that hit a chilly cache carry over a 3rd of its price.
  • Cost instruments that learn transcripts do not see it. These requests are usually not written to the
    session logs on disk (#104358); solely
    the OpenTelemetry export reveals them. The docs part on background token utilization would not record it
    both, whereas Agent View’s row summaries are documented as a Haiku-class mannequin refreshing each
    couple of minutes.
  • A less expensive variant already exists, switched off. 2.1.310 ships a quick mode: about 2k
    tokens of notes as an alternative of the complete transcript, optionally written by a smaller mannequin. The
    default remains to be the complete transcript, and solely server flags can change it.

model (revealed) what modified
2.1.32 (Feb 5) the code first seems; useless in public builds
2.1.72 (Mar 9) reachable as an SDK opt-in
2.1.117 (Apr 21) reachable within the interactive CLI behind the fork gate or a server rollout
≤ 2.1.220 (Jul 24) forked abilities are at all times summarized
2.1.232 (Aug 13) on by default for interactive background brokers
2.1.300 (Oct 14) interval turns into server-tunable, 30–240 s
2.1.310 (Oct 23) the cheaper quick mode lands, switched off

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 % after which 11.8 % within the week we picked up 2.1.233, and to about 16 % by
mid-October.

MIT © 2026 Flamerix AI. Provided as is, with out guarantee of any type;
you employ it at your personal danger. Flamerix AI isn’t answerable for any harm, knowledge loss or account
motion arising from its use. Changing a consumer’s runtime behaviour could dispute with the phrases of
the service you employ it with; checking that’s on you.

“Claude” and “Claude Code” are logos of Anthropic, PBC. This venture is unbiased and is
not affiliated with, sponsored or endorsed by Anthropic.



Source link