Claude Code のフックは、ほとんどの開発者が見過ごしてしまう機能です。設定ファイルの settings.json の hooks キー配下に置かれ、エージェントのイベントに応じてシェルコマンドを実行し、サブエージェントやメモリだけでは代替できない種類の自動化を可能にします。私は数か月間、本番環境でフックを運用しています。エージェントが停止したときに Telegram に通知するため、危険なパターンに一致する bash コマンドをブロックするため、ファイルの編集後にビルドスクリプトを起動するために使っています。本記事では、実際に機能するパターンを記録します。
Claude Code フックとは
フックとは、Claude Code が何かを実行したときに自動的に動くシェルコマンドです。以上です。プラグインも、拡張機能も、特別な実行環境もありません。コマンドを書いてイベントに紐づけるだけで、Claude が通常の動作の一部としてそれを実行します。
フックは ~/.claude/settings.json(グローバル)または .claude/settings.json(プロジェクト単位)の hooks キー配下に置かれます。フックのエントリは次のようになります:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npm run lint --silent"
}
]
}
]
}
}
実際に使うことになる 3 つのフックイベント:
- PreToolUse — Claude がツールを実行する前に発火します。非ゼロの終了コードを返すことで、アクションを完全にブロックできます。
- PostToolUse — ツールが完了した後に発火します。副作用のために使います:リンティング、ビルド、ログ出力など。
- Stop — Claude のエージェントセッションが終了したときに発火します。通知やクリーンアップに向いています。
さらに、スポーンされたサブエージェントが完了したときの SubagentStop や、コンテキストのコンパクト化が実行される前の PreCompact もあります。
matcher フィールドはツール名に対してマッチさせる正規表現です。Write|Edit はファイルへの書き込みと編集の両方を拾います。Bash は Claude が実行するすべてのシェルコマンドを拾います。すべてを拾うには matcher を空のままにします。
パターン 1:エージェント停止時の Telegram 通知
私が実行している中で最も役に立つフックです。Claude が長いタスクを終えると、ターミナルを見続ける代わりに Telegram のメッセージが届きます。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "curl -s -X POST 'https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage' -d chat_id=${TELEGRAM_CHAT_ID} -d text='Claude+stopped'"
}
]
}
]
}
}
私は、ただの ping ではなくセッションの要約全文を送るラッパースクリプトを使っています。このフックは環境変数を通じてコンテキストを渡します — CLAUDE_STOP_HOOK_ACTIVE、ツール名、ツール入力 — そのため、メッセージをより具体的にできます。
より長いセッションでは、停止理由をメッセージ本文に流し込みます。Claude はフックのペイロード内に stop_reason を含めます。ブロッカーに当たって停止したセッションは、通常どおり完了したセッションとは別のメッセージになります。
実際の効果:大きなリファクタリングを開始し、別の作業に切り替え、終わったらスマホで通知を受け取ります。ターミナルの見張り番は不要です。
パターン 2:危険な bash コマンドのブロック
非ゼロの終了コードを返す PreToolUse にすると、フックがツールの実行をブロックします。これを Bash に対する matcher と組み合わせることで、任意のシェルコマンドが実行される前にガード層を作れます。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/check-command.sh"
}
]
}
]
}
}
check-command.sh スクリプトは、stdin からコマンドを読み取ります(Claude はツール入力を JSON としてパイプします)そして、ブロックリストと照合します:
#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('command',''))")
BLOCKED_PATTERNS=(
"git push --force"
"rm -rf /"
"DROP TABLE"
"git reset --hard"
)
for pattern in "${BLOCKED_PATTERNS[@]}"; do
if echo "$CMD" | grep -qi "$pattern"; then
echo "Blocked: $pattern" >&2
exit 1
fi
done
exit 0
Exit 1はコマンドをブロックします。Claudeはstderrの出力を見て、なぜブロックされたのかを理解します。すると、確認を求めたり、より安全な代替手段を試したりできます。
これはセキュリティ境界ではありません。長い自律セッションの中でのうっかりミスを防ぐためのガードです。Claudeにはほとんどの操作を行う権限がありますが、このフックが、最初に私が「最初に私に見せるべきであって、それなしで決して実行してはいけない」と判断したパターンを検知して止めます。
私はこれをプロジェクト固有のルールにも使っています。あるプロジェクトでは、ロックファイルのチェックなしにnpm installを実行することをブロックするフックがあります。別のプロジェクトでは、本番環境のデータベース接続文字列への変更(ミューテーション)をすべてブロックします。
パターン3:ファイル編集の後にビルドをトリガー
ClaudeがTypeScriptや設定ファイルを編集するとき、すぐにビルドが走ってほしいです。私が覚えて「別ステップとしてビルド」を行うのではなく、編集への自動応答としてビルドが実行されるようにします。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/maybe-build.sh"
}
]
}
]
}
}
maybe-build.shスクリプトは、編集されたファイルがsrc/ディレクトリ内にあるかどうかを確認し、そうであればnpm run build --silentを実行します。編集されたパスは、stdin上のフックのJSONペイロードから読み取ります。
重要なポイント:PostToolUseフックは同期的に実行されます。Claudeはフックの完了を待ってから次のステップに進みます。ビルドに失敗すれば、Claudeは出力を見て、次に進んでしまう前に同じセッション内で問題を修正できます。つまり、「ちょうど変えた内容」を忘れる前に直せるのです。
このパターンは、通常CIで、編集から数時間後に表面化する種類のバグを拾い上げます。型エラー、importの不足、壊れたexport—それらはプルリクのレビューで気づくのではなく、すぐに表示されます。
フックができないこと
フックはシェルコマンドを実行します。Claudeの挙動をミッドセッションで変更したり、新しいコンテキストを注入したり、Claudeの応答を上書きしたりはしません。副作用(サイドエフェクト)だけです。
CLAUDE.md内のメモリや設定(プリファレンス)が、Claudeの考え方に影響します。フックは、Claudeの行動の周りで何が起きるかに影響します。これらは別のレイヤーです。フックは、良いプロンプトやプロジェクト設定の代替にはなりません。
また、Claudeが親の設定なしで生成されたsubagentの中にいる場合は、フックは実行されません。ディレクトリ内で動作しているsubagentには、.claude/settings.jsonにあるプロジェクトレベルのフックが適用されます。グローバルフックはトップレベルのセッションにのみ適用されます。
設定ファイルの構造
動作するフック設定の完全な例:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/check-command.sh" }]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/maybe-build.sh" }]
}
],
"Stop": [
{
"hooks": [{ "type": "command", "command": "~/.claude/hooks/notify-telegram.sh" }]
}
]
}
}
Hooks は、各イベントタイプの中で順番に実行されます。同じイベントに対する複数の hooks はすべて実行されます。PreToolUse では、最初の非ゼロの終了コードがアクションをブロックします — そのイベント内の後続の hooks は実行されません。
FAQ
hooks はどこで実行されますか — ローカルマシンですか、それとも Claude のサンドボックスですか?
hooks は、Claude Code が動いているのと同じ環境で、あなたのローカルマシン上で実行されます。環境変数、ファイルシステム、ネットワークにアクセスできます。サンドボックスはありません。
hook は Claude にデータを返せますか?
はい。hook が stdout に書き込むものはすべてキャプチャされ、Claude の次のステップに影響を与えることができます。PostToolUse hooks では、stdout の出力が Claude が見るツール結果の一部になります。PreToolUse では、stderr が空でない場合、そのブロック理由として Claude に表示されます。
ヘッドレス/cron セッションでも hooks は動きますか?
はい。hooks は Claude Code が動いている場所で実行されます。私は自動化した Paperclip エージェントのセッションで Stop hook を使っています — これは各ハートビート実行の最後に発火し、完了をファイルにログに記録します。
hook スクリプトが存在しない場合はどうなりますか?
Claude は警告をログに記録して処理を続行します。hook スクリプトが欠けていてもセッションはブロックされません。これは意図的です — hooks は追加されるものであり必須ではありません。
Skool の Build & Automate コミュニティでは、私の Build & Automate コミュニティで、より多くの自動化パターンを共有しています。そこには、Telegram 通知のセットアップ一式や、プロジェクト間で hook スクリプトをどのように構成しているかも含まれます。
Notipo を使用して公開 — ワンクリックで WordPress に投稿できる markdown エディタ。
返却形式: {"translated": "翻訳されたHTML"}



