🔥

週次リセットで消えるAIトークンを無駄にしない — token-burn を作った話

に公開1件

はじめに

Claude Code や Codex CLI を業務で使っていると、トークンの週次リセットが気になります。毎週決まった曜日にリセットされ、未使用分は繰り越されない。忙しい週は大量に余り、暇な週に限って足りなくなる。

「もったいない」

この感覚を解消するために、期日が近くなったタイミングでサブエージェントをゴリゴリ使ったりしていましたがなかなか手間なので、リセット直前の残りトークンを自動でコードレビューやバグ修正に回すCLIツール token-burn をRustで作りました。

TL;DR

  • リセット直前のAIトークンを自動消費するRust製CLIツールを作った
  • tmuxのペイン分割で複数リポジトリへのプロンプト実行を並列化
  • リセット時刻のデッドラインで全プロセスを自動終了

対象読者

  • Claude Code / Codex CLI を日常的に使っているエンジニア
  • AIアシスタントのトークン管理に課題を感じている方

環境

  • OS: macOS
  • tmux
  • gh CLI (GitHubの公開リポジトリを優先して処理したい場合のみ必要)

何を解決するか

Claude CodeとCodex CLIは、それぞれ異なる曜日・時刻にトークンがリセットされます。
人によってリセットされる日時が違うと思いますが私の場合以下のリセットスケジュールです。

  • Claude Code: 毎週木曜 20:00 (JST)
  • Codex CLI: 毎週火曜 12:00 (JST)

リセットされると未使用トークンは消滅します。手動で「何かやらせる」のは面倒だし、リセット時刻を覚えておくのも現実的ではありません。

token-burnは以下を自動化します。

  1. リセットが最も近いエージェントを自動選択
  2. 指定ディレクトリからGitリポジトリを探索
  3. 設定したプロンプトを各リポジトリに対して並列実行
  4. リセット時刻が来たら全プロセスを自動終了

以前記事にした depup と連携して

  • depup --age 2w --install で、ライブラリをリリースから2週間以上経過したバージョンにアップデート
  • アップデートしたバージョンにマイグレーションする

という感じにプロンプトに書いておけば週次で、自動でライブラリのメンテナンスをすることもできます。

https://zenn.dev/owayo/articles/ce0da822a296ca

インストール

Homebrewでインストールできます。

brew install owayo/token-burn/token-burn

ソースからビルドする場合は以下のとおりです。

git clone https://github.com/owayo/token-burn.git
cd token-burn
make install

主な仕様

1. tmuxによる並列実行

当初はtokioでプロセスを直接管理することを考えましたが、以下の理由からtmuxを採用しました。

  • リアルタイム監視: 各ワーカーの出力をペインで直接確認できる
  • 手動介入: 特定のペインだけCtrl-Cで停止できる
  • デタッチ: Ctrl-b d で端末を離れても実行が継続する

4つのワーカー(parallelism = 4)で動いている様子

各ワーカーは独立したbashスクリプトとして生成され、tmuxの個別ペインで実行されます。モニターペインは1秒間隔でマーカーファイルを監視し、プログレスバーとカウントダウンタイマーを表示します。

2. デッドライン制御

デッドライン到達時の停止は二段階です。

  1. ソフトストップ: stop マーカーファイルを作成 → 各ワーカーはタスク完了後に停止
  2. ハードキル: ユーザーがCtrl-Cを再度押すと tmux kill-session で即時終了

これにより、実行中のプロンプトが中途半端な状態でリポジトリに変更を残すリスクを最小化しています。

3. Claude Code必須フラグの自動付与

Claude Codeの出力をログに保存し、進捗モニタリングするには --verbose、--output-format stream-json、--include-partial-messages の3フラグが必須です。

codexはリアルタイムに進捗を出してくれるのですが、Claude Code側は -pオプションを付与した場合、--verbose、--output-format stream-json、--include-partial-messages でjsonlのログを出さないと途中の進捗がわかりません。
なので、これらのオプションを付与し、さらに次項のClaude Codeが出力するjsonlをパースして必要な情報をターミナルに出すという作業も必要になりました。

4. stream-json のリアルタイムパース

Claude Codeの stream-json 出力は1行1JSONで、思考過程・ツール呼び出し・テキスト出力がストリームで流れてきます。これをそのまま保存すると人間には読めないので、パイプで format-stream サブコマンドに通して可読形式に変換します。

claude "$(cat prompt.txt)" 2>&1 | tee raw.jsonl | token-burn format-stream 2>&1 | tee readable.log

変換では以下のイベントタイプを処理します。

イベント 表示
thinking 💭 に続いてドット
tool_use 🔧 ツール名 詳細情報
tool_result ✓ ツール名 or ✗ ツール名
result 💰 $X.XXXX / ⏱ Xm Xs (N turns) / 📊 in:X out:X

5. 公開リポジトリの優先処理

gh CLIで取得したリポジトリの可視性情報を使い、公開リポジトリを先に処理します。

理由は単純で、公開リポジトリのバグ修正やテスト追加のほうが、コミュニティへの貢献度が高いからです。トークンが途中で尽きた場合でも、優先度の高い成果が残ります。
このへんは設定ファイルで制御可能です。

6. ログの自動クリーンアップ

