Hook Notification của Claude Code chạy mỗi khi Claude Code gửi thông báo, thường là vì có một permission prompt đang chờ (permission_prompt) hoặc vì Claude đã xong mà bạn chưa phản hồi (idle_prompt). Nó được canh thời điểm cho lúc bạn có vẻ không ở máy: permission_prompt kích hoạt khi prompt đã chờ khoảng sáu giây mà không có phím nào được gõ, còn idle_prompt khoảng 60 giây sau khi Claude xong. Hook nhận nội dung thông báo dưới dạng JSON, không chặn được gì, và dùng cho các tác vụ phụ như hiện cảnh báo trên desktop hoặc push về điện thoại.
01Các loại thông báo
matcher của hook Notification chính là loại thông báo. Để trống để chạy cho mọi loại, hoặc liệt kê các loại bạn muốn, phân cách bằng |. Những loại bạn hay dùng nhất:
permission_promptClaude cần bạn duyệt một lần dùng tool (hoặc request mạng của một lệnh chạy trong sandbox) và prompt đã chờ khoảng sáu giâyidle_promptClaude đã trả lời xong khoảng 60 giây trước và bạn chưa gõ gì kể từ đóelicitation_dialogMột MCP server đã mở form và bạn chưa gõ gì trong khoảng sáu giâyelicitation_url_dialogMột MCP server yêu cầu bạn mở URL và bạn chưa gõ gì trong khoảng sáu giâyauth_successXác thực hoàn tấtCòn nhiều loại khác, như agent_needs_input và agent_completed cho các phiên chạy nền trong agent view, và nhóm quota_auto_resume_* cho lúc chờ hết giới hạn sử dụng. Tài liệu tham khảo về hook có danh sách đầy đủ và mới nhất.
02Quy tắc về thời điểm
Đây là chỗ nhiều người hay bị bất ngờ. Hook Notification dùng chung cơ chế thời gian với thông báo desktop của chính Claude Code, nên trong một phiên terminal, nó chỉ kích hoạt khi bạn không để ý tới màn hình:
permission_promptbắt đầu đếm khoảng sáu giây khi prompt xuất hiện. Mỗi lần bạn gõ phím, bộ đếm lại reset. Nếu bạn trả lời nhanh, nó sẽ không bao giờ kích hoạt.idle_promptkích hoạt khoảng 60 giây sau khi Claude xong việc, chỉ khi bạn chưa gõ gì kể từ đó và không còn background agent nào đang chạy. Nó không kích hoạt trong lúc Claude Code chờ giới hạn sử dụng được reset.- Một yêu cầu đến trong lúc đang có dialog khác mở sẽ được tính giờ từ lúc nó đến, nên bạn có thể nhận thông báo của nó trong khi nó vẫn đang xếp hàng sau dialog đang mở.
Các host trả lời quyền qua Agent SDK, như Claude Desktop và extension VS Code, tính giờ permission_prompt theo cách khác: khoảng sáu giây sau yêu cầu, không bị trì hoãn khi gõ phím, và bị bỏ qua nếu bạn hoặc một hook PermissionRequest trả lời trước.
Nếu bạn muốn tín hiệu không có độ trễ, hãy dùng event khác:
PermissionRequestStopNotification với idle_prompt03Hook nhận được gì
Ngoài các trường chung (session_id, transcript_path, cwd, hook_event_name), hook Notification còn nhận message của thông báo, title (không bắt buộc) và notification_type:
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"hook_event_name": "Notification",
"message": "Claude needs your permission",
"title": "Permission needed",
"notification_type": "permission_prompt"
}
message là nội dung do chính Claude Code viết, nên có thể hiển thị nguyên văn. cwd hữu ích khi bạn chạy nhiều phiên và muốn biết project nào đang hỏi.
04Hook làm được gì và không làm được gì
Hook Notification không thể chặn, trì hoãn hay thay đổi thông báo. Exit code và stderr của nó bị bỏ qua, và Claude Code loại bỏ systemMessage cũng như continue trong JSON output. Nó chỉ dùng cho các side effect.
Chỉ có một trường output mà nó dùng được: terminalSequence. Hook chạy không có terminal nên không tự ghi escape sequence được, nhưng có thể giao một sequence cho Claude Code phát ra. Nhờ vậy hook có thể kích hoạt thông báo native của terminal trong iTerm2, Ghostty, Kitty, WezTerm, Windows Terminal và nhiều terminal khác, kể cả bên trong tmux. Cách này chỉ hoạt động trong phiên tương tác khi giao diện của Claude Code đang hiển thị trên màn hình.
Setting preferredNotifChannel cũng không chặn được hook. Kể cả khi đã tắt thông báo tích hợp, event Notification vẫn kích hoạt. Setting đó chỉ thay đổi cách chính Claude Code báo cho bạn; xem hướng dẫn về terminal bell.
05Ví dụ
Handler riêng cho từng loại
Chạy script riêng cho permission prompt và cho lời nhắc idle:
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/permission-alert.sh" }]
},
{
"matcher": "idle_prompt",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/idle-alert.sh" }]
}
]
}
}
Cấp quyền thực thi cho từng script bằng chmod +x. Các lệnh hiển thị thông báo desktop cho Mac, Windows và Linux có trong cách nhận thông báo khi Claude Code xong việc, nên không nhắc lại ở đây.
Hiển thị nội dung thật và tên project
Script này (macOS và Linux) đưa nội dung thông báo của Claude Code và thư mục project vào thông báo, thay vì một chuỗi cố định:
#!/bin/bash
# ~/.claude/hooks/notify.sh
input=$(cat)
msg=$(jq -r '.message // "Claude Code needs your attention"' <<<"$input")
project=$(basename "$(jq -r '.cwd // "."' <<<"$input")")
if command -v osascript >/dev/null 2>&1; then
osascript -e 'on run argv' \
-e 'display notification (item 1 of argv) with title (item 2 of argv)' \
-e 'end run' "$msg" "Claude Code: $project"
elif command -v notify-send >/dev/null 2>&1; then
notify-send "Claude Code: $project" "$msg"
fi
exit 0
Truyền text dưới dạng tham số (on run argv) giúp AppleScript không bị lỗi khi nội dung có dấu nháy. Cần cài jq.
Thông báo native của terminal
Ví dụ của chính Anthropic dùng terminalSequence với OSC 777, loại mà Ghostty, Warp và urxvt hiểu được:
#!/bin/bash
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}'
Với iTerm2, Windows Terminal hoặc WezTerm thì dùng OSC 9, còn Kitty thì dùng OSC 99. Mọi sequence nằm ngoài danh sách cho phép đều bị bỏ qua.
06Claude Code Notifier nằm ở đâu trong bức tranh này
Một hook Notification gọi tới dịch vụ push sẽ đưa cảnh báo lên điện thoại của bạn, và với nhiều người như vậy là đủ. Hướng dẫn ntfy trình bày cách làm này.
Điểm còn thiếu là việc trả lời. Khi permission_prompt kích hoạt, Claude đang chờ một dialog mà hook Notification không thể trả lời. Claude Code Notifier giải quyết việc này bằng các hook làm được: PermissionRequest để trả về quyết định của bạn và PreToolUse trên AskUserQuestion để trả về câu trả lời của bạn. Công cụ dòng lệnh miễn phí của nó, ccn, chạy trên Mac, Windows và Linux, và tự hiển thị thông báo desktop. Khi đã ghép nối app iPhone hoặc Android, bạn có thể cho phép một lần, cho phép trong cả phiên, hoặc từ chối ngay trên điện thoại. Nếu bạn vừa gõ phím trong 30 giây gần nhất, sẽ không có gì chờ điện thoại và terminal hỏi như bình thường. Đây là công cụ độc lập, không do Anthropic phát triển. Hướng dẫn cài đặt có tại trang ccn.
07Câu hỏi thường gặp
Tại sao Notification hook của tôi không bao giờ kích hoạt?
Thường là vì bạn vẫn đang ngồi gõ phím. Mỗi lần gõ phím sẽ trì hoãn permission_prompt, còn idle_prompt chỉ kích hoạt nếu bạn không gõ gì trong khoảng một phút sau khi Claude xong việc. Để thử, hãy tạo một permission prompt, chuyển sang cửa sổ khác và chờ ít nhất sáu giây. Nếu vẫn không kích hoạt, kiểm tra xem /hooks có liệt kê hook đó không và xem checklist khắc phục sự cố.
idle_prompt là gì?
Đó là loại thông báo Claude Code gửi khi Claude đã trả lời xong khoảng 60 giây trước và bạn chưa gõ gì kể từ đó. Nó là lời nhắc rằng đến lượt bạn, không phải tín hiệu "xong" tức thì. Muốn có tín hiệu đó, hãy dùng hook Stop.
Notification hook có thể phê duyệt quyền không?
Không. Hook Notification không có quyền quyết định, nên dù in ra gì cũng không trả lời được prompt. Hãy dùng hook PermissionRequest để cho phép hoặc từ chối, như mô tả trong hướng dẫn PermissionRequest.
Notification hook có chạy không nếu tôi đặt preferredNotifChannel thành notifications_disabled?
Có. Thiết lập đó chỉ thay đổi cách Claude Code tự thông báo cho bạn. Event Notification và các hook của bạn vẫn chạy bình thường.
Tại sao tôi nhận được hai thông báo?
Thông báo có sẵn của Claude Code và hook của bạn chạy song song. Trong iTerm2, Ghostty hoặc Kitty, bạn có thể thấy cả hai. Hãy tắt một trong hai, ví dụ bằng preferredNotifChannel, hoặc chỉ giữ lại hook.