Antigravity CLI 1.1.13 のリリースノートに、埋め込みの ripgrep が実行できない環境では /codesearch がローカル検索へフォールバックする、という一行があります。
そこで手が止まりました。
フォールバックは黙って起きます。エラーは出ませんし、結果も返ってきます。つまり、落ちた先がどれくらい遅いのかを知らないまま使い続けられてしまう、ということです。
知らないままにしておきたくなかったので、運用中のリポジトリで検索経路そのものを並べて計測しました。あわせて、自分の環境がどちらの経路にいるかを確かめる手順もまとめています。
なお本記事で測ったのは Antigravity CLI の内部ではなく、フォールバックが行き来する検索エンジンそのものです。CLI の内部処理まで踏み込めていない点は、先にお伝えしておきます。
個人開発でアプリとサイトのリポジトリを行き来していると、検索が返るまでの数百ミリ秒は一日のうちに何十回も積み上がります。気づける形にしておきたい種類の差でした。
1.1.13 で ripgrep の置き場所が変わりました
一次情報として公開されている 1.1.13(2026年8月14日)の変更のうち、検索まわりは次の4点です。
| 変更 | 内容 |
|---|---|
| 展開先の移動 | 埋め込み ripgrep の展開先が /tmp からユーザーキャッシュディレクトリへ移動 |
| 整合性検証 | 展開したバイナリを SHA-256 で検証 |
| 競合の回避 | 同時実行時の衝突を避けるアトミックなリネーム |
/codesearch の耐障害性 | ripgrep が実行できない環境ではローカル検索へフォールバック |
展開先が /tmp から移った理由は、実際に運用していると想像がつきます。/tmp を noexec でマウントしている環境では、バイナリを置けても実行できません。共有マシンや検証用のコンテナでは珍しくない設定です。
実行できなくなる事情は、おおむね次の3つに分かれます。
/tmpやキャッシュ領域がnoexecでマウントされている- エンドポイントセキュリティ製品が、署名のないバイナリの実行を遮断している
- キャッシュディレクトリに書き込み権限がない
1 番目は 1.1.13 の変更で緩和されました。2 番目と 3 番目は、環境側を触らないかぎり残ります。
自分がどちらの経路にいるかは、終了コードに出ます
「実行できない」は、シェルの終了コード 126 として現れます。手元で再現できます。
cp "$(command -v rg)" "$HOME/rgtest"
chmod -x "$HOME/rgtest"
"$HOME/rgtest" --version
echo "exit=$?"手元の Linux では次のようになりました。
bash: /home/user/rgtest: Permission denied
exit=126
126 は「ファイルは見つかったが実行できなかった」を意味します。noexec マウントも、セキュリティ製品による遮断も、多くはここに現れます。ファイルが存在しない 127 とは区別できます。
ひとつ注意があります。判定に使うコマンドを head や tail にパイプしないでください。$? がパイプ後段の終了コードに置き換わり、126 が 0 に化けます。私はこの計測中に一度取り違えて、実行できているものと思い込みました。
環境を確かめるときに見る場所は3つです。
| 見るところ | コマンド | 期待する状態 |
|---|---|---|
/tmp のマウントオプション | findmnt -no OPTIONS /tmp | noexec が含まれていない |
| キャッシュ領域のマウントオプション | findmnt -no OPTIONS "${XDG_CACHE_HOME:-$HOME/.cache}" | 同上(1.1.13 以降はこちらが本命) |
| バイナリの実行可否 | 上の chmod テスト | 終了コードが 126 でない |
展開先の実体は環境によって異なります。キャッシュ領域から探すなら次のようにします。
find "${XDG_CACHE_HOME:-$HOME/.cache}" -type f -name 'rg*' 2>/dev/null同じリポジトリで、3つの検索経路を比べました
計測対象は、運用中の Next.js サイトのリポジトリです。.git を除いて 2,225 ファイル・49 MB、大半が MDX とテキストです。
比べたのは次の3つです。
ripgrep13.0.0(rg -n)- GNU grep(
grep -rn --exclude-dir=.git) - 素朴なローカル検索の代表として、Python で書いた逐次読み込み実装
3 番目はフォールバック先の実装そのものではありませんが、「特別な最適化を持たない実装」の目安として置いています。コードは次の通りです。
import os, re, sys, time
root, pat = sys.argv[1], sys.argv[2]
rx = re.compile(pat)
hits = 0
t0 = time.perf_counter()
for dirpath, dirnames, filenames in os.walk(root):
dirnames[:] = [d for d in dirnames if d != ".git"]
for fn in filenames:
path = os.path.join(dirpath, fn)
try:
with open(path, "r", encoding="utf-8", errors="ignore") as f:
for line in f:
if rx.search(line):
hits += 1
except (OSError, UnicodeError):
continue
print(f"{hits} hits {(time.perf_counter() - t0) * 1000:.0f} ms")os.walk で辿り、1 行ずつ正規表現に掛けるだけの実装です。除外は .git のみにしています。フォールバック側が持っていそうな最低限の条件に揃えるためです。
計測は同じクエリを5回ずつ流し、中央値を取りました。ページキャッシュが温まった状態での値です。
| 経路 | リテラル検索 | 正規表現検索 |
|---|---|---|
| ripgrep | 18 ms | 19 ms |
| grep -rn | 32 ms | 39 ms |
| Python 逐次読み込み | 277 ms | 281 ms |
この規模なら、いちばん遅い経路でも 0.3 秒です。体感としては「少し待つ」程度で、原因を疑うところまではいきません。
問題は規模が増えたときです。同じ内容を6部複製した 200 MB・12,654 ファイルの合成コーパスで測り直しました。複製である以上、内容の多様性は本物のモノレポと違います。あくまで規模の効き方を見るための数字として読んでください。
| 経路 | 49 MB / 2,225 ファイル | 200 MB / 12,654 ファイル | 倍率 |
|---|---|---|---|
| ripgrep | 18 ms | 56 ms | 3.1 倍 |
| grep -rn | 32 ms | 141 ms | 4.4 倍 |
| Python 逐次読み込み | 277 ms | 1,510 ms | 5.5 倍 |
対象が 4 倍になったとき、ripgrep は 3.1 倍で済んでいます。素朴な実装は 5.5 倍でした。ripgrep との比も 15 倍から 27 倍へ開いています。
つまり、小さなリポジトリで気づかなかった差は、node_modules を含む実プロジェクトの規模では気づく側に回ります。エージェントが1ターンに何度も検索を投げる使い方なら、なおさらです。
速さより先に効くのは、拾う範囲が変わることです
計測中に、速度より気になる差が出ました。走査対象のファイル数です。
rg --files . | wc -l # 2213
find . -path ./.git -prune -o -type f -print | wc -l # 222512 ファイルの差があります。中身を出すと .gitignore・.npmrc・各カテゴリの .gitkeep でした。ripgrep は既定で隠しファイルを走査しません。
今回のリポジトリでは、この 12 ファイルに検索語が含まれていなかったため、ヒット行数は3経路とも 9,714 行で一致しました。差は出ていません。
ただし条件が揃っていただけです。ripgrep は既定で .gitignore を尊重します。node_modules やビルド生成物を持つプロジェクトでは、フォールバック側がそれらを拾うかどうかで結果の量が変わります。フォールバック実装が同じ除外規則を持っている保証はありません。
速度の差は待てば済みます。拾う範囲の差は、エージェントに渡す文脈そのものを変えます。ビルド生成物の中の古いコードが検索に混ざれば、エージェントはそれを現在のコードとして読みます。私自身、重く見ているのはこちらのほうです。
実行できないと分かったときに、先に試すこと
順番をつけるなら、次のようになります。
- 終了コードが 126 かどうかを確定させる。ここを曖昧にしたまま設定を触り始めると、原因の切り分けが後戻りします
/tmpとキャッシュ領域のマウントオプションを両方見る。1.1.13 以降は展開先がキャッシュ側なので、/tmpだけ直しても変わりません- セキュリティ製品の例外申請を出すときは、展開されたバイナリが SHA-256 で検証されている点を添える。実行を許す根拠として、担当者が判断しやすくなります
- どうしても通らない環境では、フォールバックしたまま使う判断も現実的です。今回の実測なら
grep相当の経路で 2〜2.5 倍、素朴な実装で 15〜27 倍。前者なら許容できる場面は多いはずです - 検索の当たり方そのものを見直す。経路の速さより、クエリが何を拾っているかのほうが結果に効きます
5 番目については、/codesearch に渡す正規表現の既定を測り直した記事を別に書いています。検索経路を直せない環境ほど、1 回の検索で無駄なく取りにいく設計が効きます。関心があればエージェントに任せるコード検索を契約として書くもあわせてご覧ください。
サインインできない環境で 1.1.13 を動かす話はAntigravity CLI 1.1.13 の GEMINI_API_KEY 直接認証をサインイン不可の環境で使うにまとめています。制約の多い端末では、この2つは同時に効いてきます。
まずは手元の端末で chmod -x の再現を1回だけ流して、終了コードが 126 になる環境かどうかを見てください。それが分かれば、次に触る場所は自然に決まります。
計測に付き合っていただき、ありがとうございました。