Claude Code fileSuggestionで@補完を自前コマンドに置き換える
settings.jsonのfileSuggestionで、@のファイル候補を自前コマンドの出力に差し替える手順です。入出力の形、5秒と15件の制限、設定が黙って無視されるゲート条件をまとめます。
fileSuggestion は、プロンプトで @ に続けてパスを打ったときの候補を、自前のコマンドで作らせるsettings.jsonのキーです。数十万ファイルを抱えるモノレポで、組み込みの探索より事前に作った索引のほうが速いときに向きます。
ただし、書いただけでは動かない場面があります。信頼していないフォルダや、allowManagedHooksOnly を使う組織では、設定が警告なしに読み飛ばされます。この記事は、設定の書き方、コマンドの入出力、手元での動作確認、効かないときの切り分けを順に扱います。
fileSuggestionは何を置き換える設定か
fileSuggestion が置き換えるのは、@ を打ったときのファイルパス候補を作る部分です。組み込みの候補は高速なファイルシステム走査で作られます。大きなモノレポでは、プロジェクト固有の索引(あらかじめ作ったファイル一覧など)のほうが合う場合がある、というのが設定の位置づけです。
| 項目 | 内容 |
|---|---|
| 型 | 内容type と command を持つオブジェクト。type は常に "command" |
| 既定 | 内容未設定。組み込みの候補を使う |
| 書ける場所 | 内容任意の設定ファイル |
| 補足 | 内容後述のゲート条件によっては、無効になるか、管理設定の値だけが走る |
@ 自体の挙動(パスの補完を起動するキー)は、対話モードのショートカット表に載っています。fileSuggestion はその候補の出どころだけを差し替えます。
設定の書き方と、コマンドが受け取るもの
最小の設定は次の形です。
{
"fileSuggestion": {
"type": "command",
"command": "~/.claude/file-suggestion.sh"
}
}保存したら、プロンプトで @ とパスの一部を打ちます。候補はこのコマンドの出力から出ます。
コマンドの入出力は次の取り決めです。
コマンドの入出力の取り決め
入力
標準入力にJSONが1つ渡ります。
queryフィールドに、それまでに打った文字列が入ります。出力
標準出力に、改行区切りでファイルパスを出します。表示されるのは最大15件です。
時間
Claude Codeは5秒を超えると待つのをやめます。
環境変数
hookと同じ環境変数で実行されます。
CLAUDE_PROJECT_DIRも含まれます。
入力の例は {"query": "src/comp"} のような1行です。これに対して、次のようなパスを返します。
src/components/Button.tsx
src/components/Modal.tsx
src/components/Form.tsx15件を超えて出力しても、画面に出るのは15件までです。候補の並び順は、コマンド側で上位15件に絞ってから返すと制御できます。
手元で動くスクリプトを作って確かめる
最初の一本は、Gitの追跡ファイルから部分一致で絞る形が手軽です。jq が入っている前提で、~/.claude/file-suggestion.sh を作ります。
#!/bin/bash
query=$(cat | jq -r '.query')
cd "$CLAUDE_PROJECT_DIR" || exit 0
git ls-files | grep -i -F -- "$query" | head -15実行権限を付け、Claude Codeを通さずにコマンド単体で試せます。標準入力にJSONを流し込み、CLAUDE_PROJECT_DIR は自分で与えます。
chmod +x ~/.claude/file-suggestion.sh
echo '{"query": "src/comp"}' \
| CLAUDE_PROJECT_DIR="$PWD" ~/.claude/file-suggestion.shsrc/components/Button.tsx と src/components/Modal.tsx、README.md だけを追跡した小さなリポジトリで試すと、src/comp に対しては前の2つが、readme に対しては README.md が返りました。大文字小文字を区別しない grep -i を使っているためです。
この形は、あくまで動作確認用の最小例です。grep -F は連続した部分文字列にしか一致しないので、btn で Button.tsx を引くようなあいまい検索はできません。あいまい検索が欲しければ、fzf --filter のような絞り込みコマンドに差し替える手があります。コマンドが標準入力のJSONを読み、標準出力に改行区切りのパスを返す限り、中身は自由です。
事前に作った索引を読む形
「大規模モノレポ向けの事前索引」を実現するには、重い走査を @ のたびに走らせない構成にします。たとえばコミットやチェックアウトの後に、ファイル一覧を1つのテキストへ書き出しておき、候補コマンドはそれを読むだけにします。
#!/bin/bash
# 一覧は別途、git ls-files > .cache/files.txt などで更新しておく
query=$(cat | jq -r '.query')
grep -i -F -- "$query" "$CLAUDE_PROJECT_DIR/.cache/files.txt" | head -15索引の更新はClaude Codeの外の仕事です。一覧が古いと、消えたファイルが候補に出続け、増えたファイルは出ません。更新のきっかけをGitフックやビルドタスクのどこに置くかは、リポジトリごとに決めることになります。
5秒の制限が設計を決める
待ち時間の上限は5秒です。この数字は、スクリプトの作り方に直接効きます。
@で1文字打つたびにコマンドが走る前提で、起動から出力までを短く保つ- 全ファイルの走査や、ネットワーク越しの問い合わせは避ける
- 索引が使えないときは、空出力で終わらせるか、遅くても動く代替に落とす
5秒を超えたときの画面の見え方(候補が空になるのか、組み込みの候補に戻るのか)は、設定リファレンスに記載がありません。確かめたいときは、sleep 6 を入れた試験用スクリプトで、自分の環境の挙動を見るのが確実です。
fileSuggestionの経緯: 追加から候補埋もれの修正まで
設定の挙動が今の形になるまでに、版をまたいで3回の変更がありました。古い版を使い続けている環境では、ここで挙動が変わります。
v2.1.51より前の版では、信頼していないフォルダでもコマンドが走り得ました。今の「信頼していないフォルダでは止まる」という挙動は、この修正が土台です。v2.1.275より前の版では、コマンドが正しく候補を返していてもMCPサーバーを接続していると、ファイル候補が一覧の下のほうに押しやられ、見えないことがあります。
設定したのに効かないとき: ゲートの条件
fileSuggestion は、statusLine、subagentStatusLine と同じゲートに従います。ゲートは2段階で、先に「全体を止める」条件、次に「管理設定の値だけにする」条件が判定されます。
| 段階 | 条件 | fileSuggestion の結果 |
|---|---|---|
| 全体を止める | 条件管理設定が disableAllHooks を立てている | fileSuggestion の結果コマンドは走らない |
| 全体を止める | 条件フォルダが、設定ファイルのhookと同じワークスペース信頼の規則を満たさない | fileSuggestion の結果コマンドは走らない |
| 管理設定だけにする | 条件allowManagedHooksOnly が設定されている | fileSuggestion の結果管理設定の値があればそれを実行。なければ自分の値は黙って無視される |
| 管理設定だけにする | 条件管理設定以外で disableAllHooks が true になる | fileSuggestion の結果同上 |
| 管理設定だけにする | 条件--safe-mode で起動した | fileSuggestion の結果同上 |
「管理設定だけにする」場合に自分の値が無視されると、@ 候補は組み込みの候補に戻ります。エラーも警告も出ません。設定ファイルは残ったままなので、設定したはずの候補が急に変わったときは、まずここを疑います。
--safe-mode の側も、同じことを別の言い方で書いています。カスタマイズをすべて読まない起動で、ステータスラインとファイル候補のコマンドも読み込まれません。ただし管理設定のポリシーは適用されたままで、ポリシーで設定されたステータスラインとファイル候補のコマンドは、安全モードでも動きます。
切り分けの順番
効かないときは、次の順に見ると無駄がありません。
fileSuggestionが効かないときの切り分け
- 1
フォルダを信頼しているか
信頼していないフォルダでは、設定ファイルのhookと同じ規則で止まります。対話セッションで信頼ダイアログを承認済みかを確かめます。
- 2
disableAllHooksが立っていないか
どの設定ファイルにも
trueが入っていないかを見ます。管理設定側にあれば全体が止まり、それ以外の場所にあれば管理設定の値だけが残ります。 - 3
allowManagedHooksOnlyを使う組織か
組織の管理設定にこのキーがあるなら、自分の
fileSuggestionは読まれません。管理者がfileSuggestionを配っているかを確認します。 - 4
Claude Codeの版が古くないか
候補を返しているのに画面で見つからないときは、版を確かめます。v2.1.275より前では、候補がMCPリソースの下に埋もれることがあります。
@.や@./と打った場合にも同じ現象が起きていました。 - 5
コマンド単体で動くか
先ほどのように、標準入力にJSONを流してコマンドだけを実行します。ここで出力が出なければ、スクリプト側の問題です。
管理設定側のキーの意味と、ユーザー側の値が黙って効かなくなる様子は、allowManagedHooksOnlyの解説で詳しく扱っています。プラグインやスキルの読み込み元を絞る設定との関係は、strictPluginOnlyCustomizationの記事にあります。
組織で配るなら管理設定に書く
ゲートの表から、組織向けの運用方針が決まります。allowManagedHooksOnly を使う環境では、ユーザーが自分で書いた fileSuggestion は動きません。社内の索引つき候補コマンドを全員に使わせたいなら、管理設定に fileSuggestion を載せて配ります。配らなければ、ユーザーの @ 候補は静かに組み込みへ戻ります。
もう一点あります。管理設定に入れたコマンドは、--safe-mode でも動きます。トラブルシュートのために安全モードで起動しても、組織が配った候補コマンドが原因の不具合は再現し続けます。切り分けの手順書には、このことを書いておくと迷いません。
使うかどうかの目安
自前コマンドに置き換える価値が出るのは、限られた状況です。
| 状況 | 向き不向き |
|---|---|
数十万ファイル規模のモノレポで、@ の候補が遅い | 向き不向き向いている。索引つきの候補が効く |
| 生成物やベンダーディレクトリの除外ルールが独特 | 向き不向き向いている。除外をコマンド側で完全に制御できる |
社内の別システムの資産(設計書の置き場など)も @ に出したい | 向き不向き条件次第。5秒以内に返せるかが前提 |
| 普通の規模のリポジトリで、候補に不満がない | 向き不向きほぼ不要。組み込みで足りる |
| gitignore対象を候補に含める・外すだけをしたい | 向き不向き別の設定で足りる |
最後の行は、respectGitignore の守備範囲です。こちらは @ ピッカーの設定で、respectGitignoreの記事がGrepやGlobとの違いまで含めて整理しています。自前コマンドを使ったときに respectGitignore が候補へどう作用するかは、設定リファレンスに記載がありません。除外の判断は、コマンド側に持たせると考えておけば迷いません。
付随して知っておきたい周辺の設定
disableAllHooks は、hook、カスタムのステータスライン、カスタムのファイル候補コマンドをまとめて止めるキーです。一時的に全部切って原因を探したいときに使います。値が true なら3つとも止まり、false なら動きます。ただし管理設定以外の場所に書くと、管理設定の値だけが残る動きになります。管理設定に書くと、管理設定のhookまで止まります。
設定項目の全体像や、設定ファイルの優先順位は、Claude Codeの設定ガイドにまとめてあります。fileSuggestion のほかのキーとの位置関係を見たいときは、そちらの一覧が役に立ちます。
まとめ
fileSuggestion は、@ 候補を自前の索引に載せ替えられる設定です。標準入力の query を読み、改行区切りのパスを最大15件、5秒以内に返せば成立します。難所はコマンドの中身より、ゲートにあります。信頼、disableAllHooks、allowManagedHooksOnly、--safe-mode のどれかに当たると、自分の値は黙って読み飛ばされます。組織全体に効かせたいなら、管理設定に書いて配る構成が前提になります。