まず試したい「5分即効」セットアップ3選
Hooksの理論より先に、動くコードから入ろう。以下の3つは今日から使えるパターンだ。
即効テクニック1:全ファイル変更を監査ログに記録する
Claudeがどのファイルをいつ変更したかを audit.log に記録するPostToolUseフック。チームでClaude Codeを使う時の透明性確保に効く。
// ~/.claude/settings.json に追記
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "echo "$(date -Iseconds) $CLAUDE_TOOL_NAME $CLAUDE_TOOL_INPUT_FILE_PATH" >> ~/audit.log"
}
]
}
]
}
}
動作環境: Claude Code v1.0+, macOS/Linux
ポイント: $CLAUDE_TOOL_NAME と $CLAUDE_TOOL_INPUT_FILE_PATH は環境変数としてフックスクリプトに渡される
即効テクニック2:Pythonファイル編集後に自動でlintを実行する
Claudeがコードを書くたびにruffが走り、問題があればClaudeに伝わる。コードレビューサイクルが自然に短縮される。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "python3 -c "import json,sys; d=json.load(sys.stdin); f=d.get('tool_input',{}).get('file_path',''); print(f)" | xargs -I{} sh -c 'echo {} | grep -q \.py && ruff check {} 2>&1 || true'"
}
]
}
]
}
}
ポイント: フックはstdinにJSON形式のツール入力を受け取る。tool_input.file_path から編集対象ファイルのパスを取得できる
即効テクニック3:危険なrmコマンドをブロックする
PreToolUseフックでBashの危険なコマンドを検出してブロックする。誤った削除操作を防ぐ安全機構として有効だ。
#!/bin/bash
# ~/.claude/hooks/block_dangerous_bash.sh
INPUT=$(cat /dev/stdin)
CMD=$(echo "$INPUT" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('tool_input',{}).get('command',''))")
# rm -rf / や rm -rf ~/ などを検出してブロック
if echo "$CMD" | grep -qE 'rms+-rfs+(/|~/|/home/|/usr/|/etc/)'; then
echo '{"decision":"block","reason":"危険なrmコマンドを検出しました。削除先のパスを確認してください。"}'
exit 0
fi
# DROP TABLE などのSQL破壊的操作をブロック
if echo "$CMD" | grep -qiE '(DROPs+TABLE|TRUNCATEs+TABLE|DELETEs+FROM.*WHEREs+1=1)'; then
echo '{"decision":"block","reason":"破壊的なSQLコマンドを検出しました。意図した操作か確認してください。"}'
exit 0
fi
exit 0 # それ以外は許可
// settings.jsonへの登録
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/block_dangerous_bash.sh"
}
]
}
]
}
}
動作環境: Claude Code v1.0+, Bash 3.2+
注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。
HooksシステムはClaude Codeの「3つの制御レイヤー」で動く
Hooksを理解するには、Claude Codeがツールを実行する流れを把握しておくと良い。
| フェーズ | フックの種類 | できること | できないこと |
|---|---|---|---|
| ツール実行前 | PreToolUse | 許可・拒否・defer・入力変更 | 実行後の結果を変える |
| ツール実行後 | PostToolUse | フィードバック・ログ・MCP出力変更 | 実行を取り消す |
| セッション終了時 | Stop | テスト実行・後処理・強制継続 | ツール入力を変更する |
| セッション開始時 | SessionStart | 初期化・環境確認 | 重い処理(毎回走る) |
| ユーザー入力時 | UserPromptSubmit | プロンプトのバリデーション・変換 | ツールの制御 |
重要な設計原則として、「止めたいならPreToolUse、記録・検証はPostToolUse」と覚えておくとよい。PostToolUseでブロック(decision: “block”)を返すとClaudeにフィードバックが伝わるが、ツールは既に実行済みだ。
defer機能 — ヘッドレスモードでの承認フロー実装
2026年に追加された defer は、CI/CDや自社UIからClaude Codeを制御したい場合に特に重要な機能だ。
通常、Claude Codeはインタラクティブに動作する。だが claude -p "..." のヘッドレスモードでは、ユーザーへの確認(AskUserQuestionツール)が詰まってしまう。そこで defer を使う。
deferの動作フロー
# 1. ヘッドレスモードで起動(--output-format stream-json は構造化出力)
claude -p "production環境にデプロイして" --output-format stream-json > /tmp/claude_output.json
# 2. deferが発生すると exit code 0 で停止し、deferred_tool_use が出力に含まれる
# 出力例:
# {"type":"result","subtype":"tool_deferred","deferred_tool_use":{"id":"toolu_01abc","name":"AskUserQuestion","input":{"questions":[{"type":"text","text":"本当にproductionにデプロイしますか?"}]}}}
# 3. deferred_tool_use を確認してユーザーに承認を求める(独自UI)
# ... 独自の承認ロジック ...
# 4. 承認が得られたらセッションを再開(--resume でセッションIDを指定)
SESSION_ID=$(cat /tmp/claude_output.json | python3 -c "import json,sys; [print(d.get('session_id','')) for line in sys.stdin for d in [json.loads(line)] if d.get('session_id')]" | tail -1)
claude -p "承認済み: デプロイを続けて" --resume $SESSION_ID --output-format stream-json
制約(重要): deferはClaude Codeが1ターンに1つのツールコールのみ行う場合にのみ機能する。複数ツールを並列実行するターンでは使えない。
Agent SDKでのdefer実装
# 動作環境: Python 3.10+, claude-agent-sdk>=0.2.0
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher
# カスタムUIで承認を収集するフック(defer版)
async def defer_for_human_approval(input_data, tool_use_id, context):
tool_name = input_data.get("tool_name", "")
if tool_name == "Bash":
cmd = input_data.get("tool_input", {}).get("command", "")
if "deploy" in cmd or "production" in cmd:
# deferを返すとSDKが一時停止し、呼び出し元が判断できる
return {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "defer",
"permissionDecisionReason": f"本番環境操作のため人間の承認が必要: {cmd}"
}
}
return {}
async def main():
async for message in query(
prompt="APIサーバーをproduction環境にデプロイして",
options=ClaudeAgentOptions(
allowed_tools=["Bash", "Read"],
hooks={
"PreToolUse": [
HookMatcher(matcher="Bash", hooks=[defer_for_human_approval])
]
},
),
):
# stop_reason が tool_deferred の場合に独自UIで承認処理
if hasattr(message, "stop_reason") and message.stop_reason == "tool_deferred":
print(f"承認待ち: {message.deferred_tool_use}")
# ここで独自UIやSlack通知などで承認を収集する
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。
asyncio.run(main())
CI/CD連携の実践例 — pre-commitスタイルの品質ゲート
HooksとヘッドレスモードはCI/CDのパイプラインに組み込むこともできる。Stopフックを使ってテストを強制実行する例を示す。
#!/bin/bash
# ~/.claude/hooks/run_tests_after_edit.sh
# Stopフックで登録する。セッション終了時にテストを実行し、失敗したら継続させる
if git diff --name-only HEAD | grep -q '.py$'; then
echo "Pythonファイルの変更を検出。テストを実行します..."
if ! python3 -m pytest tests/ -q 2>&1; then
echo "テストが失敗しました。修正してください。"
exit 2 # exit 2 はClaudeに「まだ続けろ」のシグナル
fi
echo "テスト全て通過しました。"
fi
exit 0
// settings.jsonへの登録
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/run_tests_after_edit.sh"
}
]
}
]
}
}
ポイント: Stopフックで exit 2 を返すと、Claudeは「まだやることがある」と判断してセッションを継続する。テストが通るまでClaudeに修正を続けさせる自律的なループが実現できる。
【要注意】よくある失敗パターンと回避策
失敗1: PreToolUseとPostToolUseを逆に使う
❌ PostToolUseで decision: "block" を返してツール実行を止めようとする
⭕ ツール実行を止めたい場合はPreToolUseを使う
なぜ重要か: PostToolUseはツールが完了してから呼ばれる。この時点でブロックしても実行は取り消せない。フィードバックはClaudeに伝わるが、変更は済んでいる。
失敗2: SessionStartフックに重い処理を書く
❌ SessionStartフックでAPIコールや大きなファイルのロードを行う
⭕ SessionStartは軽い初期化のみ。重い処理はトリガーが明確なPreToolUseやPostToolUseに書く
なぜ重要か: SessionStartはClause Codeのセッションが始まるたびに毎回実行される。重い処理を書くとClaude Codeの起動が遅くなる。
失敗3: シェルプロファイルの出力がフックのJSONを壊す
❌ ~/.bashrc や ~/.zshrc に echo "ようこそ" などの出力がある状態でコマンドフックを使う
⭕ フックスクリプトは #!/bin/bash -l(ログインシェル)ではなく #!/bin/bash で書き、プロファイルの出力が混入しないようにする
なぜ重要か: Claude Codeはフックのstdoutを全てJSONとしてパースしようとする。シェルの初期化メッセージが混入するとパースエラーになり、フックが正常に動作しない。
失敗4: matcherの正規表現をテストしない
❌ "matcher": "Edit" と書いたつもりが、MCPツールの mcp__filesystem__edit_file とマッチしていると思い込む
⭕ MCPツールは mcp__<server>__<tool> 形式のため、明示的に "matcher": "Edit|mcp__.*__edit.*" のように書く
なぜ重要か: 組み込みツール名(Edit, Write, Bash等)とMCPツール名は形式が違う。片方しかマッチしていないフックは意図通りに動作しない。
参考・出典
- Hooks reference — Claude Code Docs(参照日: 2026-04-07)
- Intercept and control agent behavior with hooks — Anthropic Platform Docs(参照日: 2026-04-07)
- Claude Code hooks: A practical guide with examples (2026) — eesel AI(参照日: 2026-04-07)
- Claude Code Hooks Complete Guide (March 2026 Edition) — SmartScope Blog(参照日: 2026-04-07)
- GitHub: disler/claude-code-hooks-mastery(参照日: 2026-04-07)
MCPサーバーとの組み合わせについてはClaude CodeとMCPのコンテキスト最適化ガイドも参照してください。Claude Agent SDKでHooksをプログラムから制御する方法はClaude Agent SDK入門ガイドにまとめています。セキュリティの観点からエージェントの振る舞いを制御する考え方はAgent Governance Toolkitの活用事例も参考になります。
まとめ:今日から始める3つのアクション
- 今日:
PostToolUseフックでファイル変更ログをaudit.logに記録するだけの1行フックを設定してみる - 今週中:
PreToolUseフックで危険なBashコマンドのブロックリストを作り、誤削除防止を実装する - 今月中:
StopフックとCI連携を組み合わせ、テストが通るまでClaudeが自律的に修正するループを本番パイプラインに組み込む
ご質問・ご相談は お問い合わせフォーム からお気軽にどうぞ。
著者: 佐藤傑(さとう・すぐる)
株式会社Uravation代表取締役。早稲田大学法学部在学中に生成AIの可能性に魅了され、X(旧Twitter)で活用法を発信(@SuguruKun_ai、フォロワー10万人超)。100社以上の企業向けAI研修・導入支援を展開。著書累計3万部突破。