零弐壱蜂

[RTK] rg を叩いたら grep が動いていたときの対処方法

背景

Claude Codeで調査や修正をしていると、bashツールから rg が使われる場面は多い。rgripgrepのコマンドであり、高速で、.gitignore を尊重し、検索結果をそのまま次の判断に使いやすい。

RTK(Rust Token Killer)を入れ、Claude CodeのPreToolUseフックでシェル出力を短くしていた。しかし、ripgrepではなくgrepを使っているような挙動が見られた。

実行環境

  • macOS
  • Claude Code
  • RTK 0.38.0
  • ripgrep 15.1.0

RTKの役割

RTK(Rust Token Killer)は、LLMエージェントに渡るシェル出力を事前にフィルタ・要約するCLIプロキシである。rtk git statusrtk 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