devAlice
← AI Agents

Claude Code hooks — セッション・ツールイベントでシェルコマンドを自動実行する

settings.json の hooks でセッション開始・ツール呼び出し前後・終了時にシェルコマンドを挿入。5つの実例: セキュリティブロック・自動フォーマット・ログ記録・外部アラート。

Claude Code の Hookssettings.jsonhooks キーで定義 — は、セッション開始・ツール呼び出し前後・セッション終了時に シェルコマンドを自動実行 できる。AI が実行しようとしていることに割り込んだり、後処理を行ったり、終了時のクリーンアップをしたりできる強力な拡張ポイントだ。

このガイドは Claude Code 1.x / 公式 Hooks 仕様 を対象としている。Claude Code セットアップの上に、自動化とセキュリティのレイヤーをひとつ追加する。

TL;DR

hookイベント発火タイミング典型的な用途
SessionStartセッション開始直後メモリ同期通知、環境検証
UserPromptSubmitユーザーがプロンプトを送信した直後スラッシュコマンド認識、ログ、後処理
PreToolUseツール呼び出し直前危険なコマンドのブロック、シークレットファイル保護
PostToolUseツール呼び出し直後自動フォーマット(prettier)、lint、副作用ログ
Stopセッション終了直前変更サマリー、バックアップ、通知

重要なルール:

  • 終了コード 2 でツール呼び出しをブロックする(PreToolUse)。
  • hookのstdinにJSONが渡される — jqで解析する。
  • hookはシェルコマンド — OS差異に注意(macOS/Linux/Windows WSL)。

