バイブコーディング初心者向け: Claude Code/Codexのトークンモニターアプリを作ってみた

当記事内にアフィリエイトリンクを含みます
  • URLをコピーしました!

Claude CodeやCodexで、レート制限や現在セッションのコンテキスト使用量を確認するには、Claudeなら/usage/context、Codexなら/statusをその都度打つ必要があります。

画面の隅に常駐して、「あとどれくらい使えるか」を表示する小さなウィンドウ(HUD)があれば楽なので、Claude CodeとCodexの利用状況をまとめて表示するトークンモニター(token-monitor)を作りました。

私自身はパソコンおたくですが、プロのエンジニアではありません。AIの勉強と趣味と実益のため、ChatGPTとClaudeの月20ドルのプランを契約しています。2026年に入ってから、バイブコーディングでちょっとしたWindows GUIアプリをいくつか作るようになりました。token-monitorもその1つです。

今回はWindows 11向けに作りました。ログの保存先や外部コマンドの停止処理などを各OS向けに置き換えれば、同じ考え方でLinuxやmacOSにも応用できます。具体的な置き換え例は「実現方法」で後述します。

この記事では、できあがったコードは掲載していません。その代わり、AIエージェントが不足する細部を自分で調べたり、利用者に確認したりしながら、同等のtoken-monitorを開発できる程度の実装ガイドとしてまとめています。

正式な仕様書ではありませんが、自分でも同じようなHUDを作ってみたい方は、この記事をAIエージェントへ渡し、アプリ開発の出発点として使えます。

AIエージェントに記事を読ませる際は、WebFetch等の要約機能付きツールではなく、curlなどで本文をそのまま取得させます。要約機能を使うと、実装上の細かな注意点が落ちる可能性があるためです。

例えば、以下のようなプロンプトで依頼できます。

以下のURLの内容を、bashのcurlコマンドで取得してください(WebFetch等の要約機能付きツールは使わないこと)。取得した内容に書かれている実装ガイドに従って、token-monitor(Windows常駐HUD、Python + PySide6)を実装してください。

  • Claudeのコンテキスト上限の実測値は記事執筆時点のものなので、実装前に、私が使う全モデル分の/context表示を私に確認させてから使ってください。
  • UIデザインの細部は、私と相談して決めてください。
  • Claude Code/CodexをWSLで使っているかを私に確認し、使っているならWSL側のユーザー名を聞いてください。

対象記事URL: https://maruq.net/token-monitor/

目次

完成形の動作

  • スタートメニューやタスクバーの「token-monitor」ショートカットから起動する。
  • 既に1つ起動している状態でもう一度起動しようとすると、後から起動した方は何もせず静かに終了する(多重起動防止)。
  • HUDウィンドウは常に最前面に表示され、ドラッグで移動できる。
  • 左上のハンバーガーメニュー「☰」(または右クリック)から、表示するツール(Claude/Codex/両方)とレイアウト(横型/縦型)の切替、再起動、ヘルプ、終了ができる。「両方」選択時はClaude/Codexを同時表示する。ツール・レイアウト・ウィンドウ位置は次回起動時に復元する。

表示内容

Claude Code・Codexには通常、5時間ごと・7日ごとにリセットされる利用量の上限(レート制限)があります。HUDには、このレート制限の消費状況と、現在セッションのコンテキスト使用量を表示します。

横型では、1ツールにつき次の1行で表示します。

ctx:13% 126K/967K 5h:12%(4h58m) 7d:3%(6d18h2m)
  • ctx: 現在セッションのコンテキスト使用率とトークン数(使用/上限)。
  • 5h / 7d: 5時間/7日間のレート制限消費率と、リセットまでの残り時間。-は、現在の値を取得・表示できないことを表します。消費率が0%でもリセット時刻だけ取得できない場合は、0%(-)と表示します。また、リセット予定時刻を過ぎた枠は、消費率も残り時間も現在の値ではなくなるため、両方まとめて-にします。

Claude/Codex両方を横型で表示した例です。

横型表示

