本ページはプロモーションが含まれています

AI

Claude Code hooksの使い方|主要イベントと設定例・通知音の変え方

hooks(Claude Codeのイベントと設定例)

トム

SESで約8年、環境を変えられないもどかしさの中にいました。32歳で自社開発企業に転職し、今はClaude Codeと自動化で、仕事も時間も組み直している途中です。
・Javaバックエンドエンジニア(Java歴12年以上)
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎
詳細なプロフィール

「hooksを設定したのに、なぜか通知が鳴らない」「lintを毎回手動で走らせるのが面倒」。

Claude Codeを使い込むほど、そうした細かい引っかかりに気づくはずだ。

Claude Code hooksは、ファイル編集やコミットといった特定のイベントが起きた瞬間に、あらかじめ登録したシェルコマンドを問答無用で実行する仕組みだ。

CLAUDE.mdに「編集後はlintを回して」と書いても、Claudeが忘れることはある。hooksは違う。決定論的に、毎回必ず動く。

PreToolUse・PostToolUseなど実務で使う主要イベントの発火タイミング、.claude/settings.jsonにそのまま貼れる設定例(自動lint・タスク完了通知・危険コマンドのブロック)、「hookが動かない」ときに確認すべきポイントまでをコード付きで押さえられる。

ただし2026年に入ってイベントの種類は9個どころではなくなった。

実務でよく使うのはごく一部だが、その全体像を知らないまま組むと、あとで「このイベント名、もう無いのか」と手戻りする。

この記事でわかること

  • PreToolUse・PostToolUseなど実務で使う主要イベントの発火タイミングと使いどころ
  • .claude/settings.jsonにそのまま貼れる設定例(自動lint・タスク完了通知・危険コマンドのブロック)
  • 「hookが動かない」ときに確認すべきポイントとログでの原因特定方法
  • matcherを広げすぎない・外部入力を埋め込まないといったセキュリティ上の注意点
  • 通知音を好きな効果音に差し替える方法(terminal-notifierとドラクエの効果音の例)

Claude Codeのhooksとは?

Claude Code hooksとは何かを示す図解

Claude Codeのhooksは、特定のイベントが発生したタイミングで、あらかじめ設定しておいたスクリプトやコマンドを自動的に実行する仕組みです。

例えば、「ファイルを編集したら」や「Claudeが応答を終えたら」といったイベントをきっかけ(トリガー)に、さまざまな処理を自動で動かせます。

hooksの役割と仕組み

hooksの最大の役割は、開発ワークフローの自動化です。

釣りで魚を「フック」にかけるように、ツールの実行やセッションの開始・終了などの特定のイベントに処理を引っかけて自動実行させます。

開発者が手動で行っていた作業をClaude Codeが肩代わりしてくれるんです。

仕組みは、開発者が設定ファイルに「いつ」「何をするか」を定義し、実行スクリプトを配置するだけ。

残りはClaude Codeが引き受け、イベントを監視して条件に合致したタイミングでスクリプトを実行してくれます。

ここで押さえておきたいのが、CLAUDE.mdへの指示との違いだ。

CLAUDE.mdに「編集後はlintを回して」と書いても、それはあくまでモデルへのお願いであり、モデルが確率的に従うものにすぎない。

従わないこともある。一方hooksは、Claude Codeのハーネス自身が必ず実行する。だから判断基準はシンプルだ。

毎回絶対に実行してほしい処理(lint・フォーマット・危険コマンドのブロック)はhooksに任せ、多少のブレを許容できる方針はCLAUDE.mdに書けば十分、ということになる。

あわせて読む

なぜhooksが必要なのか

hooksが必要な理由は、主に3つあります。

ポイント

  1. コードフォーマットの統一や、テストの実行忘れといった、人が作業することで起こりがちなミスを未然に防ぐ
  2. これまで手動で行っていたビルド、テスト、デプロイなどの定型作業を自動化
  3. チーム全員に同じルール(例えば、コミット前に必ずlintチェックを行うなど)を強制する

Claude Codeにおけるhooksの位置づけ

Claude Codeにおいて、hooksはローカルの開発セッション内でイベント駆動の自動化を実現する機能です。

GitHub ActionsのようなCI/CDパイプラインそのものを構成する仕組みではない。

コミット前のlintやフォーマットなど、CI/CDに送り出す前の品質担保を手元で肩代わりする役割に近いといえます。

