結論: Claude Code Hooksは、AIエージェントの動作を「手動の承認待ち」から「自動・決定的な制御」に変える仕組みです。PreToolUseでコマンドをブロックし、PostToolUseでフォーマッタを自動実行し、Stopでセッション終了処理を確実に走らせることができます。
この記事の要点:
- 要点1: Hooksは2026年現在20種類以上のライフサイクルイベントをカバーし、settings.jsonに数行書くだけで有効化できる
- 要点2: PreToolUseはexit 2を返すだけでコマンドをブロックできる唯一の「拒否ゲート」として機能する
- 要点3: PostToolUse + Prettier/ESLintの組み合わせで、Claude Codeが編集するたびにコードが自動整形される
対象読者: Claude Codeを導入済みで、反復作業の自動化・セキュリティ強化を検討しているエンジニア・開発チームリーダー
読了後にできること: 今日すぐsettings.jsonにHookを1本追加し、Claude Codeが編集するたびにPrettierが自動実行される環境を構築できる
「Claude Codeに.envファイルを触られてヒヤリとしたことはありませんか。」
企業向けのAI研修で、こんな話をよく聞きます。Claude Codeは優秀なのですが、たまに「あっ、そこは触ってほしくなかった」という操作をする。エンジニアが常に画面をにらんでいればいいのですが、それでは結局AIに仕事を任せる意味が薄れてしまいます。
そこで2026年、Anthropicが投入したのがHooks(フック)という仕組みです。「PreToolUse」「PostToolUse」「Stop」といったライフサイクルイベントにシェルコマンドを紐づけることで、Claude Codeの動作を「手動承認待ち」から「自動・決定的な制御」に変えられます。
この記事では、Hooksの全体像から各イベントの実装例、実用パターン10選、デバッグのコツまで、コピペ可能な設定例つきで徹底解説します。Claude Codeを使いこなしているチームと、まだ恐る恐る使っているチームの差は、Hooksを知っているかどうかにあると言っても過言ではありません。
なお、Claude Codeの基本的な機能や全体像についてはClaude Code完全ガイドでまとめています。こちらと合わせて読むと、全体像がより明確になります。
まず試したい「今すぐ使えるHook」3選
難しい話の前に、今すぐ試せる設定を3つ出します。すべて~/.claude/settings.jsonに貼るだけで動きます。
即効Hook 1:Prettierの自動実行(PostToolUse)
Claude Codeがファイルを編集するたびにPrettierが自動実行されます。「AIが書いたコードなのにフォーマットが崩れている」という状況が完全になくなります。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}
設定の意味: matcherにEdit|Writeと書くと、ファイル編集・作成ツールの実行後だけ動作します。jqでstdinのJSONからファイルパスを取り出し、Prettierに渡しています。
即効Hook 2:.envファイルの保護(PreToolUse)
Claude Codeが.envやpackage-lock.jsonを書き換えようとした瞬間にブロックします。
#!/bin/bash
# .claude/hooks/protect-sensitive-files.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
PROTECTED_PATTERNS=(".env" ".env.local" ".env.production" "package-lock.json" ".git/")
for pattern in "${PROTECTED_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == *"$pattern"* ]]; then
echo "ブロック: '$pattern' は保護対象ファイルです" >&2
exit 2
fi
done
exit 0
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": ""$CLAUDE_PROJECT_DIR"/.claude/hooks/protect-sensitive-files.sh"
}
]
}
]
}
}
exit 2を返すと、Claude Codeはその操作をキャンセルします。stderrに書いたメッセージがClaudeに返り、「なぜブロックされたか」を理解した上で別の方法を探してくれます。
即効Hook 3:タスク完了通知(Notification)
Claude Codeが承認を求めて止まったとき、macOSの通知センターに表示されます。「待ってたのに実は止まってた」を防げます。
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification "Claude Codeが入力を待っています" with title "Claude Code" sound name "Ping"'"
}
]
}
]
}
}
Linuxならnotify-send 'Claude Code' '入力待ちです'、Windowsならpowershell.exe -Command "[System.Windows.Forms.MessageBox]::Show(...)"で同様のことができます。
Hooksとは何か — なぜ手動操作の自動化が重要なのか
Claude Codeは優秀ですが、「LLMとして動いている」という本質的な性質があります。同じ命令をしても、毎回まったく同じ手順を踏む保証はありません。「コード修正後は必ずPrettierを実行して」と言っても、タスクの流れによってはスキップされることがあります。
Hooksはこの問題を根本から解決します。公式ドキュメントには次のように書かれています。
Hooks provide deterministic control over Claude Code’s behavior, ensuring certain actions always happen rather than relying on the LLM to choose to run them.
「LLMに任せるのではなく、必ず実行されることを保証する」——これがHooksの本質です。
Hooksが解決する3つの問題
| 問題 | Hooksなし | Hooksあり |
|---|---|---|
| コードフォーマット | Claudeが忘れることがある | PostToolUseで100%自動実行 |
| 機密ファイル保護 | プロンプトで都度指示が必要 | PreToolUseで完全ブロック |
| セッション終了確認 | 見落としが発生する | Stopで確実に実行 |
研修でClaude Codeを教えていると、「Hooksを知った前と後で使い方が全然変わった」という声を非常によく聞きます。AIの動作を「お願いベース」から「仕組みベース」に移行できるのが、Hooksの最大の価値なんです。
Hookの種類 — 2026年現在の全ライフサイクルイベント
2026年現在、Claude Code HooksはAnthropicが公開しているリファレンスで20種類以上のイベントをサポートしています。大きく5カテゴリに分類できます。
カテゴリ1: セッション系
| イベント | 発火タイミング | 主な用途 |
|---|---|---|
SessionStart | セッション開始・再開時 | コンテキスト注入、環境変数ロード |
Setup | --init-only起動時 | CI/CDの初期化処理 |
SessionEnd | セッション終了時 | 後処理、ログ保存 |
カテゴリ2: 会話フロー系(最重要)
| イベント | 発火タイミング | 主な用途 |
|---|---|---|
UserPromptSubmit | プロンプト送信直後(Claude処理前) | コンテキスト追加、プロンプト監査 |
Stop | Claude応答終了時 | 通知、セッション終了検証 |
Notification | Claude通知送信時 | デスクトップ通知、Slack連携 |
カテゴリ3: ツール実行系(セキュリティの要)
| イベント | 発火タイミング | ブロック可否 | 主な用途 |
|---|---|---|---|
PreToolUse | ツール実行直前 | 可(exit 2) | セキュリティゲート、ファイル保護 |
PostToolUse | ツール実行成功後 | 不可 | 自動フォーマット、テスト実行 |
PostToolUseFailure | ツール実行失敗後 | 不可 | エラーログ、リトライ処理 |
PermissionRequest | 権限ダイアログ表示時 | 可(deny/allow) | 特定操作の自動承認 |
カテゴリ4: ファイル・環境変化系
| イベント | 発火タイミング | 主な用途 |
|---|---|---|
CwdChanged | 作業ディレクトリ変更時 | direnvによる環境変数再ロード |
FileChanged | 監視ファイル変更時 | 設定ファイル変更の即時反映 |
ConfigChange | 設定ファイル変更時 | 変更監査ログ |
InstructionsLoaded | CLAUDE.mdロード時 | 指示の整合性チェック |
カテゴリ5: Sub-Agent・コンパクション系
| イベント | 発火タイミング | 主な用途 |
|---|---|---|
SubagentStart | Sub-Agent起動時 | ログ、リソース管理 |
SubagentStop | Sub-Agent終了時 | 結果集約、通知 |
PreCompact | コンテキスト圧縮前 | 重要情報の保全 |
PostCompact | コンテキスト圧縮後 | コンテキスト再注入 |
settings.jsonへの登録方法
設定ファイルの場所と優先順位
Hooksの設定は2か所に置けます。
| 場所 | パス | スコープ | 用途 |
|---|---|---|---|
| ユーザーレベル | ~/.claude/settings.json | 全プロジェクト共通 | 個人の作業スタイル(通知、フォーマット等) |
| プロジェクトレベル | .claude/settings.json | そのプロジェクトのみ | チーム共有ルール(ファイル保護、必須チェック等) |
プロジェクトレベルの設定はGitにコミットしてチームで共有するのが基本的な使い方です。「チーム全員のClaude Codeが同じルールで動く」という状態を作れます。
基本構造
{
"hooks": {
"イベント名": [
{
"matcher": "ツール名(正規表現)",
"hooks": [
{
"type": "command",
"command": "実行するシェルコマンド"
}
]
}
]
}
}
複数のイベントを一つのファイルに並べて書けます。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/protect-files.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
],
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification "Claude Codeが入力を待っています" with title "Claude Code"'"
}
]
}
]
}
}
hookのtype(種類)
hookのtypeフィールドには4種類を指定できます。
| type | 動作 | 用途 |
|---|---|---|
command | シェルコマンドを実行 | 最も一般的。スクリプト呼び出し等 |
http | URLにJSONをPOST | 外部APIへの通知、Webhook連携 |
mcp_tool | 接続済みMCPサーバーのツールを呼ぶ | MCP統合フロー |
prompt | LLMによる単発評価 | 判断が必要な条件チェック |
/hooksコマンドで確認する
設定後は/hooksと入力すると、登録済みのHookの一覧と詳細(イベント・matcher・type・ソースファイル)を確認できます。設定ミスの検出にも使えます。
PreToolUse実装例 — コマンドブロック・パラメータ修正
PreToolUseは「ツール実行直前に割り込む」最強のHookです。exit 2を返すとツール実行がキャンセルされ、stderrに書いたメッセージがClaudeに返ります。
実装例1: 危険コマンドの検知・ブロック
#!/bin/bash
# .claude/hooks/security-guard.sh
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
# Bashツールの場合のみチェック
if [[ "$TOOL_NAME" == "Bash" ]]; then
# 危険なパターンのリスト
DANGEROUS_PATTERNS=(
"rm -rf /"
"rm -rf ~"
"git push --force.*main"
"git push --force.*master"
"DROP TABLE"
"DROP DATABASE"
"> /dev/sda"
"chmod -R 777 /"
)
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
if echo "$COMMAND" | grep -qE "$pattern"; then
echo "セキュリティエラー: '$pattern' は実行できません" >&2
echo "安全な代替案を使用してください" >&2
exit 2
fi
done
fi
exit 0
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ""$CLAUDE_PROJECT_DIR"/.claude/hooks/security-guard.sh"
}
]
}
]
}
}
BashのmatcherにはBash(git push *)のようにサブコマンドまで絞り込む記法も使えます。Bash(git push --force*)と書けばforce pushだけをターゲットにできます。
実装例2: .mdファイルの新規作成ブロック
Claude Codeがドキュメントファイルを勝手に作りすぎるのを防ぎたい場合に有効です。
#!/bin/bash
# .claude/hooks/block-md-creation.sh
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [[ "$TOOL_NAME" == "Write" ]] && [[ "$FILE_PATH" == *.md ]]; then
echo "ブロック: .mdファイルの新規作成は禁止されています" >&2
echo "ドキュメントを作成する場合は明示的に指示してください" >&2
exit 2
fi
exit 0
実装例3: git pushの前に確認を要求する
#!/bin/bash
# .claude/hooks/git-push-review.sh
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
if echo "$COMMAND" | grep -q "git push"; then
# 差分サマリーをClaudeへフィードバック
echo "git pushを実行しようとしています。" >&2
echo "=== 現在のgit diff HEAD~1..HEAD ===" >&2
git diff HEAD~1..HEAD --stat 2>&1 >&2
echo "" >&2
echo "問題がある場合はexit 2で止めてください。続行する場合はexit 0を返します" >&2
# 今回は止めずに警告のみ (exit 2なら完全ブロック)
exit 0
fi
exit 0
PreToolUseの入力JSON構造
PreToolUseイベントが発火すると、stdinに以下のJSONが渡されます。
{
"session_id": "abc123",
"cwd": "/Users/user/myproject",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "npm test"
}
}
Writeツールの場合はtool_input.file_pathとtool_input.contentが、Editツールの場合はtool_input.file_pathと変更内容が含まれます。
PostToolUse実装例 — 自動フォーマット・Lint・型チェック
PostToolUseはツール実行成功後に走るHookです。「Claudeが書いたコードを即座に品質チェックする」という使い方に最適です。ツール実行をブロックすることはできませんが、stdoutに書いた内容がClaudeにフィードバックされるため、問題があれば次のターンで自動修正できます。
実装例4: TypeScript型チェックの自動実行
#!/bin/bash
# .claude/hooks/typescript-check.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# .tsまたは.tsxファイルの編集時のみ実行
if [[ "$FILE_PATH" == *.ts ]] || [[ "$FILE_PATH" == *.tsx ]]; then
echo "TypeScript型チェックを実行しています..."
# tsconfig.jsonがあれば型チェック
if [[ -f "tsconfig.json" ]]; then
TSC_OUTPUT=$(npx tsc --noEmit 2>&1)
TSC_EXIT=$?
if [[ $TSC_EXIT -ne 0 ]]; then
echo "型エラーが検出されました:"
echo "$TSC_OUTPUT"
else
echo "型チェック: OK"
fi
fi
fi
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": ""$CLAUDE_PROJECT_DIR"/.claude/hooks/typescript-check.sh"
}
]
}
]
}
}
実装例5: ESLintの自動実行
#!/bin/bash
# .claude/hooks/eslint-check.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# JS/TSファイルの編集時のみ実行
if [[ "$FILE_PATH" == *.js ]] || [[ "$FILE_PATH" == *.jsx ]] ||
[[ "$FILE_PATH" == *.ts ]] || [[ "$FILE_PATH" == *.tsx ]]; then
if command -v npx &>/dev/null && [[ -f ".eslintrc.js" || -f ".eslintrc.json" || -f "eslint.config.js" ]]; then
LINT_OUTPUT=$(npx eslint "$FILE_PATH" 2>&1)
LINT_EXIT=$?
if [[ $LINT_EXIT -ne 0 ]]; then
echo "ESLintエラー:"
echo "$LINT_OUTPUT"
fi
fi
fi
実装例6: Pythonのblack + ruffの自動実行
#!/bin/bash
# .claude/hooks/python-format.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [[ "$FILE_PATH" == *.py ]]; then
# blackでフォーマット
if command -v black &>/dev/null; then
black "$FILE_PATH" 2>&1
fi
# ruffでLint
if command -v ruff &>/dev/null; then
RUFF_OUTPUT=$(ruff check "$FILE_PATH" 2>&1)
if [[ -n "$RUFF_OUTPUT" ]]; then
echo "Ruff警告:"
echo "$RUFF_OUTPUT"
fi
fi
fi
非同期Hook(async: true)
Hookの実行時間が長くなりそうな場合はasync: trueを追加することで、バックグラウンド実行にできます。Claudeの次の処理をブロックしません。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/run-all-tests.sh",
"async": true
}
]
}
]
}
}
テスト実行のような時間がかかる処理にはasync: trueが有効です。結果をファイルに書き出しておき、次のセッションで確認するフローにするとスムーズです。
Stop実装例 — セッション終了時の検証
Stopイベントは「Claudeが応答を終えた直後」に発火します。セッション全体を通じた検証、後処理、ログ記録に使います。
実装例7: console.logの残留チェック
「本番環境にconsole.logが混入した」というよくある事故を防ぎます。
#!/bin/bash
# ~/.claude/hooks/check-console-logs.sh
# Stop hookとして登録(セッション終了ごとに実行)
FOUND=$(grep -rn "console.log" --include="*.ts" --include="*.tsx" --include="*.js"
--exclude-dir=node_modules --exclude-dir=".git" . 2>/dev/null)
if [[ -n "$FOUND" ]]; then
echo "⚠️ console.logが残っています:"
echo "$FOUND"
echo ""
echo "本番デプロイ前に削除することを推奨します"
fi
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/check-console-logs.sh"
}
]
}
]
}
}
実装例8: セッション終了時のSlack通知
#!/bin/bash
# ~/.claude/hooks/slack-notify.sh
WEBHOOK_URL="${SLACK_WEBHOOK_URL}"
SESSION_ID=$(cat | jq -r '.session_id // "unknown"')
if [[ -n "$WEBHOOK_URL" ]]; then
curl -s -X POST "$WEBHOOK_URL"
-H "Content-Type: application/json"
-d "{"text": "Claude Codeセッション完了 (ID: $SESSION_ID)"}"
> /dev/null
fi
実用パターン10選
Hooksを使う上で実際に価値が高い10のパターンをまとめました。すべて公式サポートされた方法です。
パターン1: git push前の差分確認
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash(git push*)",
"hooks": [
{
"type": "command",
"command": "git log --oneline origin/main..HEAD && echo 'pushを確認しました'"
}
]
}
]
}
}
パターン2: .mdファイル作成ブロック
Claude Codeが不要なドキュメントを自動生成し続けるのを防ぎます。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty'); if [[ "$FILE" == *.md ]]; then echo 'Markdownファイルの新規作成は禁止' >&2; exit 2; fi"
}
]
}
]
}
}
パターン3: TypeScript自動チェック
(前述の実装例4参照。settings.jsonに追加するだけで動作します)
パターン4: Prettierの自動実行
(前述の即効Hook 1参照)
パターン5: ESLintの自動実行
(前述の実装例5参照)
パターン6: デスクトップ通知
(前述の即効Hook 3参照)
パターン7: SecretGuard(シークレット漏洩防止)
#!/bin/bash
# .claude/hooks/secret-guard.sh
INPUT=$(cat)
CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // empty')
# APIキーパターンの検出
PATTERNS=(
"sk-[a-zA-Z0-9]{20,}" # OpenAI API Key
"AIza[0-9A-Za-z_-]{35}" # Google API Key
"AKIA[0-9A-Z]{16}" # AWS Access Key
"ghp_[a-zA-Z0-9]{36}" # GitHub Personal Access Token
"xoxb-[0-9]+-[0-9A-Za-z]+" # Slack Bot Token
)
for pattern in "${PATTERNS[@]}"; do
if echo "$CONTENT" | grep -qE "$pattern"; then
echo "セキュリティアラート: APIキーやシークレットが含まれている可能性があります" >&2
echo "ファイルへの書き込みをブロックしました" >&2
exit 2
fi
done
exit 0
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": ""$CLAUDE_PROJECT_DIR"/.claude/hooks/secret-guard.sh"
}
]
}
]
}
}
パターン8: コンテキスト圧縮後の重要情報再注入
Claude Codeのコンテキストが満杯になると自動圧縮されますが、重要な情報が失われることがあります。
{
"hooks": {
"SessionStart": [
{
"matcher": "compact",
"hooks": [
{
"type": "command",
"command": "echo '重要: このプロジェクトはBunを使用。npmは使わないこと。コミット前にbun testを必ず実行。現在のスプリント: 認証リファクタリング'"
}
]
}
]
}
}
パターン9: direnv連携(ディレクトリ別環境変数)
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "direnv export bash > "$CLAUDE_ENV_FILE""
}
]
}
],
"CwdChanged": [
{
"hooks": [
{
"type": "command",
"command": "direnv export bash > "$CLAUDE_ENV_FILE""
}
]
}
]
}
}
パターン10: 変更監査ログ
{
"hooks": {
"ConfigChange": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "jq -c '{timestamp: now | todate, source: .source, file: .file_path}' >> ~/claude-config-audit.log"
}
]
}
]
}
}
エラーハンドリングとデバッグ
exit codeの意味を正確に理解する
Hooksで最も重要な概念がexit codeです。間違えると「止めたつもりが止まっていない」という事故が起きます。
| exit code | 動作 | stderrの扱い |
|---|---|---|
| 0 | 成功。ツール実行は続行 | 表示されない |
| 1 | エラー発生。ただしツール実行は続行 | Claudeへのフィードバックとして渡される |
| 2 | ブロック。ツール実行をキャンセル | Claudeへのフィードバックとして渡される(なぜ止まったかを説明できる) |
セキュリティ重要なHookは必ずexit 2を使います。exit 1は「エラーがあったが続行する」という意味なので、セキュリティゲートとしては機能しません。これが実際によくある誤解のひとつです。
デバッグの基本手順
Hookが期待通りに動かない場合の確認手順です。
# 1. hookスクリプトを単体で実行してみる
echo '{"tool_name":"Write","tool_input":{"file_path":"test.env"}}' | bash .claude/hooks/protect-sensitive-files.sh
# 2. exit codeを確認
echo $?
# 3. /hooksコマンドで登録状態を確認
# (Claude Code CLIで) /hooks
# 4. jqが正しく動くか確認
echo '{"tool_input":{"file_path":"test.ts"}}' | jq -r '.tool_input.file_path'
スクリプトの実行権限を忘れずに
# 必須: スクリプトに実行権限を付与
chmod +x .claude/hooks/protect-sensitive-files.sh
chmod +x .claude/hooks/security-guard.sh
実行権限がないとHookが無音でスキップされます。設定したのに動かない場合はまずここを確認してください。
標準入出力の流れ
#!/bin/bash
# デバッグ用:受け取ったJSONを全部ログに残す
INPUT=$(cat)
echo "[$(date)] Hook input: $INPUT" >> /tmp/claude-hook-debug.log
# 通常の処理へ続く...
exit 0
Hookに何が渡ってきているかを確認したい場合は、このように一時的にログを残す方法が手軽です。
パフォーマンス考慮 — Hookの実行時間制約
Hookはツール実行の直前・直後に走るため、処理時間が長いとClaude Codeの全体的なレスポンスが遅くなります。
推奨される実行時間の目安
| Hook種類 | 推奨実行時間 | 対応策 |
|---|---|---|
| PreToolUse | 1秒以内 | 単純なパターンマッチのみに絞る |
| PostToolUse(同期) | 3秒以内 | 重い処理はasync: trueで非同期化 |
| Stop | 5秒以内 | セッション終了後なので比較的余裕あり |
重い処理の非同期化
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx prettier --write "$(cat | jq -r '.tool_input.file_path')"",
"comment": "Prettierは速いので同期OK"
}
]
},
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/run-full-test-suite.sh",
"async": true,
"comment": "テストスイートは非同期で実行"
}
]
}
]
}
}
matcher を絞り込んで不要な実行を減らす
matcherを""(全マッチ)にすると、あらゆるツール実行でHookが走ります。TypeScriptチェックをBash実行時にも走らせる必要はありません。
# 悪い例: 全ツールで型チェックが走る
"matcher": ""
# 良い例: Edit/Writeのみで型チェックが走る
"matcher": "Edit|Write"
# さらに良い例: スクリプト内でファイル拡張子も確認する
if [[ "$FILE_PATH" == *.ts ]] || [[ "$FILE_PATH" == *.tsx ]]; then
# チェック実行
fi
【要注意】失敗パターン4選
Hooksを使い始めた開発者がはまりやすい失敗を4つまとめました。これを知っているだけで、多くの試行錯誤を避けられます。
失敗1: exit 1で止めようとする
❌ よくある間違い:
if [[ "$FILE_PATH" == *.env ]]; then
echo "保護ファイルです" >&2
exit 1 # これではブロックできない!
fi
⭕ 正しいアプローチ:
if [[ "$FILE_PATH" == *.env ]]; then
echo "保護ファイルです" >&2
exit 2 # exit 2でブロック
fi
exit 1はエラーを報告しつつツール実行を続行させる意味です。完全にブロックするには必ずexit 2を使います。企業のセキュリティポリシーをHookで実装する場合、この誤解が致命的になり得るので要注意です。
失敗2: スクリプトに実行権限を付与し忘れる
❌ よくある間違い: スクリプトを作成しただけで動かないと思い込む
⭕ 正しいアプローチ:
chmod +x .claude/hooks/my-hook.sh
実行権限がないとHookは無音でスキップされます。設定したのに動かない場合の最初の確認ポイントはここです。
失敗3: matcherを広げすぎてパフォーマンスが悪化する
❌ よくある間違い:
{
"matcher": "",
"hooks": [{"type": "command", "command": "npx tsc --noEmit"}]
}
⭕ 正しいアプローチ:
{
"matcher": "Edit|Write",
"hooks": [{"type": "command", "command": ".claude/hooks/typescript-check.sh"}]
}
さらにスクリプト内でファイル拡張子もチェックし、.ts/.tsxファイルのみで実行するようにしてください。
失敗4: stdin入力を読み取らずにパスをハードコードする
❌ よくある間違い:
npx prettier --write ./src/ # どのファイルを編集したか関係なく全部フォーマット
⭕ 正しいアプローチ:
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [[ -n "$FILE_PATH" ]]; then
npx prettier --write "$FILE_PATH"
fi
stdinから渡されるJSONに「どのファイルを編集したか」の情報が入っています。これを使うことで、関係のないファイルまで処理してしまう問題を防げます。
まとめ:今日から始める3つのアクション
Claude Code HooksはAIエージェントの動作を「お願いベース」から「仕組みベース」に変える、実運用に欠かせない機能です。最初は小さく始めて、徐々に拡張していくのが定着のコツです。
- 今日やること:
~/.claude/settings.jsonに通知Hook(Notification)を1本追加する。Claude Codeが止まったときに気づける環境を作るのが最初の一歩 - 今週中: プロジェクトの
.claude/settings.jsonに.env保護のPreToolUseを追加してチームでGit共有する。チーム全員のClaude Codeが同じセキュリティルールで動くようになる - 今月中: PostToolUseにPrettier+ESLint+型チェックのセットを組み込んで「AIが書いたコードが即座に品質チェックされる」パイプラインを完成させる
あわせて読みたい:
- Claude Code完全ガイド2026 — 基本操作からHooks連携まで体系的に解説
- Claude Code 20の機能ガイド — Hooks以外の高度な機能を網羅
- Claude Code プロンプト30選 — 実際の業務で使えるプロンプト集
- Claude Code全記事まとめ — 記事一覧・関連コンテンツへのハブ
- Claude Code Slash Command完全ガイド2026 — カスタムコマンド作成・チーム共有・実用パターン10選
参考・出典
- Automate workflows with hooks — Claude Code Docs — Anthropic公式(参照日: 2026-05-06)
- Hooks reference — Claude Code Docs — Anthropic公式リファレンス(参照日: 2026-05-06)
- claude-code-hooks-mastery — GitHub — 13種類のHookライフサイクル実装例(参照日: 2026-05-06)
- Claude Code Hooks Tutorial: 5 Production Hooks From Scratch — Blake Crosley(参照日: 2026-05-06)
- Claude Code hooks: A practical guide with examples — eesel AI(参照日: 2026-05-06)
著者: 佐藤傑(さとう・すぐる)
株式会社Uravation代表取締役。早稲田大学法学部在学中に生成AIの可能性に魅了され、X(旧Twitter)で活用法を発信(@SuguruKun_ai、フォロワー約10万人)。100社以上の企業向けAI研修・導入支援を展開。著書『AIエージェント仕事術』(SBクリエイティブ)。SoftBank IT連載7回執筆(NewsPicks最大1,125ピックス)。
あわせて読みたい: HooksをPlugin内にバンドルしてチームに配布する方法は、Claude Code Plugin開発完全ガイド2026で解説しています。
ご質問・ご相談はお問い合わせフォームからお気軽にどうぞ。




