I run multiple Claude Code sessions in tmux throughout the day. One pane has Claude refactoring a component, another is debugging an API issue, and I'm actively working in a third. The problem? I kept missing when Claude finished or needed permission to continue working, switching back only to find it had been waiting for minutes. After some digging, I figured out how to get notifications working properly with tmux. Here's what I learned.
Why the default setup doesn't work
Claude Code has built-in notification support for iTerm2, but when I enabled it, nothing happened in my tmux setup. Turns out there are two issues:
- Tmux buffers output from background panes, so the notification escape sequences never reach iTerm2
- Hook output doesn't automatically go to the terminal
The fix
The solution combines Claude Code's hook system with tmux's bell forwarding. When Claude stops or requests permission, we send a bell character that tmux forwards to iTerm2 and triggers a notification.
Step 1: Configure tmux
I added these lines to my ~/.tmux.conf:
# Allow escape sequences to pass through to iTerm2
set -g allow-passthrough on
# Forward bells from ALL panes to iTerm2 (not just the active one)
set -g bell-action any
# Enable bell monitoring
set -g monitor-bell on
Then reload the config: tmux source-file ~/.tmux.conf
Step 2: Set up Claude Code hooks
This is where I got stuck for a while. I added hooks to my ~/.claude/settings.json:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "printf '\\a' > /dev/tty"
}
]
}
],
"PermissionRequest": [
{
"hooks": [
{
"type": "command",
"command": "printf '\\a' > /dev/tty"
}
]
}
]
}
}The crucial part I missed initially: > /dev/tty. Without this redirect, the bell character doesn't reach the terminal. Once I added it, everything clicked.
What these hooks do
- Stop: Fires when Claude finishes and waits for my next prompt
- PermissionRequest: Fires when Claude needs permission to run a command or edit a file
Step 3: Configure iTerm2
- Open iTerm2 → Preferences → Profiles → Terminal
- Enable alerts for bell events under Notifications
- Optionally enable "Send Notification Center alerts" for visual notifications
How it all connects
┌─────────────────────────────────────────────────────────┐
│ Claude Code (background pane) │
│ └─> Hook triggers printf '\a' > /dev/tty │
│ └─> Bell reaches pane's TTY │
│ └─> tmux (bell-action any) forwards to iTerm2 │
│ └─> iTerm2 sends macOS notification │
└─────────────────────────────────────────────────────────┘
The result
Now I hear a ping whenever any of my Claude sessions need attention. No more context-switching to check on progress, no more wasted time waiting on a session that's been idle. It's a small fix, but it's made my multi-session workflow significantly smoother.
Troubleshooting
If you're not getting notifications, here's what I'd check:
No sound at all?
- Test with
printf '\a'in any pane. You should hear a bell - Check iTerm2's bell settings aren't silenced
Sound works manually but not from hooks?
- Make sure you included
> /dev/ttyin your hook command - Verify your
settings.jsonsyntax is valid JSON
Sound only works in the active pane?
- Confirm
bell-action anyis set:tmux show-options -g bell-action - Reload tmux config after making changes
If you're juggling multiple Claude Code sessions like I do, this setup is worth the few minutes it takes to configure.