noteでもコンテンツを発信中!チェックする

Claude Code hooksとは?使い方と設定方法・通知の活用例

当ページのリンクには広告が含まれている場合があります。
Claude Code hooksとは?使い方と設定方法・通知の活用例

こんにちは、ハックです。AIを相棒に、非エンジニアから今では様々なツールやアプリを開発をしている一人社長です。

「Claude Codeの作業が終わっていたのに気がつかなかった」

「CLAUDE.mdにルールを書いたのに、守ってくれない時がある」

Claude Codeを使い込むほど、こういう場面が増えてきますよね。

結論から言うと、この2つを解決するのがhooks(フック)です。hooksは、Claude Codeの動きの決まったタイミングで、あなたが指定したコマンドを必ず実行する仕組みです。

CLAUDE.mdが「お願い」なのに対して、hooksは「仕組み」なので、Claudeの気分に左右されません。

この記事では、hooksの基本と設定方法、Macで通知と音を出す手順、僕が何かトラブルが起こるたびに追加してきたフックの実例を、コピーして使える設定テンプレートつきで紹介します。

ハック(Hack)

僕は現在、約20個のフックを設定してる。どちらかというと問題が起きた際に歯止めとして設定したものが多いかな。僕も最初は通知設定から試してみたので、この記事もその順で紹介しようと思う。

駆動 愛

はい、試すならまずは「Macで通知と音を出す方法」の章を参考にするのがおすすめですね!設定ファイルに数行を追加して、/hooksで確認するだけなので、簡単に設定できます。


🧭 読み終えたとき、あなたはこうなっています

  • hooksとCLAUDE.md・Skillsの違いがわかり、どれに何を任せるかを決められる
  • SessionStart・PreToolUse・PostToolUse・Stop・Notificationなど、主なイベントがいつ発火するかがわかる
  • settings.jsonのhooksブロック(matcher・command・exit code 2)を自分で書ける
  • Macで通知バナーと音(osascript・afplay)を出す設定をコピーして使える
  • 「本番への書き込みを止める」「同じ記事を2本作らない」など、実運用している7つのフックの設定例がわかる

⚠️ この記事の信頼性について

筆者(ハック)はプログラミング未経験の状態からAI駆動開発を始め、現在はClaude Codeを日常的に使いながらツールやアプリを開発しています。仕様はAnthropic公式ドキュメント(最終確認:2026年10月1日)の原文に基づいています。Macの通知とafplayの音は、Claude Code 2.1.283・macOSの手元の環境で動作を確認しました。Windowsの通知は公式ドキュメントの例を紹介するもので、筆者の環境では動作を確認していません。バージョンによって対応するイベントや設定項目が変わることがあります。

目次

Claude Code hooksとは

Claude Codeのhooks(必ず実行される仕組み)とCLAUDE.md(お願い)の違いを並べて示した図解

Claude Codeのhooks(フック)とは、Claude Codeの動きの特定のタイミングで、自動的に実行されるコマンドのことです。公式ドキュメントでは「ユーザー定義のシェルコマンド」と説明されています。

「タイミング」とは、たとえば次のような場面です。

  • セッションを始めたとき
  • あなたがプロンプトを送信した直後
  • Claudeがファイルを編集したり、コマンドを実行したりする直前・直後
  • Claudeが応答を終えたとき

この場面ごとに「このコマンドを実行する」と登録しておくと、Claude Codeが該当の場面に来るたびに、そのコマンドが動きます。公式ドキュメントは、hooksを「LLMが実行を選択するのに依存するのではなく、特定のアクションが常に発生する」仕組みだと説明しています。

💡 補足解説:シェルコマンドとは

シェルコマンドとは、ターミナルに打ち込む命令のことです。ls(ファイルの一覧を見る)やecho(文字を表示する)などがあります。hooksには、こうしたコマンドや、コマンドを並べて保存したスクリプト(.shファイル)を登録します。

hooksでできることは、大きく3つに分かれます。

やりたいこと使うイベントの例具体例
知らせるNotification・Stop作業が終わったらMacの通知と音を出す
止めるPreToolUse危険なコマンドやファイルの編集を実行前に止める
整える・記録するPostToolUse・SessionStart編集後に自動整形する・起動時に前回の続きを読み込む

hooks と CLAUDE.md・Skills の違い

hooksとよく比べられるのが、CLAUDE.mdとSkills(スキル)です。違いは、「誰が実行するか」にあります。

実行するのは守られる確実さ向いているもの
CLAUDE.mdClaude(読んで判断する)Claudeの判断しだい方針・書き方・背景の説明
SkillsClaude(必要なときに呼び出す)Claudeが使うと判断したとき手順書・定型作業
hooksClaude Code本体(決まったタイミングで自動実行)毎回必ず通知・禁止・記録・自動整形

CLAUDE.mdに「本番には直接書き込まない」と書いても、Claudeはその文を読んで判断する側です。長い作業の途中で、ルールの優先度が下がってしまうことがあります。

一方でhooksは、Claudeの判断とは関係なく動きます。公式ドキュメントによると、PreToolUseフックがpermissionDecision: "deny"を返せば、bypassPermissionsモード(権限確認を飛ばすモード)や--dangerously-skip-permissionsで起動していても、そのツール呼び出しは止まります。「守らせたい」ことは、CLAUDE.mdではなくhooksの担当です。

ただし、なんでもhooksにすればいいわけではありません。「この書き方で統一したい」「このプロジェクトの背景はこうだ」といった伝えたいことは、CLAUDE.mdのほうが向いています。

