Claude Code can tell you when it needs you. In Ghostty, Kitty or iTerm2 it already sends a desktop notification when a task finishes or a permission prompt is waiting, and in any terminal a Notification hook can pop an alert, play a sound or ping your phone.
What you need depends on where you run it. A Mac in iTerm2 needs one setting turned on. Warp and the VS Code terminal get nothing by default, so they need a hook. Away from your desk, you want the ping on your phone. Every setting, hook name and matcher below comes from Anthropic’s docs as we read them on November 3, 2026.
Hooks work one computer at a time. Once you run sessions in three terminals and on a server, alerts arrive one by one and nothing lists what is still waiting. We make Context Board at ContextBolt for that, and the last sections cover it. It’s ours, so weigh the bias.
- Built in: Ghostty and Kitty show a desktop notification by default, and iTerm2 does once its alerts are on. For a bell in any terminal, set
preferredNotifChanneltoterminal_bell, or pick it under Local notifications in/config. - A pop-up anywhere: add a
Notificationhook to~/.claude/settings.jsonthat runsosascripton a Mac,notify-sendon Linux or PowerShell on Windows. - When it’s done: a
Stophook runs every time Claude finishes responding. Theidle_promptmatcher waits about 60 seconds and fires only if you haven’t typed. - On your phone: Remote Control pushes to the Claude app, or a hook can curl ntfy.sh.
- Many sessions: Context Board lists every Claude Code and Codex session waiting on you, on every computer you link, and three hooks make it ping you.
What Claude Code does out of the box
Claude Code fires a notification event when Claude finishes a task or pauses for a permission prompt and you appear to be away from the terminal. Anthropic’s terminal configuration page lists what each terminal does with it.
| Where you run it | What you get with no setup |
|---|---|
| Ghostty, Kitty | A desktop notification |
| iTerm2 | A desktop notification, once you turn on its alerts |
| Apple Terminal | No sound. At most a silent bell, which shows as a flash or a Dock bounce if the profile has those on |
| Warp, the VS Code terminal, others | Nothing |
| Claude desktop app | An OS notification when a session finishes a task and you aren’t looking at that session |
Turn on iTerm2’s alerts: go to Settings, then Profiles, then Terminal. Check “Notification Center Alerts”, click “Filter Alerts” and turn on “Send escape sequence-generated alerts”. Then make sure iTerm2 has notification permission in your OS settings.
Get a bell in any terminal: set preferredNotifChannel in ~/.claude/settings.json, or pick it in /config, where it is called Local notifications.
{
"preferredNotifChannel": "terminal_bell"
}
The other values are auto (the default), iterm2, iterm2_with_bell, kitty, ghostty and notifications_disabled. In Apple Terminal, also turn on Audible bell under Settings, Profiles, Advanced, or the bell stays silent.
Over SSH, the desktop notification still reaches your own computer. Ghostty and Kitty pass it to your OS without setup, and iTerm2 needs the alert setting above.
Inside tmux, notifications never reach the outer terminal until you add set -g allow-passthrough on to ~/.tmux.conf and run tmux source-file ~/.tmux.conf.
Get a desktop notification with a Notification hook
A hook is a shell command Claude Code runs at a set point in a session. The Notification hook runs when Claude Code sends a notification, alongside the built-in one. Per the hooks reference, it runs even when preferredNotifChannel is notifications_disabled, so you can switch the built-in alert off and keep your own.
The matcher picks which notifications run your command. These four cover waiting for you:
| Matcher | Fires when |
|---|---|
permission_prompt | Claude needs you to approve a tool use, and the prompt has waited about six seconds |
idle_prompt | Claude finished responding about 60 seconds ago and you haven’t typed since |
elicitation_dialog | An MCP server opens a form for you and you haven’t typed for about six seconds |
agent_needs_input | A background session starts waiting on you while agent view is open |
Leave the matcher empty to run on every type, including auth_success. Separate several with |, as the examples below do.
macOS
Open ~/.claude/settings.json, or create it, and add:
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt|idle_prompt",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}
If nothing appears, Script Editor probably lacks permission. The hooks guide says osascript sends notifications through Script Editor, fails silently without permission, and macOS never asks. Run osascript -e 'display notification "test"' once in Terminal, then turn on Allow Notifications for Script Editor in System Settings, Notifications.
Prefer a notification with a sound and its own icon? Install terminal-notifier with brew install terminal-notifier and use this as the command:
terminal-notifier -title 'Claude Code' -message 'Claude Code needs you' -sound default
Linux
The same block, with notify-send as the command:
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt|idle_prompt",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'Claude Code needs your attention'"
}
]
}
]
}
}
notify-send needs a desktop notification daemon. Headless servers, SSH sessions and most containers don’t have one. If the command is missing, install libnotify-bin on Debian or Ubuntu.
Windows
Anthropic’s own example opens a message box:
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt|idle_prompt",
"hooks": [
{
"type": "command",
"command": "powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Code needs your attention', 'Claude Code')\""
}
]
}
]
}
}
A message box can open behind your terminal. For a toast in the corner of the screen, install the BurntToast module once with Install-Module -Name BurntToast, then use this hook:
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt|idle_prompt",
"hooks": [
{
"type": "command",
"shell": "powershell",
"command": "New-BurntToastNotification -Text 'Claude Code', 'Claude Code needs your attention'"
}
]
}
]
}
}
Keep the "shell": "powershell" line. On Windows, Claude Code runs a hook’s command in Git Bash, and only falls back to PowerShell when Git Bash isn’t installed. If you run Claude Code inside WSL, powershell.exe has to be on your PATH through Windows interop.
Check it works
Type /hooks in Claude Code and your hook should be listed under Notification. To test it, press Shift+Tab until the status bar shows manual mode, ask Claude for something that needs permission, and switch to another window. The notification should arrive about six seconds later.
Get a notification when Claude Code is done
There are two ways to hear that Claude finished, and they suit different habits.
A Stop hook runs every time the main agent finishes responding, whether you are watching or not. It doesn’t run when you interrupt Claude, and an API error fires StopFailure instead. On a Mac:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code finished\" with title \"Claude Code\"'"
}
]
}
]
}
}
Swap in the Linux or Windows command from above. The Stop hook also receives last_assistant_message, the text of Claude’s final reply, so a script can put its first line in the notification.
The idle_prompt matcher fires about 60 seconds after Claude finishes, and only if you haven’t typed since and no background subagent is still running. If you are at the keyboard, it stays quiet.
Pick one. With both, a finish while you’re away pings you twice. We’d use idle_prompt for long tasks you walk away from, and Stop when you want a ping every time, such as a long build you approved in plan mode.
Add a sound
A sound is just another command in the hook:
- macOS:
afplay /System/Library/Sounds/Glass.aiff, the example in Anthropic’s terminal guide. - Linux:
paplay /usr/share/sounds/freedesktop/stereo/complete.oga, if your desktop haspaplayand the freedesktop sound theme (Ubuntu’ssound-theme-freedesktoppackage). - Windows: a BurntToast toast plays the system notification sound unless you add
-Silent.
Or set preferredNotifChannel to terminal_bell and let the terminal make the noise.
Get Claude Code notifications on your phone
The built-in way: Remote Control
Remote Control links a local session to the Claude app, and while it is on, Claude Code can push to your phone.
- Install the Claude app on iOS or Android and sign in with the account you use for Claude Code.
- Accept the app’s notification prompt.
- Start a session with
claude --remote-control, or type/remote-controlin one that is running. - Run
/configand turn on Push when actions required (permission prompts and questions), Push when Claude decides (Claude picks the moment, typically when a long task finishes), or both.
It needs a Pro, Max, Ultra, Team or Enterprise plan, and it doesn’t work with API keys. Claude Code skips the push while you are typing in or focused on that terminal. If pushes are late on iOS, check Focus modes and notification summaries.
Any plan: ntfy from a hook
ntfy turns an HTTP request into a phone notification, with no sign-up. Install the ntfy app, subscribe to a topic name nobody would guess, and point a hook at it:
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt|idle_prompt",
"hooks": [
{
"type": "command",
"command": "jq -r '.message // \"Claude Code needs you\"' | curl -s -H 'Title: Claude Code' -d @- https://ntfy.sh/your-long-random-topic"
}
]
}
]
}
}
The hook gets its details as JSON on standard input, and jq pulls out the message field, such as “Claude needs your permission”. Since there is no sign-up, the ntfy docs call a topic in effect a password, so make it long and random.
Pushover works the same way with your app token and user key:
curl -s -F "token=APP_TOKEN" -F "user=USER_KEY" -F "message=Claude Code needs you" https://api.pushover.net/1/messages.json
Why your Claude Code notification doesn’t fire
Work down this list:
- You were at the keyboard:
permission_promptwaits until you haven’t typed for about six seconds, and every keystroke restarts the wait. For a hook that runs the moment Claude asks, use thePermissionRequestevent instead. - Your terminal gets no built-in alert: Warp and the VS Code terminal get nothing. Add a hook or set
terminal_bell. - macOS blocked it: see the Script Editor fix above, and check that your terminal app may send notifications.
- tmux swallowed it: add
set -g allow-passthrough on. - The hook isn’t loaded: if
/hooksdoesn’t list it, check the JSON. Each event is a key inside onehooksobject, so addNotificationbeside your other events instead of replacing them. Matchers are case-sensitive. - The command fails on its own: run it in a terminal first. On Linux over SSH,
notify-sendhas no daemon to talk to. If you see “jq: command not found”, installjq. - Windows ran it in the wrong shell: add
"shell": "powershell"to a PowerShell command.
See every waiting session on one board
Every hook above lives in one settings file on one computer. Run Claude Code in two terminals and VS Code on your laptop, and Codex on a server, and the alerts arrive one at a time with no list of what is still waiting.
On one computer, Anthropic’s agent view helps. claude agents lists your background sessions and which ones need input. It sees the sessions on that machine.
Context Board shows them all. Link each computer with the one line from the board’s Connect window, and the Needs you widget lists every Claude Code and Codex session waiting on you, on every linked computer, in a terminal, VS Code or an app. Each row says what it wants: “Asked you a question”, “Has a plan for you to approve” or “Wants your OK to go on”, and how long ago it started waiting. Only each session’s title, project and state leave your computer, never what you and Claude said.
- Wants your OK to go onFix checkout test · Claude Code · laptop2m
- Asked you a questionRelease notes · Codex · server6m
- Has a plan for you to approveDocs rewrite · Claude Code · laptop14m
The board shows those sessions. It does not send a notification for them by itself. For a ping, add the hooks below.
Make the board ping you
The board takes a status from any agent over HTTP. When one changes to needs_you, the board puts it in its bell and, if you allowed notifications in Settings, Notifications, shows a browser notification with the board open or closed. “Agents that need you” is on by default there. On an iPhone or iPad the browser shows them only while the board is open, so pair it with ntfy on those.
Step 1, get a key: in the board, open Connect, then Claude Code under Your AI. Under Other ways (Set it up again, if Claude Code is already connected), click Make a link with a key. The key is the part of the link after /mcp/, starting cbk_. It works without signing in, so treat it like a password. You can remove it any time in Connected.
Step 2, save this script as ~/.claude/board-status.sh and run chmod +x ~/.claude/board-status.sh. It needs curl and jq.
#!/bin/bash
# Tells Context Board what this Claude Code session is doing.
# Usage: board-status.sh working | done | needs_you
KEY="cbk_paste_your_key_here"
input=$(cat)
dir=$(jq -r '.cwd // ""' <<<"$input")
session=$(jq -r '.session_id // "session"' <<<"$input")
msg=$(jq -r '.message // ""' <<<"$input")
last="${TMPDIR:-/tmp}/board-status-$session"
# PostToolUse fires on every tool call: send "working" once, not each time
[ "$1" = "working" ] && [ "$(cat "$last" 2>/dev/null)" = "working" ] && exit 0
echo "$1" > "$last"
body=$(jq -nc --arg a "Claude Code · ${dir##*/}" --arg s "$1" --arg d "$msg" \
'{agent: $a, status: $s} + (if $d == "" then {} else {detail: $d} end)')
curl -s -m 10 -X POST https://board.contextbolt.com/v1/agent \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d "$body" > /dev/null
Step 3, add the hooks to ~/.claude/settings.json:
{
"hooks": {
"UserPromptSubmit": [
{ "hooks": [{ "type": "command", "command": "~/.claude/board-status.sh working", "async": true }] }
],
"PostToolUse": [
{ "hooks": [{ "type": "command", "command": "~/.claude/board-status.sh working", "async": true }] }
],
"Notification": [
{ "matcher": "permission_prompt|idle_prompt", "hooks": [{ "type": "command", "command": "~/.claude/board-status.sh needs_you", "async": true }] }
],
"Stop": [
{ "hooks": [{ "type": "command", "command": "~/.claude/board-status.sh done", "async": true }] }
]
}
}
Step 4, allow notifications: in the board, open Settings, then Notifications, and click Allow notifications on this device. Each device asks once.
The board only notifies when the status changes to needs_you, so a second wait in a row with nothing in between stays silent. The script marks the session working when you send a prompt and again after the next tool runs, which is what happens once you approve a permission, so the next wait pings you again. "async": true keeps the request from slowing Claude down.
Each session shows as “Claude Code · ” and its folder name, and the notification body is Claude Code’s own message, such as “Claude needs your permission to use Bash”. The script sends no prompt text. If the computer is also linked, the same wait can show twice in Needs you, once from the computer and once from the hook.
The same board holds your Claude Code and Codex limits as rings with their reset times, which our guide on how to check Claude Code usage compares with /usage. Context Board is free for 3 days, then $12 a month, with every widget included.
Which setup to use
| You want | Use |
|---|---|
| An alert in Ghostty, Kitty or iTerm2 | Nothing to install. Turn on iTerm2’s alerts |
| A sound in any terminal | preferredNotifChannel set to terminal_bell |
| A pop-up in Warp, VS Code or Windows | A Notification hook for your OS |
| A ping only when you walked away | The idle_prompt matcher |
| A ping every time it finishes | A Stop hook |
| Your phone | Remote Control push, or ntfy from a hook |
| Many sessions on many computers | Context Board’s Needs you widget, plus the board hooks for a ping |
Start with the hook for your operating system and the permission_prompt|idle_prompt matcher. That covers the two waits that cost you the most time. When you have more sessions than you can watch, open Context Board, link your computers, and keep the Needs you list on screen. For the rest of what Claude Code can put on a board, see the Claude Code dashboard guide.