Claude Code に通知機能を追加

Claude Code に通知フックを組み込んでいる。エージェントが判断を求めて止まったとき作業が完了したときエラーで停止したときの3場面で、Windows のトースト通知を出す仕組みで、現在の仕様は以下のとおり。

3
通知する場面
(確認待ち・完了・エラー)
60秒
完了通知を出す
下限のしきい値
1本
PowerShell
スクリプト
0
追加インストール
したモジュール

通知を出す3つの場面

通知は3種類。それぞれ別の音を割り当ててあり、鳴った音だけで用件が区別できる。

Claude Code
確認待ち — agent
Bash コマンドの実行許可を求めています
閉じる
判断を求めて止まった 許可プロンプトや入力待ちで停止した瞬間に鳴る。経過時間のしきい値はない。ただし許可プロンプトは自動運転系のモードのときだけ鳴る(後述)
Notification.Reminder
Claude Code
作業完了 — agent / 5.2分
調査結果を3つのファイルにまとめました
閉じる
作業が終わった 応答の末尾を要約して本文に載せる。開始から60秒以上かかったときだけ鳴る
Notification.Default
Claude Code
エラーで停止 — agent / 4.0分
ドライブに接続できませんでした。VPN が切れているため先に進めません
閉じる
失敗して止まった 完了時の応答が失敗を示していた場合に鳴る。完了と同じ60秒のしきい値が適用される。音だけが完了と別
Notification.IM

見出しには作業フォルダ名が入る。複数のセッションを並行で走らせていても、どのプロジェクトからの通知かが通知だけで分かる。

通知の方式 — 単発音・常駐表示

音は一度だけ鳴って終わる。通知そのものは操作するまで画面から消えない。Windows のトーストは既定では数秒で消えて通知センターに埋もれるが、scenario="reminder" を指定してあるため自動では引っ込まない。

音を聞き逃しても、見逃しにはならない。

音が「いま起きたこと」を、居残るトーストが「戻ってきたとき」を受け持つ構成になっている。

完了通知のしきい値 — 60秒

完了・エラーの通知には下限のしきい値がある。開始(ユーザーが送信した時刻)から60秒未満で終わったターンでは、完了・エラーいずれも鳴らさない。しきい値の対象外は確認待ちだけで、これは経過時間にかかわらず鳴る(許可プロンプトはモードによる出し分けが別にある。次項)。

02040 80100120秒 60 しきい値 鳴らさない 鳴らす 60秒未満の短い応答 60秒以上かかった応答 経過時間 = ユーザーが送信してから応答が終わるまで
図1 完了・エラー通知のしきい値。60秒未満で終わった場合はどちらも鳴らさず、60秒以上ならどちらも鳴らす対象になる(完了かエラーかは応答内容で別途判定)。確認待ちはこのしきい値の対象外。

確認待ちの出し分け — permission_mode

確認待ち通知のうち、許可プロンプトnotification_typepermission_prompt)だけは、経過時間ではなくそのターンの権限モードで出し分けている。defaultplan(目の前で承認する通常モード)では鳴らさず、acceptEditsautobypassPermissionsdontAsk の自動運転系モードのときだけ鳴る。許可プロンプト以外の確認待ち(入力待ちアイドルなど)はモードに関わらず常に鳴る。

モードの判定に使う値は、UserPromptSubmit が送信のたびに記録している。開始時刻とあわせて、そのターンの permission_mode を一時ファイルに書き、Notification がそれを読んで比較する。

仕組み — フック3点

Claude Code には、セッション中の特定のタイミングで任意のコマンドを実行するフックという機構がある。使っているのは3つ。

セッションの時間 → エージェントが作業中(画面を見ていない) 続きの作業 送信した(無音) 判断を求めて止まった 応答が終わった UserPromptSubmit Notification Stop 時刻とモードを記録 許可プロンプトはモード次第 60秒以上なら鳴らす
図2 3つのフックの発火位置。UserPromptSubmit は通知を出さず、開始時刻とそのターンの permission_mode を一時ファイルに書くだけ。Stop は経過時間を、Notification はモードを、それぞれこのファイルから読んで判定する。ユーザーの送信を起点にしているので、エージェントの実作業時間ではなく人間が待っていた時間で判定される。
フック発火するときやること
UserPromptSubmitユーザーが送信した開始時刻と permission_mode を記録するだけ。通知は出さない
Notification許可プロンプト・入力待ち「確認待ち」を通知。許可プロンプトはモードで出し分け、それ以外はしきい値なしで常に鳴らす
Stop応答が終わった経過時間が60秒以上なら、内容を見て「完了」または「エラー」を通知

設定はユーザー全体の settings.json に置いてある(プロジェクト単位ではない)。

// ~/.claude/settings.json(抜粋)
{
  "hooks": {
    "Stop": [
      { "hooks": [ {
          "type": "command",
          "command": "powershell -NoProfile -File notify.ps1 -Event Stop",
          "timeout": 20
      } ] }
    ]
  }
}
フックは標準入力で JSON を受け取る。Stop なら transcript_path が渡ってくるので、会話ログの末尾から直近の応答本文を拾って通知の本文に使える。

「エラーで停止」の判定はこの応答本文を使う。専用のフックは無いため、末尾の文面に失敗を示す語が含まれているかで振り分ける方式になっている。誤判定した場合も音の種類が変わるだけで、通知が出ること自体は変わらない。

実装要件

  • PowerShell 5.1 で実行する。トースト表示に使う Windows.UI.Notifications 型は PowerShell 7 には存在しないため、フックのコマンドは 5.1 の絶対パスを指定してある。
  • スクリプトは UTF-8 BOM 付きで保存する。PowerShell 5.1 は BOM の無い .ps1 を cp932 として読むため、BOM が無いと日本語コメントとヒアストリングの終端が壊れる。
  • 送信元の表示名を登録してある。HKCU\SOFTWARE\Classes\AppUserModelId にキーを作り「Claude Code」の表示名を設定。Windows の通知設定に独立した項目として並び、個別にオン・オフできる。
  • 追加モジュールは使っていない。Windows の Windows.UI.Notifications を直接呼び出しており、BurntToast 等は不要。

エージェント側の運用ルール

通知の仕組みに加えて、そもそも停止の回数を減らすための作法をエージェント側の記憶として持たせてある。以降のセッションにも引き継がれる。

  • 長い作業に入る前に、所要の見込みを一言告げる。
  • 確認事項は途中で小出しにせず、着手前にまとめて聞く。

まとめ

  • 通知は3種類——確認待ち・完了・エラー——で、それぞれ別の音が鳴る。見出しには作業フォルダ名が入る。
  • 音は単発、通知は scenario="reminder" により操作するまで残る。
  • 完了・エラーは開始から60秒未満なら鳴らさない。しきい値の対象外は確認待ちだけ。
  • 許可プロンプトはモードで出し分ける。defaultplan では鳴らさず、acceptEditsautobypassPermissionsdontAsk のときだけ鳴る。判定用のモードは UserPromptSubmit が毎ターン記録する。
  • UserPromptSubmitNotificationStop の3フックで構成し、設定は ~/.claude/settings.json
  • 実行には PowerShell 5.1・UTF-8 BOM・AppUserModelId 登録が要る。追加モジュールは不要。
  • エージェント側には、所要見込みの事前告知と確認事項の事前集約というルールも持たせてある。
タイトルとURLをコピーしました