公式ドキュメントも、すべてのセッション開始時にコンテキストを追加したいなら、CLAUDE.mdの使用を検討するよう案内しています。

CLAUDE.mdの書き方とSkillsの使い方は、以下の記事でまとめています。

あわせて読みたい
CLAUDE.mdとは?書き方とコピペで使える用途別テンプレおすすめ5選 CLAUDE.mdとは?から作り方、書き方、置き場所・必要な項目まで全てを1ページで解説。Claude Code初心者がそのまま使える用途別テンプレ実例5つ付き。3,000トークン以内に収めるルールと、守られないときの対処法、RulesやSkillsやAGENTS.mdとの違いもまとめました。
あわせて読みたい
Claude Code Skills(スキル)とは?使い方・作り方とおすすめの探し方を初心者向けに解説 Claude Code Skills(スキル)とは何か?からインストールから使い方・作り方までを初心者向けに解説します。スキルの探し方からおすすめのスキル、自分の作業をスキル化にするかどうかの判断の基準、使うときの注意点までわかりやすくまとめてみました。

Claude Code hooksの種類とイベント一覧

Claude Code hooksの主なイベントが、起動から応答終了までのどの順番で発火するかを示した時間軸の図解

hooksの「タイミング」のことを、イベントと呼びます。公式リファレンスの一覧表には、2026年10月1日時点で33種類のイベントが載っています。

全部を覚える必要はありません。多くの人が使うのは、次の7つ前後です。

よく使う4つ:SessionStart・PreToolUse・PostToolUse・Stop

イベント発火するタイミング止められる?
SessionStartセッションが始まったとき・再開したとき止められない
PreToolUseツール呼び出し(ファイル編集・コマンド実行など)が実行される前止められる
PostToolUseツール呼び出しが成功した後止められない(すでに実行済みのため)
StopClaudeが応答を終えたとき止められる(Claudeが作業を続ける)

それぞれ、使い方のイメージは次のとおりです。

SessionStart:起動した瞬間に動きます。matcher(後の章で説明します)で、startup(新しく起動)・resume(再開)・clear(/clearの後)・compact(会話の圧縮後)に絞れます。標準出力に書いた文字は、Claudeの文脈に追加されます。前回の続きを読み込ませる用途に向いています。

PreToolUse:最も使う機会が多いイベントです。Claudeがツールを使おうとした瞬間に、そのツール名と引数をフックが受け取ります。ここでexit 2(後で説明します)を返すと、ツールの実行そのものがキャンセルされます。

PostToolUse:ファイルを編集した後にPrettier(コードの整形ツール)を実行する、といった「後始末」に向いています。公式ドキュメントにあるとおり、ツールはすでに実行されているので、操作を元に戻すことはできません。

Stop:Claudeが応答を終えるたびに発火します。公式ドキュメントには、タスクが完了したときだけではなく、応答を終えるたびに発火すると書かれています。また、あなたが途中で割り込んだときには発火しません。

Notification・UserPromptSubmit・PreCompact

イベント発火するタイミング使い道
NotificationClaude Codeが通知を送るとき(許可を待っている・入力を待っている等)通知・音
UserPromptSubmitあなたがプロンプトを送信した直後、Claudeが処理する前依頼ごとにルールを添える
PreCompact会話の圧縮(/compactや自動圧縮)の前圧縮前の処理

Notificationは、matcherで通知の種類を絞れます。代表的なものは次の2つです。

matcher発火するタイミング
permission_promptClaudeがツールの使用許可を求めていて、約6秒待っている
idle_promptClaudeが約60秒前に応答を終えて、その後あなたが何も入力していない

UserPromptSubmitは、matcherに対応していません。プロンプトを送信するたびに、必ず発火します。標準出力に書いた文字は、Claudeの文脈に追加されます。

そのほかのイベント

残りのイベントは、表で名前だけ紹介します。必要になったときに、公式リファレンスで確認してください。

イベント発火するタイミング
PermissionRequestツール呼び出しに許可の判断が必要なとき
PostToolUseFailureツール呼び出しが失敗した後
SubagentStart・SubagentStopサブエージェントの開始・終了
StopFailureAPIエラーでターンが終わったとき
SessionEndセッションが終了したとき
ConfigChangeセッション中に設定ファイルが変わったとき
CwdChanged・FileChanged作業ディレクトリ・監視中のファイルが変わったとき
PostCompact会話の圧縮が終わった後

このほか、エージェントチーム・Worktree・MCPの入力要求などのイベントもあります。この記事では扱いません。

hooksの「ハンドラー」(実行される中身)には、シェルコマンドのほかに、HTTPで外部サービスへ送る型、LLM(Claudeのモデル)に判断させるプロンプト型などもあります。この記事では、最も使われるシェルコマンド型("type": "command")だけを説明します。

Claude Code hooksの設定方法と書き方

Claude Code hooksの設定を、イベント・matcher・commandの3段の入れ子で示した図解

hooksは、settings.json(Claude Codeの設定ファイル)にhooksブロックを追加して設定します。書き方は、次の3段の入れ子です。

  1. どのイベントに反応するか(PreToolUse・Stopなど)
  2. どんなときに発火させるかを絞るmatcher(「Bashツールのときだけ」など)
  3. 発火したときに実行するcommand(実行するコマンド)

一番小さい形は、次のようになります。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Bashが実行されます' >&2"
          }
        ]
      }
    ]
  }
}

"PreToolUse"がイベント、"matcher": "Bash"が絞り込み、"command"が実行する内容です。matcherの階層と、その中のhooks配列の階層が2つあるのが、最初につまずきやすい点です。「イベント → matcherのグループ → 実行するもの」の順に入れ子になっている、と覚えてください。

