目次

1.hooksとは何か
2.hook eventsとsettings.jsonについて
3.hooksを使ってみた
4.おわりに

1.hooksとは何か

hooks とはエージェントループ内の特定のポイントでスクリプトまたはプログラムを実行できる機能です。

例えばエージェントループ内に hooks のカスタムロジックを組むことで以下のようなことが実現できます。
(以下は Tailor Gemini CLI to your workflow with hooks から引用し日本語訳したものです)

  • コンテキストの追加:モデルがリクエストを処理する前に、関連情報 (最近の git コミット、Jira チケット、ローカルドキュメントなど) を挿入します。
  • アクションの検証:潜在的に危険な操作が実行される前に確認し、ブロックします。特定の要件が満たされるまで反復処理を継続し、モデルのパフォーマンスを向上させます。
  • ポリシーの適用:組織全体のセキュリティとコンプライアンスの要件を自動的に実装します。
  • ログ記録と最適化:ツールの使用状況を追跡し、ツールの選択を動的に調整して、モデルの精度を向上させ、トークンコストを削減します。
  • 通知:Gemini CLI がアイドル状態、入力待ち、またはツールの確認が必要なときに更新を取得します。

本ブログでは hooks を使用するための最低限の設定説明から実際に動かしてみた結果を紹介します。

2.hook eventsとsettings.jsonについて

hook eventsについて

hooks を使うにあたって、最低限抑えておく必要があるのが作成したスクリプトをどの hook events で使うかです。

hook events とは hooks で設定するスクリプトをどこで発動させるか、そのトリガーを指定するところとなります。

hook events は11個あります。
(以下は公式ドキュメントの hook events 箇所を日本語訳したもののキャプチャです)

例えば AI が API キーやパスワードなどの機密データを誤ってコードに書き込む事を hooks を使って防ぎたいのであれば、hook events の BeforeTool を指定し、そこで機密データのチェックスクリプトが発動するように設定しておきます。

以下は Tailor Gemini CLI to your workflow with hooks に記載されているサンプルで、AI が生成、書き込もうとしているコンテンツの中に機密情報パターンがないかを確認するスクリプトです。

#!/usr/bin/env bash
# Read hook input from stdin
input=$(cat)

# Extract content being written using jq
content=$(echo "$input" | jq -r '.tool_input.content // .tool_input.new_string // ""')

# Check for common secret patterns
if echo "$content" | grep -qE 'api[_-]?key|password|secret|AKIA[0-9A-Z]{16}'; then
  # Return structured denial to the agent
  cat <<EOF
{
  "decision": "deny",
  "reason": "Security Policy: Potential secret detected in content.",
  "systemMessage": "Security scanner blocked operation"
}
EOF
  exit 0
fi

# Allow the operation
echo '{"decision": "allow"}'
exit 0

BeforeTool を hooks のトリガーとし、指定ツールを使用する前にスクリプトを発動させます。
これを実現するには、settings.json への設定が必要となります。

settings.jsonへのhooks設定について

hooks の発動条件は、settings.json で定義します。
Tailor Gemini CLI to your workflow with hooks に記載されているサンプルに対し、各設定の役割をコメント追記したものが以下です。

まず、hook events を指定。
次に、その hook events をどのツールに適用させるか、hook の命名、実行方式指定、実行するスクリプトパスの指定、そして作成する hook の description を定義します。 

{
  "hooks": {
    // hook events 定義
    // BeforeTool: ツール実行直前に発動
    "BeforeTool": [
      {
        // matcher: どのツールに対して hook を適用するか
        // "write_file|replace" = write_file または replace ツールが実行される直前
        "matcher": "write_file|replace",
        "hooks": [
          {
            // name: この hook の識別名(ログやパネルで表示される)
            "name": "secret-scanner",

            // type: hook の実行方式
            // "command" = 指定したコマンド/スクリプトを実行
            "type": "command",

            // command: 実行するスクリプトのパス
            // $GEMINI_PROJECT_DIR = プロジェクトルートディレクトリに自動展開
            "command": "$GEMINI_PROJECT_DIR/.gemini/hooks/block-secrets.sh",

            // description: この hook の目的を説明
            // /hooks panel コマンドで表示される
            "description": "Prevent committing secrets"
          }
        ]
      }
    ]
  }
}

基本的な使い方としては、プロジェクトディレクトリの .gemini/settings.json もしくは、ホームディレクトリの ~/.gemini/settings.json に設定します。
(設定優先順位としてはプロジェクトディレクトリが優先されます。詳しくは公式ドキュメントの Configuration を参照ください)

上記サンプルのスクリプトや hooks の設定をプロジェクトディレクトリに設定し、Gemini CLI を立ち上げてみます。

プロジェクトディレクトリの構造は以下です。
hooks フォルダには先ほどのスクリプト、settings.json には先ほどの hooks の設定を記入しています。

PJ_DIR/
└── .gemini/
    ├── hooks/
    │   └── block-secrets.sh
    └── settings.json

Gemini CLI を立ち上げ、/hooks panel コマンド(登録済み hooks をステータス付きで表示する)を実行したのが以下です。

/hooks panel コマンドを実行すると、設定したスクリプトが信頼たるものかの確認を促すワーニングメッセージ、どの hook events で、どの hook が設定されているか、その hook の名前、概要、利用可能状態が表示されます。