前提条件

  • Claude Code 1.x インストール済み — Claude Code セットアップ
  • jq インストール済み(brew install jq / apt install jq / winget install jqlang.jq
  • settings.json の編集権限(通常は ~/.claude/settings.json

ベースラインをダウンロードする

devAlice 推奨の5つの Hook ベースライン + permissions の deny/allow リスト — ダウンロードしてカスタマイズしてください。

settings.json
# 1. ダウンロード
curl -fsSL https://devalice.jaceclub.com/assets/ai-agents/claude-code-hooks/settings.example.json -o settings.json
 
# 2. SHA-256検証
shasum -a 256 settings.json
# Expected: 30c1d4117a935cac03b601c71125c11b71733c8c59517ab129fd8913cfb8a69e
 
# 3. 内容確認(特にPreToolUse hooks)
less settings.json
 
# 4. 所定の場所にコピー(macOS/Linux)
mkdir -p ~/.claude
cp settings.json ~/.claude/settings.json

⚠️ 注意: Hook は 任意のシェルコマンドを実行 する。他者の Hook を適用する前は 必ず内容を確認 してください。このサンプルは安全な5つの Hook ベースラインですが、お使いの環境に合わせてレビューし適用してください。


1. Hooks 構造 — 5分

~/.claude/settings.jsonhooksキー:

{
  "hooks": {
    "EventName": [
      {
        "matcher": "regex or tool name",  // 省略可
        "hooks": [
          {
            "type": "command",
            "command": "/bin/bash -lc 'actual shell command'"
          }
        ]
      }
    ]
  }
}

マッチングルール:

  • matcher なし → 全イベントで発火
  • matcher = ツール名(BashWriteEditRead…)→ そのツールのみ
  • matcher = 正規表現(^/(?:ej|euijinpro)\\b)→ UserPromptSubmit でプロンプトテキストにマッチ

stdinに渡されるJSON:

{
  "session_id": "...",
  "transcript_path": "/path/to/transcript.jsonl",
  "cwd": "/Users/...",
  "tool_name": "Bash",
  "tool_input": { "command": "..." },
  "tool_response": { /* PostToolUseのみ */ }
}

jq -r .tool_input.commandで取り出す。


2. SessionStart — コンテキストを読み込む

最もシンプルな Hook。セッション開始時に1行表示する:

"SessionStart": [
  {
    "hooks": [
      {
        "type": "command",
        "command": "/bin/bash -lc 'printf \"[session start] %s\\nmemory sync: latest (skip)\\n\" \"$(date \"+%Y-%m-%d %H:%M:%S\")\"'"
      }
    ]
  }
]

stdoutはシステムメッセージとして表示される。以下の用途に使える:

  • メモリファイルの自動ロードをトリガー
  • プロジェクト固有のコンテキスト出力
  • 開始時のgitステータスサマリー
# より詳細な例
command='/bin/bash -lc "echo [session start]; git -C \"$PWD\" status -s; git -C \"$PWD\" log --oneline -3"'

3. PreToolUse — 危険なコマンドをブロックする(最も重要な Hook)

exit 2 でブロック。AI が危険なシェルコマンドを実行しようとしても止めることができる。

3.1 危険なパターン

"PreToolUse": [
  {
    "matcher": "Bash",
    "hooks": [
      {
        "type": "command",
        "command": "/bin/bash -lc 'cmd=$(jq -r .tool_input.command); case \"$cmd\" in *\"rm -rf /\"*|*\"sudo rm\"*|*\":(){\"*) echo \"blocked dangerous command: $cmd\" >&2; exit 2;; esac'"
      }
    ]
  }
]

ブロックされるパターン:

  • rm -rf / — システム破壊
  • sudo rm — 広範な削除(必要な場合はホワイトリストで許可)
  • :(){ — フォークボム(:(){ :|: & };:

3.2 シークレットファイルの編集をブロックする

{
  "matcher": "Write|Edit",
  "hooks": [
    {
      "type": "command",
      "command": "/bin/bash -lc 'path=$(jq -r .tool_input.file_path); case \"$path\" in */.env|*/credentials.json|*/.aws/credentials) echo \"blocked secret-file edit: $path\" >&2; exit 2;; esac'"
    }
  ]
}

.envcredentials.json~/.aws/credentialsなどへの誤った編集を防ぐ。

3.3 特定ディレクトリを保護する

command='/bin/bash -lc "path=\$(jq -r .tool_input.file_path); case \"\$path\" in /etc/*|/System/*) echo \"blocked system path: \$path\" >&2; exit 2;; esac"'

4. PostToolUse — 自動フォーマット / Lint / ログ

ツール呼び出し のクリーンアップ。

4.1 Prettier自動フォーマット

"PostToolUse": [
  {
    "matcher": "Edit|Write|MultiEdit",
    "hooks": [
      {
        "type": "command",
        "command": "/bin/bash -lc 'path=$(jq -r .tool_input.file_path); case \"$path\" in *.ts|*.tsx|*.js|*.jsx) prettier --write \"$path\" 2>/dev/null || true ;; esac'"
      }
    ]
  }
]

AI の Write/Edit 後に prettier が自動フォーマット。編集ごとに約0.5秒かかる。

4.2 変更ファイルをログに記録する

command='/bin/bash -lc "path=\$(jq -r .tool_input.file_path); echo \"[changed] \$(date +%T) \$path\" >> ~/.claude/change.log"'

セッション内の全ファイル変更を時刻順に記録する。

4.3 型チェック / Lint(重い処理は Stop に移動)

毎回の編集で tsc --noEmit を実行するのはコストがかかる。Stop Hook(§6)で行う方が効率的だ。


5. UserPromptSubmit — スラッシュ検出 / 後処理トリガー

"UserPromptSubmit": [
  {
    "matcher": "^/(?:ej|euijinpro)\\b",
    "hooks": [
      {
        "type": "command",
        "command": "/bin/bash -lc 'echo \"[ej skill] prompt earmarked for euijin.pro logging\" >&2'"
      }
    ]
  }
]
  • スラッシュコマンドを検出 → 外部システム(Slack、別途ログ)をトリガー
  • 特定キーワードの自動ラベリング(urgentbug
  • トークンバジェットのしきい値チェック

6. Stop — セッション終了時のクリーンアップ

"Stop": [
  {
    "hooks": [
      {
        "type": "command",
        "command": "/bin/bash -lc 'printf \"\\n[session end] %s\\n\" \"$(date \"+%Y-%m-%d %H:%M:%S\")\"'"
      }
    ]
  }
]

用途:

  • 変更ファイルのgitステータスサマリー
  • バックアップ(rsync または git stash
  • 外部への終了通知
  • 型チェック / ビルドの1回実行
command='/bin/bash -lc "if git diff --quiet; then echo \"[clean]\"; else echo \"[changes]\"; git diff --stat; fi"'

7. permissions — Deny / Allow

Hooks とは別ですが、settings.json で最も重要なセキュリティキーだ。

"permissions": {
  "deny": [
    "Bash(rm -rf /:*)",
    "Bash(sudo rm:*)",
    "Read(.env)",
    "Read(.env.local)",
    "Read(.aws/credentials)",
    "Read(*/credentials.json)"
  ],
  "allow": [
    "Bash(git status:*)",
    "Bash(git log:*)",
    "Bash(git diff:*)",
    "Bash(pnpm:*)",
    "Bash(npm:*)",
    "Bash(node:*)"
  ]
}
  • deny は無条件に優先 — Hook ブロックを補完する
  • allow はユーザーへの確認なしに自動承認(頻繁に使う安全なコマンド)
  • その他は毎回ユーザーに確認する

このガイドの Hook は deny と重複しています — 多層防御だ。


8. settings.jsonの場所と優先順位

場所スコープ備考
~/.claude/settings.jsonユーザー全体全プロジェクト
<project>/.claude/settings.jsonプロジェクトプロジェクト進入時にユーザー設定とマージ
<project>/.claude/settings.local.jsonプロジェクト + ユーザーローカル.gitignore推奨

マージ順: ユーザー → プロジェクト → プロジェクト.local。後が前を上書きする。

Hook は マージではなく追記 — ユーザー5つ + プロジェクト3つ = 合計8つが実行される。


9. デバッグ — Hook が発火しない場合

9.1 stdin ペイロードを確認する

一時的なデバッグ Hook:

{
  "matcher": "Bash",
  "hooks": [
    {
      "type": "command",
      "command": "/bin/bash -lc 'cat > /tmp/claude-hook-debug.json'"
    }
  ]
}

cat /tmp/claude-hook-debug.json | jq .

9.2 終了コードをテストする

command='/bin/bash -lc "echo dbg >&2; exit 2"'

→ ブロッキング(PreToolUse)が機能しているか確認する。

9.3 Hook の発火を確認する

command='/bin/bash -lc "echo \"[hook fired $$ $(date +%T)]\" >> ~/.claude/hook-trace.log"'

セッション後にログを確認する。

9.4 JSON 構文エラー

settings.json は厳格 — 末尾カンマやエスケープ漏れがよくある。jq . ~/.claude/settings.json で検証してください。


10. トラブルシューティング

「command not found: jq」

brew install jq(macOS)/ sudo apt install jq(Linux)/ winget install jqlang.jq(Windows)

Hook が発火するが何もしない

  • command は1行である必要がある。複数行の場合は \\n を使うか、別スクリプトを呼び出してください。
  • シェルエスケープに注意 — JSON 内の \" は二重エスケープだ。

PreToolUse の exit 2 が無視される

  • exit 2 がシェルコマンドの最終行に確実に到達しているか確認してください。
  • set -e 環境では case ;; が exit 0 になることがある — マッチしたブランチ内で直接 exit 2 してください。

Prettier が動かない

  • プロジェクトルートに prettier がインストールされているか確認(pnpm prettier --version)。
  • Hook の PATH に node_modules/.bin が含まれていない可能性 → npx prettier または絶対パスを使用してください。

settings.json の変更が反映されない

  • セッションの再起動が必要だ。または /config reload(サポートされている場合)。
  • JSON 構文エラーにより静かに無視されている可能性がある。jq . で検証してください。

次のステップ

参考リンク

変更履歴

  • 2026-05-12 — 初版(devAlice M2 シード展開)