何の意図で修正等が行なわれたか後で追えるようにワーカーは実行ログを保存します。
実行ごとに YYYYMMDD_HHMMSS_<agent-name> 形式のディレクトリが生成されます。放置すると際限なく増えるため、デフォルト7日で自動削除する仕組みを入れました。
ディレクトリ名のタイムスタンプ部分をパースし、閾値より古ければ削除します。パース不能な名前(ユーザーが手動で作ったディレクトリなど)は安全のためスキップします。

設定例

[settings]
parallelism = 4 # 並列数
skip_within = "1d" # 対象のディレクトリがこの期間以内に処理済みならスキップ
cleanup_after = "7d" # この期間より古いレポートディレクトリを自動削除

[prompts]
default = "prompts/default.md" # agentにわたすプロンプト内容が書かれたファイルへのパス

[[agents]]
name = "claude"
command = ["claude", "-p", "--dangerously-skip-permissions", "--model", "opus"]
reset_weekday = "monday"
reset_time = "09:00"
timezone = "Asia/Tokyo"

[[agents]]
name = "codex"
command = ["codex", "exec", "--sandbox", "danger-full-access", "-c", "model='gpt-5.3-codex'", "-c", "model_reasoning_effort='xhigh'"]
reset_weekday = "thursday"
reset_time = "09:00"
timezone = "Asia/Tokyo"

[[scan]]
base_dirs = ["~/GitHub"]
recursive = true # ネストされたサブディレクトリも再帰的に探索
username = "your-github-username"
public_first = true # 公開リポジトリを優先するか
exclude = ["archived-project"]

[[targets]]
directory = "~/git/hoge-hoge"
prompt = "prompts/fix-coverage.md"

トークンを使い尽くすのが目的なので、model_reasoning_effort='xhigh' にしたりしてます。

プロンプトの例(prompts/default.md)
このプロジェクトのコードベース全体を徹底的にレビューしてください。

## 方針

**確実なバグのみ修正する。** 推測や好みに基づく変更は行わない。

## レビュー観点

以下のすべての観点から、時間をかけて深く分析してください:

### 正確性・ロジック
- オフバイワンエラー、境界条件の見落とし
- 型の不整合、暗黙の型変換による意図しない挙動
- 競合状態、デッドロックの可能性
- nil/null/undefined の未処理パス

### セキュリティ
- インジェクション(SQL, コマンド, XSS)
- 認証・認可のバイパス可能性
- 機密情報の露出(ログ、エラーメッセージ)
- 安全でないデシリアライズ

### エラーハンドリング
- 握りつぶされている例外・エラー
- パニック/クラッシュを引き起こすパス
- リソースリーク(ファイル、コネクション、メモリ)

### パフォーマンス
- O(n²) 以上の計算量で改善可能なもの
- N+1 クエリ
- 不要なメモリアロケーション

### テストカバレッジ
- テストが存在しない重要なロジック・関数を特定する
- 境界値、異常系、エッジケースのテストが不足している箇所
- 不足しているテストケースを実際に追加する

## 出力ルール

1. 問題を発見したら、なぜそれがバグと断言できるのか根拠を示す
2. 再現条件または発生シナリオを具体的に説明する
3. 修正コードを提示する
4. 「おそらく」「かもしれない」レベルのものは修正せず、指摘のみに留める
5. スタイルの好みやリファクタリング提案は行わない

## ライブラリアップデート

`depup` コマンドで依存パッケージを最新化し、破壊的変更に対応する。

**手順:**

1. `depup --install` をプロジェクトルートで実行
2. プロジェクトルートに、 `biome.json` があれば `biome migrate` も実行
3. depup の出力を確認し、メジャーバージョンアップがあるか判定
4. メジャーバージョンアップがある場合:
   - 該当ライブラリのマイグレーションガイドを Context7 で検索
   - 破壊的変更に該当するコードを Grep で特定
   - コードを修正
5. Lint/Format/ビルド/コンパイル確認
   プロジェクト内のコードに対して、検出された言語に応じたlint、format、test、buildを実行する
6. 既存テストの実行で動作確認

## ドキュメント更新

バグ修正・テスト追加の完了後、変更内容を反映してドキュメントを更新する。
ドキュメントに抜け・漏れ・誤りがあれば修正する。

対象ファイル:
- `AGENTS.md` または `CLAUDE.md` — 一方が他方へのシンボリックリンクの場合、実体ファイル(リンク先)のみを編集する。両方は編集しない。
- `README.md` およびその他の README(例: `README.ja.md`)

使い方

# 設定ファイルの作成
token-burn init

# ドライランで実行計画を確認
token-burn run -n

# 実行
token-burn run

token-burn run を引数なしで実行すると、リセットが最も近いエージェントが自動選択されます。--agent claude で明示的に指定することも可能です。

まとめ

token-burnは「もったいない」を動機に作った小さなツールですが、実装してみるとプロセス管理、タイムゾーン計算、シェルスクリプト生成、ストリーム処理など、意外と多くの要素が絡むツールになりました。

AIコーディングアシスタントのトークンを無駄にしたくない方、リセット前に何か有効活用したいと考えている方の参考になれば幸いです。

https://github.com/owayo/token-burn

Discussion

いしはるいしはる

勿体無い精神が消費の節約ではなく増長になってしまうディストピアを見た気分です。。