設定説明に関しては以上となります。
続いては作成したスクリプトを hooks で実行してみます。
※ちなみにスクリプト(シェルスクリプト or JavaScript)を作成したら、実行可能状態とする必要があります。

chmod +x .gemini/hooks/*.sh
chmod +x .gemini/hooks/*.js

3.hooksを使ってみた

実行環境情報は以下となります。

  • macOS:Sequoia 15.7.3
  • Node.js のバージョン( node --version ):24.11.1
  • Gemini CLI のバージョン( gemini --version ):0.27.3
  • 利用モデル:Gemini 2.5 を含んだ Auto モード
  • 設定しているMCP(設定しているが hooks の実行検証では呼び出されていません):AWS Knowledge MCP Server と AWS Terraform MCP Server

試す hook events は BeforeToolです。
設定するスクリプトは先程のサンプルスクリプトにログ出力設定を追加したものとします。

BeforeToolでの機密情報有無スキャン

スクリプト(block-secrets.sh)の内容は以下です。
5箇所、ログ関係の簡単な処理を追加しています。

  • ログファイルを定義しタイムスタンプ付きでログ記録する関数を追加。
  • 実行開始ログを追加。(hooks が実行開始されたことを記録)
  • コンテンツ情報ログとしてスキャン対象のコンテンツサイズを記録。
  • 機密情報検出ログ🚨
  • 機密情報不検出ログ✅
#!/usr/bin/env bash

LOG_FILE=".gemini/hooks/debug.log"

log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
}

input=$(cat)
log "BeforeTool hook started (secret-scanner)"

# Extract content being written using jq
content=$(echo "$input" | jq -r '.tool_input.content // .tool_input.new_string // ""')

log "Content length: ${#content} bytes"

# Check for common secret patterns
if echo "$content" | grep -qE 'api[_-]?key|password|secret|AKIA[0-9A-Z]{16}'; then
  log "🚨 SECRET DETECTED!"

  # Return structured denial to the agent
  cat <<EOF
{
  "decision": "deny",
  "reason": "Security Policy: Potential secret detected in content.",
  "systemMessage": "Security scanner blocked operation"
}
EOF
  exit 0
fi

log "✅ No secrets found - allowing operation"
echo '{"decision": "allow"}'
exit 0

settings.json は以下です。

{
  "hooks": {
    // hook events 定義
    // BeforeTool: ツール実行直前に発動
    "BeforeTool": [
      {
        // matcher: どのツールに対して hook を適用するか
        // "write_file|replace" = write_file または replace ツールが実行される直前
        "matcher": "write_file|replace",
        "hooks": [
          {
            // name: この hook の識別名(ログやパネルで表示される)
            "name": "secret-scanner",

            // type: hook の実行方式
            // "command" = 指定したコマンド/スクリプトを実行
            "type": "command",

            // command: 実行するスクリプトのパス
            // $GEMINI_PROJECT_DIR = プロジェクトルートディレクトリに自動展開
            "command": "$GEMINI_PROJECT_DIR/.gemini/hooks/block-secrets.sh",

            // description: この hook の目的を説明
            // /hooks panel コマンドで表示される
            "description": "Prevent committing secrets"
          }
        ]
      }
    ]
  }
}

ディレクトリ構造は以下です。
ログ出力先として debug.log を追加しています。
hooks のベストプラクティスとして、hooks はバックグラウンドで実行されるため、専用のログファイルの用意を推奨しています)

PJ_DIR/
└── .gemini/
    ├── hooks/
    │   ├── block-secrets.sh
    │   └── debug.log
    └── settings.json

では hooks が発動するか試してみます。
Gemini CLI を立ち上げます。hooks の設定ができています。

では、ユーザープロンプトを入力してみます。以下を入力します。
(下記キー情報は実在しない本ブログ用のランダムな文字列ですが、念のためマスキングしております)
※機密情報有無チェックのセキュリティ目的の hook なので、環境変数にキー情報を直接記載する形でタスク定義ファイルの作成を依頼します。
今回は稼働確認なので、このようなプロンプトとしていますが、実務においてはこのような形は取らず、IAMロールをご使用ください。

task.json を作成し、以下の環境変数を設定してください:
- AWS_ACCESS_KEY_ID: AKIAIO***************
- AWS_SECRET_ACCESS_KEY: ************************KEY

実行結果は以下です。

WriteFile の実行に対し、Security Policy: Potential secret detected in content. とのことで、期待通り実行拒否されました。
debug.log においても機密情報を検知したことのログが書き込まれています。

[2026-02-xx xx:xx:xx] BeforeTool hook started (secret-scanner)
[2026-02-xx xx:xx:xx] Content length: 368 bytes
[2026-02-xx xx:xx:xx] 🚨 SECRET DETECTED!

hooks の実行についてはこれで以上です。

4.おわりに

hooks について簡単な説明から実際に hooks を1つ動かしてみました。
Gemini CLI の公式ドキュメントを見ると、本ブログ執筆時点で hooks に関するドキュメントが4つ見つかりました。

情報量が多いことから hooks は奥深い機能かと思われます。
本ブログで言及できているのは hooks のわずかな機能であり、hooks の本領は複数の hook events を組み合わせたワークフロー設計にあると思います。

ぜひ複数の hook events を組み合わせた独自のワークフローを設計し、 自分たちのプロジェクトに合わせた hooks を試してみてください。
本ブログが Gemini CLI 活用の一助となれば幸いです。