はじめに
リポジトリ全体を 1 ファイルにまとめて LLM に渡す「詰め込み系 CLI」は、いまや AI コーディングの標準装備です。対象読者は、コードベースを丸ごと LLM のコンテキストに載せたい開発者、または CI でリポジトリのスナップショットを LLM に食わせる仕組みを作っている人です。
同じリポジトリを同じ条件で詰めるのだから、出てくるトークン数はどのツールでも似たようなものだろう、と考えていました。実際に 4 種類を走らせたところ、最少 167,232 トークンに対して最多 728,914 トークン、4.4 倍の差 が出ました。しかも、その差を生んでいたのは圧縮アルゴリズムの優劣ではなく、たった 1 ファイルを拾うか捨てるか という既定の除外挙動の違いでした。
さらに条件を揃えて測り直すと順位が入れ替わり、今度は「一番トークンが少ないツール」が 本体のテストコードを黙って落としていた ことが分かりました。以下、実測値で追っていきます。
実測結果一覧(リポジトリそのまま)
評価軸は測定前に「実行時間・出力バイト数・トークン数・収録ファイル数」の 4 つに固定しました。トークン数はツール自己申告ではなく、全ツールの出力を tiktoken の o200k_base で統一計測しています。
| ツール | 実行時間(中央値) | 出力バイト | トークン数 | 最少比 |
|---|---|---|---|---|
ai-digest 1.5.1
|
0.60 秒 | 657,438 | 167,232 | 1.00 |
gitingest 0.3.1
|
1.17 秒 | 684,668 | 170,834 | 1.02 |
repomix 1.17.0 --compress
|
0.84 秒 | 1,255,906 | 665,019 | 3.98 |
repomix 1.17.0
|
0.63 秒 | 1,373,182 | 688,856 | 4.12 |
files-to-prompt 0.6
|
0.07 秒 | 1,533,063 | 728,914 | 4.36 |
測定条件は次のとおりです。
- コーパス: psf/requests をコミット
414f0513c33883adf6f2b46901d4f0b38a455851(2026-07-27)で--depth 1クローンしたもの。.gitを除いて 128 ファイル、合計 4,451,533 バイト - 実行環境: Node.js
v22.22.2/ Python3.11.15 - 各ツール 3 回実行し、中央値を採用
- 出力形式は Markdown 系に揃えた(repomix は
--style markdown)
--compress を付けた repomix が付けない repomix とほぼ同じトークン数(665,019 対 688,856、わずか 3.5% 減)に留まっている点が、最初の違和感でした。公式ドキュメントの Code Compression は「関数シグネチャや型定義を残して実装を削る」と説明していますが(公式では実験的機能と明記されています)、この結果では効いているように見えません。
4.4 倍差の犯人は 883KB の SVG 1 ファイル
出力のバイト数をトークン数で割ると、原因の当たりが付きます。
| ツール | バイト/トークン |
|---|---|
| ai-digest | 3.93 |
| gitingest | 4.01 |
| repomix | 1.99 |
| files-to-prompt | 2.10 |
日本語を含まない英語ソースコードなら、おおむね 3.5〜4.0 バイト/トークンに落ち着きます。repomix と files-to-prompt だけが 2 前後まで下がっているのは、自然言語でもコードでもない何か を大量に飲み込んでいるサインです。
コーパス内のファイルをサイズ順に並べると、すぐに見つかりました。
$ find . -type f -not -path './.git/*' -printf '%s %p\n' | sort -rn | head -5
2189478 ./ext/requests-logo.ai
883794 ./ext/requests-logo.svg
306086 ./docs/_static/requests-sidebar.png
192073 ./ext/requests-logo.png
192073 ./ext/requests-logo-compressed.png
ext/requests-logo.svg はロゴの SVG で、中身は改行のない巨大なパスデータです。これ単体を tiktoken にかけると 563,459 トークン でした。出力に SVG のパスデータ(<path や sodipodi)が含まれているかを調べると、切り分けが完了します。
| ツール | SVG 本文の収録 |
|---|---|
| repomix | あり |
| files-to-prompt | あり |
| ai-digest | なし |
| gitingest | なし |
repomix と files-to-prompt は SVG を「テキストファイル」として素直に本文へ取り込み、ai-digest と gitingest は既定で落とします。この 1 ファイルだけで、4.4 倍差のほぼ全部が説明できてしまいました。
条件を揃えたら順位が入れ替わった
「アセット類は自分で除外するのが前提」という運用は現実的なので、ext/ ディレクトリを削って 121 ファイルにし、同じ測定をやり直しました。
| ツール | 実行時間(中央値) | 出力バイト | トークン数 | 収録ファイル数 |
|---|---|---|---|---|
repomix --compress
|
0.75 秒 | 371,779 | 101,445 | 113 |
| repomix | 0.61 秒 | 489,055 | 125,282 | 113 |
| files-to-prompt | 0.08 秒 | 649,056 | 165,444 | 94 |
| ai-digest | 0.67 秒 | 657,049 | 167,123 | 119 |
| gitingest | 1.09 秒 | 684,274 | 170,774 | 118 |
順位が完全にひっくり返りました。さきほど最下位だった repomix が最少で、--compress の効果もこちらでは 125,282 → 101,445 トークン(19.0% 減) とはっきり出ています。1 回目の測定で圧縮が効いていないように見えたのは、削減対象にならない SVG のパスデータが分母を膨らませていたからでした。
ただし収録ファイル数の列を見ると、repomix だけが 121 ファイル中 113 ファイルしか出力していません。
トークン数が少ない理由は「黙って捨てていた」から
repomix を冗長出力で走らせると、標準出力に理由が書かれていました。
🔎 Security Check:
──────────────────
3 suspicious file(s) detected and excluded from the output:
1. docs/user/advanced.rst
- 2 security issues detected
2. tests/test_requests.py
- 1 security issue detected
3. tests/test_utils.py
- 5 security issues detected
These files have been excluded from the output for security reasons.
除外されていたのは、requests の 本体テストコード 2 本(tests/test_requests.py は 108KB でリポジトリ最大のソースファイル)と、ユーザーガイドの中核ドキュメント(docs/user/advanced.rst、41KB)です。認証まわりのサンプルに含まれるダミーのユーザー名・パスワードが「機微情報らしきもの」として引っかかったものと見られます。
このチェックは --no-security-check で無効化できます。実際に外して測り直しました。
| 実行モード | 収録ファイル数 | トークン数 |
|---|---|---|
| repomix(既定・セキュリティチェック有効) | 113 | 125,269 |
repomix --no-security-check
|
116 | 168,524 |
同じリポジトリ・同じツールで 34.5% の差 です。そして 168,524 トークンという値は、ai-digest の 167,123・files-to-prompt の 165,444 とほぼ横並びで、「repomix が圧倒的にトークン効率が良い」という 2 回目の結論も消えました。
つまり実測から言えるのは、次の 1 点に尽きます。
詰め込み系 CLI のトークン数を横並び比較しても、性能ではなく既定の除外設定を比べているだけになりがち。
なお --no-security-check でも 121 ファイル中 116 ファイルで、除外されていたのは PNG 1 件とテスト用の秘密鍵 4 件(tests/certs/**/*.key)でした。ai-digest は 119 ファイルを収録しており、この秘密鍵 4 件も本文に含めています。テスト用のダミー鍵とはいえ、実リポジトリで同じ挙動になると困る場面はありそうです。
ツールごとの既定挙動の違い
収録ファイルの差分を取ると、それぞれの設計思想がはっきり出ました。
| ツール | 121 ファイル中 | 落としていたもの |
|---|---|---|
| ai-digest | 119 | バイナリ画像のみ |
| gitingest | 118 | バイナリ画像ほか |
| repomix(既定) | 113 | 画像・秘密鍵・セキュリティ判定に触れた 3 ファイル |
| files-to-prompt | 94 | ドットで始まるパスすべて・画像 |
files-to-prompt の未収録 27 件は、.coveragerc や .pre-commit-config.yaml に加えて、.github/workflows/ 配下の 9 本すべて が含まれていました。CI の設定を LLM に読ませたいケースでは致命的なので、--include-hidden を明示する必要があります。Unix 哲学に沿った最小構成という性格そのままで、find や ripgrep と組み合わせて渡すファイルを自分で決める使い方が前提の設計です。
速度面では files-to-prompt が 0.08 秒と突出しており、最も遅い gitingest の 1.09 秒に対して 13.9 倍高速 でした。ファイルを読んで連結するだけの実装なので当然ではありますが、大きなリポジトリを繰り返し詰めるループを回すなら効いてくる差です。
実際に使うときの選び方
実測を踏まえて、次のように整理しました。
repomix を使う場合の実務的な注意は 1 つだけです。標準出力の Security Check の行を読み飛ばさないこと。今回のように「本体のテストコードが丸ごと落ちている」状態で LLM に質問すると、モデルは黙って不完全なコンテキストで答えます。落ちたこと自体はエラーではないので、CI に組み込むなら除外件数を検知して失敗させる仕組みが要ります。
repomix のセキュリティチェックは Secretlint ベースで、認証情報らしき文字列パターンに反応します。今回の 3 ファイルは、いずれも認証サンプルにダミーの資格情報が書かれている箇所を持っており、同系統の誤検知と考えられます。
実測して分かったこと
3 回測り直して結論が 3 回変わりました。
- 素で測ると files-to-prompt が最多で ai-digest の 4.4 倍
- アセットを除くと repomix が最少で、圧縮も 19.0% 効く
- セキュリティチェックを外すと repomix も他と横並び(+34.5%)
ベンチマークの数字そのものより、「同じ入力を与えたつもりでも、ツールごとに 実際に読まれているファイルが違う」という点が、実務では効いてきます。トークン数を見る前に収録ファイル数を数える、という順番にしてからは、LLM の回答が妙に的外れなときの原因切り分けが速くなりました。
比較の前提として、今回のコーパスは 121〜128 ファイル・約 4.5MB の Python リポジトリ 1 本です。TypeScript のモノレポや、node_modules を含むリポジトリでは各ツールの既定の .gitignore 解釈がさらに効いてくるはずで、そこは未検証です。
関連記事
- Codex Security CLIをSemgrepと比較、$1.28で所見0件だった
- mcp-cliに時刻取得を頼んだら、Geminiは無視しOpenAIは例外で落ちた
- OpenSRE の health、58連携中で未設定のAWSだけ failed だった