背景
Claude Codeで調査や修正をしていると、bashツールから rg が使われる場面は多い。rg はripgrepのコマンドであり、高速で、.gitignore を尊重し、検索結果をそのまま次の判断に使いやすい。
RTK(Rust Token Killer)を入れ、Claude CodeのPreToolUseフックでシェル出力を短くしていた。しかし、ripgrepではなくgrepを使っているような挙動が見られた。
Claude Codeで調査や修正をしていると、bashツールから rg が使われる場面は多い。rg はripgrepのコマンドであり、高速で、.gitignore を尊重し、検索結果をそのまま次の判断に使いやすい。
RTK(Rust Token Killer)を入れ、Claude CodeのPreToolUseフックでシェル出力を短くしていた。しかし、ripgrepではなくgrepを使っているような挙動が見られた。
RTK(Rust Token Killer)は、LLMエージェントに渡るシェル出力を事前にフィルタ・要約するCLIプロキシである。rtk git status や rtk grep のように、既存コマンドの出力を短くするサブコマンドを持つ。
Claude CodeのPreToolUseフックに rtk hook claude を入れると、bashツールの実行前にコマンド文字列を検査し、対象コマンドをRTK版へ書き換えられる。今回問題になったのは、素の rg ... が rtk grep ... に変換された点である。
rtk grep は検索結果をファイル単位にまとめ、空白を削り、結果数を上限で切り詰める検索用サブコマンドである。人間がざっと読むには便利だが、素のripgrepと同じ出力・同じ検索範囲を期待すると差が出る。
RTK設定で rg を除外する前は、rg --version を実行するとripgrepではなくgrepのバージョン文字列が返っていた。
$ rg --version
grep (BSD grep, GNU compatible) 2.6.0-FreeBSD一方で、シェル上の解決先はripgrepだった。
$ type -a rg
rg is /opt/homebrew/bin/rgフルパス指定やRTKのフィルタなし実行では、素のripgrepが実行された。
$ /opt/homebrew/bin/rg --version # フルパス
ripgrep 15.1.0
$ rtk proxy rg --version # RTK のフィルタなし実行
ripgrep 15.1.0最後にRTKの事前確認コマンドで、当時の書き換え結果を見る。
$ rtk rewrite rg foo src
rtk grep foo src
$ rtk hook check rg foo src
rtk grep foo src原因はシェルのalias/function/PATHではなく、Claude CodeのPreToolUseで動く rtk hook claude による書き換えである。
通常のシェル解決であれば、type -a rg で見える /opt/homebrew/bin/rg が実行される。しかしClaude Codeのbashツールでは、シェルに渡すコマンドの前段でPreToolUseフックが動く。このフックが rg ... を rtk grep ... に変換していた。
そのため、シェル上ではripgrepに見えていても、実行時にはRTKの検索用サブコマンドが動く。type -a の結果と実行実体が食い違った理由はここにある。
rtk grep は素のripgrepではない。ripgrep互換の引数を一部受け付けるが、出力はRTK向けに整形・短縮される。
影響は以下の通りである。
--json や --files-with-matches のような機械処理向け出力を期待しても、素のripgrepと同じ形式にはならない。.gitignore で無視されるファイルまで検索対象に入る場合がある。grep_max_results=200 / grep_max_per_file=25 の上限で、検索結果が切り詰められる。問題は、明確なエラーにならず「それらしい結果」が返ることである。検索漏れや検索範囲の差に気付かないまま判断してしまう。
その場で素のripgrepを使うなら、フルパス指定かRTKのフィルタなし実行を使う。
/opt/homebrew/bin/rg <args> # フルパス指定で書き換え回避
rtk proxy rg <args> # RTK のフィルタなし実行
rtk run 'rg <args>' # sh -c で実行、フィルタも追跡もなし恒久対応は、RTK設定で rg を書き換え対象から外すことである。
# ~/Library/Application Support/rtk/config.toml
[hooks]
exclude_commands = ["rg"]設定後は、RTKのhook checkと rg --version で確認する。
$ rtk hook check rg foo
No rewrite for: rg foo
exit=1
$ rg --version
ripgrep 15.1.0