GUIで設定する複雑なパイプラインとは異なり、コードベースで手軽に自動化を導入できるのが大きな特徴。

小規模なチェックから本格的なデプロイフローまで、幅広い用途に対応できる柔軟性を持っています。

まさに、開発者のかゆいところに手が届く機能といえるでしょう。

hooksはどう使う?【基本編】

Claude Code hooksの基本的な使い方の手順を示す図解

ここからは、実際にClaude Codeでhooksを使うための基本的な手順を解説します。

hooksの設定は、settings.jsonを直接編集して行う。/hooksコマンドは、設定済みのhooksを確認するための閲覧用メニューだ。

/hooksコマンドで設定済みのhooksを確認する

Claude Codeのチャット欄で/hooksと入力すると、設定済みのhooksを一覧できる読み取り専用のブラウザが開く(hooksの追加・編集はここからはできない)。

各hookについて、定義されている設定ファイル(ユーザー設定・プロジェクト設定・プラグインなど)と、実行されるコマンドの全文を確かめられる。設定を書いたあとに「意図したhookが読み込まれているか」を確認するのに便利だ。

hooksを追加するときは、settings.jsonを編集するか、Claudeに設定を依頼する。書き込み先の使い分けの目安は次のとおり。

  • 通知音やログなど個人的な設定 → ~/.claude/settings.json
  • 危険コマンドのブロックなどチームで統一したいルール → .claude/settings.json(Gitで管理し、チーム全員に共有)
あわせて読む

hooksを設定する手順

ここからは、settings.jsonを直接編集する方法を見ていく。

  1. 以下の設定ファイルを作成する
text
.claude/settings.json
  1. 設定ファイルに“hooks”セクションを追加する。たとえば、ファイル編集後にlintを走らせたいなら、以下のように書く。
text
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npm run lint"
          }
        ]
      }
    ]
  }
}

3. スクリプト本体(もし自作するなら)を用意・実行可能に

例えば ./.claude/hooks/pre-commit-check.shのようなスクリプトを作って、それを設定ファイルの command で呼び出します。

bash
#! /bin/sh
echo "Lint & testsを実行します..."
npm run lint
npm test

作成後に、

bash
chmod +x .claude/hooks/pre-commit-check.sh

を実行して実行権限を付与します。

event

フック(hook)イベント の一覧と、それぞれの意味・使いどころです。

本記事の内容はClaude Code公式ドキュメント(code.claude.com/docs/en/hooks)の記載に基づきますが、Claude Code自体のアップデートで挙動が変わる可能性があるため、重要な自動化を組む前には公式ドキュメントで最新仕様を確認するとよいでしょう。

イベント名いつ発火するか主な用途・補足
PreToolUseツールを実行する直前(“tool call” を起こす前)に発動。 ツールの実行を 制御する(ブロック・許可)ために使う。例えば「このディレクトリのファイルを編集しようとしてる?それ、大丈夫?」というチェックに。 
PostToolUseツールが 成功裏に終了したあと に発動。 ツール実行後の “後片付け” や “フォーマット” や “ログ記録” に最適。実行を取り消すには遅いタイミングなので、「実行後のチェック・追加作業」が主。
NotificationClaude Code がユーザーに通知を出す時(例:ユーザー入力を待った/ツール使用許可を求めた)に発動。 通知をカスタム化したり、デスクトップ通知・サウンド・ログを差し込んだり。
UserPromptSubmitユーザーがプロンプト(質問・指示)を送信した 直後に発動、つまり Claude に処理される前。 プロンプトの内容を検証したり、補足コンテキストを付加したり、特定タイプの入力をブロックしたり。
Stopメインの Claude Code エージェントが応答を終了したときに発動(ただし、ユーザー割り込み/中断による停止では発動しない)。 セッション終了時の “クリーンアップ” やログ書き出し、次のタスク起動などに。
SubagentStop“サブエージェント”(タスクとして起動された別インスタンス)終了時に発動。 例えば内部で複数のエージェントを並行実行しているとき、「このサブタスク終わったぞ」というタイミングで何かを挟む。
PreCompactClaude Code がコンテキストを圧縮(compact)しようとする直前に発動。 セッション中の文脈(会話履歴)が大きくなってきたとき、自動で整理・圧縮される “compact” 処理に先立って何かを行う。
SessionStart新しいセッションを開始する、または既存セッションを再開するタイミングで発動。 プロジェクトのコンテキストロードとか、初期化処理、前回セッションの復元などに利用。
SessionEndセッションが終わる(終了・クリア・ログアウトなど)ときに発動。 セッション統計を書いたり、リソース解放したり、ログ出力など
PostToolUseFailureツールの実行が失敗した直後に発動。 エラー内容に応じた後処理・リトライ判断・エラーログの集約に使う。
PermissionDenied自動モードでツール実行の権限が拒否されたときに発動。 拒否理由の記録や、代替手段への切り替え通知に使う。
SubagentStartサブエージェントが起動したときに発動。 SubagentStopとペアで使い、サブエージェントの実行時間計測やログの開始点記録に使う。
TaskCompletedタスク管理ツールでタスクが完了としてマークされたときに発動。 完了条件のチェック(品質ゲート)や進捗通知に使う。

