Claude Codeのcurrent_usageで直近リクエストの内訳を読む
Claude Code statuslineのcontext_window.current_usageで、直近APIレスポンスのトークン内訳とキャッシュ利用量を読み取り、拡張コンテキストウィンドウを見分ける方法をまとめます。
Claude Codeのstatuslineがstdinで受け取るJSONには、context_window.current_usageという、直近のAPIレスポンス1回分のトークン内訳を持つフィールドがあります。似た名前のtotal_input_tokensと何が違うのか、いつnullになるのか、そして拡張コンテキストウィンドウで動いているかをどう見分けるのかをまとめます。
current_usageとは何か
context_window.current_usageは、直近のAPIレスポンス1回分のトークン数を4つのカテゴリーに分けて持つオブジェクトです。
| フィールド | 内容 |
|---|---|
input_tokens | 内容キャッシュを経由しない、生の入力トークン |
output_tokens | 内容直近のレスポンスでモデルが生成した出力トークン |
cache_creation_input_tokens | 内容直近のリクエストでキャッシュに新規書き込みされたトークン |
cache_read_input_tokens | 内容直近のリクエストでキャッシュから読み込まれたトークン |
キャッシュの効き具合をライブで見る最も直接的な方法は、statuslineスクリプトでこのcurrent_usageオブジェクトを読むことです。used_percentageのような集計値だけでは、入力のうちどれだけがキャッシュ経由かまでは分かりません。内訳をそのまま出したいときは、この4フィールドを直接読みます。
/contextコマンドが表示する内訳と混同しないように区別しておきます。/contextはシステムプロンプト・CLAUDE.md・MCPツール・読み込んだファイルといった発生源ごとにトークンを分類します。一方current_usageは発生源を区別せず、直近1回のAPIレスポンスをキャッシュの状態(フレッシュな入力か、キャッシュへの新規書き込みか、キャッシュからの読み込みか、出力か)で分類します。同じ「トークンの内訳」でも、軸が発生源かキャッシュ状態かで別物になる点は押さえておく価値があります。
total_input_tokensとの違い
紛らわしいのは、context_window.total_input_tokensという別フィールドの存在です。名前だけを見ると「セッション開始からの累計入力」に見えますが、実際は違います。total_input_tokensはinput_tokens・cache_creation_input_tokens・cache_read_input_tokensの3つを合算した値で、current_usageと同じ、直近のAPIレスポンス1回分を指します。累計ではありません。
つまり両者は同じ時点・同じリクエストの数値を、合算して見るか内訳で見るかの違いでしかありません。使い分けは単純です。
| 知りたいこと | 使うフィールド |
|---|---|
| いま文脈がどれだけ埋まっているか(進捗バー表示など) | 使うフィールドcontext_window.used_percentage または total_input_tokens |
| キャッシュ読み込みと新規入力の比率 | 使うフィールドcontext_window.current_usageの4フィールド |
| 直近レスポンスの出力トークン数だけ | 使うフィールドcurrent_usage.output_tokens(total_output_tokensも同じ値を指す) |
セッションを通じた累計コストを出したいなら、current_usageでもtotal_input_tokensでもなくcost.total_cost_usdを使います。この2つのフィールドは、あくまで「直近レスポンス時点のコンテキストウィンドウの中身」を映すスナップショットです。
完全なJSONスキーマの例では、current_usageがinput_tokens: 8500・cache_creation_input_tokens: 5000・cache_read_input_tokens: 2000のとき、total_input_tokensは15500になっています。8500+5000+2000の合計と一致し、output_tokensの1200はこの合計には含まれていません。この数値の対応関係を覚えておくと、自作のstatuslineで内訳から合計を計算し直したときに、値がずれていないかの検算に使えます。
nullになる2つのタイミング
current_usageは常に値が入っているわけではありません。nullになるのは次の2つのタイミングです。
- セッション内で最初のAPIレスポンスが返る前
/compactの直後から、次のAPIレスポンスが返るまでの間
1つ目はセッション起動直後、statuslineがまだ何もAPIレスポンスを受け取っていない状態です。2つ目は見落としやすい方です。会話が長くなり自動または手動で/compactが走ると、要約の完了と同時にcurrent_usageはいったんnullに戻り、次のやり取りでAPIレスポンスが返るまでその状態が続きます。
jqでこれを素通しすると、nullが算術評価に渡ってprintfがエラー終了し、statusline全体が空白表示になります。フォールバックは必須です。
input=$(cat)
cache_read=$(echo "$input" | jq -r '.context_window.current_usage.cache_read_input_tokens // 0')used_percentage・remaining_percentageもセッション序盤はnullになり得るフィールドなので、同じフォールバックが要ります。
used_percentageが数えているのは入力トークンだけ
context_window.used_percentageは便利な計算済みフィールドですが、計算式を知らずに使うと解釈を誤ります。この値はinput_tokens + cache_creation_input_tokens + cache_read_input_tokensだけから算出され、output_tokensは含みません。
自分でcurrent_usageから同じ割合を再計算するときも、この入力トークンだけの式に合わせないと、used_percentageの値とずれます。output_tokensを分子へうっかり含めてしまうと、実際より高い使用率を表示してしまいます。長い応答を生成した直後ほどこのズレは大きくなるため、独自集計のstatuslineほど注意が必要な点です。
cache_creationとcache_readの比率が示すもの
cache_creation_input_tokensとcache_read_input_tokensは、単なるトークン数ではなく課金レートも異なります。cache_read_input_tokensは標準の入力レートのおよそ10%で課金され、cache_creation_input_tokensはキャッシュ書き込みレート(TTLによって変わる、より高いレート)で課金されます。read側の比率が高いほど、実コストは下がっている計算です。
read対creationの比率が高い状態は「キャッシュがよく効いている」サインで、creationがターンをまたいで高いまま続くなら「プレフィックス(会話の先頭側)が何か変わっている」兆候です。モデル切り替えやCLAUDE.mdの編集直後にcreationが跳ねるのは、この兆候の典型例です。
書き込みレートはTTL(キャッシュの生存期間)によっても変わります。既定は5分TTLで、1時間TTLを使うとキャッシュは長く温存される代わりに書き込みレートが上がります。Claude Codeはサブスクリプション契約の範囲内でメイン会話に1時間TTLを自動要求しますが、プランの利用上限を超えて使用量クレジットに入ると5分TTLへ切り替わります。5分TTLのセッションでは、アイドルが5分を超えるだけでも自然にcache_creation_input_tokensが跳ね上がるため、creationが高いターンを見るたびに「プレフィックスが壊れた」と早合点しない方が安全です。どちらのTTLで書き込まれたかはcurrent_usageには出ず、claude -p "hello" --output-format jsonを実行して結果のusage.cache_creationにあるephemeral_1h_input_tokens・ephemeral_5m_input_tokensを見ると確認できます。statuslineのcache_creation_input_tokensはこの2つを合算した値です。
セッション全体の累計比率はprompt_cache.hit_ratioという別フィールドが持っていますが、これはメイン会話の最初のレスポンス以降を通じた累計で、サブエージェントのリクエストは含みません。current_usageベースの比率は直近1回のリクエストだけを見ている点が異なります。平均だけでなく直近の落ち込みにも気づきたいなら、両方を並べて表示すると差が見えます。キャッシュがどの単位で共有・分離されるかといった全体像はClaudeのプロンプトキャッシュの仕組みで扱っています。
context_window_sizeで拡張コンテキストウィンドウを見分ける
context_window.context_window_sizeは、そのモデルが持つコンテキストウィンドウの上限をトークン数で返します。既定は200000で、拡張コンテキストに対応するモデルでは1000000になります。
statuslineスクリプトの中でこのフィールドの値を見るだけで、いま拡張コンテキストウィンドウで動いているセッションかを判定できます。
input=$(cat)
size=$(echo "$input" | jq -r '.context_window.context_window_size // 200000')
if [ "$size" -eq 1000000 ]; then
echo "🔭 拡張コンテキスト"
fi似た名前のフィールドにexceeds_200k_tokensがありますが、これは別物です。直近レスポンスの合計トークン数(入力・キャッシュ・出力の合算)が200kを超えたかどうかを、実際のウィンドウサイズに関係なく固定のしきい値で判定するフラグです。拡張コンテキストウィンドウのモデルでcontext_window_sizeが1000000の状態でも、使用量が200kを超えていればexceeds_200k_tokensはtrueになります。「拡張コンテキストで動いているか」を知りたいときはcontext_window_size、「大量のトークンを使っているか」を知りたいときはexceeds_200k_tokensと分けて使います。対応モデルの一覧や換算目安、コスト設計はClaude 1Mコンテキストの実務活用にまとめています。この固定しきい値は、拡張コンテキストウィンドウのセッションで誤警告につながることがあります。詳しくはexceeds_200k_tokensとは — 拡張コンテキストウィンドウでも200kで判定される固定しきい値で扱っています。
直近リクエストのキャッシュ内訳を表示するstatusline
current_usageの4フィールドを組み合わせると、直近1回のリクエストがどれだけキャッシュに乗ったかを、その場でパーセント表示できます。
input=$(cat)
fresh=$(echo "$input" | jq -r '.context_window.current_usage.input_tokens // 0')
write=$(echo "$input" | jq -r '.context_window.current_usage.cache_creation_input_tokens // 0')
read=$(echo "$input" | jq -r '.context_window.current_usage.cache_read_input_tokens // 0')
total=$((fresh + write + read))
if [ "$total" -gt 0 ]; then
hit=$((read * 100 / total))
else
hit=0
fi
echo "💾 直近リクエストのキャッシュ命中率 ${hit}%"セッション全体の傾向を見たいだけなら/usageコマンドやprompt_cacheオブジェクトの方が手軽です。上のスクリプトが向くのは、いま実行した1回のやり取りだけを切り出して確認したい場面で、キャッシュが崩れた直後のターンを特定するときに役立ちます。
サブエージェントの行にcurrent_usage相当のフィールドはない
メインのstatusLineが受け取るcontext_window.current_usageは、メインセッションの直近リクエストだけを表します。並行して動くサブエージェントの行(subagentStatusLine)には、同じ粒度の内訳はありません。tasks配列の各要素が持つのはcontextWindowSize(そのモデルのコンテキストウィンドウ上限)とtokenCount(現在のトークン数)という合計値だけで、input_tokensやcache_read_input_tokensのような内訳フィールドはサブエージェント側には存在しません。
サブエージェントの文脈使用率だけを出すならtokenCountをcontextWindowSizeで割れば足りますが、キャッシュがどれだけ効いているかまで見たい場合は、メインセッションのcurrent_usageを読むほかありません。両者は入力・出力とも別のstdinオブジェクト(statusLine向けのセッション全体JSONと、subagentStatusLine向けのtasks配列)として届くため、1つのスクリプトで両方を扱う場合は設定を分けて登録します。
よくあるつまずき
current_usageがnullのままjqの算術に渡り、statusline全体が空白になる(// 0のフォールバックを忘れる)exceeds_200k_tokensを「拡張コンテキストウィンドウを使っているか」の判定に使ってしまう。実際は実ウィンドウサイズに関係ない固定200kしきい値のフラグused_percentageを自前で再計算する際にoutput_tokensを分子へ含めてしまい、本来の値より高く出る/compact直後の一瞬だけcurrent_usageがnullに戻ることを知らず、「フィールドが消えた」と誤解して実装を壊す
まとめ
context_window.current_usageは、直近1回のAPIレスポンスをinput_tokens・output_tokens・cache_creation_input_tokens・cache_read_input_tokensの4つに分解して見せるフィールドです。total_input_tokensとの違いは累計かどうかではなく、合算して返すか内訳で返すかだけで、どちらも同じ直近レスポンスの値を指します。拡張コンテキストウィンドウで動いているかはcontext_window_sizeが1000000かどうかで判定でき、実ウィンドウサイズに関係なく動くexceeds_200k_tokensと混同しないことが実装の分かれ目になります。statuslineの設定自体を一から組みたい場合はClaude Code statuslineの設定と表示項目の選び方、セッション内で何が文脈に積まれているかを俯瞰したい場合はClaude Codeのコンテキストウィンドウを可視化して中身を確認する方法を合わせて読むと、statuslineの数値がどこから来ているかの全体像がつかめます。