Claude Code ステータスラインにFable 5のモデル別リミット表示を追加した

開発claude-code-tools

Claude Code ステータスラインにFable 5のモデル別リミット表示を追加した

Claude 5ファミリーの上位モデル Fable 5 を使い始めた。上位モデルには全モデル共通の週間リミットとは別に、モデル別の週間リミットがある。ところが手元のステータスラインに出しているのは5時間枠と7日枠の2つだけで、Fableの枠がどれだけ残っているかは見えない。「Fable 5のリミットも多分取れるようになってると思うんで、表示してくれませんか」の一言から着手して、結果10行の追加で済んだ。

ステータスラインに使用量を出す仕組み自体は3月に作ったものがそのまま動いている。Claude Codeが認証に使うOAuthトークンで内部の使用量APIを叩き、5時間枠・7日枠の使用率とリセット時刻をバー表示するPythonスクリプトだ。今回はその続きになる。

APIレスポンスに limits 配列が増えていた

まずAPIが何を返しているかの確認から。スクリプトは使用量APIのレスポンスを60秒キャッシュしているので、キャッシュファイルを整形して眺めるだけでいい。すると、3月時点にはなかった limits という配列が増えていた。

"limits": [
  {
    "kind": "session",
    "group": "session",
    "percent": 0,
    "severity": "normal",
    "resets_at": null,
    "scope": null,
    "is_active": false
  },
  {
    "kind": "weekly_all",
    "group": "weekly",
    "percent": 43,
    "severity": "normal",
    "resets_at": "2026-07-24T08:59:59+00:00",
    "scope": null,
    "is_active": false
  },
  {
    "kind": "weekly_scoped",
    "group": "weekly",
    "percent": 78,
    "severity": "warning",
    "resets_at": "2026-07-24T08:59:59+00:00",
    "scope": {
      "model": { "id": null, "display_name": "Fable" },
      "surface": null
    },
    "is_active": true
  }
]

探していたものがそのまま入っていた。kind: "weekly_scoped" のエントリが scope.model.display_name: "Fable" を持ち、これがFable 5専用の週間枠だ。全モデル共通の weekly_all が43%なのに対し、Fableスコープは78%。全体枠の半分も使っていないのに、Fableの枠は8割近く尽きている。この非対称が見えていなかったわけで、表示する価値は明白だった。

エントリに severity: "warning"is_active: true が付いているのも示唆的だ。API側は「いま効いている制約はこれ」と教えてくれている。従来の five_hour / seven_day フィールドも残っているので、既存の表示は壊れない。

余談だが、レスポンスには seven_day_opus / seven_day_sonnet といったモデル名付きの旧フィールドが null のまま残っていて、その横に tangeloiguana_necktieomelette_promotionalnimbus_quillcinder_coveamber_ladder という未リリース機能らしきコードネームのフィールドが並んでいる。モデル別リミットを固定フィールドで増やす方式をやめて、汎用の limits 配列に移行した過渡期のようだ。

実装: モデル名をハードコードしない

追加したのは、limits 配列からモデルスコープ付きのエントリを拾って、既存の5h/7dと同じ「バー+パーセント+リセットまでの残り時間」形式で並べるループだけ。

for lim in usage.get("limits") or []:
    model_scope = (lim.get("scope") or {}).get("model") or {}
    label = model_scope.get("display_name")
    if not label:
        continue
    pct = lim.get("percent") or 0
    resets = lim.get("resets_at") or ""
    t = time_until(resets) if resets else "?"
    ctx_parts.append(f"{label} {make_bar(pct)} {int(pct)}% ⏳{t}")

ラベルはAPIが返す display_name をそのまま使う。「Fable」をハードコードしていないので、今後別のモデルにスコープ付きリミットが設定されても、スクリプトを触らずに勝手に並ぶ。weekly_allsession は scope が null なので既存表示と重複しない。

表示はこうなった。

📁 ~/Git_repo/eurekapu-nuxt4
🐙 eurekapu-nuxt4 | 🌿 main | 💪 Fable 5
ctx █░░░░░░░░░ 12% | 5h ░░░░░░░░░░ 2% ⏳4h55m | 7d ████░░░░░░ 43% ⏳4d10h | Fable ████████░░ 79% ⏳4d10h

3行目の末尾にFableの枠が加わり、「7日枠はまだ半分残っているが、Fableはあと2割」が一目で分かる。上位モデルをいつ温存していつ使うかの判断材料が、ターミナルから離れずに手に入る。

振り返り

3月に作ったときの「一度仕組みを作ると、後から情報を足しやすい」がそのまま効いた回だった。OAuthトークンの取得・API呼び出し・キャッシュ・バー描画は全部使い回しで、今回書いたのは実質10行。キャッシュファイルを覗いてレスポンスの変化を確認するところから表示確認まで、数分で終わった。

APIが非公式である点は3月と変わらない。limits 配列という構造からして今後もフィールドは動きそうだが、スコープ付きエントリを汎用に拾う実装にしたので、モデルのラインナップが変わる程度なら追従できるはずだ。