3語のステータス行が token の 15〜20% を食う、Claude Code の agent_summary を止める方法

Flamerix AI は自身の OpenTelemetry で、agent_summary が Claude Code の支出全体の 16.4% を占め、メインの会話より多いことを見つけた。30 秒ごとにエージェントの会話記録を丸ごと Opus に送り、3〜5 語の進捗を書かせる仕組みだ。80 行の Bun preload で止め、バージョンごとの検証結果も公開している。

日本語
コピー

Linux で Claude Code 2.1.257〜2.1.312 を対象に検証済み(検証済みバージョンを参照)。バイナリは改変しない(BUN_OPTIONS=--preload)。アップデートで知らないうちに元に戻ることがあるので、検証を参照。

TL;DR

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

すべての Claude Code プロセスで恒久的に有効にする方法はインストールを参照。

問題

約 30 秒ごとに、バックグラウンドエージェントごとに、Claude Code はそのエージェントのトランスクリプト全体をエージェント自身のモデル(通常は Opus)に送り、「直近の操作を 3〜5 語で説明せよ」と問い合わせる。返答はエージェントパネルのステータス行を更新するだけで、モデルにも会話にも届かない。無効にする設定は存在せず、2.1.232(2026 年 8 月)以降はデフォルトで有効になっている。

この異常は DRIM が Claude Code の OpenTelemetry エクスポートから検出した。claude_code.api_request イベントを query_source でグループ化すると、agent_summary がメインの会話そのものより高いコストを占めていた。

query_source = agent_summaryフック導入前の週2 日後
Claude Code 全体の支出に占める割合16.4 %(メインの会話:15.7 %)0 %
全 API リクエストに占める割合19.7 %、およそ 5 回に 1 回0 %
うち Opus での支出96 %—
出力トークンあたりの入力トークン約 9,000 : 1—

ここでの支出は Claude Code 自身によるリクエスト単位の見積もり(cost_usd)であり、請求額ではない。サブスクリプションの場合に失われるのはレート制限の余裕だ。計測したのは私たちだけではない。#86879 には 18〜26 %という 4 件の独立した計測結果が集まっている。

修正(仕組み)

no-agent-summary.js は Bun のプリロード(約 80 行のコード)。setTimeout/setInterval をラップし、コールバックのソーステキストに要約処理の目印(たとえば [AgentSummary] Timer fired のログ行)が含まれていれば、タイマーを仕掛けずに何もしないハンドルを返す。それ以外のタイマーはそのまま通す。OpenTelemetry のエクスポートでは、抑制されたリクエストは query_source = agent_summary を持つ claude_code.api_request イベントとして現れる。

より単純な方法ではなくタイマーフックを使う理由:このモジュールは Bun のプリコンパイル済みバイトコードとして出荷されるため、バイナリ内の JS テキストを書き換えても何も変わらず、API クライアントもラップされた globalThis.fetch を経由しない。しかし Function.prototype.toString はバイトコードから実行される場合でもコールバックのソースを返すので、内部の文字列からタイマーを識別できる。何もしないタイマーにはちょうど 2³¹−1 ms を指定している。Node と Bun はこれより大きな遅延を 1 ms として扱うため、「無限」の遅延は即座に発火してしまう。

インストール

  1. no-agent-summary.js を安定した場所に置き、その絶対パスを控えておく。

  2. すべての Claude Code プロセスが受け取れるよう、BUN_OPTIONS をグローバルに設定する。次のいずれか:

    # ~/.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 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
    

    または、claude という名前のラッパーを PATH より前の PATH に置く(case により、ある Claude Code プロセスが別のプロセスを起動しても冪等になる):

    #!/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. デーモンと起動中の全セッションを再起動し、BUN_OPTIONS のある環境から Claude Code を起動する:

    claude daemon stop --any

環境変数

変数値効果
CC_AGENT_SUMMARY_MODEoff(デフォルト)、passoff はサマリータイマーを抑止する。pass は A/B 対照群で、ロードとログは行うがタイマーには一切手を付けない。それ以外の値は stderr に警告を出し、off として動作する。
CC_AGENT_SUMMARY_LOGファイルパス、任意ロード時に preload active mode=… bun=… hooked=… を追記する。一致したタイマーごとに 1 行(先頭 20 件まで)と、終了時のカウントを書く。
CC_AGENT_SUMMARY_MARKERファイルパス、任意ロード時に preload active … の行で上書きされる。

