Get notified when Claude Code finishes or needs you
Claude Code already sends a desktop notification in iTerm2, Ghostty and Kitty when it finishes a task or waits for your permission and you seem to be away. In Apple’s Terminal, Warp or the VS Code terminal you turn it on yourself: one setting rings the terminal bell, and a Notification hook can run any command, from a sound to a banner.
- The short answer
- When it notifies you
- Terminal bell
- A hook for a banner or sound
- Which event to use
- Several sessions
- Alerts and focus
- On your phone
- Claude Desktop
- Questions
The short answer
| Where you use Claude Code | What to do |
|---|---|
| Ghostty or Kitty | Nothing. Notifications reach the macOS Notification Center on their own. |
| iTerm2 | In Settings → Profiles → Terminal, check “Notification Center Alerts”, click “Filter Alerts” and turn on “Send escape sequence-generated alerts”. |
| Terminal, Warp, VS Code, Cursor | Set "preferredNotifChannel": "terminal_bell", or add a Notification hook. |
| Inside tmux | Add set -g allow-passthrough on to ~/.tmux.conf, or the alert never leaves tmux. |
| Claude Desktop | Nothing. It notifies you when a session finishes and you aren’t looking at it. |
| Your phone | Start Remote Control and turn on push notifications in /config. |
When Claude Code notifies you, and when it doesn’t
Claude Code’s alerts are late on purpose: they’re meant for when you’ve looked away. In a terminal session:
- A permission prompt notifies you once it has waited about six seconds and you haven’t typed. Every keystroke pushes that back.
- A finished response notifies you about 60 seconds later, if you haven’t typed since and no background agent, such as a subagent, is still running.
- A usage-limit wait sends no “finished” notification. When the limit resets and Claude carries on by itself, a separate notification type fires.
So if you sit at the terminal typing, you won’t hear a thing, and if you step away, the “finished” alert comes a minute late. For a signal the moment something happens, hook the Stop and PermissionRequest events instead.
Turn on the terminal bell
The simplest option works in any terminal. Run /config in Claude Code and change Local notifications, or add this line to your settings:
~/.claude/settings.json
{
"preferredNotifChannel": "terminal_bell"
}
The other values are auto (the default), iterm2, iterm2_with_bell, kitty, ghostty and notifications_disabled. In Apple’s Terminal, Claude Code’s first-run setup may have turned the audible bell off. If the bell stays silent, turn it back on in Terminal’s Settings → Profiles → Advanced → “Audible bell”.
A desktop banner or a sound with a hook
Hooks are commands that Claude Code runs at fixed points in a session. A Notification hook runs whenever Claude Code would notify you, in any terminal, next to the built-in alert. This one shows a macOS banner:
~/.claude/settings.json
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}
If your settings already have a "hooks" object, add "Notification" inside it next to the other events rather than replacing it. Type /hooks in Claude Code to check that the hook is listed.
No banner? osascript shows its banners through the Script Editor app. If Script Editor has no permission to send notifications, the command fails silently and macOS doesn’t ask. Run osascript -e 'display notification "test"' in a terminal first, and if nothing appears, allow Script Editor in System Settings → Notifications.
For a sound instead of a banner, play one of the system sounds in /System/Library/Sounds:
"command": "afplay /System/Library/Sounds/Glass.aiff"
Which event to use for which moment
The matcher of a Notification hook picks the notification type. Two other events fire with no delay at all.
| Moment | Event and matcher | When it fires |
|---|---|---|
| Claude asks for permission | Notification, permission_prompt | After about six seconds without typing |
| Claude asks for permission, right away | PermissionRequest | Immediately. Keep the hook silent: a hook that prints a decision approves or denies for you |
| Claude finished and you’re away | Notification, idle_prompt | About 60 seconds after the last response |
| Claude finished a response | Stop | Immediately, after every response, so it can get noisy |
| An MCP server asks you to fill in a form | Notification, elicitation_dialog | After about six seconds without typing |
Separate matchers can play different sounds, so you can tell “it needs me” from “it’s done” without looking:
~/.claude/settings.json
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [{ "type": "command", "command": "afplay /System/Library/Sounds/Ping.aiff" }]
},
{
"matcher": "idle_prompt",
"hooks": [{ "type": "command", "command": "afplay /System/Library/Sounds/Tink.aiff" }]
}
]
}
}
Several sessions at once
With three or four sessions open, “Claude Code needs your attention” doesn’t say which one. Every hook gets a JSON object on standard input with the session’s folder in cwd, the alert text in message and the type in notification_type. This script puts the folder name in the banner’s title:
~/.claude/hooks/notify.sh
#!/bin/bash
# Shows which project needs you, and why
input=$(cat)
project=$(basename "$(jq -r '.cwd' <<<"$input")")
message=$(jq -r '.message // "Needs your attention"' <<<"$input")
osascript -e 'on run argv' \
-e 'display notification (item 1 of argv) with title (item 2 of argv)' \
-e 'end run' "$message" "Claude Code · $project"
Make it executable with chmod +x ~/.claude/hooks/notify.sh and point the hook at it with "command": "\"$HOME\"/.claude/hooks/notify.sh". Passing the text as arguments keeps quotes in a message from breaking the AppleScript. The script needs jq; if which jq prints nothing, install it with Homebrew.
For naming, isolating and watching several sessions, see running several Claude Code sessions without losing track.
Some terminals can also show each session’s state themselves (working, waiting on you or done) through the Program Status Protocol, OSC 7501. Claude Code 2.1.295 and later reports it with nothing to turn on; your terminal’s documentation says whether and where it shows it.
Keep alerts from breaking your focus
An alert for every finished response trains you to switch windows and check. In threads where developers compare setups, that checking comes up again and again as what breaks concentration. One developer called alt-tabbing to check on Claude “such a flow killer”. A few habits help:
- Alert on what needs you. A permission prompt or a question blocks the session until you answer. A finished response can usually wait.
- Give the two a different weight. A clear sound for
permission_prompt, a soft one or none foridle_prompt. - Check finished work in batches, at the end of a focus block, instead of the moment each session finishes.
- Leave the agents alone on a break. A notification that reaches you while you stretch or make tea turns the break into more work.
What to do with the waits themselves is a guide of its own: what to do while Claude Code is working.
On your phone
With Remote Control on (/remote-control in a session, or claude --remote-control), Claude Code can push to the Claude app on your phone. Allow notifications for the app, then in /config turn on Push when Claude decides, for long tasks that finish or a decision Claude needs, and Push when actions required, for permission prompts and questions. You can also ask for one in the prompt, for example “notify me when the tests finish”.
In Claude Desktop
The Code tab sends a macOS notification when a session finishes a task and you aren’t viewing it. Hooks from ~/.claude/settings.json run there too, with one difference: permission_prompt fires about six seconds after Claude asks, whether or not you’re typing.
A quieter option: Meowdoro
Other apps show agent status in the notch too; we compared them in notch apps for AI coding agents. We make Meowdoro, so read this part as a disclosure as much as a suggestion. It’s a focus timer that lives around the MacBook notch and connects to Claude Code, in a terminal or in Claude Desktop, and to Codex through each agent’s own plugin system. Every session shows in a small black island as working, finished, failed or waiting for you, with the question or permission it’s waiting on, and a click takes you to it.
During a focus round, anything that needs you slides out as one silent line for four seconds, or waits until you peek. During a break nothing about agents shows at all, and when the next focus starts, one line says what happened while you rested. Its hooks only listen: they never approve a permission or answer an agent. It’s free before December 2026, then a one-time $20 for one Mac, on macOS 14 or later. How the island shows agents · focus without interruptions.
Questions
Can Claude Code play a sound when it’s done?
Yes. Set preferredNotifChannel to terminal_bell for the terminal’s bell, or add a Notification hook with the idle_prompt matcher, or a Stop hook, that runs afplay with a sound from /System/Library/Sounds.
Why don’t I get notifications in the VS Code terminal?
By default Claude Code sends desktop notifications only in Ghostty, Kitty and iTerm2. In VS Code, Cursor or Warp, use a Notification hook or the terminal bell.
How do I get notified only when Claude needs permission?
Give the Notification hook the matcher permission_prompt. For an alert the instant Claude asks, use a PermissionRequest hook that only plays a sound and prints nothing.
Do notifications work over SSH?
Yes, in Ghostty, Kitty and iTerm2: the desktop notification travels back over SSH to your Mac. In iTerm2, turn on forwarding as in the table above. A hook runs on the machine where Claude Code runs, so osascript there only works when that machine is a Mac.
How do I get the same for Codex?
Codex has its own notification settings and hooks; see Codex notifications.
Why did my notification arrive a minute late?
That’s the idle_prompt timing: about 60 seconds after Claude finishes, and only if you haven’t typed. Use a Stop hook for an alert as soon as it finishes.
Sources: the Claude Code documentation on hooks, the hooks guide, terminal configuration, settings, Remote Control and the desktop app, read on October 26, 2026. Claude Code changes quickly; if something here no longer matches, write to meow@meowdoro.com.