Claude Code を長時間動かしていて、確認待ち・アイドル状態を取りこぼしたくない開発者向け
Claude Code に夜間バッチや長時間リファクタを任せていて、画面を見ていない間に『この権限を承認していい?』や『20分くらい何もしてないけど大丈夫?』を取りこぼしたくない場面で使う。設定は .claude/settings.json の hooks セクションに Notification ブロックを足し、matcher に permission_prompt / idle_prompt などの種類を書いて、command にスクリプトの置き場所を書き込むことで仕込む
Notification は、Claude Code が画面の上で読者に何か知らせを出す瞬間を捕まえるフックです。具体的には「権限を承認していいですか」「30秒くらい何もしてないですけど大丈夫ですか」みたいなメッセージが Claude Code から出る、その瞬間に自前のスクリプトを走らせて、ターミナルでビープを鳴らす、Mac の通知センターに出す、Slack に流す、みたいな仕掛けを差し込めます。
長時間 Claude Code に作業させていて、画面を見ていない間に「permission を承認してください」が来て止まる、あれを防ぐための仕組みです。承認そのものを自動化する道具ではない、というのが地味に大事なポイント。
噛み砕くと、Claude が「ちょっと待った」を言った瞬間に走るベル
Notification を会議室のホワイトボードに例えると、こうなります。
Claude Code は黙々と作業しているけど、たまにホワイトボードに「これ消していいですか?」「20分くらい何も言われてないんですけど次どうします?」と書きにくる。Notification フックは「ホワイトボードに何か書かれた瞬間、隣のデスクのベルを鳴らす」担当です。
ベルを鳴らすだけで、書かれた内容に「いいよ」「ダメ」と答える権限は持っていません。返事は人間がやる前提。
大事な前提:matcher に書くのは「ツール名」じゃない
Notification の設定で一番転びやすいのがここ。matcher 欄に Bash や Edit を書いても、フックは絶対に発火しません。matcher が見ているのは「ツールの種類」ではなく「お知らせの種類」だからです。これを公式は notification type と呼んでいます。
公式が許す matcher 値は次の6種類だけ。
permission_prompt- 「このコマンド実行していい?」の権限確認idle_prompt- 一定時間入力がなくて Claude が確認してくる瞬間auth_success- 認証が通った瞬間elicitation_dialog- MCP サーバーが追加情報を聞いてくるダイアログを開いた瞬間elicitation_complete- そのダイアログのやりとりが終わった瞬間elicitation_response- ダイアログに返事が入った瞬間
PreToolUse / PostToolUse の matcher(あっちはツール名で絞る)と感覚で混同しがち。書式が似ているだけに、本気で踏みます。
「cooking-blog で夜中作業中にビープを鳴らす」を例に手順を見る
自分の cooking-blog プロジェクトを開いて、Claude Code に「レシピカテゴリのページを全部組み直して」とお願いした。寝る前に走らせて朝までに終わらせたい。けど途中で「rm -rf old-recipes/ を実行していい?」が出て、それに気づかず Claude がずっと止まっている、これが一番もったいない。Notification フックでビープを鳴らします。
ステップ1: フック用スクリプトをホームに置く
ホームフォルダ直下に notify-claude.sh を作って、以下を貼ります。これは公式 docs の Notification 用サンプルそのままで、メッセージ本文を抜き出してターミナル経由で OS に通知を出させる中身。
#!/bin/bash
# Notification hook: ping the desktop when Claude Code needs attention.
input=$(cat)
title="Claude Code"
body=$(jq -r '.message // "Needs your attention"' <<<"$input")
seq=$(printf '\033]777;notify;%s;%s\007' "$title" "$body")
jq -nc --arg seq "$seq" '{terminalSequence: $seq}'
仕組みは2段。標準入力で受け取った構造化データから message を取り出して、ターミナル用の特殊な制御文字列を組み立てる。それを terminalSequence として返すと、Claude Code 側がその文字列をターミナルに流して通知を発火させてくれます。
ステップ2: 実行できる状態にする
$ chmod +x ~/notify-claude.sh
これ忘れると、フックは登録されてもスクリプト自体が走らず無音で死にます。ハマる定番。
ステップ3: cooking-blog の settings.json にフックを登録する
プロジェクト直下の .claude/settings.json を開いて、hooks セクションに以下を足す。
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"command": "~/notify-claude.sh"
}
]
}
]
}
}
matcher を permission_prompt に絞っているので、権限承認の瞬間だけビープが鳴る。idle_prompt も鳴らしたければ、同じブロックの matcher を "permission_prompt|idle_prompt" にする手もあるし、別ブロックで分けてもいい。
ステップ4: 動作確認
Claude Code を cooking-blog で起動して、わざと権限が要りそうな指示を出します。たとえば「old-recipes/ フォルダを丸ごと消して」と頼む。「実行していいですか」のダイアログが出る瞬間に、ターミナルから「ピーン」と通知が出れば成功。
ステップ5: ここで初心者がやりがちな勘違い
「ビープが鳴ったら自動で『はい』と答えてほしい」と思って、フック側で承認を返そうとする人が多い。これはできません。Notification フックには decision control が無い、つまり「許可する/拒否する」の判定権限を持っていないからです。
承認の自動化をやりたいなら、Notification ではなく PreToolUse フックや PermissionRequest 側で permissionDecision を返すのが正解。Notification はあくまで「知らせを横取りして外に流す」役割。
ステップ6: stderr で気づくミスもある
スクリプトが失敗したとき、Notification フックは exit code 2 で抜けても Claude Code を止めることはできません。標準エラー出力(stderr)に出した内容がユーザー画面に表示されるだけ。だからスクリプトのデバッグ中は、echo "debug: ..." 1>&2 で stderr に流して挙動を確認すると速いです。
つまり Notification は何をしてくれるのか
- やってくれる: Claude Code が画面に通知を出す瞬間を捕まえて、自前のスクリプトで OS 通知・ビープ・Slack 連携・ログ書き出しを走らせる。matcher で「権限確認だけ」「アイドルだけ」と種類を絞れる
- やってくれない: 通知の内容に対して「はい/いいえ」を機械的に答えること。承認自動化は別フックの仕事で、PreToolUse の
permissionDecisionや PermissionRequest のdecision.behaviorで書く - 意味が薄い場面: ターミナルから一歩も離れず常に画面を見ながら使う使い方。鳴らしても自分で見ているので二重に気づくだけになる
使いどころ3シナリオ
シナリオ1: cooking-blog の夜間バッチ作業
レシピ300件を Markdown から HTML へ一括変換させたい時、寝ながら走らせる。matcher を permission_prompt にして OS 通知を鳴らしておけば、夜中に「画像の差し替えしていい?」が来ても枕元のスマホが反応してくれます。連動先を Slack の自分専用チャンネルに変えれば、外出中でも気づける。
シナリオ2: 家計簿アプリの画面を3日かけて作り直し
家計簿アプリの収支グラフ画面を3日かけて作り直してもらっている最中。idle_prompt matcher を仕込んでおくと、Claude が「次のステップどうします?」と20〜30分黙ったタイミングだけ通知を鳴らせます。「permission ばかり鳴って騒がしい」を避けたいときに、種類で絞り込めるのが効きます。
シナリオ3: チームで OSS を手元にコピーした初日
会社で github.com/some-org/internal-tool をプロジェクト一式手元にコピーしてきて、Claude Code に構造を読ませている。MCP サーバー連携で社内 DB をつないでいる場合、elicitation_dialog matcher を使うと「MCP が追加情報を聞いてきたタイミング」だけ通知を出せます。普段の作業ノイズに埋もれず、MCP 由来の確認だけ気づける運用になります。
初心者が踏みやすい落とし穴
- matcher に
BashやEditを書いて発火しない。Notification の matcher はツール名ではなく notification type の6種類だけ。間違えると無音で消える - 承認を自動で返そうとする。Notification は decision control を持っていません。フックの返り値で「はい」と答える設計は無効。承認自動化は PreToolUse / PermissionRequest の役割
- スクリプトに実行権限を付け忘れる。
chmod +xしていないと、settings.json は正しく書けていても起動できず、エラーログも目に入らないまま無音で死ぬ - Elicitation 系3種を Notification 内で完結させようとする。
elicitation_dialog等の matcher 値はあくまで「elicitation が起きた事実」を知る窓。dialog の内容に介入したいなら別フックの Elicitation / ElicitationResult を使う - terminalSequence の応答書式を間違える。返事は1行の構造化データで
{"terminalSequence": "..."}の形で書く。テキストをそのまま echo するだけだと Claude Code 側に拾われません - exit code 2 で Claude を止めようとする。Notification は止められません(Can block: No)。「ここで処理を中断させたい」が目的なら PreToolUse 側で書く
- 本番のセンシティブ情報を Slack に丸投げする。
messageの中に「rm したいフォルダの場所一覧」など機密文字列が乗ることがあるので、外部送信する設計なら送信先を自分専用 DM や private channel に絞る
書き方
.claude/settings.json に Notification ブロックを書く。matcher にはツール名ではなく notification type(permission_prompt / idle_prompt / auth_success / elicitation_dialog / elicitation_complete / elicitation_response の6種類のいずれか、または | で連結した正規表現)を入れる
やってみるとこうなる
入力
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{ "type": "command", "command": "~/notify-claude.sh" }
]
}
]
}
}
出力例
Claude Code から notify-claude.sh に標準入力で渡る構造化データは以下の形。message にユーザー向けメッセージ本文が入っている。スクリプト側は jq で .message を取り出し、ターミナル用の制御文字列を組み立てて {"terminalSequence": "..."} の形で返すと、Claude Code がその文字列をターミナルに流して通知を発火させる。
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../transcript.jsonl",
"cwd": "~/cooking-blog",
"hook_event_name": "Notification",
"message": "Claude needs your permission to use Bash"
}
このページに出てきた言葉
- フック
- 特定のイベントが起きた瞬間に、自前で用意したスクリプトを差し込んで走らせる仕組み。Claude Code の挙動の節目に処理を割り込ませられる
- matcher
- フック設定の絞り込み条件。Notification では notification type(permission_prompt など6種類)のいずれかを書く。空にすると全種類で発火する
- notification type
- Claude Code が出す通知の種類。permission_prompt / idle_prompt / auth_success / elicitation_dialog / elicitation_complete / elicitation_response の6種類が公式に定義されている
- settings.json
- Claude Code の設定をまとめたファイル。プロジェクト直下の .claude フォルダ内に置き、フックの登録もここに書く
- stderr
- プログラムが持つ『エラー用の出力チャンネル』。Notification では exit code 2 で抜けても Claude Code を止められないが、stderr に書いた内容はユーザー画面に表示される
- terminalSequence
- Notification フックが応答に書ける返答キー。ターミナルに流すべき制御文字列をここに入れると、Claude Code がそれをターミナルに送って通知を発火させる
- decision control
- フックが Claude Code の挙動に対して『許可する/拒否する』を返す権限のこと。Notification はこれを持たない。承認・拒否の自動化は PreToolUse / PermissionRequest 側で書く