2026年に入りイベントの種類は大幅に増え、2026年10月時点の公式hooksリファレンスには33種類が載っている(イベントは随時追加されるため、最新の一覧は公式ドキュメントで確認したい)。

上記のイベントは実務で最もよく使う顔ぶれであり、まずはここから使い始めれば十分だ。

matcher

matcher は、フック設定内で「どのツール実行(またはどの条件)に対してこのフックを走らせるか」を指定するフィルターです。

つまり「ツール名」「ツールの入力/出力」「ファイルパス」といった条件にマッチしていたら、該当フックが発動する、という仕組みです。 

具体的には、以下のようなルールがあります

  • matcher は主に PreToolUse/PostToolUse イベントのときに使われます。 
  • matcher に指定できる値としては ツール名の文字列(厳密一致)や、正規表現パターン(例:Edit|Write)が使えます。 
  • すべてのツールに対してフックを走らせたいときは matcher: "*" や空文字 "" で “無条件” に設定可能です。 

いくつか matcher を使うときに押さえておくべき仕様ポイントがあります。

キーワード説明
ツール名一致(exact match)例えば matcher: "Write" と書けば「ツール名がちょうど Write のとき」に発動。 
正規表現/複数候補matcher: "Edit|Write" のようにパイプ(|)区切りの正規表現で複数ツールをOR条件指定できる。 
ワイルドカード/空文字matcher: "*" や matcher: ""(もしくは matcher を省略)で「すべてのツール/条件」に適用可能。 
大文字・小文字区別公式ドキュメントでは、matcherは大文字・小文字を区別するとされている。つまり “Write” と “write” は別扱い。 
対象イベント限定matcherは主にPreToolUse・PostToolUseで使われるが、PostToolUseFailureなど拡張イベントの一部でもツール名で絞り込める。Notificationはツール名ではなく通知の種類(permission_prompt・idle_promptなど)で絞り込む。UserPromptSubmit・Stopなどmatcherを持たないイベントでは、matcherは指定しても使われない。なお、PermissionRequestはmatcherを持たず、毎回発火する(絞り込みたいときはifフィールドを使う)。 

イベントによってmatcherが受け付ける値も変わる。

例えばSessionStartはstartup|resume|clear|compact|fork、SessionEndはclear|resume|logout|prompt_input_exit|otherのように、ツール名ではなく「何がきっかけで発生したか」という区分を指定する形になる。

ツール名でmatcherするのはPreToolUse・PostToolUseなど一部のイベントに限られる点を押さえておこう。

利用可能なツール名(matcher で指定する値)は、主に以下のようなものがあります。

ツール名説明
Bashシェルコマンドを実行するツール
Readファイルを読み込むツール
Editファイルの一部を編集するツール
Writeファイルへの書き込みを行うツール
Globファイルパターンで検索するツール
Grepファイル内容を正規表現で検索するツール
WebFetchWeb ページの情報を取得するツール
WebSearchWeb検索を行うツール
NotebookEditJupyter Notebookを編集するツール
Agent(旧称Task)サブエージェントを起動するツール
TodoWriteタスクリストを管理するツール

matcherを正規表現で書くときは、思っている通りにマッチしているかを事前に確認したほうがいい。

実際にPythonのreモジュールで検証してみると、"Edit|Write"はEditとWriteだけに一致し、"mcp__memory__.*"はmcp__memory__storeのようなMCPツール名に一致する。