注意点

  • インストール後はデーモンを再起動する。 デーモン、pty ホスト、事前起動済みの bg-spare セッションは、デーモンを起動したクライアントの環境を引き継ぐ。BUN_OPTIONS を設定する前に起動したデーモンは、フックの付かないセッションを作り続ける。だから claude daemon stop --any が必要になる。
  • ヘッドレス実行でも必要: claude -p、cron、CI、エディタ連携。
  • プラットフォーム: Linux のみ検証済み。macOS と Windows は未検証。Windows では /$bunfs/ のゲートがフックをインストールしない可能性が高い。
  • A/B: CC_AGENT_SUMMARY_MODE=pass はフックをロードするが、すべてのタイマーを有効にする。サマリーが戻ってくるので、off の結果がフックによるものだと分かる。
  • バックグラウンドプロセス: デーモン、pty ホスト、bg-spare の環境に --preload(Linux では /proc/<pid>/environ)が必要。なければデーモンを再起動する。

確認(更新のたびに)

  1. プリロードがロードされる:

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

    preload active mode=off … が出れば期待どおり。何も出なければ、BUN_OPTIONS がプロセスに届いていないか、パスが絶対パスになっていない。

  2. タイマーが抑止される: 同じ BUN_OPTIONS と CC_AGENT_SUMMARY_LOG=/tmp/nas.log で、バックグラウンドのサブエージェントを 1〜2 分動かす。ログに summary timer #1 suppressed (setTimeout, delay=30000) が出て、エージェントのパネルのステータス更新が止まる。OpenTelemetry をエクスポートしているなら、query_source = agent_summary はゼロのままのはず。すべての失敗モードを捕まえられるのはこの確認だけ。

フェイルオープン

マッチングはソーステキストで行う。アンカーはタイマーに渡すコールバックの内側になければならない。アップデートでこれが崩れるとフックは何にもマッチせず、要約は黙って戻ってくる。起こりうるパターンは次のとおり。

  • ログ行やクエリソース ID の名前が変わる;
  • コールバックが fn.bind(...) 経由で渡される(toString にソースがない)か、別のラッパーを挟む;
  • 文字列がコールバックの外の共有定数に移る;
  • タイマーがラップされていない API(timers/promises、スケジューラのループ)に移る。

だからアップデートのたびに Verify を再実行すること。

効果

  • マシン上のすべての Claude Code プロセス(2.1.301)で動かしている。それ以降 agent_summary リクエストはゼロで、代わりに増えたサイドクエリもない。
  • サブエージェント、バックグラウンドエージェント、フォークしたスキル、バックグラウンドセッションは通常どおり動く。スキップされるのは要約のフォークだけ。
  • 目に見える変化: エージェントごとのパネルステータスが更新されなくなる。SDK の task_progress には summary がない。
  • オーバーヘッド: タイマーコールバックの種類ごとに Function.prototype.toString が 1 回、WeakMap にキャッシュされる。claude --version: 約 10 ms → 約 17 ms(測定 1 回)。

検証済みバージョン

npm の @anthropic-ai/claude-code-linux-x64 から取得した Linux x64 バイナリ(sha256 はネイティブインストーラの manifest.json チェックサムと一致)。静的: 展開したバンドルの要約タイマーコールバックにフックのアンカーがある。ライブ: claude -p --model haiku と CLAUDE_CODE_AGENT_PROGRESS_SUMMARIES=1 を使い、サブエージェント 1 体が約 20 秒のステップを 8 回実行、--debug-file 内の [AgentSummary] Forking を数える。

