How to get a notification when Claude Code finishes or needs your input
The short answer
Add "preferredNotifChannel": "terminal_bell" to ~/.claude/settings.json and
Claude Code rings the terminal bell when it finishes or waits on a permission prompt, once you
appear to be away. Claude Code sends desktop notifications by default only in Ghostty, Kitty and
iTerm2, and iTerm2 shows them only after you turn on its alert settings. For a sound, a desktop
toast or a phone push in any terminal, add a Stop hook (every finished turn) and a Notification
hook (permission prompts and idle reminders). Or let a light show it.
Or let a light show it
A sound needs you at the desk and listening, and a toast needs you looking at the screen. A light works from across the room, with headphones on, and adds no extra ping.
- What it does
-
AC Bridge turns the smart lights and plugs you already own (Hue, LIFX, Govee, WiZ, Home Assistant and more) into a status light for Claude Code and the Codex CLI, with the hooks already wired (on Codex you approve them once in
/hooks). In the example colours from our homepage, the lamp breathes blue while the agent works, flashes red when it needs permission and turns green when it has finished; you pick the colours, and give each project its own lamp or let one lamp follow several. - What it costs
-
One plan: a 7-day free trial with no card needed, then £2.99 a month if you add a card to keep going; without one the trial just ends and nothing is charged. Cancel any time from your account. It works with the Claude Code or Codex you already run, on Windows, macOS or Linux. There is no API key to buy.
- What it collects
-
LAN devices are driven straight from your machine and their keys never leave it; your account, settings, device list, usage counts and session states sync through our servers. Your prompts, code and session transcripts are never collected. Privacy policy.
- What it follows
-
On Claude Code, AC Bridge takes needs permission from the Notification hook's
permission_promptmatcher; finished followsStop. On Codex it followsPermissionRequest, so the light changes as soon as Codex asks. See the hook events AC Bridge uses for the full list, and our Codex notifications guide for Codex's own alerts.
Generated image: a desk lit red, an example colour, while a Claude Code session needs permission.
Try it on your own lights Start the 7-day free trial, or read the setup docs and the status light guide first.
Get a notification or sound when Claude Code is done
Stop fires at the end of every turn, whether or not you are at the keyboard. Pick the
command for your system. Every hook event, with more examples, is in the Claude Code hooks guide.
macOS: a notification with osascript
~/.claude/settings.json
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code finished\" with title \"Claude Code\"'",
"async": true
}]
}]
}
}
osascript posts through Script Editor. If nothing appears, run
osascript -e 'display notification "test"' once in Terminal, then allow notifications
for Script Editor in System Settings, Notifications.
Linux
~/.claude/settings.json
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "command",
"command": "notify-send 'Claude Code' 'Finished'",
"async": true
}]
}]
}
}
notify-send needs a desktop notification daemon, so it does nothing on a headless
server or over plain SSH. On Debian and Ubuntu it comes from the libnotify-bin
package.
Windows
~/.claude/settings.json
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "command",
"command": "powershell.exe -NoProfile -ExecutionPolicy Bypass -Command \"New-BurntToastNotification -Text 'Claude Code', 'Finished'\"",
"async": true
}]
}]
}
}
BurntToast is a PowerShell module
that shows a real toast in the corner of the screen. Install it once from Windows PowerShell, the
shell the hook starts, not PowerShell 7:
Install-Module -Name BurntToast -Scope CurrentUser. The command adds
-ExecutionPolicy Bypass because Windows' default execution policy blocks module
scripts. The project is archived and no longer maintained, but its last release is still on the
PowerShell Gallery. The official docs use a MessageBox instead, which opens a dialog
that can land behind your terminal.
Play a sound when Claude Code finishes
On a Mac, the command afplay plays a system sound file, so a Stop hook can
ring Glass every time Claude finishes a turn. Linux and Windows need their own sound
command, or skip the hook and use the terminal bell.
~/.claude/settings.json
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "command",
"command": "afplay /System/Library/Sounds/Glass.aiff",
"async": true
}]
}]
}
}
Too chatty?
Stop fires on every turn, one-line answers included. The idle_prompt
matcher on the Notification hook waits until you have been away for about a minute. Still too much? See
It fires after every turn.
Claude Code notifications not working
Each fix links the GitHub issue behind it, with its state as of 31 October 2026. A closed issue means the thread is closed, not that every symptom is gone, so try the fix on your own version.
The gotcha
Both Notification types, and the built-in bell and desktop alert that share their
timing, fire in a terminal only when you appear to be away: stop typing and they come, keep
typing and they wait. permission_prompt waits about six seconds.
idle_prompt is not a "waiting for input" signal: it fires about 60 seconds after
Claude finished responding, and only if you have not typed since. For a signal the moment it
happens, use Stop for "done" and PermissionRequest for "needs
permission".
| What you see | Most likely cause | Go to |
|---|---|---|
| Nothing in the VS Code extension | A Claude Code older than 2.1.233, or the bell setting, which is reported to do nothing in the extension panel | In the VS Code extension |
| The alert comes a minute after Claude stopped | idle_prompt, working as designed |
It arrives about a minute late |
| An alert after every single reply | A Stop hook, or a Notification hook with no matcher |
It fires after every turn |
| "Waiting for input" when Claude is not waiting | A reported Windows issue (#58753) | On Windows it fires when Claude is not waiting |
| Silence inside tmux | tmux is not passing the notification on | Inside tmux |
| You want the alerts gone | The built-in alert and your hooks switch off in different places | Turning notifications off |
In the VS Code extension
Until Claude Code 2.1.233 the Notification hook did not fire for permission prompts in
the VS Code extension or in Claude Desktop. Reports ran from October 2025 (#8985, 67
reactions) to July 2026 (#79881), and both were closed as fixed in 2.1.233. The bell and desktop-alert setting, preferredNotifChannel, is reported to have no effect
in the extension panel (#92830, open). A request for native toasts in the extension, #57230,
is open too, with 57 reactions.
What to do, in order:
- Update Claude Code to 2.1.233 or later.
-
For a sound or a toast, use a hook rather than the bell setting. A
Stophook is reported to fire in the extension panel (in the threads of #79881 and #92830), and a maintainer said on #13203 thatPermissionRequesthooks work from extension version 2.1.30. -
Or run
claudein the VS Code integrated terminal instead of the panel. The bell and the hooks then work as they do in any terminal.
Checked against the Claude Code docs on .
It arrives about a minute late
That is idle_prompt. It does not fire while a background agent is still running, or
while Claude Code waits for a claude.ai usage-limit reset. There is no setting for the delay; a
request for one, #13922, is open with 42 reactions. For an alert with
no wait, change the event: Stop for "done", and
PermissionRequest for "needs permission".
Checked against the Claude Code docs on .
It fires after every turn
That is Stop, which also skips a turn you interrupt. Two ways to make it quieter:
- Switch to the
idle_promptmatcher onNotification. -
If a
Notificationhook with no matcher fires for things you did not expect, give it one of the two matchers from the Notification hook.
Checked against the Claude Code docs on .
On Windows it fires when Claude is not waiting
One Windows user reported a "waiting for input" toast at the end of every turn of a looping
session (#58753, closed for inactivity without a fix). If you see the same, let hooks tell you
instead: Stop for "done" and PermissionRequest for "needs permission".
Setting preferredNotifChannel to notifications_disabled turns the built-in
alert off and leaves your hooks running.
Checked against the Claude Code docs on .
Inside tmux
Since Claude Code 2.1.78 (March 2026), Claude Code wraps its notifications for tmux itself
(#19976, closed). tmux still has to pass them on: add
set -g allow-passthrough on to ~/.tmux.conf, then run
tmux source-file ~/.tmux.conf. A Stop hook that calls
notify-send or osascript talks to the OS directly, so tmux is not in its
way.
Checked against the Claude Code docs on .
Turning notifications off
- Built-in alert: set
preferredNotifChanneltonotifications_disabledin~/.claude/settings.json. Your hooks still run. - One hook: delete its entry. The file is strict JSON, so comments are not allowed.
- Every hook: set
"disableAllHooks": true, which also turns off a custom status line. For one run only, start Claude Code withclaude --settings '{"disableAllHooks": true}', which takes precedence over project and local settings. - Claude Desktop and the VS Code extension: set
CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKSto1to stopNotificationhooks for unanswered permission requests (Claude Code 2.1.233 or later). It has no effect in terminal sessions.
A request for one off switch, #12046 (41 reactions), was closed with a pointer to
notifications_disabled. Remote Control pushes have their own two toggles in
/config.
Checked against the Claude Code docs on .
Notification hook not working? Test it step by step
-
Paste the hook's command into your own shell, for the Linux example
notify-send 'Claude Code' 'test'. If nothing appears, fix the command first. -
In Claude Code, type
/hooks. The hook should be listed. If it is not, the settings file has a JSON syntax error (trailing commas and comments are not allowed), the hook is in the wrong file, you have not accepted the folder's trust prompt, or the file watcher missed your edit: run the file through a JSON validator, check the path, then restart the session. If the menu showsOnly hooks from managed settings run here, your organization has switched onallowManagedHooksOnly, so hooks in your own settings files do not run and are not listed. -
Ask Claude something tiny, such as "Reply with the word ok". A
Stophook fires when it finishes. -
For
permission_promptorPermissionRequest, press Shift+Tab until the status bar shows manual mode, since other modes may never prompt. Ask for something that needs your approval, then stop typing and wait about ten seconds. -
Listed but silent? Check the matcher. Matchers are case-sensitive, and a
Notificationmatcher has to be one of the types in the hooks reference, such aspermission_prompt,idle_promptoragent_completed. -
Press
Ctrl+Oto open the transcript view and look for the hook's outcome. A failed hook shows ahook errornotice with the first line of its stderr; a hook that worked shows nothing, so check for its effect instead. -
For exit codes, stdout and stderr, read the debug log. Start Claude Code with
claude --debug-file /tmp/claude.logand runtail -f /tmp/claude.login another terminal. Already running? Type/debugmid-session to switch logging on and find the log path.
Keep "async": true on a notifier hook while you test, so a slow command never holds Claude
up. Checked against the Claude Code docs on .
Get a notification when Claude Code is waiting for input: the Notification hook
A hook runs your own command, so it works in every terminal and can play a sound or show a notification. Hooks run alongside the built-in alert, not instead of it.
The two matchers most people want
This one shows a Linux desktop notification; swap in the macOS or Windows command from the Stop hook.
Make it your own
"async": trueruns the command in the background, so a slow notifier never holds Claude up.- Leave the matcher out to fire on every notification type; the hook gets
notification_typeandmessageas JSON on stdin if you would rather branch in one script. - For a sound on macOS, the command can be
afplay /System/Library/Sounds/Glass.aiff. - Type
/hooksin Claude Code to check that the hook is registered; edits to the settings file are normally picked up without a restart. - More examples: hooks guide.
~/.claude/settings.json
{
"hooks": {
"Notification": [{
"matcher": "permission_prompt",
"hooks": [{
"type": "command",
"command": "notify-send 'Claude Code' 'Needs your permission'",
"async": true
}]
}, {
"matcher": "idle_prompt",
"hooks": [{
"type": "command",
"command": "notify-send 'Claude Code' 'Waiting for you'",
"async": true
}]
}]
}
}
Instant permission alerts with PermissionRequest
PermissionRequest fires the moment Claude is about to show a permission prompt, with
no six-second wait and whether or not you are typing.
A PermissionRequest hook that prints a decision approves or denies the request for
you. So this one runs in the background and prints nothing: with "async": true the
hook cannot decide anything, so the normal prompt still appears.
It does not cover a sandboxed command's network request, an MCP server's input form or Claude's
AskUserQuestion tool. A PreToolUse hook with the matcher
AskUserQuestion runs when Claude calls the tool.
~/.claude/settings.json
{
"hooks": {
"PermissionRequest": [{
"hooks": [{
"type": "command",
"command": "notify-send 'Claude Code' 'Asking for permission'",
"async": true
}]
}]
}
}
Add a notification sound with one line of settings
Claude Code's own alert is the preferredNotifChannel setting, shown as
Local notifications in /config.
Ring the bell in any terminal
~/.claude/settings.json
{
"preferredNotifChannel": "terminal_bell"
}
The bell rings only when you appear to be away. Looking for
claude config set --global preferredNotifChannel terminal_bell? The
claude config command is no longer part of Claude Code (the 2.0.0 release notes say
"Unshipped claude config command"), so use /config or this snippet.
The other values
auto is the default. It sends a desktop notification in Ghostty, Kitty and iTerm2, and
does nothing in most other terminals. The rest are iterm2,
iterm2_with_bell, kitty, ghostty and
notifications_disabled. Turning notifications off does not stop your hooks.
In Apple's Terminal, auto rings the bell only when its audible bell is off. If you
accepted Claude Code's first-run terminal setup there, it turned the audible bell off, so with
terminal_bell you hear nothing until you switch Audible bell back on in the
Terminal profile's Advanced settings. Details:
terminal configuration.
Notifications in iTerm2, Ghostty and Kitty
With the default auto setting, Claude Code sends a real desktop notification in
Ghostty, Kitty and iTerm2, and nothing in most other terminals. Windows Terminal, Warp and the VS
Code terminal need the bell or a hook.
-
One switch first
Claude Code notifications in iTerm2
- Open Settings, Profiles, Terminal.
- Tick Notification Center Alerts.
- Click Filter Alerts and enable Send escape sequence-generated alerts.
The value
iterm2_with_bellrings the bell as well. -
Warp's own alerts
Claude Code notifications in Warp
Warp has its own agent notifications: add its Claude Code plugin once, from the chip Warp shows or by hand. You then get toasts, a notification mailbox and, with Warp in the background, desktop alerts.
-
Bell or hook
Claude Code notifications in WezTerm
Set
terminal_bell, or use the terminal hook below. WezTerm'snotification_handlingoption decides what it shows:SuppressFromFocusedPaneskips the pane you are looking at. -
Works out of the box
Claude Code notifications in Ghostty
If alerts never come, check that Ghostty's own
desktop-notificationsoption, on by default, has not been turned off in its config. -
No setup needed
Claude Code notifications in Kitty
If an alert goes missing, look for a
filter_notificationrule: Kitty can filter desktop notifications before they reach you. -
One line of config
Claude Code notifications in tmux
tmux sits between Claude Code and your terminal, so a desktop alert gets through only if tmux passes it on. The fix is under Inside tmux. The terminal hook below works inside tmux as it stands.
A terminal hook for terminals with no built-in alert
A hook has no terminal of its own, so it prints a terminalSequence and Claude Code
sends it for you. OSC 777 reaches Warp, WezTerm, Ghostty and urxvt; OSC 9 reaches iTerm2, Windows
Terminal and WezTerm; OSC 99 reaches Kitty.
~/.claude/hooks/terminal-notify.sh
#!/bin/bash
input=$(cat)
body=$(jq -r '.message // "Needs your attention"' <<<"$input")
seq=$(printf '\033]777;notify;%s;%s\007' "Claude Code" "$body")
jq -nc --arg seq "$seq" '{terminalSequence: $seq}'
Make it executable and add it as a Notification command hook. It needs
jq. Leave "async": true off this one hook, because Claude Code has to read
what it prints, and expect nothing with claude -p. Details:
emit terminal notifications.
The Claude desktop app
The Code tab sends an OS notification when a session finishes a task and you are not viewing it. A session in a project gets the project's notifications instead: Claude posts, a thread errors or it needs input. Open Notifications in the project's sidebar menu to add one for each turn or to turn them off.
Two macOS reports were open on 31 October 2026: turn-complete notifications that come and go (#97368) and an app that never registers with Notification Center (#73370).
Over SSH
The notification still reaches your own computer; Ghostty and Kitty hand it to the OS with no setup.
Still nothing?
Check that your terminal app is allowed to send notifications in the OS settings.
Claude Code notifications on Windows and in the Windows Subsystem for Linux
On Windows
Claude Code runs hook commands in Git Bash, or in PowerShell when Git Bash is not installed; set
"shell": "powershell" on a hook to choose. The BurntToast command in the Stop hook works
from either, because it starts powershell.exe itself. For Windows Terminal, the
terminal hook needs OSC 9: make its
printf line seq=$(printf '\033]9;%s\007' "$body").
For a toast with no module, and how to check one, see Claude Code notifications on Windows.
In a Linux distribution on Windows
Under the Windows Subsystem for Linux, notify-send usually has no notification daemon
to talk to, so call Windows instead. Windows programs are on the Linux PATH through
interop: the same powershell.exe command from the Stop hook works unchanged, and the toast
appears on your Windows desktop. Install BurntToast in Windows PowerShell, not inside Linux.
powershell.exe can take a moment to start, which is one more reason for
"async": true.
Claude Code notifications in VS Code
In the extension
A small coloured dot on the spark icon shows a tab's status: blue means a permission request is
pending, orange means Claude finished while the tab was hidden. The dot is a visual cue only. For a
sound or a toast, use a hook: from Claude Code 2.1.233, the permission_prompt matcher
fires about six seconds after Claude asks, and it does not wait for you to stop typing. Details:
VS Code docs.
In the integrated terminal
The integrated terminal gets no built-in desktop alert, so run claude there with the
terminal bell or a Stop or
Notification hook. If a notification still does not
arrive, see In the VS Code extension for the known issues.
For which hooks fired in the panel and in the terminal on a live run, see Claude Code notifications in VS Code.
Get Claude Code notifications on your phone
Claude Code can push to your phone without a hook. The push comes with Remote Control.
-
Check your plan
Remote Control needs a Claude Pro, Max, Ultra, Team or Enterprise plan. API keys are not supported, and it is not available with Amazon Bedrock, Google Cloud's Agent Platform or Microsoft Foundry. On Team and Enterprise an Owner must switch it on first.
-
Install the app
Install the Claude app on your phone, sign in with the same account and organization you use for Claude Code, and allow its notifications.
-
Switch it on
Run
/remote-controlin Claude Code, start it withclaude --remote-control, or turn on Enable Remote Control for all sessions in/config. -
Choose your pushes
In
/config, turn on Push when Claude decides (Claude typically sends one when a long-running task finishes or when it needs a decision from you), Push when actions required (permission prompts and questions), or both. They are the settingsagentPushNotifEnabledandinputNeededNotifEnabled, and both are off by default. You can also ask in the prompt, for examplenotify me when the tests finish.
When a push is skipped
Pushes go out only while Remote Control is active, and are skipped while you are typing in, or
focused on, the connected terminal. To skip them while you are at your desk, set
CLAUDE_CLIENT_PRESENCE_FILE to the path of a marker file: Claude Code skips the push
while that file exists. Have a screen-lock listener create the file when you unlock and delete it
when you lock (Claude Code 2.1.181 or later).
If nothing arrives
/configmust not show No mobile registered: open the Claude app so it can refresh its push token.- No iOS Focus mode or notification summary should be holding the push back.
- Android battery optimisation should not be delaying the Claude app.
ntfy, from a hook
ntfy is a free push service with Android and iOS
apps. Use it for a push from a plain Stop hook, or when Remote Control is not an
option. Subscribe to a topic in the app, then publish to it from a hook. There is no sign-up, so
the topic name works like a password: pick one nobody could guess.
-o /dev/null keeps curl quiet. ntfy replies with JSON, and Claude Code reads JSON that a
hook prints as hook output, so keep the hook's stdout empty. Put the same command in a
Notification hook for permission prompts. It needs a POSIX shell, which means macOS,
Linux, or Windows with Git Bash installed. Titles, priorities and self-hosting:
ntfy publishing docs.
~/.claude/settings.json
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "command",
"command": "curl -s -o /dev/null -d \"Claude Code finished\" ntfy.sh/your-hard-to-guess-topic",
"async": true
}]
}]
}
}