一方で、公式ドキュメントによると、英数字・_・-・|・,・空白だけの文字列は完全一致の名前(のリスト)として扱われ、それ以外の文字を含むとアンカーなしのJavaScript正規表現として扱われる。"^Notebook"はNotebookEditのようにNotebookで始まるすべてのツールに一致する。逆に"Edit.*"のように先頭を固定しない書き方は、EditとNotebookEditの両方に一致してしまう。ツール名ちょうどに絞りたいときは"^Edit$"のように前後を固定する。

「先頭を固定したつもりのmatcherが、意図しないツールにも一致していた」という事故を避けるために、本番投入前に一致するツールを確認しておく習慣をつけたい。

type

typeで指定できる値は現在5種類ある。

シェルコマンドを実行するcommand、外部URLへPOSTするhttp、接続済みMCPサーバーのツールを呼び出すmcp_tool、LLMに単発で判定させるprompt、ツールを使えるサブエージェントを起動して検証させるagentだ。

promptとagentはすべてのイベントで使えるわけではなく、対応イベントは限られる。

commandタイプには、実行を細かく制御するオプションも用意されている。

argsでコマンドへの引数を配列として分離指定でき、コマンド文字列を組み立てる際のクォート崩れを避けられる。

async: trueを指定すると、hookの完了を待たずに次の処理へ進む(重い処理をブロッキングにしたくないとき向き)。

スクリプトのパスは./.claude/hooks/xxx.shのような相対パスではなく、${CLAUDE_PROJECT_DIR}/.claude/hooks/xxx.shのようにプレースホルダーで指定するのが安全だ。

相対パスはClaude Codeの実行時カレントディレクトリに依存するため、プロジェクトルート以外から起動されると解決に失敗することがある。

あわせて読む

条件付き実行(ifフィールド)と環境変数の活用

hooksの設定には、type以外にも実務でよく使う制御用フィールドがある。代表的なのがifフィールドとallowedEnvVarsだ。

  • if(条件付き実行): 例えば"if": "Bash(rm *)"のように書くと、実行しようとしているBashコマンドがrmで始まるときだけhookを発動できる。すべてのBash実行にhookをかけたくない場合に便利。
  • allowedEnvVars(環境変数の許可リスト): httpタイプでSlack通知やWebhookに外部送信する際、allowedEnvVarsで明示的に許可した環境変数だけが送信対象になる。意図しない値の漏洩を防ぐ仕組みだ。
  • timeout・once: timeoutでhookの実行時間上限を秒単位で指定でき、onceをtrueにすると最初に成功した実行のあとでhookが取り除かれるが、これはスキルのフロントマターに書いたhookでのみ有効で、settings.jsonに書いても無視される。

hooksを使う上でのセキュリティ上の注意点

hooksは便利な反面、ユーザーの権限で任意のシェルコマンドを無条件に実行する仕組みでもある。ここを軽視すると、自動化のつもりが事故の入り口になる。

  • matcherを広げすぎない: matcherを"*"にして全ツールに同じhookをかけると、意図しない操作にまでコマンドが発火する。まずは特定のツール・イベントに絞って検証し、動作を確認してから対象を広げるほうが安全だ。
  • 外部入力をコマンドにそのまま埋め込まない: ツールの入力値やプロンプト内容を検証せずにシェルコマンドへ展開すると、コマンドインジェクションのリスクがある。固定コマンド+引数を渡す形に留め、動的な文字列展開は最小限にする。
  • チーム共有設定はレビューを通す: .claude/settings.jsonはGitで管理されチーム全員に配布される。追加・変更するコマンドは、通常のコード変更と同様にプルリクエストでレビューしてからマージする運用が推奨される。

PreCompactイベントの使いどころ

長時間セッションでは、会話履歴が一定量を超えるとClaude Codeが自動でコンテキストを圧縮(compact)する。

PreCompactは、その圧縮が実行される直前に発火するイベントだ。

圧縮されると、それ以前の会話の細かい経緯は失われやすい。

PreCompactで圧縮直前の会話ログをファイルに書き出しておけば、あとから「あのときどういう判断をしたか」を追いかけられる。

text
"hooks": {
    "PreCompact": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "mkdir -p .claude/logs && jq -r .transcript_path | xargs -I{} cp {} .claude/logs/pre-compact-$(date +%s).jsonl"
          }
        ]
      }
    ]
}

基本イベント以外の拡張イベント(PermissionRequest・TaskCompletedなど)

ここまで紹介した9イベント(PreToolUse・PostToolUse・Notification・UserPromptSubmit・Stop・SubagentStop・PreCompact・SessionStart・SessionEnd)は基本セットにすぎない。