バージョン公開日sha256静的約 2.5 分のエージェント実行での要約フォーク: フックなし / フック pass / フック off備考
2.1.3122026-10-274f4178ce41d8OK5 / 5 / 02026-10-28 に latest。対話モード: フックなし 6、off は 0
2.1.3102026-10-23b73676430af1OK5 / 5 / 0
2.1.3082026-10-22356733f185faOK5 / 6 / 02026-10-28 に stable。pass の実行ではエージェントのステップ数が 8 ではなく 9 だった
2.1.3012026-10-15bc1aad9982c7OK5 / 5 / 0以前のフックビルドでも同じ。対話モードの off も 0。2026-10-26 から日常的に使用、テレメトリ上の agent_summary リクエストは 0
2.1.2802026-09-221e08503dbdf3OK1 / 1 / 0(タイマー発火 11 / 11 / 0)対話モード: このバージョンでは -p で要約を有効にできない。エージェントが権限プロンプトで止まったため、以降のタイマーは変化のないトランスクリプトをスキップした
2.1.2572026-09-019a64bda9d872OK1 / 1 / 0(タイマー発火 11 / 11 / 0)2.1.280 と同じ

5 / 5 / 0 = フォークはこのバージョンで発生し、フックを読み込むだけでは何も変わらず、off がそれを取り除く。

設定項目が存在しない理由

  • ドキュメントに載っているスイッチは、オンにする方向にしか働かない。 SDK オプションの agentProgressSummaries はデフォルトが false だが、バンドル内では OR の片方の項にすぎず、これを書き込むコードパスはすべて true を設定する。つまり false では何も変わらず、非公開の CLAUDE_CODE_AGENT_PROGRESS_SUMMARIES も要約を有効にするだけだ。
  • 間隔はサーバー側が決める。 モデルファミリーごとのサーバーフラグで指定され、30〜240 秒にクランプされる。デフォルトがすでに最小値であり、タイマーを無効にする値は存在しない。
  • わかりやすい環境変数は効かない。 一部のパッケージャーが設定する DISABLE_NON_ESSENTIAL_MODEL_CALLS は、バイナリ内に一切出現しない。CLAUDE_CODE_FORK_SUBAGENT=0 と CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 は確かに停止させるが、フォークのサブエージェントやバックグラウンドエージェントもろとも止めてしまう。
  • プロンプトキャッシュは安くするが、安くはない。 これらの呼び出しの約 98 % はキャッシュからトランスクリプトを再読み込みする。コールドキャッシュに当たる残り約 2 % が、コストの 3 分の 1 以上を占める。
  • トランスクリプトを読むコストツールには見えない。 これらのリクエストはディスク上のセッションログに書き込まれない(#104358)。OpenTelemetry のエクスポートでしか確認できない。バックグラウンドのトークン使用量に関するドキュメントの節にも記載はなく、Agent View の行サマリーは Haiku クラスのモデルが数分おきに更新すると書かれている。
  • より安価な亜種はすでにあり、オフになっている。 2.1.310 には short モードが同梱されている。トランスクリプト全体ではなく約 2k トークンのメモを書き、任意でより小さなモデルに書かせることもできる。デフォルトは依然としてトランスクリプト全体で、サーバーフラグでしか変更できない。

タイムライン(2026 年)

バージョン(公開日)変更内容
2.1.32(2 月 5 日)コードが初めて登場。公開ビルドでは死んでいる
2.1.72(3 月 9 日)SDK のオプトインとして到達可能に
2.1.117(4 月 21 日)フォークゲートまたはサーバーロールアウト経由で対話型 CLI から到達可能に
≤ 2.1.220(7 月 24 日)フォークされたスキルは常に要約される
2.1.232(8 月 13 日)対話型バックグラウンドエージェントでデフォルト有効に
2.1.300(10 月 14 日)間隔がサーバー側で調整可能に、30〜240 秒
2.1.310(10 月 23 日)より安価な short モードが登場、オフのまま

テレメトリでは、週あたりの支出シェアが 7 月の 3.5〜7%(当社ではフォークゲートがすでに開いていた)から 7.3%へ、2.1.233 を取り込んだ週には 11.8%へと上がり、10 月中旬には約 16%に達した。

ライセンスと免責事項

MIT © 2026 Flamerix AI。現状のまま提供され、いかなる種類の保証も伴わない。使用は自己責任で。Flamerix AI は、本ソフトウェアの使用に起因する損害、データ損失、アカウントに対する措置について一切責任を負わない。クライアントの実行時の挙動を変更すると、利用中のサービスの規約に抵触する可能性がある。それを確認するのは利用者の責任である。

「Claude」および「Claude Code」は Anthropic, PBC の商標である。本プロジェクトは独立したものであり、Anthropic との提携、後援、承認関係はない。

出典: GitHub Gist← ホームへ戻る