こちらのスクリーンショットでは、Claudeの表示は5h:0%(-)となっています。前述の「消費率0%でリセット時刻だけ取得できない」ケースです。

Codexの5h欄が-なのは、記事執筆時点で、OpenAIが2026年7月12日からPlus・Business・Proの5時間枠を一時的に解除しているためです。

縦型では、同じ項目を値と補足の2行に分けて縦に並べます。例えばctxなら1行目に13%、2行目に126K/967Kという形です。具体的な余白や並びは、使う画面サイズに合わせてAIと相談しながら決めてください。

椅子の背もたれに体を預けて伸びをするアライグマ。モニターにはトークン使用量HUDが表示されている

必要な環境

  • Python 3系、PySide6(PythonのGUI用ライブラリ)
  • Claude Code CLI

私は普段、VS Code拡張機能のClaude CodeとCodexを使っています。しかし、このアプリはClaudeのレート制限をclaude -p "/usage"で取得するため、VS Code拡張機能とは別にClaude Code CLIもインストールしておく必要があります。

Codex側はログファイルを読むだけなので、Codex CLIは要りません。

実現方法

※Linux/Macの場合、以下の説明で出てくるpythonw.exepython3 script.py &のようなバックグラウンド起動に、taskkillpkill等に読み替えてください。WSL連携の節はWindows固有の話なので無視してください。

  • Pythonスクリプトとして作り、exe化はしない。pythonw.exe(コンソール画面を表示せずに実行するPython実行ファイル)経由でそのまま実行する。
  • GUIにはPySide6というライブラリを使う。常に最前面に表示され続けるイベントループ駆動(常時待機し、操作やタイマーなどのイベントに応じて処理を行う)のGUIアプリとして動く。表示は10秒おきにローカルファイルを再読込して更新する。
  • データ取得はブラウザやAPIを直接呼ばず、Claude Code・Codexがそれぞれローカルに残すログファイルの直接読み取りと、Claude CLIのヘッドレス呼び出し(-pオプションによる非対話実行。/usageをこれで叩く)だけで完結させる。

データの取り方と保存

このアプリでは、表示する値ごとに取得元が異なります。以下の3種類を、それぞれ別の場所から取得します。取得した結果や表示設定の保存先は最後にまとめます。

ログは毎回全件走査せず、末尾の一定範囲だけを読み、先頭の不完全な行を捨ててJSONLとして解析します。

Codex: コンテキスト使用率(ctx)、5時間制限、7日制限の情報の取り方

Codexは、1行に1件ずつ記録が並ぶログファイル~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonlにセッションのやり取りを残しています。1行は、そのターンの出来事を表す封筒(envelope)で、トップレベルのtype"event_msg"固定、トークン使用量とレート制限はpayloadの中に入っています。最新のログファイルを開き、いちばん新しいpayload.type == "token_count"の行を探せばよいです。中身はこうなっています(一部省略)。

{
  "timestamp": "2026-07-13T11:10:41.962Z",
  "type": "event_msg",
  "payload": {
    "type": "token_count",
    "info": {
      "total_token_usage": { "total_tokens": 20973691 },
      "last_token_usage":  { "total_tokens": 172499 },
      "model_context_window": 353400
    },
    "rate_limits": {
      "primary":   { "used_percent": 21.0, "window_minutes": 300,   "resets_at": 1783690689 },
      "secondary": { "used_percent": 19.0, "window_minutes": 10080, "resets_at": 1784259400 }
    }
  }
}
  • コンテキスト使用量は直近時点のスナップショットであるlast_token_usageを使う。total_token_usageはセッション全体の累計なので使わない。コンテキスト上限はmodel_context_window
  • レート制限は、primaryを5h、secondaryを7dと決め打ちしてはいけない。window_minutesで5時間(300分)枠・7日(10080分)枠を判別する。used_percentが消費率、resets_atがリセット時刻(Unix秒)。rate_limitsにはこの2つ以外のキー(credits等)が含まれることもあるが無視してよい。

Claude: コンテキスト使用率(ctx)の情報の取り方

