フックを足したのに、期待していたガードが一度も働いていなかった——そう気づくのは、たいてい何かが通ってしまったあとなのだと思います。
GitHub の Antigravity CLI リポジトリに、まさにその症状の報告があります。macOS の arm64 で、CLI 1.2.1 と 1.2.2 のとき、ログには「5 つの名前付きフックを hooks.json から読み込んだ」と出て、/hooks にもマッチャーとコマンドが並びます。それなのにフックのプロセスが一つも起動せず、エラーも出ないのだそうです。同じ設定・同じアカウント・同じ端末で、1.1.28 に戻すと動いた、という内容です。
この件について、原因が確定しているわけではありません。報告者自身も「実行側の不具合ではないか」と推測している段階で、修正版の記載も私が確認した範囲ではありませんでした。ですから本稿は「直し方」ではなく、自分の環境で起きているのが設定の誤りなのか、実行側の問題なのかを、10 分で切り分ける手順を書き残します。
「読み込めた」と「実行された」は別の事実です
/hooks に一覧が出るのは、設定ファイルをパースできたことの証拠でしかありません。フックが呼ばれたことの証拠にはならないのです。
ここを混同すると、設定ファイルを何度も書き直す方向へ進んでしまいます。一覧に出ているのに動かないなら、設定の文字面を疑う前に、まず「そもそも一度でも起動したか」を別の目で確かめます。
表示されたことと、実行されたことは、別々に証拠を取ります。 今回の線引きは、この一文です。
捨てログ 3 行の設定を置く
確かめ方は単純です。何もしないフックを 3 つ置き、呼ばれたら 1 行ずつファイルへ追記させます。報告者も同じ発想の「カナリア設定」で切り分けていました。
設定ファイルの置き場所は、報告では ~/.gemini/config/hooks.json でした。お使いの版で場所が違う場合は、公式ドキュメントの記載を優先してください。
{
"canary-invocation": {
"PreInvocation": [
{ "type": "command", "command": "echo \"$(date +%T) PreInvocation\" >> /tmp/agy-hook-canary.log", "timeout": 5 }
]
},
"canary-tool": {
"PreToolUse": [
{
"matcher": "*",
"hooks": [
{ "type": "command", "command": "echo \"$(date +%T) PreToolUse\" >> /tmp/agy-hook-canary.log", "timeout": 5 }
]
}
]
},
"canary-stop": {
"Stop": [
{ "type": "command", "command": "echo \"$(date +%T) Stop\" >> /tmp/agy-hook-canary.log", "timeout": 5 }
]
}
}何を解決する設定かというと、フックの中身(検査や承認)を一切含めず、「呼ばれた」という事実だけを残すためのものです。中身が複雑だと、動かない原因が設定なのかスクリプトなのか分からなくなります。
形が二通りある点にご注意ください。報告によると、PreToolUse はマッチャーと入れ子の hooks 配列を持つ形、PreInvocation と Stop は平らな形でした。この差は別の Issue でも話題になっており、形を揃えてしまうと読み込み自体は通っても期待どおりに動かない、という落とし穴になりえます。timeout の単位は版によって解釈が違う可能性があるので、私は短めの値から始めています。
1 ターンだけ回して、ログを見る
ログを空にしてから、LLM 呼び出しとツール呼び出しが 1 回ずつ起きる短い依頼を 1 ターン流します。報告者は agy -i で 1 ターンだけ実行していました。
rm -f /tmp/agy-hook-canary.log
agy -i
# 起動後に「README.md の先頭 5 行を読んで」と頼み、応答が終わるまで待ちます
cat /tmp/agy-hook-canary.log結果は 3 通りに分かれます。
1 つ目は、3 行そろう場合です。実行側は正常で、疑うべきは中身のスクリプトか、マッチャーの条件のほうです。
2 つ目は、1 行か 2 行だけの場合です。イベントごとに通り道が違う可能性があるので、どのイベントだけ欠けているかを控えておきます。入れ子の形と平らな形の取り違えも、ここで疑います。
3 つ目は、ファイルがそもそも作られない場合です。/hooks に一覧が出ているなら、設定の誤りだけでは説明しにくくなります。報告の症状と同じ形ですので、版を確かめてください。
版を動かして、差だけを見る
3 つ目だったときは、CLI の版以外を変えずに、もう一度同じ 1 ターンを流します。報告では 1.1.28 で 3 行そろい、1.2.1 と 1.2.2 では何も残らなかったとのことです。
agy --version
# 版を戻せる手段(パッケージマネージャーや配布物)は、お使いの導入方法に合わせてくださいもう一点、報告には気になる記述がありました。1.2.2 のバイナリを入れる前から起動していたプロセスでは動き続け、入れたあとに起動したプロセスでは動かなくなった、というものです。常駐させている CLI は、更新した直後に再起動したときはじめて症状が出る、ということになります。更新のあとは、カナリアを 1 ターン流す習慣を付けておくと安心です。
動かない間の置き場所を決める
実行側の問題だと分かったとき、個人開発の私なら、フックだけに頼らない形へ寄せるかもしれません。
フックで止めたかった処理は、git の pre-push のような、エージェントの外側にある関門に二重に置いておきます。フックが沈黙しても、push の直前で止まるからです。具体的な組み方は、別の記事で書いた Hooks と git pre-push の二段ゲート設計 に詳しくまとめています。
そして、更新の直前に版を控え、更新のあとにカナリアを 1 ターン流します。直近の版で修正されたかどうかは、この記事を書いた時点で私は確かめられておりません。最新の Issue の状態は、ご自身の目でご確認いただければと思います。
まずは今日、捨てログ 3 行の設定を hooks.json に足して、1 ターン流してみてください。ログが 3 行そろえば、安心して本来のフックの中身に戻れます。