← レッスンに戻る
第6章 · Claude Code応用

Hooks で振る舞いを制御する

Hooks · 約 14 分

重要キーワード

English日本語説明
Hook フック イベント発生時に実行されるシェルコマンド
PreToolUse ツール実行前 Claude がツールを呼ぶ直前のイベント
PostToolUse ツール実行後 ツール実行直後のイベント
Exit Code 終了コード 0=成功 / 2=ブロック / その他=警告

Hooks (フック)

特定のイベント発生時に シェルコマンドを実行 する仕組み。 メモリやプロンプトでは強制できない、決定論的な自動化 に向きます。

イベント例

設定例 (.claude/settings.json)

#!/bin/bash
# .claude/scripts/guard-bash.sh
input=$(echo "$CLAUDE_TOOL_INPUT_JSON" | jq -r '.command')
if [[ "$input" =~ rm\ -rf\ / ]]; then
  echo "Blocked: dangerous rm -rf detected" >&2
  exit 2
fi

Hook の役割

exit code の意味

環境変数

Hook 実行時には便利な環境変数が渡されます: - $CLAUDE_PROJECT_DIR: プロジェクトルート - $CLAUDE_TOOL_NAME: 呼ばれたツール名 (PreToolUse / PostToolUse) - $CLAUDE_TOOL_INPUT_JSON: ツール入力 (PreToolUse)

実用例 1: 編集後フォーマット

{
  "hooks": {
    "UserPromptSubmit": [{
      "hooks": [{ "type": "command", "command": "echo "$(date -Iseconds) $(pwd) $CLAUDE_USER_PROMPT" >> ~/claude.log" }]
    }]
  }
}

実用例 2: 危険コマンドブロック

PreToolUseBash ツールに対し、入力に rm -rf / などが含まれていたら exit 2 でブロック。

#!/bin/bash
# .claude/scripts/guard-bash.sh
input=$(echo "$CLAUDE_TOOL_INPUT_JSON" | jq -r '.command')
if [[ "$input" =~ rm\ -rf\ / ]]; then
  echo "Blocked: dangerous rm -rf detected" >&2
  exit 2
fi

実用例 3: ロギング

{
  "hooks": {
    "UserPromptSubmit": [{
      "hooks": [{ "type": "command", "command": "echo "$(date -Iseconds) $(pwd) $CLAUDE_USER_PROMPT" >> ~/claude.log" }]
    }]
  }
}

注意


本番運用パターン集 (コピペで使える)

パターン 1: 編集後に変更ファイルだけフォーマット (高速)

「全プロジェクトを毎回フォーマット」は遅すぎる。変更ファイルだけ に絞る:

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "echo \"$CLAUDE_TOOL_INPUT_JSON\" | jq -r '.file_path' | xargs -I{} ruff format {}"
      }]
    }]
  }
}

→ 編集された そのファイルだけ ruff format が走る。100 ms 以内で終わる。

パターン 2: シークレット流出をブロック (PreToolUse)

.env や鍵ファイルへの 書き込み・読み込み を未然にブロック:

.claude/scripts/guard-secrets.sh:

#!/usr/bin/env bash
input=$(cat)
file=$(echo "$input" | jq -r '.tool_input.file_path // empty')
cmd=$(echo "$input" | jq -r '.tool_input.command // empty')

# .env, *.pem, *.key, secrets/ への書き込みを拒否
if [[ "$file" =~ \.env(\..+)?$ ]] || [[ "$file" =~ \.(pem|key|p12)$ ]] || [[ "$file" =~ ^secrets/ ]]; then
  echo "Blocked: writes to secret files are forbidden ($file)" >&2
  exit 2
fi

# Bash で curl https://... | bash 系を拒否
if [[ "$cmd" =~ curl.*\|.*bash ]] || [[ "$cmd" =~ wget.*\|.*sh ]]; then
  echo "Blocked: piping curl/wget to shell is forbidden" >&2
  exit 2
fi

exit 0

settings.json:

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Edit|Write|Bash",
      "hooks": [{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/scripts/guard-secrets.sh" }]
    }]
  }
}

→ Claude が .env を編集しようとした瞬間に止まり、stderr の文言を見て自己修正を試みる。

パターン 3: 全プロンプトをログに残す (監査)