hooks を書く場所(ユーザー・プロジェクト)

hooksを書く場所で、効く範囲が変わります。

書く場所効く範囲共有
~/.claude/settings.json自分のすべてのプロジェクトしない(自分のMacだけ)
.claude/settings.jsonそのプロジェクトだけできる(リポジトリに含められる)
.claude/settings.local.jsonそのプロジェクトだけしない(Claude Codeが作るときにgitで無視される)

通知のように「どのプロジェクトでも欲しい」ものは~/.claude/settings.jsonに、「このプロジェクトのルール」は.claude/settings.jsonに書きます。このほか、組織の管理者が配る管理ポリシー設定や、プラグイン・スキルの中にhooksを持たせる方法もあります。

すでにhooksキーがある場合は、hooksオブジェクト全体を置き換えるのではなく、既存のイベントのキーの隣に新しいイベントを追加します。各イベント名は、ひとつのhooksオブジェクトの中のキーです。

settings.jsonそのものの場所や、設定の優先順位は、以下の記事で詳しく説明しています。

あわせて読みたい
Claude Codeの初期設定ガイド|settings.jsonの場所と権限の書き方 Claude Codeの設定ファイルの場所と、最初にやっておきたいおすすめ設定をまとめました。モデル・effort・学習オプトアウトから、許可(allow)と拒否(deny)の権限設定の書き方までわかります。(※コピペで使えるおすすめ設定テンプレート付)

matcher と command の書き方

matcherは、フックを発火させる条件の絞り込みです。何に対して絞り込むかは、イベントによって違います。

イベントmatcherが絞り込む対象値の例
PreToolUse・PostToolUseツール名Bash・`Edit\Write`
SessionStartセッションの始まり方startup・resume・compact
Notification通知の種類permission_prompt・idle_prompt
UserPromptSubmit・Stopmatcher非対応(毎回発火)(書いても無視される)

matcherの値の評価のされ方には、ルールがあります。

