Claude Code의 Notification hook은 Claude Code가 알림을 보낼 때마다 실행돼요. 대개 권한 프롬프트가 대기 중이거나(permission_prompt) Claude가 작업을 마쳤는데 답하지 않았을 때(idle_prompt)예요. 자리를 비운 것처럼 보일 때 실행되도록 타이밍이 잡혀 있어요. permission_prompt는 키 입력 없이 프롬프트가 약 6초 기다린 뒤, idle_prompt는 Claude가 끝나고 약 60초 뒤에 실행돼요. hook은 알림 텍스트를 JSON으로 받고, 아무것도 막을 수 없으며, 데스크톱 알림이나 휴대폰 push 같은 부수 효과용이에요.
01알림 타입
Notification hook의 matcher는 알림 타입이에요. 비워 두면 모든 타입에 실행되고, 원하는 타입만 |로 나열할 수도 있어요. 자주 쓰게 될 타입은 다음과 같아요.
permission_promptClaude가 도구 사용(또는 샌드박스 명령의 네트워크 요청) 승인을 기다리고, 프롬프트가 약 6초간 대기한 경우idle_promptClaude가 약 60초 전에 응답을 마쳤고 그 뒤로 입력하지 않은 경우elicitation_dialogMCP 서버가 폼을 열었고 약 6초간 입력하지 않은 경우elicitation_url_dialogMCP 서버가 URL을 열어 달라고 요청했고 약 6초간 입력하지 않은 경우auth_success인증 완료이 밖에도 agent view의 백그라운드 세션용 agent_needs_input, agent_completed와 사용량 한도 대기용 quota_auto_resume_* 타입들이 있어요. 최신 전체 목록은 hooks 레퍼런스에 있어요.
02타이밍 규칙
많은 분들이 여기서 헷갈려요. Notification hook은 Claude Code 자체 데스크톱 알림과 타이밍을 공유하기 때문에, terminal 세션에서는 화면을 보고 있지 않을 때만 실행돼요.
permission_prompt는 prompt가 나타나면 약 6초 타이머를 시작해요. 키를 입력할 때마다 타이머가 초기화되기 때문에, 빨리 응답하면 아예 실행되지 않아요.idle_prompt는 Claude가 작업을 마치고 약 60초 후에 실행되는데, 그동안 입력이 없고 실행 중인 백그라운드 에이전트도 없을 때만 실행돼요. Claude Code가 사용량 한도 초기화를 기다리는 동안에는 실행되지 않아요.- 다른 대화상자가 열려 있을 때 도착한 요청은 도착한 시점부터 시간을 재요. 그래서 열린 대화상자 뒤에서 아직 대기 중인데도 알림이 먼저 올 수 있어요.
Claude Desktop이나 VS Code 확장처럼 Agent SDK로 권한에 응답하는 호스트에서는 permission_prompt 타이밍이 달라요. 요청 후 약 6초에 실행되고, 입력해도 미뤄지지 않으며, 사용자나 PermissionRequest hook이 먼저 응답하면 건너뛰어요.
지연 없는 신호가 필요하다면 다른 이벤트를 사용하세요.
PermissionRequestStopidle_prompt를 지정한 Notification03hook이 받는 데이터
공통 필드(session_id, transcript_path, cwd, hook_event_name) 외에도 Notification hook은 알림의 message, 선택적인 title, 그리고 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는 Claude Code가 직접 작성한 문구라서 그대로 보여줘도 괜찮아요. 여러 세션을 동시에 실행할 때 어느 프로젝트에서 요청했는지 알고 싶다면 cwd가 유용해요.
04hook으로 할 수 있는 것과 없는 것
Notification hook은 알림을 막거나, 지연시키거나, 바꿀 수 없어요. exit code와 stderr는 무시되고, JSON 출력의 systemMessage와 continue도 Claude Code가 버려요. 오로지 부수 효과를 위한 hook이에요.
사용할 수 있는 출력 필드는 terminalSequence 하나예요. hook은 terminal 없이 실행되므로 이스케이프 시퀀스를 직접 쓸 수는 없지만, Claude Code에 넘겨서 대신 출력하게 할 수 있어요. 이를 이용하면 iTerm2, Ghostty, Kitty, WezTerm, Windows Terminal 등에서, 심지어 tmux 안에서도 terminal 자체 알림을 띄울 수 있어요. 단, Claude Code 인터페이스가 화면에 떠 있는 대화형 세션에서만 동작해요.
preferredNotifChannel 설정으로도 hook을 막을 수 없어요. 기본 알림을 꺼도 Notification 이벤트는 계속 실행돼요. 이 설정은 Claude Code 자체 알림 방식만 바꿔요. 자세한 내용은 terminal 벨 가이드를 참고하세요.
05예제
타입별로 다른 핸들러 사용하기
권한 prompt와 유휴 알림에 각각 별도의 스크립트를 실행해요.
{
"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" }]
}
]
}
}
각 스크립트에 chmod +x로 실행 권한을 주세요. Mac, Windows, Linux용 데스크톱 알림 명령어는 Claude Code 작업 완료 시 알림 받는 방법에 있으니 여기서는 생략할게요.
실제 메시지와 프로젝트 표시하기
이 스크립트(macOS, Linux)는 고정된 문자열 대신 Claude Code의 메시지와 프로젝트 폴더를 알림에 표시해요.
#!/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
텍스트를 인자(on run argv)로 넘기면 메시지에 따옴표가 있어도 AppleScript가 깨지지 않아요. jq가 설치되어 있어야 해요.
terminal 자체 알림
Anthropic의 공식 예제는 Ghostty, Warp, urxvt가 인식하는 OSC 777과 함께 terminalSequence를 사용해요.
#!/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}'
iTerm2, Windows Terminal, WezTerm에서는 OSC 9를, Kitty에서는 OSC 99를 사용하세요. 허용된 시퀀스 외에는 무시돼요.
06Claude Code Notifier의 역할
push 서비스를 호출하는 Notification hook을 쓰면 휴대폰으로 알림을 받을 수 있고, 많은 분들에게는 이것으로 충분해요. 이 방법은 ntfy 가이드에서 다뤄요.
아쉬운 점은 응답이에요. permission_prompt가 실행될 즈음 Claude는 대화상자에서 대기 중인데, Notification hook으로는 여기에 응답할 수 없어요. Claude Code Notifier는 응답이 가능한 hook을 사용해요. PermissionRequest로 결정을 돌려주고, AskUserQuestion에 대한 PreToolUse로 답변을 돌려줘요. 무료 커맨드라인 도구인 ccn은 Mac, Windows, Linux에서 동작하며 자체적으로 데스크톱 알림을 띄워요. iPhone이나 Android 앱을 페어링하면 휴대폰에서 한 번 허용, 세션 동안 허용, 거부를 선택할 수 있어요. 최근 30초 안에 입력한 적이 있으면 휴대폰을 기다리지 않고 평소처럼 terminal에서 물어봐요. Anthropic이 만든 제품이 아닌 독립 도구예요. 설치 방법은 ccn 페이지에 있어요.
07FAQ
Notification hook이 전혀 실행되지 않는 이유는 뭔가요?
대부분 아직 키보드 앞에 있기 때문이에요. 키를 입력할 때마다 permission_prompt가 미뤄지고, idle_prompt는 Claude가 작업을 마친 뒤 약 1분 동안 입력이 없어야 실행돼요. 테스트하려면 권한 prompt를 띄운 다음 다른 창으로 전환하고 최소 6초 기다려 보세요. 그래도 실행되지 않으면 /hooks에 등록되어 있는지 확인하고 문제 해결 체크리스트를 참고하세요.
idle_prompt는 무엇인가요?
Claude가 약 60초 전에 응답을 마쳤고 그 후로 입력이 없을 때 Claude Code가 보내는 알림 타입이에요. 즉각적인 '완료' 신호가 아니라 이제 사용자 차례라는 리마인더예요. 즉시 완료 알림이 필요하면 Stop hook을 사용하세요.
Notification hook으로 권한을 승인할 수 있나요?
아니요. Notification hook에는 결정 권한이 없어서 무엇을 출력해도 prompt에 응답할 수 없어요. 허용하거나 거부하려면 PermissionRequest 가이드에 설명된 대로 PermissionRequest hook을 사용하세요.
preferredNotifChannel을 notifications_disabled로 설정해도 Notification hook이 실행되나요?
네. 그 설정은 Claude Code가 직접 알림을 보내는 방식만 바꿔요. Notification 이벤트와 hook은 그대로 실행돼요.
알림이 두 번 오는 이유는 뭔가요?
Claude Code의 기본 알림과 hook이 함께 실행되기 때문이에요. iTerm2, Ghostty, Kitty에서는 둘 다 보일 수 있어요. preferredNotifChannel 등으로 하나를 끄거나 hook만 남겨 두세요.