スリ飯屋MaLankaのフリーエンジニアな日々

このブログでは、フリーランスエンジニアとしての実体験から、フリーランスエンジニアに関するノウハウ、ブログや沖縄移住、スリランカの最新情報について発信します。

Claude Codeのステータスラインにusage情報を表示する — バイナリ解析で見つけた正しい方法

※提携先の広告(リンク、バナー等)を含む場合があります
  • Claude Codeのステータスラインにrate limit・コンテキスト使用率を常時表示できる
  • usage APIは存在するがanthropic-beta ヘッダーなしだと認証エラーになる
  • OAuthトークン取得にはanthropic-beta: oauth-2025-04-20ヘッダーが必須
Claude Codeのrate limit、毎回/usage開かないと分からないのがストレスだった。
ステータスラインにカスタムコマンドを設定すれば常時表示できますよ。
それZennの記事で見た!やってみよう。

そう思って始めたら、認証エラーとレートリミットの無限ループで3時間溶かすという地獄を見ました。

最終的にClaude Code自身がバイナリ解析を始め、「なぜ動かないのか」の根本原因を特定するという展開に。この記事では完成したスクリプトの設置方法と、そこに至るまでの試行錯誤の全記録をお届けします。

完成形と設定方法

まず結果から。こんな感じで表示されます。

Claude Codeのステータスラインにモデル名・コンテキスト使用率・コスト・rate limitを常時表示している画面
完成形。モデル名・コンテキスト・コスト・行変更・ブランチ・rate limitが常時表示される

ステータスラインに以下の情報が常時表示されます。

表示項目 説明
モデル名(プラン) Opus 4.6 (Max) のように表示
コンテキスト使用率 使用率に応じて緑→黄→赤に変化
セッションコスト そのセッションでの累計コスト
行変更数 +追加行数 / -削除行数
ディレクトリ・ブランチ 現在のディレクトリ名とGitブランチ
5時間rate limit プログレスバー + % + リセット時刻
7日間rate limit プログレスバー + % + リセット日時

スクリプトの設置

~/.claude/statusline-command.sh として以下のスクリプトを保存します。

#!/bin/bash

# Claude Code Status Line
# Usage data from Messages API response headers (anthropic-ratelimit-unified-*)

SESSION_DATA=$(cat)

# --- Extract session info ---
MODEL=$(echo "$SESSION_DATA" | jq -r 'if .model | type == "object" then .model.display_name // .model.id // "?" else .model // "?" end')
CTX_PCT=$(echo "$SESSION_DATA" | jq -r '.context_window.used_percentage // 0')
LINES_ADDED=$(echo "$SESSION_DATA" | jq -r '.cost.total_lines_added // 0')
LINES_REMOVED=$(echo "$SESSION_DATA" | jq -r '.cost.total_lines_removed // 0')
COST_USD=$(echo "$SESSION_DATA" | jq -r '.cost.total_cost_usd // 0')
CWD=$(echo "$SESSION_DATA" | jq -r '.cwd // ""')

GIT_BRANCH=""
if [ -n "$CWD" ]; then
  GIT_BRANCH=$(git -C "$CWD" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
fi

# --- Plan info from keychain ---
CREDS=$(security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null || echo "")
SUB_TYPE=$(echo "$CREDS" | jq -r '.claudeAiOauth.subscriptionType // ""' 2>/dev/null || echo "")
case "$SUB_TYPE" in
  max) PLAN="Max" ;;
  pro) PLAN="Pro" ;;
  free) PLAN="Free" ;;
  *) PLAN="$SUB_TYPE" ;;
esac

# --- Color helpers ---
c() { echo "\033[38;2;$1m"; }
RESET="\033[0m"
BOLD="\033[1m"
DIM=$(c "100;110;114")
SEP=" $(c "60;70;74")│${RESET} "