matcherの書き方評価のされ方
"*"・""・省略すべてに一致
英数字・_・-・スペース・,・`\`だけ完全一致(`\や,`で区切ると、どれか1つに完全一致)
それ以外の文字を含むJavaScriptの正規表現(文字列のどこかに一致すれば発火)

たとえばEdit|Writeは、EditツールかWriteツールのどちらかに完全一致します。一方、Edit.*のように記号を含めると正規表現として扱われ、EditとNotebookEditの両方に一致します。完全一致させたいときは^Edit$のように^と$で挟みます。また、matcherは大文字小文字を区別します。

matcherの絞り込みに加えて、ツールのイベントではifフィールドも使えます。"if": "Bash(git *)"のように、権限ルールと同じ書き方でコマンドの中身まで絞れるので、gitコマンドのときだけスクリプトを動かせます。ただし公式ドキュメントによると、ifはあくまでベストエフォートの絞り込みです。確実な許可・拒否が必要な場面では、権限システム(permissions)の使用が案内されています。

commandは、実行するコマンドです。ワンライナー(1行のコマンド)を直接書くことも、スクリプトのパスを書くこともできます。スクリプトを指すときは、プロジェクトのルートを表す$CLAUDE_PROJECT_DIRが使えます。

{
  "type": "command",
  "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-prod-write.sh"
}

JSONの中では、"を\"と書く必要があります。引用符が多くなりすぎるときは、スクリプトを別ファイルに分けると読みやすくなります。スクリプトには、chmod +xで実行権限を付けます。

chmod +x .claude/hooks/block-prod-write.sh

フックは、ツールの情報を標準入力(stdin)にJSONで受け取ります。たとえば、Claudeがnpm testを実行しようとしたとき、PreToolUseフックには次のようなJSONが渡されます。

{
  "session_id": "abc123",
  "cwd": "/home/user/my-project",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test"
  }
}

スクリプトは、このJSONから必要な値を取り出して判断します。取り出しにはjq(JSONを扱うコマンド)がよく使われます。jqが入っていなければ、Macではbrew install jqでインストールします。たとえば実行されるコマンドの文字列は、jq -r '.tool_input.command'で取り出せます。

exit code 2 で操作を止める仕組み

フックがClaude Codeに結果を伝える方法は、終了コード(exit code)です。スクリプトの最後にexit 0やexit 2と書いた数字のことです。

終了コード意味
exit 0成功。フックは異議なし(通常の権限確認は、そのまま続く)
exit 2ブロッキングエラー。ツール呼び出しなどを止める。stderr(標準エラー出力)の文がClaudeに返る
それ以外(exit 1など)非ブロッキングエラー。エラーの通知は出るが、操作はそのまま進む

ここで大事なのは、止めたいときはexit 2を使うことです。公式ドキュメントにも、Claude Codeはexit 1を非ブロッキングエラーとして扱い、従来のUnixの失敗コードであっても操作を進ませる、と警告が載っています。exit 1で止めたつもりが、止まっていなかったという事故が起きます。

exit 2のとき、標準エラー出力に書いた文は、エラーメッセージとしてClaudeにフィードバックされます。たとえば、公式ドキュメントに載っている、危険なコマンドを止めるスクリプトは次のとおりです。

#!/bin/bash
# stdin から JSON 入力を読み取り、コマンドをチェック
command=$(jq -r '.tool_input.command' < /dev/stdin)

if [[ "$command" == rm* ]]; then
  echo "Blocked: rm commands are not allowed" >&2
  exit 2  # ブロッキング エラー: ツール呼び出しが防止される
fi

exit 0  # 決定なし: 通常の権限フローが適用される

>&2は、文字を標準エラー出力に送る書き方です。Claudeは「Blocked: rm commands are not allowed」という文を受け取るので、理由を理解して別の方法を探せます。止めるだけでなく、理由を日本語で書いておくと、Claudeが次にやることを正しく選びやすくなります。

exit 2が何をするかは、イベントによって違います。

イベントexit 2で起きること
PreToolUseツール呼び出しを止める
UserPromptSubmitプロンプトの処理を止めて、プロンプトを消去する
StopClaudeが止まるのを防ぎ、会話を続けさせる
SessionStart止められない。stderrがあなたに表示され、実行は続く

また、exit 2のときは標準出力のJSONは無視されます。公式ドキュメントは、「exit 2でstderrを返す方法」か「exit 0でJSONを返す方法」のどちらか一方をフックごとに選ぶよう案内しています。この記事のフックは、すべて前者(exit 2)で書きます。

/hooks で設定を確認する

設定したら、Claude Codeの画面で/hooksと入力します。/hooksは、設定済みのhooksを見られる読み取り専用のメニューです。

/hooks

メニューでは、イベントの一覧と、フックを設定したイベントの横に件数が表示されます。イベントを選ぶとmatcherが、フックを選ぶと詳細(イベント・matcher・タイプ・設定元のファイル・実行するコマンド)が表示されます。各フックには、設定元を表すラベルが付きます。

ラベル設定元
User~/.claude/settings.json
Project.claude/settings.json
Local.claude/settings.local.json
Pluginプラグインのhooks/hooks.json

「設定したはずのフックが、どのファイルのものか分からない」というときは、ここで設定元を確認できます。/hooksから追加・変更・削除はできません。変更するときは、settings.jsonを直接編集するか、Claudeに「このフックを追加して」と頼みます。/hooksなどのコマンド全体は、以下の記事にまとめています。

あわせて読みたい
Claude Codeのコマンド一覧|スラッシュコマンドの使い方とカスタムコマンドの作り方 Claude Codeでよく使う便利なコマンドを一覧表でまとめました。スラッシュコマンドの基本的な使い方に加え、著者が純正コマンドよりも日常的に使っているカスタムコマンドの作り方や具体的な活用事例もわかります。

Claude Codeのhooksで通知を出す方法(Mac・Windows)

Claude Codeの通知を、ターミナル・VS Code版ではhooksで設定し、デスクトップアプリでは設定なしで出せることを示した図解

hooksの使い方として、最初におすすめなのが通知です。AIに作業を任せている間に、ほかの作業をして、終わったら知らせてもらう。これだけで、待ち時間の使い方が変わります。

Claude Codeは、Claudeが「許可を待っているとき」や「入力を待っているとき」に、Notificationイベントを発火させます。ここに通知コマンドを登録します。

Macで通知を出す(osascript)

Macには、osascriptというコマンドがあります。これを使うと、画面の右上に通知バナーを出せます。公式ドキュメントにも載っている方法です。

まず、~/.claude/settings.jsonを開いて、次の内容を追加します。ファイルが存在しない場合は、新しく作ります。

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

"matcher": ""は、すべての種類の通知で発火するという意味です。display notificationの後の文字が通知の本文、with titleの後の文字が通知のタイトルです。本文は日本語にも変えられます。

追加したら、/hooksでNotificationに1件と表示されるかを確認します。そのあと、通知が出るかを試します。

  1. Shift+Tabを押して、ステータスバーに⏸ manual mode onと出る状態にする
  2. Claudeに、許可が必要な作業(ファイルの作成など)を頼む
  3. ターミナルから別のアプリに切り替えて、数秒待つ

許可待ちの状態が約6秒続くと、通知が出ます。

💡 補足解説:通知が出ないときの確認(Script Editorの通知許可)

公式ドキュメントによると、osascriptの通知は、Macに組み込まれているScript Editorというアプリを通して出ます。Script Editorに通知の権限がないと、コマンドは静かに失敗して、macOSも許可を求めてきません。ターミナルでosascript -e 'display notification "test"'を1回実行して、Script Editorを通知設定に表示させます。それでも出ないときは、「システム設定」→「通知」を開き、リストのScript Editorを見つけて「通知を許可」をオンにします。

通知を「許可待ち」と「入力待ち」で出し分けたいときは、matcherにpermission_promptかidle_promptを指定します。permission_promptは、許可を求めて約6秒待っているとき、idle_promptは、応答を終えて約60秒たっても何も入力がないときです。

作業が終わったら音を鳴らす(afplay)

通知バナーに気づけない人には、音もおすすめです。Macのafplayコマンドで、音声ファイルを再生できます。

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "afplay /System/Library/Sounds/Glass.aiff"
          }
        ]
      }
    ]
  }
}

この設定は、Stopイベント(Claudeが応答を終えたとき)に、Macに標準で入っているGlass.aiffの音を鳴らします。Stopにはmatcherがないので、書かなくても大丈夫です。筆者の環境(macOS)で、鳴ることを確認しています。

音の種類を変えたいときは、同じフォルダにある別のファイルに差し替えます。ファイルの一覧は、次のコマンドで見られます。

ls /System/Library/Sounds

バナーと音を両方にしたいときは、コマンドを;でつなぎます。

{
  "type": "command",
  "command": "osascript -e 'display notification \"作業が終わりました\" with title \"Claude Code\"'; afplay /System/Library/Sounds/Glass.aiff"
}

NotificationとStopの違いも、ここで整理しておきます。

イベント鳴るとき向いている使い方
Notification許可待ち(約6秒後)・入力待ち(約60秒後)「Claudeが待っている」ときの通知
StopClaudeが応答を終えるたび「作業が終わった」ときの通知・音

長い作業を任せるならStop、許可を求められて止まっているのに気づけないならNotification、というのが基本です。Stopは、短い応答のたびに鳴るので、うるさく感じるならNotificationのidle_promptだけに絞る方法もあります。

Windows で通知を出す

Windowsでは、公式ドキュメントにPowerShellを使った例が載っています。

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Code needs your attention', 'Claude Code')\""
          }
        ]
      }
    ]
  }
}

この例は、画面の隅に出る通知ではなく、ダイアログボックス(小さなウィンドウ)を開きます。そのため、ターミナルの背後に開いてしまうことがあります。ダイアログが見えないときは、まずPowerShellで同じコマンドを直接実行して、動くかを確かめてください。WSL(Windows上のLinux環境)でClaude Codeを動かしている場合は、powershell.exeがPATHから呼び出せる必要があります。

この記事の筆者はMacで動作を確認しているため、Windowsの例は公式ドキュメントの記載の範囲の紹介にとどめています。Linuxは、公式ドキュメントにnotify-sendを使う例があります。

デスクトップアプリは設定なしで通知が出る

Claude Codeのデスクトップアプリは、hooksを設定しなくても、Macの通知が出ます。アプリに標準で備わっている純正の通知なので、この記事の設定は不要です。

この章のhooksの通知は、ターミナルで使うClaude Codeと、VS Code版向けの方法です。ターミナルやVS Codeの拡張機能には、作業の終わりを知らせる仕組みが標準では用意されていないため、hooksで補います。

VS Code版の使い方は、以下の記事で説明しています。

あわせて読みたい
Claude CodeをVS Codeで使う方法|拡張機能とターミナルの違いと設定手順 Claude CodeをVS Codeで使う手順を初心者にもわかりやすくまとめてみました。VS Code拡張機能のインストール方法から、知っておくと便利な使い方も解説します。拡張機能と統合ターミナル環境の違いなど、基本知識をこの記事から得ることができます。

Claude Code hooksのおすすめ活用例7つ

Claude Codeのhooksで防げる7つの事故と、フックが止めること・自動で行うことを対応させた図解

ここからは、僕が実際に運用しているフックのうち、なにか問題が起きてから作ったものを7つ紹介します。

ハック(Hack)

フックは、最初から「あったら便利そう」で作ると、たいてい使わなくなります。僕のフックが残っているのは、どれも「あのやらかしは二度とごめんだ」という痛い思いから作ったからです。下の7つは、事故の内容と、何を止めているかをセットで書きます。ファイル名や実際のパスは、自分の環境に合わせて読み替えてください。

7つとも、同じ型で書きます。「設定ファイルにフックを登録する」+「判断するスクリプトを書く」の2点セットです。設定は.claude/settings.json(プロジェクト用)、スクリプトは.claude/hooks/フォルダに置きます。スクリプトにはchmod +xで実行権限を付け、jqをインストールしておいてください。

本番への書き込みを止める

起きた事故:ブログ記事を、WordPress(サイトを作るシステム)へ反映する作業で、僕が手で直して公開済みだった記事を、手元の古い原稿で上書きしてしまいました。気づいたのは、読者から「内容が前に戻っている」と指摘された後でした。

止めること:決められた公開手順以外のやり方で、本番環境に書き込むコマンドを止めます。

PreToolUseのBashで、コマンドの文字列を見て判断します。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-prod-write.sh"
          }
        ]
      }
    ]
  }
}
#!/bin/bash
# .claude/hooks/block-prod-write.sh
COMMAND=$(jq -r '.tool_input.command')

# 本番への書き込みに使うコマンドが含まれていて、正規の手順(deploy.sh)を通っていなければ止める
if echo "$COMMAND" | grep -qE 'rsync|scp|wp post update' && ! echo "$COMMAND" | grep -q 'deploy.sh'; then
  echo "Blocked: 本番への書き込みは ./deploy.sh を使ってください" >&2
  exit 2
fi

exit 0

grep -qEの後ろのrsync|scp|wp post updateは、本番への書き込みに使う道具の名前です。自分の環境で使っているものに書き換えます。ポイントは、「何でもダメ」ではなく「正規の手順(deploy.sh)を通せば許可」にしたことです。全部を禁止すると、必要な作業まで止まってしまうからです。

Claudeには「Blocked: 本番への書き込みは ./deploy.sh を使ってください」が返るので、Claudeはコマンドを書き直して、正規の手順を使い直します。

個人情報を外へ出さない

起きた事故:記事のテンプレートに、僕の本名がそのまま混ざりかけました。匿名で運営しているのに、本名が公開されるところでした。

止めること:本名やパソコンのユーザー名が含まれるコマンド・ファイル編集を止めます。

コマンドだけでなく、ファイルの書き込みも対象にしたいので、matcherにBash|Edit|Writeを指定します。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-personal-info.sh"
          }
        ]
      }
    ]
  }
}
#!/bin/bash
# .claude/hooks/block-personal-info.sh
# ツールに渡される引数(コマンド・書き込む内容)を丸ごと1つの文字列にして調べる
INPUT=$(jq -r '.tool_input | tostring')

if echo "$INPUT" | grep -qE 'yamada-taro|山田太郎'; then
  echo "Blocked: 本名またはローカルパスが含まれています。匿名の表記に直してください" >&2
  exit 2
fi

exit 0

yamada-taro|山田太郎の部分に、止めたい言葉を|でつないで書きます。jq -r '.tool_input | tostring'は、ツールに渡される引数(コマンドや書き込む内容)を、全部まとめて1つの文字列にする書き方です。ツールごとに引数の項目名が違っても、1行で調べられます。

根拠のない情報の公開を止める

起きた事故:公式ドキュメントに書いていない仕様を、書いてあるかのように断定した記事を公開してしまいました。下書きの段階で誰も気づけず、公開後に見つかりました。

止めること:「事実の確認表(ファクトチェックリスト)」が未記入のまま、公開コマンドを実行しようとしたら止めます。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/require-fact-check.sh"
          }
        ]
      }
    ]
  }
}
#!/bin/bash
# .claude/hooks/require-fact-check.sh
COMMAND=$(jq -r '.tool_input.command')

# 公開コマンドのときだけ確認する
if echo "$COMMAND" | grep -q 'publish.sh'; then
  # チェックリストに未チェックの項目「- [ ]」が残っていたら止める
  if grep -q '\- \[ \]' fact-check.md; then
    echo "Blocked: fact-check.md に未確認の項目があります。確認してから公開してください" >&2
    exit 2
  fi
fi

exit 0

この例では、fact-check.mdというチェックリスト(Markdownの- [ ]で書いた確認項目)に、未チェックのものが残っていたら、publish.shの実行を止めます。確認を「お願い」ではなく「通らないと進めない関門」にするのが、hooksの使い方のひとつです。

同じ記事を2本作らない

起きた事故:すでに書いてある記事と同じキーワードで、別の記事を書き始めていました。Claudeは、新しい記事を頼まれたので、新しいファイルを作っただけです。

止めること:同じ名前の記事が、すでにあるのに、新しく下書きを作ろうとしたら止めます。

PreToolUseのWrite(ファイルの新規作成)を対象にします。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-duplicate-draft.sh"
          }
        ]
      }
    ]
  }
}
#!/bin/bash
# .claude/hooks/block-duplicate-draft.sh
FILE_PATH=$(jq -r '.tool_input.file_path // empty')

# drafts フォルダの中の、まだ存在しないファイルを作るときだけ調べる
if [[ "$FILE_PATH" == */drafts/* && ! -e "$FILE_PATH" ]]; then
  # 「24-claude-code-hooks.md」の先頭の番号を取った「claude-code-hooks.md」を取り出す
  NAME=$(basename "$FILE_PATH" | sed -E 's/^[0-9]+-//')
  if ls "$(dirname "$FILE_PATH")" | grep -qE "^[0-9]+-${NAME}$"; then
    echo "Blocked: 同じ名前の下書きがすでにあります($NAME)。既存のファイルを確認してください" >&2
    exit 2
  fi
fi

exit 0

ファイル名が「番号-キーワード.md」の形式になっている前提で、番号を無視してキーワード部分が同じならば止めます。! -e "$FILE_PATH"は「そのファイルがまだ存在しない」という意味です。この条件があるので、すでにある下書きを上書きして直す作業は、止まりません。

起動時に前回の続きを読み込む

起きた事故:前回の作業の続きのつもりで話しかけたのに、Claudeは前回の内容を知らずに、別の作業を始めてしまいました。毎回「昨日はここまでやった」と説明する手間もかかっていました。

自動で行うこと:セッションを始めるたびに、「次にやること」を書いたメモを、Claudeに読み込ませます。

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup|resume",
        "hooks": [
          {
            "type": "command",
            "command": "cat \"$CLAUDE_PROJECT_DIR\"/NEXT.md"
          }
        ]
      }
    ]
  }
}

SessionStartは、標準出力に書いた文字が、Claudeの文脈(会話の前提)として追加されます。そのため、スクリプトは不要で、cat(ファイルの中身を表示するコマンド)でメモを表示するだけで済みます。matcherのstartup|resumeは、新しく起動したときと、再開したときだけ、という意味です。

読み込ませるNEXT.mdは、プロジェクトの直下に、数行で書いておきます。

## 次にやること
- 記事24のH2「通知」の下書きを確認する
- 公開前に fact-check.md の未確認項目を消す

このメモは、短く保つのがコツです。長くなると、毎回の起動で、その分だけ文脈を使ってしまうからです。

依頼ごとにルールを差し込む

起きた事故:作業ごとに守るべきルールを、別のファイルにまとめていました。ところが、記事を書く依頼のときに、Claudeがそのルールのファイルを読まずに書き始めることがありました。

自動で行うこと:依頼の内容を見て、関係するルールの場所を、毎回Claudeに添えます。

UserPromptSubmitは、あなたがプロンプトを送信した直後、Claudeが処理する前に発火します。フックは、プロンプトの文章をpromptという項目で受け取れます。

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/add-rules.sh"
          }
        ]
      }
    ]
  }
}
#!/bin/bash
# .claude/hooks/add-rules.sh
PROMPT=$(jq -r '.prompt')

# 依頼に「記事」が含まれていたら、記事のルールの場所を添える
if echo "$PROMPT" | grep -q '記事'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "UserPromptSubmit",
      additionalContext: "記事の依頼です。作業の前に rules/article.md を読んでください。"
    }
  }'
fi

exit 0

additionalContextに書いた文章が、Claudeの文脈に追加されます。公式ドキュメントには、additionalContextはhookSpecificOutputの内側に書かなければならず、JSONの最上位に置くと無視されると書かれています。書き間違えやすいので、この形をそのままコピーして使ってください。

なお、ここだけはexit 2ではなく、exit 0で、JSONを返す方法を使っています。先ほど説明したとおり、1つのフックでは「exit 2」か「exit 0+JSON」のどちらかに統一します。

1ターンの使用量を記録する

起きた事故:トークン(Claudeが処理する文字量の単位)を使いすぎた日がありました。ところが、どの作業で多く使ったのかが、後から分かりませんでした。

自動で行うこと:Claudeが応答を終えるたびに、時刻とセッションの情報を記録します。

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '[(now | todate), .session_id, .transcript_path] | @tsv' >> ~/.claude/turn-log.tsv"
          }
        ]
      }
    ]
  }
}

Stopのフックには、時刻・セッションID・会話の記録ファイルのパス(transcript_path)などが渡されます。このワンライナーは、それを1行にまとめて、~/.claude/turn-log.tsvに追記します。jqのnow | todateは、現在の時刻を日時の文字に変える書き方です(公式ドキュメントの設定変更を記録する例でも使われています)。

Stopは、あなたが途中で割り込んだときには発火しません。そのため、ログは「Claudeが応答を最後まで終えた回」だけの記録になります。

トークンの使用量そのものを日別・セッション別に集計したいときは、記録したログと合わせて、ccusageが便利です。手順は以下の記事で解説しています。

あわせて読みたい
ccusage完全マニュアル|インストール方法や便利な使い方をClaude Codeで解説 こんにちは、ハックです。 Claude Codeを使っていて、こんなことを感じたことはありませんか? 「なんで今日だけこんなに早く制限に引っかかったんだろう?」「毎回同じ...

Claude Code hooksの確認方法と削除・無効化

Claude Codeのhooksの確認・一時的な無効化・削除の3つの方法を並べた図解

フックを設定した後の、確認・無効化・削除の方法をまとめます。

確認:/hooksで、設定済みのフックを見られます。どのイベントにいくつ設定されているか、どのファイルの設定かが分かります。

削除:settings.jsonから、そのフックのエントリを消します。

一時的に全部を無効化:設定ファイルに、次の1行を書きます。

{
  "disableAllHooks": true
}

注意点は、個別のフックだけを、設定を残したまま無効にする方法はないことです。disableAllHooksは、すべてのフックをまとめて無効にします。1つだけ止めたいときは、そのエントリを消す(または別の場所に退避する)ことになります。

設定ファイルのhooksを直接編集した場合、変更は通常、自動で反映されます。数秒たっても/hooksに出てこないときは、ファイルの変更を見逃した可能性があります。セッションを再開して、読み込み直します。

フックが動かないときは、次の順で確認します。

症状確認すること
/hooksに出てこないJSONが正しいか(最後の,やコメントは書けない)/ファイルの場所が正しいか
出ているのに発火しないイベント名とmatcherが、ツール名と合っているか(大文字小文字を区別する)
hook errorと出るスクリプトが意図せずexit 0以外で終わっている。`echo ‘{“tool_name”:”Bash”,”tool_input”:{“command”:”ls”}}’ \./my-hook.sh`で試す
command not foundスクリプトのパスを絶対パスか$CLAUDE_PROJECT_DIRで書く
jq: command not foundjqをインストールする
スクリプトが実行されないchmod +xで実行権限を付ける

スクリプトの動作は、フックを登録する前に、自分で1回試すのがおすすめです。ターミナルで、サンプルのJSONを渡して動かします。

echo '{"tool_name":"Bash","tool_input":{"command":"rsync -av ./ server:/var/www"}}' | ./.claude/hooks/block-prod-write.sh
echo $?

echo $?は、直前のコマンドの終了コードを表示します。止めたい入力で2、通したい入力で0が出れば、スクリプトは想定どおりです。

実行の詳細を見たいときは、2つの方法があります。

  • Ctrl+Oを押してトランスクリプト表示を開く:ブロックされたときのフィードバックや、エラー通知が見られる
  • claude --debug-file /tmp/claude.logで起動し、別のターミナルでtail -f /tmp/claude.logを実行する:どのフックがマッチして、終了コードが何だったかまで見られる。起動後に見たい場合は、セッション中に/debugを実行する

なお、フックが成功したときは、画面には何も表示されません。動いているかどうかは、通知が鳴る・ファイルが整形されるといった「効果」で確認するか、デバッグログを見てください。

ここまでで直らない、Claude Code自体が動かない、といったときは、以下の記事でエラー文ごとの切り分けを説明しています。

あわせて読みたい
Claude Codeのエラー対処法|動かない・使えないときの原因と直し方 Claude Codeがエラーで動かない・使えないときなど、よくあるエラーの対処法を、初心者にもわかりやすくまとめてみました。500・529・429・401など、エラー文ごとの原因と、待つ・直す・切り替えるのどれをやるかがわかります。

追加設定(プラグイン・MCP・フック)が原因かを調べるには、claude --safe-modeで起動する方法も載せています。

MCPで追加したツールの実行も、フックで止められます。MCPサーバーの追加と設定は、以下の記事でまとめています。

あわせて読みたい
Claude Code MCPとは?設定方法・追加方法とおすすめMCPサーバー7選 Claude CodeのMCPとは何か?設定方法・追加方法を初心者にもわかりやすくまとめてみました。claude mcp addの使い方から、設定ファイルの場所(スコープ)、実際に使っているおすすめMCPサーバーまで詳しく解説します。

Claude Code hooksのベストプラクティス

Claude Codeのhooksを運用するときの4つのコツを示したチェックリスト

最後に、約20本のフックを運用してきて分かった、フックを増やしすぎないための考え方をまとめます。

ハック(Hack)

事故が起きるたびにフックを足していたら、いつの間にか約20本になっていました。すると、あるフックが別のフックの邪魔をして、肝心なときに止まってほしいフックが効かない、ということが起き始めました。今は、本当に重要なものだけに絞っています。「念のため」のフックは、増やさないのがコツです。

1. 1本目は、通知か、過去に起きた事故を止めるものにする

最初から何本も用意する必要はありません。通知を1本追加して、動くことを確かめたら、次は「実際に困った場面」を1つだけ選んで、フックにします。この記事の7つも、すべて実際の事故から作ったものです。

2. 発火する場面を絞る

matcherを省略したり"*"にしたりすると、そのイベントのたびに発火します。たとえばPreToolUseでmatcherを書かないと、ファイルを1つ読むたびにスクリプトが動きます。BashやEdit|Writeなど、必要なツールだけに絞ります。さらにif(例:"if": "Bash(git *)")を使えば、コマンドの中身が合うときだけスクリプトを起動できます。

3. フックが同時に動くことを前提にする

公式ドキュメントによると、同じイベントにマッチするフックは、並列(同時)に実行されます。いくつかの決まりがあります。

  • ひとつのフックがdenyを返しても、同じイベントの別のフックの実行は止まらない(ログを書くフックは、止められた操作でも記録を残す)
  • 複数のフックの結果は、最も厳しい判断が優先される(denyがallowより強い)
  • 複数のPreToolUseフックが、ツールへの入力を書き換える(updatedInput)と、最後に完了したものが勝つ。フックは並列で動くので、順番は決まらない。同じツールの入力を書き換えるフックを、複数作らない

僕が「フックが干渉した」と感じたのは、まさにこの部分でした。同じ場面を対象にしたフックが複数あると、どれが効いているのか分からなくなります。

4. 止めるときの理由を、Claudeに分かる文で書く

exit 2のときの標準エラー出力は、Claudeへのフィードバックになります。「Blocked」だけでなく、「本番への書き込みは ./deploy.sh を使ってください」のように、次に何をすればいいかまで書きます。Claudeは、それを読んで、やり方を変えます。

5. exit 2を使う

止めたいときにexit 1を使うと、止まりません。ポリシーを守らせたいフックには、必ずexit 2を使います。

6. フックで書いたルールは、settings.jsonと一緒にバックアップする

~/.claude/settings.jsonとフックのスクリプトは、セットで保存します。スクリプトだけ消えると、command not foundのエラーが、毎回のツール実行のたびに出てしまいます。

7. 自動整形にはPostToolUse、ただしBash経由の書き換えは別に考える

公式ドキュメントにあるとおり、Claudeは、シェルコマンドの実行によってファイルを作成・変更することもできます。Edit|Writeだけをmatcherにしたフックでは、Bash経由で書き換えられたファイルを見逃します。すべてのファイル変更を確認したいときは、ターンごとに1回、作業フォルダ全体をチェックするStopフックを追加します。

なお、ifフィルターは「ベストエフォート」の絞り込みです。公式ドキュメントは、許可・拒否を確実に強制したい場合は、フックではなく権限システム(permissions)を使うよう案内しています。フックは「止める仕組み」として強力ですが、権限の設定と組み合わせて使うのが安全です。

権限の書き方は、以下の記事で説明しています。

あわせて読みたい
Claude Codeの初期設定ガイド|settings.jsonの場所と権限の書き方 Claude Codeの設定ファイルの場所と、最初にやっておきたいおすすめ設定をまとめました。モデル・effort・学習オプトアウトから、許可(allow)と拒否(deny)の権限設定の書き方までわかります。(※コピペで使えるおすすめ設定テンプレート付)

まとめ:Claude Code hooksは、通知1本から始めて、事故を止めるフックへ広げる

  • hooksは、Claude Codeの動きの決まったタイミング(イベント)で、コマンドを必ず実行する仕組み。CLAUDE.mdは「お願い」、hooksは「仕組み」
  • 書き方は、settings.jsonに「イベント → matcher → command」の3段で書く。止めたいときはexit 2(exit 1は止まらない)
  • Macの通知と音は、NotificationやStopにosascriptとafplayを登録するだけ。デスクトップアプリは設定なしで通知が出る
  • 実運用のフックは、過去の事故から作る。本番書き込み・個人情報・根拠なしの公開・重複記事をPreToolUseで止め、SessionStart・UserPromptSubmit・Stopで読み込み・添付・記録をする
  • 増やしすぎると、フック同士が干渉する。本当に重要なものだけに絞る

hooksは、最初、非エンジニアにとってはややとっつきにくく感じますが、最初の1つを設定するまではハードルが高く感じる機能です。でも、実際にやってみると意外とそう難しいことはありません。通知の設定なら、settings.jsonに10行ほど追加するだけで動きます。

まずは、この記事の「Macで通知を出す」の設定を、~/.claude/settings.jsonに追加してみましょう。

/hooksで1件と表示されて、通知が出たら、次は「過去に困った場面」を1つ思い出して、止めるフックを作ってみてください。

出典(Anthropic公式ドキュメント・2026年10月1日確認)

以上、ハックでした!いつも読んでくださり、ありがとうございます🙏


AI HACKSでは、AIの活用術、0からの起業・副業・最新のAIトレンドニュースなどをリアルタイムで発信しています。その他、AIで開発した無料アプリ・ツール・プロンプトテンプレートなども随時公開中です。

note (ai_hacks_jp) や、𝕏(@ai_hacks_jp)でも日々、AIの実践情報を投稿しています。

Claude Code hooksとは?使い方と設定方法・通知の活用例

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

ABOUT

AI駆動ソロプレナー
AIを活用した個人開発・起業・副業に関する最新の情報を発信しています。

目次