Don't Miss Your Claude Code Notifications

March 21, 2025

One of my personal quirks of working with Claude Code is that it often runs autonomously for a while, then suddenly needs your input. And when you miss it, you have the session waiting there without burning your token for minutes, sometimes hours. You easily miss it when you're not watching the terminal (and of course it happens all the time when you have 5 sessions running in parallel). A few tricks I find useful, from local to remote.

The Local Case: Hooks

Claude Code supports hooks — shell commands that run in response to lifecycle events. To get notification when you're on your laptop, the simplest approach is a notification hook that plays a system sound via osascript, and it's hard for you to miss it with a banner and a ringing sound:

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

There's also a Stop hook that's triggered when Claude is on pause, which could be task completion or the program halting for some reason.

One caveat: the stop hook fires for every agent that finishes, not just the top-level session. In team mode, each sub-agent completion triggers a ping, which gets noisy fast.

This all works fine locally. The challenge starts when you're SSH'd into a remote machine.

The Remote Problem

When you run Claude Code on a remote server over SSH, osascript runs on the remote machine — which has no display, no notification center, and no speakers. The notification goes nowhere.

I went through several approaches before finding something reliable.

Attempt 1: Terminal Bell

The simplest idea — emit a bell character:

echo -e '\a' > /dev/tty

In iTerm2, you can configure bell sounds and even "Notify when bell rings" in the profile settings. The problem: it only works if iTerm is focused, and the notification behavior is inconsistent across sessions.

Attempt 2: iTerm2 Triggers

iTerm2 supports regex triggers under Profile → Advanced → Triggers. The idea:

  1. Stop hook echoes a marker: echo -e 'TASK_COMPLETE' > /dev/tty
  2. Trigger matches TASK_COMPLETE and runs osascript locally to display a notification

This worked... sometimes. The trigger matching seemed unreliable across different session states.

What Actually Works: OSC 9

OSC 9 is a terminal escape sequence that sends a notification directly to the macOS notification center, even if the terminal isn't focused. And crucially, it works over SSH.

Test it locally:

printf '\e]9;This will show as a notification\a' > /dev/tty

For tmux on the remote machine, you need passthrough enabled:

# In remote ~/.tmux.conf
set -g allow-passthrough on

Then wrap the escape sequence in tmux passthrough:

printf '\ePtmux;\e\e]9;Claude Code task done\a\e\\' > /dev/tty

Final Stop Hook for Remote

This handles both tmux and non-tmux sessions:

{
  "hooks": {
    "Stop": [
      {
        "matcher": {},
        "command": "if [ -n \"$TMUX\" ]; then printf '\\ePtmux;\\e\\e]9;Claude Code task done\\a\\e\\\\' > /dev/tty; else printf '\\e]9;Claude Code task done\\a' > /dev/tty; fi"
      }
    ]
  }
}

Limitation: this won't work if the tmux session is detached. The escape sequence needs a live terminal connection to travel through.

True Remote Notifications: ntfy.sh

If you need notifications when you're not connected to the terminal at all — say you're away from your laptop — you need an external push mechanism.

ntfy.sh is the simplest & most reliable option I've found. It's a pub/sub notification service: you publish to a topic URL, and any device subscribed to that topic gets a push notification.

curl -d "Claude Code task done" ntfy.sh/your-topic-name

Subscribe on your phone via the ntfy app, and you'll get a push notification wherever you are.

The tradeoff: topics are public by default, so anyone who knows your topic URL can listen. You can self-host ntfy if that matters, or use authentication tokens. Other options like Telegram bots, Slack webhooks, or email work too, but ntfy has the lowest setup friction.

Summary

MethodLocalRemote (SSH)Detached/Mobile
osascript hookYesNoNo
Terminal bellPartialPartialNo
iTerm2 triggersPartialPartialNo
OSC 9 escapeYesYesNo
ntfy.sh / TelegramYesYesYes

Start with OSC 9 for SSH workflows — it's the best balance of reliability and simplicity. Add ntfy.sh when you need notifications that survive disconnection.