On Linux, Claude Code sends a desktop notification by itself only in a few terminals, such as Ghostty and Kitty. Everywhere else, add a Notification hook that runs notify-send 'Claude Code' 'Claude Code needs your attention' to ~/.claude/settings.json, plus a Stop hook if you want to know the moment Claude finishes. notify-send comes from libnotify (libnotify-bin on Debian and Ubuntu) and needs a running notification daemon, which GNOME and KDE Plasma provide and which headless servers and SSH sessions do not have.
01What Claude Code does on its own
When Claude finishes a task or waits for a permission and you seem to be away, Claude Code fires a notification event. Anthropic's terminal guide says Ghostty and Kitty turn this into a desktop notification; other terminals, such as GNOME Terminal, Konsole or the VS Code terminal, show nothing.
You can ask for a bell in any terminal instead:
{
"preferredNotifChannel": "terminal_bell"
}
What a bell does depends on the terminal and desktop. It may beep, flash, or mark the window as urgent. The terminal bell guide covers this. For a real notification, use a hook.
02Install notify-send
Check whether you have it:
notify-send 'Claude Code' 'test'
If the command is not found, install it:
sudo apt install libnotify-bin # Debian, Ubuntu, Mint
sudo dnf install libnotify # Fedora, RHEL
sudo pacman -S libnotify # Arch
If the command runs but nothing appears, you have no notification daemon. GNOME, KDE Plasma, Cinnamon and Xfce include one. On a tiling window manager such as Sway, i3 or Hyprland, install and start one yourself, for example mako or dunst. Wayland and X11 both work, because notify-send talks to the daemon over D-Bus, not to the display.
03A Notification hook
This is the Linux example from Anthropic's hooks guide. Add it to ~/.claude/settings.json, beside any keys you already have:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'Claude Code needs your attention'"
}
]
}
]
}
}
Type /hooks in Claude Code to see it listed under Notification. The empty matcher fires for every notification type. The main ones are permission_prompt, after an approval has waited about six seconds without you typing, and idle_prompt, about 60 seconds after Claude finishes. The Notification hook guide has the full list.
04Know the moment Claude finishes
idle_prompt comes a minute late. A Stop hook runs as soon as Claude ends its turn. It takes no matcher:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "notify-send -a 'Claude Code' 'Claude Code' 'Claude has finished'"
}
]
}
]
}
}
-a sets the app name the daemon shows. Other useful options: -u critical keeps the notification on screen until you dismiss it on most daemons, and -i dialog-information adds an icon. More on this event in the Stop hook guide.
05Show the real message, with a sound
Hooks receive JSON on standard input, and Notification input includes a message field. A script can show that text and play a sound. Save this as ~/.claude/hooks/notify-linux.sh:
#!/bin/bash
msg=$(jq -r '.message // "Claude Code needs your attention"')
notify-send -a 'Claude Code' 'Claude Code' "$msg"
paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null || true
Make it executable with chmod +x ~/.claude/hooks/notify-linux.sh and use ~/.claude/hooks/notify-linux.sh as the hook command. jq is in every distribution's packages. paplay works with PulseAudio and with PipeWire's PulseAudio layer, and the sound file comes from the freedesktop sound theme (sound-theme-freedesktop on Debian and Ubuntu). Use any .oga or .wav you like.
06No notify-send? Use an escape sequence
If your terminal understands notification escape sequences, a hook can ask Claude Code to send one. Hooks have no terminal of their own, so you return the sequence in a terminalSequence field and Claude Code writes it. Anthropic's reference lists OSC 777 for Ghostty, urxvt and Warp, and OSC 99 for Kitty. For example:
#!/bin/bash
body=$(jq -r '.message // "Needs your attention"')
seq=$(printf '\033]777;notify;%s;%s\007' "Claude Code" "$body")
jq -nc --arg seq "$seq" '{terminalSequence: $seq}'
This needs no daemon on the machine Claude Code runs on, which is why it is also the trick for remote servers over SSH.
07When notify-send works in a shell but not from Claude Code
notify-send needs the D-Bus session address of your desktop login. Hooks inherit Claude Code's environment, so Claude Code started from a desktop terminal is fine. Claude Code started over SSH, from a systemd service, in a container, or inside a tmux server that was first started from SSH, may not have it, and the notification goes nowhere. Run echo $DBUS_SESSION_BUS_ADDRESS in the same shell you start claude from; if it is empty, desktop notifications from that session will not show. The tmux guide and the SSH guide cover those set-ups.
08Where Claude Code Notifier fits
The hooks above are a sound choice when you work at the machine. They cannot reach you once you leave the desk, and a desktop notification cannot answer Claude.
Claude Code Notifier is an independent tool (made by TouchTap, not by Anthropic) built on Claude Code's hooks. Its free command line tool, ccn, runs on Mac, Windows and Linux. On Linux:
curl -fsSL https://claudecodenotifier.com/install.sh | sh
or npx @touchtap/ccn if you have Node.js. It adds its hook entries to ~/.claude/settings.json, leaves everything else in place and keeps a backup. From then on it shows a Linux desktop notification when Claude finishes, needs a permission or asks a question. That part needs no network and no phone. It runs for a few milliseconds per event; nothing stays running in the background.
Pair an iPhone or Android phone and the same events arrive as push notifications, even on a machine with no desktop at all. From the phone you can allow or deny a permission, pick an answer to Claude's question, and send the next instruction after Claude finishes. See pairing a phone, the ccn page and pricing for the phone apps. On Linux, ccn keeps its token in a file readable only by you.
If you install ccn, remove your own notify-send hooks to avoid duplicates.
09FAQ
Why does notify-send work in my terminal but not in the hook?
Usually the hook has no D-Bus session address, because Claude Code was started over SSH, in a container or in a tmux server started without one. Start Claude Code from a desktop terminal, or use a phone push instead.
Which package provides notify-send?
libnotify-bin on Debian and Ubuntu, and libnotify on Fedora and Arch. You also need a notification daemon, which full desktops include.
Does this work on Wayland?
Yes. notify-send uses D-Bus, so it works the same on Wayland and X11 as long as a notification daemon is running.
How do I make the notification stay until I see it?
Add -u critical to the notify-send command. Most daemons keep critical notifications on screen until you dismiss them.
Can I get Claude Code notifications on a headless Linux server?
Not as desktop notifications, because there is no desktop. Use an escape sequence through your SSH terminal, or a push service such as ccn's phone app. The SSH guide compares the options.