実際にはさらに多くのイベントが存在する。

代表例がPermissionRequest(権限確認ダイアログが表示されるタイミングで発火し、自動許可・自動拒否の判定に使える)、PostToolUseFailure(ツール実行が失敗した直後に発火し、エラー内容に応じた後処理に使える)、PermissionDenied(自動モードでツール実行が拒否されたときに発火)、SubagentStart(サブエージェントの起動時に発火。

終了時のSubagentStopとペアで使う)、TaskCompleted(タスク管理ツールでタスクが完了マークされたときに発火し、品質ゲートとして使える)だ。

古い情報や勘違いによる誤った名称にも注意したい。PostResponseという名称のイベントは存在せず、応答完了時に使うべきはStop。

PreResponseではなくUserPromptSubmitが該当する。

すべてのイベントを網羅的に覚える必要はなく、まずは基本の9イベントから使い始めれば十分だ。

hookが「ブロックできる」かどうかは、実はexit codeで機械的に決まる。

終了コードでブロックできるのはexit code 2のときだけで(ブロックできるイベントに限る。JSONでdecisionを返す方法もある)、それ以外の非ゼロ値(exit 1を含む)は「非ブロッキングのエラー」として扱われ、処理はそのまま続行される。

「exit 1で止まるはず」という思い込みは、hooksを組むときに誰もが一度は踏む典型的なハマりどころだ。

例で理解するhooksの流れ

上記で設定したhooksのもう少し具体的なhooksの流れを見てみましょう。

  1. ユーザーの操作 ユーザーが Claude Code を使用してファイルを編集する。例えば、コードエディタで TypeScript ファイルを開いて内容を変更
  2. ツールの呼び出し Claude Code は内部で Edit ツールを使用して、編集されたファイルを処理
  3. フックのトリガー PostToolUse イベントが発生し、matcher が "Edit" に一致するため、設定されたフックが実行
  4. コマンドの実行 フック内で指定されたコマンド(この場合は npm run lint)が実行
  5. 結果の確認 npm run lint の実行結果がターミナルに表示され、コードの静的解析結果を確認

hooksを活用した実践例

Claude Code hooksを活用した実践的な自動化例を示す図解

基本を理解したところで、次はより実践的なClaude Codeのhooks活用例を3つ紹介する。これらの実践例を参考に自動化を導入してみよう。

実践例に共通するのは、いずれも数行のJSON設定だけで導入できる点だ。

自動通知(サウンド再生)

MacのClaude Codeの作業が完了した際に自動で通知音を送るhooksです。

通知音をオリジナルの効果音に変える方法は、後述の「通知音をカスタムする実例」で詳しく解説します。

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

通知をSlack・Telegramにも広げる

macOSのサウンド通知だけでなく、Notificationイベントを使えばSlack・Telegramなどチャットツールへの通知にも広げられる。

離席中や長時間タスクの実行中でも気づきやすくなるのが利点だ。

例えば、Slack Incoming Webhookへcurlでメッセージを送る場合の設定は以下のようになる。

text
"hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "curl -X POST -H 'Content-type: application/json' --data '{\"text\":\"Claude Codeがユーザー入力を待っています\"}' https://hooks.slack.com/services/XXXX/XXXX/XXXX"
          }
        ]
      }
    ]
}

通知先を複数登録したい場合は、hooks配列に実行したいコマンドを並べて追加するだけでよい。

pre-commitでのlintとフォーマット実行

これは最も一般的で効果的なhooksの一つです。

ファイル編集のたびにESLintやPrettierといったツールを自動実行し、コーディング規約に沿わないコードが残るのを防ぎます。

text
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "sh ./.claude/hooks/pre-commit-check.sh"
          }
        ]
      }
    ]
  }
}

.claude/hooks/pre-commit-check.sh スクリプト例:

bash
#!/bin/sh
echo "コードフォーマットとlintチェックを実行中..."
npm run format
npm run lint

通知音をカスタムする実例|ドラクエの効果音に差し替える方法

Claude Codeを1日動かしていると、許可を求められるたび、処理が終わるたびに通知が鳴ります。私の環境ではhooksから通知を出していて、標準のシステムサウンドを鳴らしていました。何十回も聞くうちに単調に感じてきたため、ドラクエの効果音に差し替えました。

許可待ちは「カーソル音」、完了は「バシルーラのSE」にしています。ここでは、その手順と、つまずいた点を順に紹介します。

