Guide

How to get a Claude Code notification when it is done

How to get a Claude Code notification when it is done

To get a Claude Code notification when done, the fastest route is the terminal bell: run claude config set --global preferredNotifChannel terminal_bell and your terminal beeps when the agent finishes or stops to ask you something. That works while the terminal is visible. The moment you are heads-down in another window — an editor, a browser, a game — the bell stops reaching you, and you need something that draws on top. This guide walks the full ladder, from the one-line bell to a Stop hook desktop alert, to a phone push, to an ambient overlay toast that survives fullscreen.

Why you alt-tab

An AI coding agent is not a batch job. Claude Code pauses — for permission before a risky command, for clarification when your instructions are ambiguous, and at the end of a turn waiting for your next move. Those pauses are the whole interaction. Hand it a refactor, go read a PR, and the run quietly stalls on a prompt you never saw.

So you alt-tab. You flick back to the terminal every minute or two to check whether it is waiting on you. That checking is the babysitting — the thing a notification is supposed to delete. The fix is to let the agent reach you instead of you reaching for it. The rest of this post is four ways to do that, from least to most reachable. If the underlying problem resonates, it is the subject of stop babysitting your AI coding agent.

Bell plus Stop hook

Start with the built-in. Claude Code has a preferredNotifChannel setting; set it to terminal_bell and the terminal rings on the events that need you:

claude config set --global preferredNotifChannel terminal_bell

No restart needed in current builds. By default Claude Code already sends OS-level desktop notifications in a few terminals that support them — Ghostty, Kitty, and iTerm2 — so if you live in one of those you may have alerts already. Everywhere else, the bell is your fallback.

The catch is structural: a terminal bell only fires if the terminal is focused or visible. Put a fullscreen app on top and the OS mutes or drops the BEL byte. The bell solves "I clicked into Slack in the same window manager," not "I am in another app." For that you need a hook.

Claude Code exposes lifecycle hooks — shell commands that fire on specific events. Three matter here, and it is worth getting the names right because people mix them up:

A minimal Stop hook that pops a native macOS notification goes in ~/.claude/settings.json:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude finished\" with title \"Claude Code\" sound name \"Glass\"'"
          }
        ]
      }
    ]
  }
}

Verify the exact hook schema against the official hooks reference before you rely on it — Anthropic revises payload fields between releases. On Linux swap osascript for notify-send; on Windows, a PowerShell toast. Add a matching handler under Notification if you also want a ping when it stops to ask you something, not just when it is done.

Desktop notification

The osascript hook above is the difference between "the terminal beeped" and "a banner appeared in the corner of my screen." A desktop notification is drawn by the OS notification center, so it surfaces over your editor and browser even when the terminal is buried — exactly what the bell cannot do.

One more useful property: desktop notifications can travel over SSH. If you run Claude Code on a remote box and connect from your laptop, a hook that triggers a local notifier on your machine still reaches you. The terminal bell, by contrast, rings wherever the shell thinks "the terminal" is — often nowhere useful.

The gap that remains: a banner over a fullscreen app is unreliable. macOS and Windows both suppress or queue notifications when something is in true fullscreen, and most games and many editors run that way. So a desktop notification is a solid upgrade over the bell for normal windowed work, and still leaks the instant you go fullscreen. Two ways out of that: send the signal to your phone, or draw it yourself on top.

Phone push

If the run is long enough that you have walked away from the desk, the right surface is your pocket. The same Stop and Notification hooks can curl a push service instead of (or alongside) the local notifier. A one-line ntfy publish is the common pattern:

curl -s -d "Claude Code finished" ntfy.sh/your-private-topic-name

Wire that as the command in a Stop hook and you get a push on your phone when the agent finishes. ntfy, Pushover, or a Slack/Discord webhook all work the same way — it is just an HTTP POST from the hook. Several community projects package this up, and the more advanced ones use the PreToolUse payload to send an Allow/Deny prompt you can tap from the phone, so you do not have to run back to approve a command. That is the ceiling of the DIY approach: notification plus remote approval, glued together from hooks and a push service you maintain.

The trade-off is that you are now operating a notification pipeline. Topic names, an extra service, a script per machine, and no shared state between "the alert" and "the terminal you then have to go find." It works; it is just yours to keep working.

Backgrind ambient toasts

This is the layer Backgrind is built around, and it is the on-brand answer to the fullscreen gap above. Backgrind runs your real claude CLI — your login, your history — inside an always-on-top terminal that floats over any app, including borderless-fullscreen games. When the agent needs you, the notification is an ambient toast plus an accent ring on the tab that needs attention — drawn by the overlay itself, so it shows up over a fullscreen app where an OS banner would be suppressed.

Two design choices make it feel different from a raw hook setup. First, the alerts are driven by the same Claude Code lifecycle hooks under the hood — Notification, Stop, PreToolUse — so it fires only on a decision or a finish, never on every tool call. No firehose. Second, a background daemon owns the agent, separate from the window, so the notification keeps firing even while the overlay is hidden and the work survives a UI restart. You can read more on that split in running Claude Code in the background, and on running several at once in multiple agent tabs.

Phone via Live

The overlay handles "I am at the machine but in another app." For "I left the room," Backgrind has Live mode: a browser console you reach from your phone where you can read the agent's output and answer its prompts. It is the same idea as the DIY ntfy Allow/Deny trick, but with the full terminal behind it instead of a one-shot button — you can type a follow-up, not just tap yes. Live is the headline Plus feature, and Plus trial users get it during the trial. More on the remote story in controlling your coding agent from your phone.

Which method

Pick by where you actually are when the agent stops:

The DIY ladder is real and worth knowing — bell, hook, push — and for many people it is enough. The thing it cannot give you cleanly is a signal that survives fullscreen and ties back to the live terminal, which is the niche the overlay fills.

Frequently asked questions

How do I get a Claude Code notification when done?

The quickest way is the terminal bell: run claude config set --global preferredNotifChannel terminal_bell and your terminal beeps when Claude finishes or waits for input. For something you can hear or see while in another app, wire a Stop hook to osascript (macOS) or a push service like ntfy.

Which Claude Code hook fires when the agent finishes?

The Stop hook fires when Claude finishes its response (its turn). The Notification hook fires when Claude needs your attention, such as waiting for input or a permission decision. Both live under the hooks key in settings.json. PreToolUse fires before a tool runs and can pause for allow/deny.

Why does the terminal bell not reach me when I am gaming or in another app?

A terminal bell only does something if the terminal is focused or at least visible. Once a fullscreen game or editor is on top, the bell is muted or ignored by the OS. To get a signal over a fullscreen app you need a separate surface that draws on top, like a desktop notification, a phone push, or an always-on-top overlay.

Should I fire a notification on every tool call?

No. Notify only on the transitions that need you: a permission decision (Notification or PreToolUse) and "done" (Stop). Firing on every PostToolUse turns into a firehose you learn to ignore, which defeats the point.

Where Backgrind fits

Backgrind is an overlay over your real Claude Code CLI, not an agent or a model of its own — it renders the terminal and forwards your input, and the notifications it fires come from the same Claude Code hooks you would wire by hand. What it adds is the surface those hooks were missing: ambient toasts that draw over a fullscreen app where an OS banner gets suppressed, fired only on a decision or a finish rather than on every tool call, plus Live mode so you can answer a prompt from your phone instead of running back to the desk. If you only ever code in a visible terminal, the built-in bell is genuinely enough. If you are alt-tabbing out of a game or an editor, that is the gap Backgrind closes — see the live demo to feel the notification loop.