問題:AI エージェントはまず「全部」読もうとする
Claude Code や Cursor など AI コーディングツールを使って日常的にコードを書いている開発者にとって、大きなコードベースを調査させたときのトークン消費は無視できない問題です。Read を繰り返し、grep を広く打ち、関係するかどうか分からないファイルを次々と読み込む——これは「地図なしに現地を歩き回る」状態です。
bonsai はこの問題を一段手前で解決するツールです。コードベースのシグネチャ・doc・行番号だけを抽出し、LLM が「次に何を読むか」を決めるための地図を生成します。
仕組み:骨格だけを取り出す
bonsai の処理は一本道です。tree-sitter による AST 解析でシンボルを正確に拾い、PageRank で「他から多く参照される重要なシンボル」を上位に浮かせます。--max-tokens で予算を指定すれば、その範囲に収まるように自動的に取捨選択されます。
対応言語は Rust / Python / TypeScript / JavaScript / Go の 5 言語が tree-sitter ベースで精度高く動作します。PHP は tree-sitter の ABI 不整合(v15 vs v14)のため正規表現ベースの実装になっており、一般的なパターンはカバーしますが完全ではありません。Java / C# / Ruby 等は現時点で未対応です。
インストールと基本的な使い方
現時点での入手方法はソースからのビルドです。リポジトリをクローンしてから以下を実行します。
cargo install --path crates/cli
インストール後は bonsai コマンドをそのまま使えます。
# カレントディレクトリ全体の地図(Markdown 出力)
bonsai
# 言語指定 + トークン予算つき
bonsai src --lang rust --max-tokens 4000
# 重要箇所を先頭に寄せる(重みのシードを明示)
bonsai . --max-tokens 4000 --focus Engine --focus 'src/parser/*'
# JSON 出力(エージェント組み込み向け)
bonsai src --lang rust --format json -o map.json
bonsai.toml をリポジトリに置けば focus = [...] や show_body = N を設定として固定できます。CI への組み込みにも適しています。
トークン効率の実測値
実際に計測した差は無視できません。Python 123 ファイルのコードベースで比較しました。
| アプローチ | 対象 | 推定トークン |
|---|---|---|
| bonsai(骨格のみ) | 123 ファイルの骨格 | 約 7,000 |
| Read/grep(通常) | 約 40 ファイル(全文+部分) | 約 30,000〜35,000 |
骨格 123 ファイルと全文 40 ファイルを比べて 4〜5 倍のトークン差 があります。地図があれば「どの 40 ファイルを読むか」をあらかじめ絞れるため、調査の総コストはさらに下がります。
5 工程で使い分ける調査フロー
bonsai は「一発で答えを出す」ツールではありません。調査を段階的に深めるための起点です。
| 工程 | 目的 | コマンド |
|---|---|---|
| 1. 概要把握 | 全体像を安く掴む | bonsai . --max-tokens 4000 |
| 2. 影響範囲調査 | 変更対象の波及先を確認 | bonsai . --dependents Engine --dep-depth 1(デフォルトは 2 ホップ) |
| 3. 詳細調査 | 特定シンボルの本体を展開 | bonsai . --zoom Engine |
| 4. テスト確認 | 関連テストを把握 | bonsai tests/ --zoom Engine --include-private |
| 5. レビュー | コード差分を確認 | /code-review(別ツール) |
# 工程1 → 工程2 → 工程3 の典型的な流れ
bonsai src --lang rust --max-tokens 4000
bonsai src --lang rust --dependents FileMap --dep-depth 1
bonsai src --lang rust --zoom apply_token_budget
1 段目で「何がいるか」を把握し、2 段目で「どこに影響するか」を確認し、3 段目で「中身はどうか」を見る。その後、必要なファイルだけを Read で完全に読む——この流れが基本です。
--show-body N を使えば各シンボルの本体先頭 N 行だけを付加することもでき、骨格と完全展開の中間の粒度を選べます。--zoom はデフォルトで def/ref グラフ上の 1-hop 隣接ファイルも本体展開します。パスで指定したときに展開が広がりすぎる場合は --zoom-depth 0 で展開なしにできます。
影響範囲調査:--dependents の使い方
変更前に「何が壊れる可能性があるか」を把握できます。
# BayesianRiskModel を変更したとき、直接の呼び出し元を確認
bonsai api --lang python --dependents BayesianRiskModel --dep-depth 1
# 全推移閉包(dep-depth 0 = 無制限)
bonsai api --lang python --dependents BayesianRiskModel --dep-depth 0
--dep-depth のデフォルトは 2 ホップ(seed の直接の呼び出し元とその呼び出し元)です。広い範囲が必要なときは省略し、まず絞りたいときは --dep-depth 1 から試すのが実用的です。
ただし、注意点があります。FileMap のような中核型に --dependents をかけると 29 ファイル中 24 ファイルがヒットするケースがありました。ほぼ全ファイルが依存する型には ref グラフが機能しません。対策は、中核型より「具体的な関数」を seed にすること(apply_token_budget → 3 ファイルに絞れた)です。
構築サイトを探したいときは grep "ClassName {" src -r と組み合わせるのが確実です。bonsai は「型が使われているファイル群」は特定できますが、「どの行で構築しているか」は grep の方が直接的です。
aider repo-map との違い:決定性
同種のツールとして aider repo-map があります。aider repo-map は会話の中で言及された識別子を重み付けに使うため、会話の文脈によって出力が変わります。
bonsai は会話非依存・決定的です。同じコードベース・同じコマンドは常に同じ地図を返します。コードが変わらなければ地図も変わらないため、チームでの共有や CI への組み込みに向いています。重みのシードは --focus <pattern> で明示します。
| ツール | 重み付けの根拠 |
|---|---|
| repomix / code2prompt | なし(全文連結) |
| ctags | なし(位置インデックスのみ) |
| aider repo-map | 会話で言及した識別子 |
| bonsai | 静的解析のみ・決定的。シードは --focus で明示 |
限界:地図は目的地ではない
bonsai の地図には意図的に含まれないものがあります。
引数の型・デフォルト値の詳細、条件分岐・リトライ・エラーハンドリングのロジック、具体的なプロバイダ設定の切り替え条件——これらは骨格から読み取れません。Edit を書くための正確な行内容は最終的に Read が必要です。
--include-private なしでは private 関数が --zoom のパターンマッチ対象外になります。#[test] 付き関数はデフォルトでも骨格に出ますが、他の private シンボルを対象にしたいときは明示的に --include-private を付けてください。
「骨格を読めば実装を理解できる」という期待は誤りです。bonsai は「どこを読むか」を決める前段のコストを下げるツールであり、Read の代替ではありません。
まとめ
bonsai が提供するコアバリューは 2 つです。
トークン効率化——全文読み込みと比べて 4〜5 倍のトークンを削減できる実測値があります。123 ファイルの骨格が 7,000 トークンで収まるため、「全部読む」前に「何を読むか」を安く決められます。
決定性——会話に依存しない静的解析です。同じコードベース・同じコマンドは常に同じ地図を返します。コードが変わらなければ地図も変わらず、チーム共有・CI 組み込みに向きます。
この 2 つが組み合わさることで、AI エージェントが大規模コードベースを扱うときの「最初の数千トークン」をどこに使うかという問いへの実践的な答えになっています。骨格は地図であり、地図は目的地ではない。bonsai はその「地図」を低コストで、かつ毎回同じ精度で提供するツールです。