AC Bridge

How to get a notification when Claude Code finishes or needs your input

Last updated · Last verified against the Claude Code and Codex docs on

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_prompt matcher; finished follows Stop. On Codex it follows PermissionRequest, 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.

A generated home office desk lit red, an example colour for a Claude Code permission prompt
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:

  1. Update Claude Code to 2.1.233 or later.
  2. For a sound or a toast, use a hook rather than the bell setting. A Stop hook is reported to fire in the extension panel (in the threads of #79881 and #92830), and a maintainer said on #13203 that PermissionRequest hooks work from extension version 2.1.30.
  3. Or run claude in 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_prompt matcher on Notification.
  • If a Notification hook 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 preferredNotifChannel to notifications_disabled in ~/.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 with claude --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_HOOKS to 1 to stop Notification hooks 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

  1. 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.

  2. 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 shows Only hooks from managed settings run here, your organization has switched on allowManagedHooksOnly, so hooks in your own settings files do not run and are not listed.

  3. Ask Claude something tiny, such as "Reply with the word ok". A Stop hook fires when it finishes.

  4. For permission_prompt or PermissionRequest, 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.

  5. Listed but silent? Check the matcher. Matchers are case-sensitive, and a Notification matcher has to be one of the types in the hooks reference, such as permission_prompt, idle_prompt or agent_completed.

  6. Press Ctrl+O to open the transcript view and look for the hook's outcome. A failed hook shows a hook error notice with the first line of its stderr; a hook that worked shows nothing, so check for its effect instead.

  7. For exit codes, stdout and stderr, read the debug log. Start Claude Code with claude --debug-file /tmp/claude.log and run tail -f /tmp/claude.log in another terminal. Already running? Type /debug mid-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": true runs 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_type and message as 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 /hooks in 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.

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.

  1. 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.

  2. 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.

  3. Switch it on

    Run /remote-control in Claude Code, start it with claude --remote-control, or turn on Enable Remote Control for all sessions in /config.

  4. 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 settings agentPushNotifEnabled and inputNeededNotifEnabled, and both are off by default. You can also ask in the prompt, for example notify 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

  • /config must 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
      }]
    }]
  }
}