仕組み|terminal-notifierとhooksの組み合わせ

Claude Code本体に通知音を選ぶ設定項目は見当たらなかったため(2026年8月時点)、hooksから自前の通知を鳴らす形にしています。

~/.claude/settings.jsonのhooksで、PermissionRequestとStopの2イベントから、notify.shというシェルスクリプトを呼び出しています。

notify.shは、Claude CodeからJSONで渡されるイベント情報を受け取ります。種別に応じてメッセージとサウンドを切り替え、terminal-notifierでmacOSの通知として表示する仕組みです。

bash
if [ "$EVENT" = "permission" ]; then
  MESSAGE="ボス許可をくれ"
  SOUND="nc46869_ドラクエ_カーソル音"
else
  MESSAGE="ボス完了した"
  SOUND="nc479263_バシルーラのSE(HD-2D版_DQ3)"
fi
terminal-notifier -title "Claude Code" -message "$MESSAGE" -sound "$SOUND"

変更が必要なのは、MESSAGEとSOUNDの2つの変数だけです。まだterminal-notifierを入れていなければ、Homebrewで入れます(2026年8月時点で確認済みの手順)。

bash
brew install terminal-notifier

最初につまずいたのは、-soundオプションの仕様です。音声ファイルのパスを直接渡すのではなく、macOSのシステムサウンド名(拡張子を除いたファイル名)を指定する仕様になっています。ダウンロードフォルダに置いたwavファイルのままでは鳴らず、macOSがサウンドとして認識する場所に置く必要があります。

手順|~/Library/Soundsに置いてSOUND変数を書き換える

~/Library/Sounds/は、macOSが個人用のカスタムサウンドとして認識するディレクトリです。ここにwavファイルを置くと、拡張子なしのファイル名で参照できます。

bash
mkdir -p ~/Library/Sounds
mv ~/Downloads/nc46869_ドラクエ_カーソル音.wav ~/Library/Sounds/

次に、notify.shのSOUND変数を、拡張子を除いたファイル名に書き換えます。日本語や括弧を含むファイル名でも、そのまま指定して動きました。

notify.shを編集する前に、terminal-notifierを単体で叩いて鳴るか確認しておくと安全です。

bash
terminal-notifier -title "テスト" -message "音テスト" -sound "nc46869_ドラクエ_カーソル音"

完了と許可待ちで音とメッセージを鳴らし分ける

notify.shは、$EVENTが「permission」かどうかで分岐しています。許可待ちと完了で違う音を割り当てると、画面を見なくても耳だけで状況が分かります。

イベント音源役割
許可待ち(permission)ドラクエのカーソル音短く軽快な音で「反応待ち」を示す
完了(stop)バシルーラのSE存在感のある音で「終わった」を示す

メッセージ文言も同時に変えると、体験が統一されます。私は「許可を求めています」を「ボス許可をくれ」に、「処理が完了しました」を「ボス完了した」に変えました。

音量調整|ffmpegのvolumeフィルタで音源を加工する

効果音は、選んだ瞬間は満足しても、何度も鳴らすうちに「思ったより音が大きい」と感じます。terminal-notifierの-soundには音量のパラメータがないため、音源ファイル自体を加工します。

bash
ffmpeg -y -i 元ファイル.wav -filter:a "volume=0.5" 一時ファイル.wav
mv 一時ファイル.wav 元ファイル.wav

volume=0.5は、現在の音量の50%にするという意味です。同じファイル名で上書きすれば、notify.sh側の設定をそのまま使い回せます。

私は、倍率を0.7、0.5、0.5、0.2と4回に分けて掛け、最終的に元の音量の3.5%程度まで下げました。一気に下げると、下げすぎて無音同然になったときに大きい音源から作り直す羽目になります。少しずつ試して聞き直すのが、結果的に近道でした。

音が鳴らないときによくある原因

鳴らない場合は、次の3つのどれかに絞られます。

  • ファイル名のスペルミス(SOUND変数の値と~/Library/Sounds/内のファイル名が一致しているか)
  • ~/Library/Sounds/への移動漏れ(ls ~/Library/Sounds/で存在を確認)
  • macOSの通知設定で、terminal-notifierの通知がオフになっている

私は3つ目に気づかず、しばらく設定ファイルばかり疑っていました。通知そのものが出ているかを先に確認すると、原因の切り分けが早くなります。