color_by_pct() {
  local pct=$1
  if [ "$pct" -ge 80 ] 2>/dev/null; then echo "231;111;81"
  elif [ "$pct" -ge 50 ] 2>/dev/null; then echo "241;196;15"
  else echo "46;204;113"; fi
}

bar() {
  local pct=$1 color=$2
  local filled=$(( pct / 5 ))
  local empty=$(( 20 - filled ))
  local out=""
  out+="$(c "80;85;90")["
  out+="$(c "$color")"
  for ((i=0; i<filled; i++)); do out+="█"; done
  out+="$(c "50;55;60")"
  for ((i=0; i<empty; i++)); do out+="░"; done
  out+="$(c "80;85;90")]"
  out+="${RESET}"
  echo "$out"
}

# --- Fetch usage via Messages API headers ---
CACHE_FILE="/tmp/claude-usage-cache.json"
LOCK_FILE="/tmp/claude-usage-cache.lock"
CACHE_TTL=900

fetch_usage() {
  if [ -f "$CACHE_FILE" ]; then
    local cache_age
    cache_age=$(( $(date +%s) - $(stat -f %m "$CACHE_FILE" 2>/dev/null || echo 0) ))
    if [ "$cache_age" -lt "$CACHE_TTL" ]; then
      cat "$CACHE_FILE"; return
    fi
  fi

  if [ -f "$LOCK_FILE" ]; then
    local lock_age
    lock_age=$(( $(date +%s) - $(stat -f %m "$LOCK_FILE" 2>/dev/null || echo 0) ))
    if [ "$lock_age" -lt 30 ]; then
      [ -f "$CACHE_FILE" ] && cat "$CACHE_FILE" || echo &#39;{}&#39;; return
    fi
  fi

  echo $$ > "$LOCK_FILE"

  local token
  token=$(echo "$CREDS" | jq -r &#39;.claudeAiOauth.accessToken // empty&#39; 2>/dev/null || echo "")
  if [ -z "$token" ]; then
    rm -f "$LOCK_FILE"
    [ -f "$CACHE_FILE" ] && cat "$CACHE_FILE" || echo &#39;{"error":"no_token"}&#39;
    return
  fi

  local hf="/tmp/claude-usage-headers.txt"
  curl -s -D "$hf" --max-time 10 \
    -H "Authorization: Bearer $token" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: oauth-2025-04-20" \
    -H "content-type: application/json" \
    -d &#39;{"model":"claude-haiku-4-5-20251001","max_tokens":1,"messages":[{"role":"user","content":"hi"}]}&#39; \
    "https://api.anthropic.com/v1/messages" > /dev/null 2>/dev/null

  rm -f "$LOCK_FILE"

  if [ -f "$hf" ]; then
    local fu fr su sr
    fu=$(grep -i "ratelimit-unified-5h-utilization" "$hf" | awk &#39;{print $2}&#39; | tr -d &#39;\r&#39;)
    fr=$(grep -i "ratelimit-unified-5h-reset" "$hf" | awk &#39;{print $2}&#39; | tr -d &#39;\r&#39;)
    su=$(grep -i "ratelimit-unified-7d-utilization" "$hf" | awk &#39;{print $2}&#39; | tr -d &#39;\r&#39;)
    sr=$(grep -i "ratelimit-unified-7d-reset" "$hf" | awk &#39;{print $2}&#39; | tr -d &#39;\r&#39;)
    if [ -n "$fu" ]; then
      jq -n --arg fu "$fu" --arg fr "$fr" --arg su "$su" --arg sr "$sr" \
        &#39;{five_hour:{utilization:($fu|tonumber),reset:($fr|tonumber)},seven_day:{utilization:($su|tonumber),reset:($sr|tonumber)}}&#39; \
        > "$CACHE_FILE"
      cat "$CACHE_FILE"; rm -f "$hf"; return
    fi
    rm -f "$hf"
  fi

  echo &#39;{"error":"fetch_failed"}&#39; > "$CACHE_FILE"
  cat "$CACHE_FILE"
}

続いて後半のパース・表示部分です。上記の fetch_usage 関数の続きに追加してください。

USAGE=$(fetch_usage)

# Parse usage
F5_PCT=0; F7_PCT=0; F5_RST=""; F7_RST=""; HAS=false
if echo "$USAGE" | jq -e &#39;.five_hour&#39; >/dev/null 2>&1; then
  HAS=true
  F5_PCT=$(echo "$USAGE" | jq -r &#39;.five_hour.utilization // 0&#39; | awk &#39;{printf "%d",$1*100}&#39;)
  F5_E=$(echo "$USAGE" | jq -r &#39;.five_hour.reset // 0&#39;)
  [ "$F5_E" -gt 0 ] 2>/dev/null && F5_RST=$(TZ=Asia/Tokyo date -r "$F5_E" "+%H:%M" 2>/dev/null)
  F7_PCT=$(echo "$USAGE" | jq -r &#39;.seven_day.utilization // 0&#39; | awk &#39;{printf "%d",$1*100}&#39;)
  F7_E=$(echo "$USAGE" | jq -r &#39;.seven_day.reset // 0&#39;)
  [ "$F7_E" -gt 0 ] 2>/dev/null && F7_RST=$(TZ=Asia/Tokyo date -r "$F7_E" "+%m/%d %H:%M" 2>/dev/null)
fi

# --- Build output ---

# Line 1: Model (Plan) | Ctx | Cost | Lines | Dir on Branch
CTX_C=$(color_by_pct "$CTX_PCT")
L1="${BOLD}${MODEL}${RESET}"
[ -n "$PLAN" ] && L1+=" ${DIM}(${PLAN})${RESET}"
L1+="${SEP}$(c "$CTX_C")${CTX_PCT}%${RESET}"
L1+="${SEP}$(c "180;180;180")\$$(printf &#39;%.2f&#39; "$COST_USD")${RESET}"
L1+="${SEP}$(c "46;204;113")+${LINES_ADDED}${RESET}$(c "100;110;114")/${RESET}$(c "231;111;81")-${LINES_REMOVED}${RESET}"
DIR_NAME=""
if [ -n "$CWD" ]; then
  DIR_NAME=$(basename "$CWD")
fi
if [ -n "$DIR_NAME" ]; then
  L1+="${SEP}$(c "180;190;200")${DIR_NAME}${RESET}"
  [ -n "$GIT_BRANCH" ] && L1+=" $(c "60;70;74")on${RESET} $(c "129;178;210")${GIT_BRANCH}${RESET}"
fi

echo -e "$L1"

# Line 2-3: Rate limit bars
if [ "$HAS" = true ]; then
  F5_BAR=$(bar "$F5_PCT" "$(color_by_pct "$F5_PCT")")
  F5_C=$(color_by_pct "$F5_PCT")
  L2="5h ${F5_BAR} $(c "$F5_C")${F5_PCT}%${RESET}"
  [ -n "$F5_RST" ] && L2+="  ${DIM}reset ${F5_RST}${RESET}"
  echo -e "$L2"

  F7_BAR=$(bar "$F7_PCT" "$(color_by_pct "$F7_PCT")")
  F7_C=$(color_by_pct "$F7_PCT")
  L3="7d ${F7_BAR} $(c "$F7_C")${F7_PCT}%${RESET}"
  [ -n "$F7_RST" ] && L3+="  ${DIM}reset ${F7_RST}${RESET}"
  echo -e "$L3"
else
  echo -e "${DIM}Usage loading...${RESET}"
fi

前半・後半を1つのファイルとして ~/.claude/statusline-command.sh に保存すれば完成です。

settings.jsonへの追加

~/.claude/settings.json に以下を追加します。

{
  "statusLine": {
    "type": "command",
    "command": "bash ~/.claude/statusline-command.sh"
  }
}

実行権限の付与と、jq(JSONパーサー)のインストールを忘れずに。

chmod +x ~/.claude/statusline-command.sh

# jqが入っていなければインストール
jq --version || brew install jq
設定するだけなら簡単そうだな。

設定自体はシンプルです。ただ、ここに至るまでの道のりが壮絶だったのでその話をします。

きっかけ — Zennの記事を見て「これやりたい」

こちらの記事を見て「これは便利だ」と思ったのがすべての始まりです。

zenn.dev

記事の内容は明快で、statusLine 設定にスクリプトを指定するだけ。Claude CodeのAPIからusage情報を取得して表示する仕組みです。

これ、Claude Codeにやらせればすぐ終わるでしょ。

そう思って「これ、できる?」とClaude Codeに投げたところ、ものの1分で最初のスクリプトが完成しました。

最初の成果物 — 動いたけどバグだらけ

Claude Codeが生成したスクリプトを設定し、再起動すると確かにステータスラインに何かが表示されました。

ただ、表示がおかしい。

モデル名がJSON丸ごと表示される

{"id": "claude-opus-4-6", "display_name": "Opus 4.6"} │ Ctx: 0%
モデル名がJSONオブジェクトそのまま出てるんだけど。

sessionデータの .model フィールドが文字列ではなくオブジェクトで返ってきていました。.model.display_name を取る必要があったのに、.model をそのまま出力していた。

パーセント記号が二重になる

Ctx: 0%% │ 5h ▱▱▱▱▱▱▱▱▱▱ 0%%

echo -e で出力しているのに %% と書いていたため、printf のエスケープと混同していたようです。echo -e なら % 単体でOK。

Usage が全部0%

5h  ▱▱▱▱▱▱▱▱▱▱ 0%
7d  ▱▱▱▱▱▱▱▱▱▱ 0%
APIからusage情報が取得できていないようです。キーチェーンのサービス名を確認します。

ここからが本番でした。

認証エラーとレートリミットで3時間溶かした話

OAuthトークンがJSONの中にJSON

Claude Codeはキーチェーンの Claude Code-credentials にOAuthトークンを保存しています。ところがこの値、JSONオブジェクトの中にアクセストークンが入っている構造でした。

# 取得した値の構造
{
  "claudeAiOauth": {
    "accessToken": "sk-ant-oat01-...",
    "expiresAt": 1772677734017,
    "subscriptionType": "max",
    ...
  }
}

最初のスクリプトでは -a "oauth_token" -w のように直接トークンを取ろうとしていましたが、-w で取れるのはJSONオブジェクト全体。そこから .claudeAiOauth.accessToken をjqで抽出する必要があったのです。

レートリミット自爆

トークンは取れるようになりましたが、APIエンドポイント /api/oauth/usage にリクエストすると OAuth authentication is currently not supported が返ってくる。

え、このAPIってそもそも動くの?

後から分かったことですが、この時点でanthropic-beta: oauth-2025-04-20 ヘッダーを付けていなかったのが原因です。OAuthトークンでAnthropicのAPIを叩くにはこのヘッダーが必須で、なしだと認証方式として認識されません。

ただ、この時はその事実を知る由もなく、Claude Codeはデバッグのためにキャッシュファイルを削除しました。

rm -f /tmp/claude-usage-cache.json

これが致命的だった。 ステータスラインのスクリプトはClaude Codeが数秒おきに実行します。キャッシュファイルがない状態でスクリプトが動くと、毎回APIを直接叩いてしまう

結果、APIに大量のリクエストが飛び、429 Rate Limited の嵐に。

{
  "error": {
    "message": "Rate limited. Please try again later.",
    "type": "rate_limit_error"
  }
}
キャッシュTTLを360秒から900秒に変更し、ロックファイル機構を追加しました。

ロックファイルとエラーキャッシュを入れて連打を止めたものの、すでにレートリミットは発動済み。3時間経っても429が返り続ける状態になりました。

そもそもこのAPI、存在するの?

3時間以上レートリミットが解除されない。流石におかしい。

2026年 3月 5日 09時42分: Rate limited. Please try again later.
2026年 3月 5日 12時22分: Rate limited. Please try again later.
3時間ずっとrate limitって、これ本当に存在するエンドポイントなのか?

別のエンドポイントを片っ端から試しました。

/api/oauth/usage         → Rate limited(もう叩きすぎ)
/api/usage               → 404 Not Found
/v1/usage                → 404 Not Found
/api/auth/usage          → 404 Not Found

全滅です。

ここで発想を転換します。「Claude Code自体は /usage の情報を正しく取得できている。なら、Claude Codeがどうやってデータを取っているのか調べればいい」

Claude Codeがバイナリ解析を始めた

Claude Codeのバイナリからusageエンドポイントを探します。
AIが自分自身のバイナリを解析するの?

はい、Claude Codeが stringsgrep を使って自分自身のバイナリファイルを解剖し始めました。

stringsとgrepでClaude Code本体を解剖

まずClaude Codeが内部で使っているURLパターンを抽出。

grep -ao &#39;https://[a-zA-Z0-9._/-]*usage[a-zA-Z0-9._/-]*&#39; \
  ~/.local/share/claude/versions/2.1.69
https://claude.ai/admin-settings/usage
https://claude.ai/settings/usage
https://code.claude.com/docs/en/data-usage
https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md

完全URLでの検索では見つからない。(実際には api/oauth/usage は相対パスとしてバイナリに含まれていたのですが、この時点ではフルURL検索だったため引っかからなかった。これは後から判明します。)

anthropic-ratelimit-unified-* ヘッダーの発見

別の角度から、レートリミット関連の文字列を検索。

grep -ao &#39;[a-zA-Z_-]*rate[_-]*limit[a-zA-Z_-]*\|[a-zA-Z_-]*utilization[a-zA-Z_-]*&#39; \
  ~/.local/share/claude/versions/2.1.69 | sort -u
anthropic-ratelimit-unified-
anthropic-ratelimit-unified-5h-reset
anthropic-ratelimit-unified-5h-utilization
anthropic-ratelimit-unified-7d-reset
anthropic-ratelimit-unified-7d-utilization
anthropic-ratelimit-unified-status

見つけました。 Claude Codeは専用のusage APIなど使っていない。通常のMessages APIのレスポンスヘッダーにrate limit情報が含まれているのです。

隠し鍵 anthropic-beta: oauth-2025-04-20

ヘッダーの存在は分かりましたが、OAuthトークンでMessages APIを叩くと 401 Unauthorized が返る。通常のAPIキーとは認証方式が違うはず。

バイナリからリクエストヘッダーの設定部分を抽出しました。

grep -aob &#39;anthropic-beta&#39; ~/.local/share/claude/versions/2.1.69

コードを読み解くと、Claude Codeは以下のヘッダーを付けてAPIリクエストを送っていました。

Authorization: Bearer {OAuthトークン}
anthropic-beta: oauth-2025-04-20

この anthropic-beta ヘッダーがOAuth認証に必要な鍵だったのです。公式ドキュメントには載っていません。

早速テスト。

TOKEN=$(security find-generic-password -s "Claude Code-credentials" -w | jq -r &#39;.claudeAiOauth.accessToken&#39;)

curl -s -D /tmp/headers.txt \
  -H "Authorization: Bearer $TOKEN" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: oauth-2025-04-20" \
  -H "content-type: application/json" \
  -d &#39;{"model":"claude-haiku-4-5-20251001","max_tokens":1,"messages":[{"role":"user","content":"hi"}]}&#39; \
  "https://api.anthropic.com/v1/messages" > /dev/null

レスポンスヘッダー:

anthropic-ratelimit-unified-status: allowed
anthropic-ratelimit-unified-5h-utilization: 0.02
anthropic-ratelimit-unified-5h-reset: 1772697600
anthropic-ratelimit-unified-7d-utilization: 0.44
anthropic-ratelimit-unified-7d-reset: 1772935200
やっと取れた!

完全に動作しました。 5h utilization: 2%、7d utilization: 44%。/usage で表示される値と一致。

最終的に分かったこと

ここまでの調査で判明した事実をまとめます。

/api/oauth/usage は存在する — ただし anthropic-beta ヘッダーが必須

当初「/api/oauth/usage エンドポイントは存在しない」と考えていましたが、追加調査でこれは誤りだと判明しました。

バイナリを改めて精査すると、Claude Code内部にこのエンドポイントを呼び出すコードがしっかり存在していました。

// Claude Code v2.1.69 内部のコード(バイナリから抽出・整形)
let R = {
  "Content-Type": "application/json",
  "User-Agent": Bh(),
  ..._.headers  // ← ここにBf()の結果が展開される
};
let q = `${t8().BASE_API_URL}/api/oauth/usage`;
return (await UR.get(q, {headers: R, timeout: 5000})).data

そして _.headers に展開される Bf() 関数の中身はこう。

function Bf() {
  return {
    headers: {
      Authorization: `Bearer ${_.accessToken}`,
      "anthropic-beta": "oauth-2025-04-20"
    }
  }
}

つまり /api/oauth/usageanthropic-beta: oauth-2025-04-20 ヘッダーを付ければ正常に動く。 前のセッションでうまくいかなかったのは、Claude Codeが生成したスクリプトにこのヘッダーが含まれていなかっただけでした。

最初から anthropic-beta ヘッダーさえ付いていれば、バイナリ解析なんて要らなかったわけか。

なぜ参考記事を見ても動かなかったのか

ここで「参考にしたZennの記事はなぜこの問題に触れていないのか」という疑問が湧きます。

記事の内容を改めて確認すると、具体的なスクリプトのコードは掲載されていませんでした。 「Claude Codeにこういう仕様でスクリプトを作らせた」という説明と、完成後のスクリーンショットだけ。

ZennやQiitaでよくあるパターンだ。AIに生成させたコードを貼って、実際に動くかどうか検証が甘いケース。

実際、私がClaude Codeに同じ指示を出した時も、最初に生成されたスクリプトには anthropic-beta ヘッダーが含まれていませんでした。Claude Code自身が、自分のOAuth認証に必要なヘッダーを知らないのです。

これは考えてみれば当然で、anthropic-beta: oauth-2025-04-20 は公式ドキュメントに記載されておらず、Claude Codeのバイナリ内部にしか情報がありません。Claude(LLM)がこのヘッダーの存在を学習データから知る手段がない。

参考記事の著者も同じ状況に遭遇した可能性が高いですが、スクリプトのコードが非公開なので、最終的に動いているのか、あるいは記事公開時点では動作未確認だったのかは分かりません。

「AIに作らせました」系の記事は、動作確認済みかどうか見極めが重要ですね。

これはClaude Codeに限った話ではなく、ZennやQiitaのAI関連記事全般に言えることです。特にAIが生成したコードをそのまま掲載している記事は、細かい認証やヘッダーの部分で実は動かないケースが少なくありません。

usage情報のもう一つの取得方法 — Messages APIのレスポンスヘッダー

/api/oauth/usage エンドポイント以外に、Claude CodeはMessages APIのレスポンスヘッダーからもrate limit情報を取得しています。

ヘッダー名 内容
anthropic-ratelimit-unified-status 現在のステータス(allowed等)
anthropic-ratelimit-unified-5h-utilization 5時間使用率(0.0〜1.0)
anthropic-ratelimit-unified-5h-reset 5時間リセットのUnixタイムスタンプ
anthropic-ratelimit-unified-7d-utilization 7日間使用率(0.0〜1.0)
anthropic-ratelimit-unified-7d-reset 7日間リセットのUnixタイムスタンプ

OAuth認証に必要な3つの要素

OAuthトークンでMessages APIを叩くには以下の3つが必要です。

要素
トークン取得先 macOSキーチェーン Claude Code-credentials.claudeAiOauth.accessToken
認証ヘッダー Authorization: Bearer {token}
betaヘッダー anthropic-beta: oauth-2025-04-20これがないと401

キャッシュ設計は必須

ステータスラインのスクリプトはClaude Codeが数秒おきに実行します。毎回Messages APIを叩くと:

  1. レートリミットに引っかかる(実体験済み)
  2. Haikuのトークンを無駄に消費する

今回のスクリプトでは以下の対策を入れています。

  • キャッシュTTL: 15分 — APIは15分に1回だけ叩く
  • ロックファイル — 複数のstatusline呼び出しが同時にAPIを叩かない
  • エラーキャッシュ — API失敗時もキャッシュファイルを作成し、TTL期間は再リクエストしない
キャッシュなしでデバッグした結果、3時間以上のレートリミットを食らった。みんなは気をつけて。

おまけ — 見た目のカスタマイズ

基本的な表示ができたら、見た目も凝りたくなるのが人の性です。

プラン名の表示

キーチェーンの認証情報には subscriptionType フィールドが含まれています。これを使ってモデル名の横にプラン名を表示。

Opus 4.6 (Max)

カラフルなプログレスバー

使用率に応じて色が変わるプログレスバー。20セグメントのブロックスタイルです。

[████████████░░░░░░░░] 60%   ← 金色(50%超え)
[████████████████████] 95%   ← 赤色(80%超え)
[████░░░░░░░░░░░░░░░░] 20%   ← 緑色(50%未満)

ディレクトリとブランチ

作業ディレクトリ名とGitブランチを表示。地味に便利。

📂 hatena_blog on 🔀 main
sessionデータの `.cwd` フィールドからディレクトリを取得し、そこで `git rev-parse` を実行しています。

5hバーと7dバーの色分け・セパレーター

5時間と7日間のバーが同じ色だと一瞬どちらか分かりにくいので、色系統を変えるのもおすすめです。

  • 5hバー: シアン系(青→水色→赤)
  • 7dバー: パープル系(紫→ラベンダー→赤)

バーの間に薄いセパレーターラインを入れると、さらに見やすくなります。

5時間バーをシアン系、7日間バーをパープル系に色分けし、間にセパレーターを入れたカスタマイズ例
色分け+セパレーターで視認性アップ。80%を超えるとどちらも赤になる

rate limitティアの表示

Maxプランの場合、rateLimitTier フィールドに default_claude_max_20x のような値が入っています。ここから倍率部分を抽出すれば Opus 4.6 (Max 20x) のように表示可能です。

最終的な表示例

🤖 Opus 4.6 (Max 20x) │ 📊 21% │ 💰 $1.98 │ ✏️ +48/-12 │ 📂 hatena_blog on 🔀 main
⏱  [████░░░░░░░░░░░░░░░░] 10%  ↻ 17:00
─────────────────────────────────
📅 [████████░░░░░░░░░░░░] 42%  ↻ 03/08 11:00

これがClaude Codeの画面下部に常時表示されます。 rate limitが80%を超えると赤くなるので、「そろそろヤバいな」と一目で分かる。

結局、参考記事を見て「すぐ終わるでしょ」と思ってから完成まで、丸1セッション使い切ったよ。
途中でバイナリ解析を始めたのは想定外でしたね。

でもおかげで、Claude Codeが内部でどうやってrate limit情報を管理しているのか完全に理解できました。遠回りしたからこそ得られた知見です。

同じことをやろうとしてハマっている人がいたら、この記事が助けになれば幸いです。