Get notified when Claude Code needs input or finishes
Claude Code will happily sit blocked for an hour because you missed a permission prompt. The fastest fix is one command: claude config set --global preferredNotifChannel terminal_bell rings the terminal bell whenever Claude needs attention. For real alerts, add a Notification hook for asks and a Stop hook for finishes; and if you want to answer without touching the terminal, NotchViber for Claude Code turns each ask into a clickable card in your MacBook notch.
Why Claude Code sessions block silently
Claude Code stops and waits in three situations: it asks a clarifying question through its AskUserQuestion tool, it hits a permission prompt for a command or edit it is not allowed to run, or it finishes planning and waits for you to approve the plan before touching code.
None of these resolve on their own. Permission prompts and plan approvals wait indefinitely, and the model does zero work until you answer.
Whether you hear about it depends on your terminal. Out of the box many setups show nothing, so a session you started before lunch can sit blocked for an hour while your 5-hour usage block keeps ticking on the wall clock.
Fastest fix: the terminal bell
One command enables a bell whenever Claude Code wants attention:
claude config set --global preferredNotifChannel terminal_bell
It works in every terminal and takes effect without a restart. Terminals like iTerm2 can layer a Dock badge or alert on top of the bell for background tabs.
The limits are obvious: one generic beep for everything, no message text, and silence if your Mac is muted. Set the channel back to none to turn it off, and see the terminal configuration docs for per-terminal notification options.
Built-in Notification hooks
Hooks are shell commands Claude Code runs at lifecycle events. The Notification event fires when Claude needs your permission or has been idle waiting for input for about 60 seconds. Anthropic's hooks guide uses exactly this event for a macOS desktop notification; add this to ~/.claude/settings.json:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}
Run /hooks inside Claude Code to confirm the hook is registered. One macOS gotcha from the official docs: osascript routes notifications through Script Editor, and if Script Editor lacks notification permission the command fails silently. Run osascript -e 'display notification "test"' once, then enable Script Editor under System Settings > Notifications.
The empty matcher fires on every notification type. To narrow it, set the matcher to one of these values:
| Matcher | Fires when |
|---|---|
permission_prompt | Claude needs you to approve a tool use |
idle_prompt | Claude is done and waiting for your next prompt |
agent_needs_input | A background session starts waiting on your input |
agent_completed | A background session finishes or fails |
The two agent matchers need Claude Code v2.1.198 or later and only fire while agent view (claude agents) is open.
Sound on finish: the Stop hook
The Notification event covers asks, but idle_prompt only fires after the session has sat idle. For an immediate done sound, use the Stop event, which fires the moment Claude finishes responding.
This config plays distinct system sounds for finishes and permission asks using afplay, which ships with macOS:
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{ "type": "command", "command": "afplay /System/Library/Sounds/Ping.aiff" }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "afplay /System/Library/Sounds/Glass.aiff" }
]
}
]
}
}
Any file in /System/Library/Sounds works: Glass, Ping, Hero, Submarine, Funk. Hooks load at session start, so open a new session after editing settings.
Hook commands receive the event as JSON on stdin, including the session id and event-specific fields. That means you can pipe it through jq and forward it anywhere: a push service, a Slack webhook, a log file. Full schemas live in the hooks reference.
What a notification cannot do
Every option above ends the same way: you switch to the terminal, find the right window among however many sessions you run, read the prompt, and type an answer. The alert tells you Claude wants something, not what it wants.
Anthropic's answer for parallel sessions is agent view, a TUI listing background sessions with working, waiting, and done states. It helps, but it lives in a terminal, and you have to open it to see it.
Answer from the notch with NotchViber
Disclosure first: NotchViber is our app. NotchViber for Claude Code is a free macOS notch app that watches your local Claude Code transcripts under ~/.claude/projects and turns waiting sessions into something you can see and click.
The collapsed bar shows a status dot: blue while a session works, cyan the moment one waits. Sounds fire on finish, on questions, and on permission asks, so it covers what the Stop and Notification hooks do without any settings.json edits.
Hover and the island expands into a session list with live activity and todo progress. Blocked AskUserQuestion prompts render as cards with numbered options, permission prompts as Allow / Always / Deny buttons, and pending plan reviews as Markdown.
One click types the answer into your terminal through macOS Accessibility keystrokes, so approving a plan or denying a command never means hunting for a window. If you would rather look first, NotchViber jumps to the exact window in Ghostty, iTerm2, Terminal, WezTerm, kitty, Alacritty, Warp, Zed, Cursor, or VS Code; tmux and Zellij sessions are attributed to their server process.
Everything runs locally: the app reads JSONL transcript files, makes no network calls, and touches no credentials. It needs macOS 14+ on Apple Silicon, the dmg is under 1 MB, and on Macs without a notch it runs as a floating pill. If you want to compare alternatives, see our roundup of Claude Code notch apps.
Which setup to use
- Terminal bell: ten seconds of setup, works everywhere, tells you nothing beyond the fact that something happened.
- Notification and Stop hooks: precise, scriptable, official. Best if you want desktop notifications, custom sounds, or forwarding to another device.
- NotchViber: adds the missing half, seeing what the ask is and answering it in one click. It coexists with hooks because it reads transcripts instead of hooking events.
Most people end up combining two. Hooks handle audible alerts for muted or remote setups, and the notch handles local sessions where a one-click answer beats a window switch.
Frequently asked questions
Does Claude Code send a notification when it finishes?
Not reliably by default; what you see depends on your terminal. Enable the bell with claude config set --global preferredNotifChannel terminal_bell, or add a Stop hook that plays a sound or posts a desktop notification the moment a response ends.
How do I make Claude Code play a sound when it needs input?
Add a Notification hook in ~/.claude/settings.json with a command like afplay /System/Library/Sounds/Ping.aiff. The event fires when Claude needs permission or is idle waiting for input, and the permission_prompt matcher limits it to approval asks.
Why does my osascript notification hook show nothing on macOS?
osascript routes notifications through Script Editor, which fails silently without notification permission. Run osascript -e 'display notification "test"' once, then enable Script Editor under System Settings > Notifications and test again.
Can I approve Claude Code permission prompts without the terminal?
Not with built-in tooling; prompts only accept input in the session's terminal. NotchViber for Claude Code (our app) renders permission prompts as Allow, Always, and Deny cards in the macOS notch and types your choice into the terminal via Accessibility keystrokes.
What is the difference between the Notification and Stop hooks?
Stop fires the moment Claude finishes responding, which makes it the right event for a done sound. Notification fires when Claude needs permission or has been idle waiting for input, so use it for needs-you alerts.