ここでは2イベントだけを変えましたが、他のイベントにもそれぞれ別の音を割り当てられます。「今どのフェーズか」を耳だけで判別できる環境も作れます。

hooksを使うときによくあるエラーと対処法

Claude Code hooksでよくあるエラーとその対処法を示す図解

hooksは便利ですが、設定でつまずくこともあります。ここでは、よくあるエラーとその対処法を紹介します。

エラーの大半は「実行権限」「設定ファイルの記述ミス」「shebang」の3点に集約されます。

hookが動かないときに確認すべきポイント

「設定したはずなのにhookが動かない…」というときは、まず以下の3点を確認しましょう。

ポイント

  1. 実行権限は付与されているか?:最も多い原因です。chmod +x .claude/hooks/your-script-name.shコマンドで、スクリプトに実行権限が付与されているか確認
  2. 設定ファイルの記述は正しいか?:Claude Code hooksは、Gitフックのように決まった名前のファイルを.claude-hooksディレクトリに置く方式ではない。.claude/settings.json(または~/.claude/settings.json)のhooksセクションに、イベント名・matcher・実行コマンドをJSONで直接記述する方式。イベント名やmatcherの綴りにタイポがないか、JSONの構文が壊れていないかを確認する
  3. スクリプトのshebangは正しいか?:スクリプトの1行目に#!/bin/shや#!/bin/bashといったshebangが記述されているか確認。どのシェルでスクリプトを実行するかを指定する重要な記述
  4. シェルの起動ファイルが出力を汚染していないか?:.zshrcや.bashrcにechoやexportの出力メッセージが仕込まれていると、hookのコマンド実行時にその出力が標準出力へ紛れ込み、JSON形式の出力を期待するhookでパースエラーになることがある。対処法は、hookから呼ぶスクリプトの1行目を非対話シェル(#!/bin/sh等)にするか、.bashrc側で非対話実行時に早期returnする([[ $- != *i* ]] && return等)ことだ

ログで原因を特定する方法

問題が解決しない場合は、ログを確認するのが一番の近道です。

Claude CodeにはCtrl+Oで開くトランスクリプト表示があり、hookの失敗やブロックを確認できます(成功時は原則何も表示されず、失敗時は「〜 hook error」の通知とエラー内容の先頭行が表示される)。

フル情報が必要ならclaude --debug(または--debug-file <path>)で起動し、書き出されたデバッグログを読むと、どのhookが一致したか・終了コード・stdout/stderrの全文まで確認できます。

また、スクリプト内でset -xコマンドを実行すると、どのコマンドが実行されているかを詳細にログ出力できるため、デバッグに役立ちます。

hooks活用のベストプラクティス

Claude Code hooksを安全に活用するベストプラクティスを示す図解

要点は、フックを高速に保つこと・冪等性を意識すること・エラー処理を丁寧に行うことの3つだ。

安全にhooksを使うための設計指針

  • フックは高速に保つ: PreToolUseのようにClaudeの操作をブロックするhookは、処理が数秒で終わるように設計しましょう。重い処理(例: E2Eテスト)は、async: trueを指定して完了を待たずに実行するのがおすすめです。
  • 冪等性(べきとうせい)を意識する: フックスクリプトは、何度実行しても同じ結果になるように作りましょう。これにより、予期せず再実行された場合でも問題が起きにくくなります。
  • エラー処理を丁寧に行う: スクリプトが失敗した場合は、分かりやすいエラーメッセージを出力して処理を中断するようにします。これにより、問題の早期発見につながります。
あわせて読む

開発効率を上げるhooksの組み方

  • チームでhooksを共有する: .claude/settings.jsonと.claude/hooksディレクトリをGitの管理対象に含めることで、チーム全員が同じフックを利用できます。これにより、開発環境の差異による問題を減らし、チーム全体の生産性を向上させられます。
  • 小さな自動化から始める: 最初から複雑なワークフローを組もうとせず、まずは「コードフォーマットの自動化」のような、簡単で効果の大きいものから導入してみましょう。成功体験を積み重ねることが大切です。

よくある質問

Q1. Claude Code hooksとは何ですか?

A1. 特定のイベント(ファイル編集やコミットなど)が起きた瞬間に、あらかじめ登録したシェルコマンドを自動実行する仕組みです。CLAUDE.mdへの指示と違い、決定論的に毎回必ず動作します。

Q2. hooksはどこで設定しますか?

A2. .claude/settings.json(プロジェクト共有用)または~/.claude/settings.json(個人設定用)に、イベント・matcher・実行コマンドをJSON形式で記述します。Claude Codeのチャット欄で/hooksと入力すると、設定済みのhooksを確認できます(閲覧専用で、追加・編集はsettings.jsonで行います)。

Q3. hooksのtypeにはどんな種類がありますか?

A3. シェルコマンドを実行するcommand、外部URLへPOSTするhttp、MCPサーバーのツールを呼ぶmcp_tool、LLMに判定させるprompt、サブエージェントを起動するagentの5種類があります。

Q4. hookが動かないときはどう対処しますか?

A4. まずchmod +xでスクリプトに実行権限が付与されているか、.claude/settings.jsonのイベント名・matcherの綴りにタイポがないか、スクリプトのshebang(#!/bin/sh等)が正しいかの3点を確認します。

Q5. hooksで通知をカスタマイズできますか?

A5. はい。Notificationイベントを使えば、macOSのサウンド再生だけでなく、Slack Incoming WebhookへのcurlコマンドでSlack通知に広げることもできます。

Q6. CLAUDE.mdとhooksはどう使い分けますか?

A6. CLAUDE.mdへの指示はモデルが確率的に従うもので、毎回実行されるとは限りません。hooksはハーネスが決定論的に必ず実行するため、lint・フォーマット・危険コマンドのブロックなど「絶対に毎回実行してほしい処理」に向いています。

Q7. Claude Code hooksのイベントは全部で何種類ありますか?

A7. 基本の9イベント(PreToolUse・PostToolUse・Notification・UserPromptSubmit・Stop・SubagentStop・PreCompact・SessionStart・SessionEnd)に加え、2026年10月時点の公式リファレンスでは33種類まで拡大しています。実務でよく使うのは基本9イベントとPostToolUseFailure・PermissionDenied・SubagentStart・TaskCompletedなど一部です。

Q8. hookでコマンドの実行を確実にブロックするにはどうすればいいですか?

A8. スクリプトからexit code 2を返してください。終了コードでブロックできるのはexit code 2のときだけで(ブロックできるイベントの場合)、それ以外の非ゼロ値(exit 1を含む)は非ブロッキングのエラーとして扱われ、処理はそのまま続行されます。

Q9. Claude Codeの通知音は変更できますか?

A9. できます。hooksから呼び出すシェルスクリプト内で、terminal-notifierのSOUND変数をmacOSのシステムサウンド名に差し替えれば、好きな効果音を通知音にできます。

Q10. terminal-notifierの-soundに音声ファイルのパスを直接指定できますか?

A10. できません。-soundオプションはmacOSのシステムサウンド名(拡張子を除いたファイル名)だけを受け付けます。音源ファイルは~/Library/Sounds/に置く必要があります。

Q11. 通知音の音量を下げるにはどうすればいいですか?

A11. terminal-notifierの-soundには音量のパラメータがないため、ffmpegのvolumeフィルタで音源ファイル自体を加工します。一気に下げず、少しずつ試して聞き直す方法が安全です。

まとめ|Claude Codeのhooksで自動化の幅を広げよう

hooksの要点を整理すると、次のようになる。

  • hooksとは: 特定のイベントをきっかけに、処理を自動実行する仕組み。
  • 目的: ヒューマンエラーの防止、開発効率の向上、チーム開発の標準化。
  • 使い方: .claude/settings.jsonにイベント・matcher・実行コマンドをJSONで記述し、必要に応じて呼び出すスクリプトに実行権限を付与するだけ。
  • 活用例: Slack通知、lint実行、自動テスト、デプロイの自動化など。

hooksを使いこなせば、これまで手作業に奪われていた時間を取り戻し、より創造的な開発作業に集中できます。

REVISIONS / 改訂履歴
REV.DATE内容
42026-10-06記載内容の事実確認と修正
32026-08-292026年8月時点の情報で全体を見直し
22026-08-022026年8月時点の情報で全体を見直し(古い記述を6件更新)
12025-10-19初版
  • この記事を書いた人
  • 最新記事

トム

SESで約8年、環境を変えられないもどかしさの中にいました。32歳で自社開発企業に転職し、今はClaude Codeと自動化で、仕事も時間も組み直している途中です。
・Javaバックエンドエンジニア(Java歴12年以上)
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎
詳細なプロフィール

-AI