{
  "hooks": {
    "UserPromptSubmit": [{
      "hooks": [{
        "type": "command",
        "command": "jq -r '\(.timestamp) \(.prompt)' >> $HOME/.claude/audit.log"
      }]
    }]
  }
}

→ 全プロンプトが ~/.claude/audit.log に記録される。コンプライアンス要件のある現場で必須。

パターン 4: セッション終了時に WIP コミット

「Claude Code を閉じる前に必ず checkpoint」を強制:

{
  "hooks": {
    "Stop": [{
      "hooks": [{
        "type": "command",
        "command": "cd $CLAUDE_PROJECT_DIR && git diff --quiet || (git add -A && git commit -m 'wip: claude session end')"
      }]
    }]
  }
}

→ 未コミット変更があればセッション終了時に自動 commit。作業ロスト防止

パターン 5: 危険 git コマンドの追加ガード

PreToolUseBash を Inspect:

#!/usr/bin/env bash
cmd=$(jq -r '.tool_input.command' < /dev/stdin)
case "$cmd" in
  *"git push --force"*|*"git push -f "*)
    echo "Blocked: force push is forbidden. Use --force-with-lease if necessary, manually." >&2
    exit 2
    ;;
  *"git reset --hard"*)
    echo "Blocked: hard reset can lose work. Confirm manually." >&2
    exit 2
    ;;
  *"rm -rf "*)
    echo "Blocked: rm -rf is restricted. Use a more specific pattern." >&2
    exit 2
    ;;
esac
exit 0

Hooks デバッグのコツ

演習問題

演習 1: 編集後フォーマッタを Hook で強制

Python プロジェクトで Edit / Write 直後に ruff format が走る Hook を設定してください。

  1. .claude/settings.json を編集 (もしくは新規作成)
  2. PostToolUse + matcher "Edit|Write"
  3. command に ruff format $CLAUDE_PROJECT_DIR を設定
  4. Claude Code セッションで何かファイルを編集し、自動フォーマットを確認
スタータープロンプト:
Python プロジェクト用に `.claude/settings.json` の hooks セクションを書いてください。
- PostToolUse の matcher を "Edit|Write" に
- 実行コマンドは `ruff format $CLAUDE_PROJECT_DIR`
- JSON のみ回答、解説不要
ヒントを見る

ruff がインストールされていない場合は pip install ruff で入ります。設定の検証は Claude Code 側で /hooks を打つと現在有効な hook が確認できます。

演習 2: 危険コマンドブロックの Hook

Bash ツール呼び出しで rm -rf が含まれていたらブロックする PreToolUse Hook を作ってください。

Hook スクリプト (bash) を .claude/scripts/guard.sh に置き、settings.json から呼び出します。

スタータープロンプト:
次の構成を作るための完全なファイル内容を 2 つ示してください。
1. `.claude/scripts/guard-bash.sh`: Bash ツール入力を `$CLAUDE_TOOL_INPUT_JSON` から jq で取り出し、 "rm -rf" を含めば exit 2 でブロック
2. `.claude/settings.json`: PreToolUse の matcher "Bash" でこのスクリプトを呼ぶ設定
ヒントを見る

exit 2 のとき stderr に書いた文言が Claude に渡るので、ブロック理由をきちんと出力すること。jq が必要です。

理解度チェック

  1. Hooks を設定するファイルは?
    1. .claude/hooks.yaml
    2. .claude/settings.json
    3. .clauderc
    4. claude.toml
  2. Hook を exit code 2 で終了させると?
    1. 成功扱い
    2. Claude が処理を止めてアクションを取り消す
    3. OS が再起動する
    4. 新しいセッションが始まる
  3. Hooks に向くタスクは?
    1. 毎回フォーマッタを走らせる
    2. クリエイティブなアイデア出し
    3. 詩の生成
    4. 感情分析
  4. Hook 実行中に使える環境変数は?
    1. $CLAUDE_PROJECT_DIR
    2. $ANTHROPIC_API_KEY
    3. $PATH のみ
    4. $HOOK_NAME
解答と解説を見る
  1. B — `.claude/settings.json` の hooks セクションに書きます。
  2. B — exit 2 はブロック信号として扱われます。
  3. A — 決定論的に毎回行いたい処理に最適です。
  4. A — $CLAUDE_PROJECT_DIR や $CLAUDE_TOOL_NAME などが渡されます。