Claude Codeも~/.claude/projects/<プロジェクト名>/*.jsonlにセッションの記録(トランスクリプト)を残します。最新のトランスクリプトファイルを開き、いちばん新しい記録(1行がAIの応答1回分)を見ます。そこに含まれるmessage.usageという項目に使用量が入っています。ただし数値はinput_tokenscache_creation_input_tokenscache_read_input_tokensoutput_tokensの4種類に分かれているので、表示に使う使用量はこの4つの合計になります。今使っているモデルは同じ行のmessage.modelで分かるので、そのモデルに応じた上限(分母)を選びます。

コンテキストの上限(分母)はCodexと違ってログに書かれていないため、実機の/context表示で確認した値を、モデルごとに直接持っておきます(実測2026-07-11: Sonnet 5=967,000、Opus 4.8・Fable 5=1,000,000、Haiku 4.5=200,000)。この値は自分の環境の/context表示で確認してください。未実測のモデルはctx表示を諦めます(-)。モデルの判定は前方一致で行ってください。message.modelはバージョン名の後ろに文字列が続くことがあります。

Claude: 5時間制限、7日制限の情報の取り方

Claudeのレート制限情報はローカルのログに記されていません。そこで、claude CLI自体をclaude -p "/usage" --no-session-persistenceという形でヘッドレス実行(対話画面を出さずに1回だけ実行するモード)し、返ってきた出力をパース(決まった形式の文章として読み取り、必要な値を取り出すこと)します。--no-session-persistenceを付けないと、この裏側の呼び出し自体が空のセッションとしてトランスクリプトに残ってしまい、上記のコンテキスト読み取りを汚染するため必須です。

なお、このポーリングでトークン消費や追加課金は発生しません(実測確認済み)。claudeをヘッドレス実行する際の出力は、encoding="utf-8"を明示して読んでください(既定のままだとWindowsで文字化けすることがあります)。

5h/7dの数値やリセット時刻はそれぞれ独立した項目に分かれておらず、/usageを手で打った時に画面に出るのと同じ、人間向けの文章がまるごと返ってきます。たとえば中身はこうなっています。

You are currently using your subscription to power your Claude Code usage

Current session: 17% used · resets Jul 12, 7:09pm (Asia/Tokyo)
Current week (all models): 21% used · resets Jul 18, 1:59pm (Asia/Tokyo)

1行目の前置き文(「今あなたはサブスク範囲内でClaude Codeを使っています」という意味)の後に、5時間枠(Current session)と週次枠(Current week)の行が続きます。つまり5h/7dの数値もリセット時刻も、構造化されたデータからではなく、この人間向けの文章から読み取ることになります。

この出力は状況によって一部が省略されることがあるので、それに対応した実装が必要です。詳しくは後述の「実装ガイドの補足: 実装時の注意点」で説明します。

claudeコマンドの実行間隔は自分の環境で決めてください。私は90秒にしています。ただし90秒だと私の環境では5回に1回ほど失敗します(連続失敗はまれ)。120秒間隔なら失敗しませんでした。

状態の保存とキャッシュ

ウィンドウ位置・表示設定・レート制限の取得結果(キャッシュ)は、スクリプトと同じ場所のstate/フォルダに、それぞれ小さなファイルとして保存します。

  • ウィンドウ位置: window_position.jsonxy座標を保存する。
  • 表示設定: display_preferences.jsonに、表示中のツール(current_tool。0=Claude、1=Codex、2=両方)と縦型レイアウトかどうか(vertical_layout)を保存する。次回起動時に、この2つとウィンドウ位置から表示を復元する。
  • レート制限のキャッシュ: claude_usage_cache.jsonに取得時刻(fetched_at)と/usageの生の出力(text)を保存する。パース済みの数値ではなく生の文章のまま持っておき、読むたびにパースし直す。数値行を含まない異常応答や呼び出し失敗が3回連続した時だけ、このキャッシュを削除する(理由は後述の「実装ガイドの補足」参照)。

どのファイルも、壊れて読めなければ中身を捨ててデフォルト値から始める設計にしておきます(位置なら既定位置、キャッシュなら空)。この割り切りが、後述の「実装ガイドの補足: 実装時の注意点」で触れる同時読み書きへの備えになっています。

机に肘をつき頬杖をついて目を閉じ、小さく微笑むアライグマ。机には細かいメモやカードが散らばっている

まとめ

token-monitorは、Claude CodeとCodexがローカルに残すログと、Claude CLIの/usage出力を組み合わせて、現在セッションのコンテキスト使用量とレート制限を常時表示するアプリです。

ブラウザやAPIを直接使わずに実現できますが、人間向けに出力される文章の揺れ、巨大化するJSONLログ、WSL側の探索、外部コマンドのタイムアウトなど、実際に作ってみないと気づきにくい問題がありました。

トークンの残量を画面の隅に出しておくだけの小さなアプリですが、その仕組みとデータの取り方を、AIが不足する細部を補いながら同等のアプリを開発できるようにまとめました。

非エンジニアでバイブコーディング初心者の私は、技術的な詳細を、一つ一つClaudeやCodexに教えてもらいながら書いています。皆さんも、読んでいて分からない言葉が出てきたら、同じようにAIに聞きながら読み進めてもらえば大丈夫だと思います。

実際、ClaudeのSonnetやCodexのTerraでも、記事の内容を理解し、実装方針を組み立てられることを確認しています。

ここから先の「実装ガイドの補足」は、実装の際にぶつかった細かな罠を、AI自身にまとめさせたものです。

ここから先は、実装をAIに依頼する人や、内部の仕組みに興味がある人向けの補足です。一般的な紹介だけを読みたい方は、ここまでで構いません。この記事を実装ガイドとしてAIに渡すときは、補足まで含めて読ませてください。

実装ガイドの補足: 実装時の注意点

ここまでの説明には出てこない、実装時に見落としがちな点が8つあります。

人間向けの画面表示を機械に読ませるのは脆い

Claudeのレート制限は、/usageコマンドの出力——つまり人間が読むための文章——をパースして取り出していますが、この出力は状況によって形が揺れます。リセット時刻が省略されることや、数値の行自体が出ないことがあります。正式なAPIではない「画面表示」をデータ源にする以上、「常に同じ形で出てくる」とは決して仮定せず、一部が欠けても壊れないパースにします。区切り文字(など)も決め打ちにせず、usedresetsの間はどんな文字列が来ても拾えるくらい緩いパターンにしておきます。

resetsの日時には、パース時点のローカルタイムゾーンを使ってください。

取得に3回連続で失敗した時だけclaude_usage_cache.jsonを消して「-」表示に戻します。単発・2連続の失敗では前回値を表示し続けます(実測では、劣化はほとんど単発で、2〜3連続もまれに起きます)。リセットまでの残り時間は取得済みのリセット時刻からローカルで計算するので取得できていない間も正確に進み、消費率も数分のずれでは実用上問題にならないためです。

エラーが「無言のクラッシュ」になる場所がある

GUIライブラリ(Qt)には、ライブラリ側から呼び出されるコールバック関数(描画処理など)があり、この中でエラーが起きると、通常のエラー処理が一切効かず、メッセージも出さずにプロセスが黙って落ちます。ログも出ないので手がかりゼロ。対策は、この種の関数の中身を丸ごとエラー捕捉で囲み、原因をログファイルへ書き出してから、改めてクラッシュさせることでした。

同時に読み書きするとファイルが壊れる

レート制限の取得結果をキャッシュするファイルに、10秒ごとに読みに行く表示処理と、取得できた瞬間に書きに行くバックグラウンド処理の両方からアクセスします。単純に「まるごと書き込む」実装だと、書き込みの途中で表示側が読みに行き、中途半端なJSONを掴んでパース失敗することがありました。対策は、読み込み側で壊れを検知したら安全な既定値にフォールバックすることです。書き込み側をアトミックにする(一時ファイル経由でリネームする等)手もありますが、このアプリの状態ファイルはどれも壊れて失っても実害がデフォルト値へのリセット程度で済むため、そこまではしていません。

取得トリガーを表示更新と同居させると、劣化時に連射してしまう

「キャッシュが古いか」の判定を、表示更新関数(数秒おきに呼ばれる)の中に置き、「前回成功した時刻からの経過秒数」で判定する作りに、最初はなっていました。すると劣化応答が続く間は前回成功時刻が進まないため、この判定が毎回「古い」ままになり、本来90秒に1回のはずの/usage呼び出しが、表示の更新間隔(数秒)そのままの頻度で連射されてしまいました。劣化中だけ取得間隔が短くなる悪循環です。対策は、取得処理を表示更新から完全に切り離し、取得専用のスレッドが「取得する→90秒待つ→取得する→…」を、結果が成功でも失敗でも淡々と繰り返す設計にすることでした。

頭をかきながらモニターを指差し、困り笑いを浮かべるアライグマ。机には虫眼鏡とドライバーが置かれている

WSL側も探索する

WSL上でもClaude/Codexを使っている場合、同じ形式のログがWSL側の各ディストリビューション(WSL上で動くLinux環境)にもあるので、Windows側と併せて探索対象に含めます(例: \\wsl.localhost\<ディストリビューション名>\home\<ユーザー>\.claude\projects.codex\sessions)。WSL側のユーザー名はWindows側のユーザー名と一致するとは限らないため、自分の環境で実際のWSL側ユーザー名を確認してから使ってください。

ただし、停止中のWSLに\\wsl.localhost\...で直接アクセスすると、そのディストリビューションが起動してしまいます。先にwsl -l --runningで起動中のディストリビューションを確認し、起動中のもの(複数あれば、対象ログを持つディストリビューションのうち1つ)だけを探索します。Windows側とこのWSL側を合わせた候補の中から、最終更新が最新の1ファイルを使います。

WSL起動確認を表示更新のたびに同期で呼ぶと、GUIが固まりうる

WSL側も探索する場合、「起動中のディストリビューションを確認する」処理(wsl -l --running相当)を表示更新関数の中でそのまま同期呼び出しすると、WSL起動中やサービスが重い時にHUD全体がタイムアウト秒数ぶんフリーズします。表示は10秒ごとに繰り返し呼ばれるため、この確認を毎回律儀に呼ぶのは負荷的にも無駄です。対策は、この確認結果を短いTTL(例: 30秒)でキャッシュし、古くなった時だけ別スレッドで非同期に更新することです。Claude・Codex双方の探索が同じ確認を使う場合は、共有のキャッシュ・更新処理に一本化します(独立に呼ぶと1回の表示更新でフリーズの機会が2倍になるため)。

外部コマンドのタイムアウトは、Windowsでは孫まで止めないと固まりうる

claude -p "/usage"を時間切れ付きで呼ぶとき、claudeがさらに別のプロセス(孫)を起動していると、通常の停止は直接の子(claude)しか止められず孫が生き残ります。Windowsでは出力を受け取る管(パイプ)がその孫が生きている限り閉じないため、出力を読み取る処理がそこで無期限に固まります。対策は、プロセスツリーごと強制終了(taskkill /F /T)してから読み直すことです。

「最新の記録」は素朴に選ぶと、サブエージェントや合成エラーを拾ってしまう

探索はprojects/<プロジェクト名>/<セッションID>.jsonlの1階層だけに留めてください。奥のサブフォルダまで探すと、サブエージェント(Taskツールなどが裏で動かす別セッション)の記録まで拾ってしまい、それが最新ファイルとして選ばれてctxの値が狂います。

また、Claude Codeは、レート制限や認証エラーが起きた時に、通常のやり取りとは別枠の「エラー通知用の記録」(isApiErrorMessage: trueが立ち、モデル名も実在しない"<synthetic>"、使用量はすべて0)を書き込むことがあります。これを普通の記録と同じに扱うと、レート制限に達した直後にこの記録が最新として拾われ、ctxの表示が0%に化けます。判定して読み飛ばす必要があります。

よかったらシェアしてね!
  • URLをコピーしました!
目次