Directed Notifications for Claude Code Async Programming
This afternoon I leveled up my previous Claude Code notifications. Now I have Claude’s notifications:
- grouped by project/directory
- take me directly to the relevant terminal pane if clicked
- persisted until I act on them
Read that original post for details, but generally I have Claude send me notifications in two channels: general prompt and hooks.
In that previous configuration, I was using Apple’s built-in notifications via AppleScript. Now, I’ve finally bitten the bullet and upgraded to julienXX’s terminal-notifier
package that lets you customize much more. Specifically, it lets you set:
- an application to activate upon notification click
- a shell command to execute upon notification click
- a group identifier for grouping notifications
- and a bunch of other options
So, where previously all the Claude notifications were bunched together and clicking any did nothing but bring up AppleScripts, now I can have each Claude instance send its own notifications to its own group and when I click one I’m brought directly to that Claude Code panel in my terminal.
Installation
You’ll need to install:
- terminal-notifier
- a terminal that allows for programmatic tab/panel activation
- I use WezTerm
- (you could replicate this in
tmux
orkitty
, for example)
Once you have those installed, you can install a Claude Code Hook to get a desktop notification whenever it needs you to unblock its progress on a task. It will ping you when it needs permission or input on a task, with details about the permission.
Here’s what I have in my ~/.claude/settings.json
user settings:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "jq -r '.message' | xargs -I {} terminal-notifier -message \"{}\" -title \"Claude Hook\" -group \"$(pwd):hook\" -execute \"/opt/homebrew/bin/wezterm cli activate-pane --pane-id $WEZTERM_PANE\" -activate com.github.wez.wezterm"
}
]
}
]
}
}
Breaking that down:
# parse out the message field from the hook payload sent by Claude Code
jq -r '.message' | \
# pipe that into terminal-notifier as the message
xargs -I {} terminal-notifier -message \"{}\" \
# title it Claude Hook so I can distinguish it from Claude itself
-title \"Claude Hook\" \
# group it by the directory Claude is operating in, suffixed with ':hook'
-group \"$(pwd):hook\" \
# focus this Claude instance's pane within the terminal multiplexer when the notification is clicked
-execute \"/opt/homebrew/bin/wezterm cli activate-pane --pane-id $WEZTERM_PANE\" \
# activate WezTerm when the notification is clicked
-activate com.github.wez.wezterm
This is using WezTerm’s activate-pane CLI command and its $WEZTERM_PANE
environment variable for each session.
So that takes care of notifying me when Claude needs permission for something. I also tell Claude Code to notify me when it accomplishes something (and it’s about to stop). Here’s the relevant section in my user settings prompt ~/.claude/CLAUDE.md
:
After making a set of changes to files or satisfying a task, you MUST display a `terminal-notifier` notification to tell me what's been done. Use a title and a brief descriptive message. Here's an example:
```bash
terminal-notifier -message "I've finished refactoring the FooBar class into smaller methods" -title "Claude Code" -group $PWD -execute "/opt/homebrew/bin/wezterm cli activate-pane --pane-id $WEZTERM_PANE" -activate com.github.wez.wezterm
```
This is very similar to the hook implementation but I just have it grouping by the present working directory. Since I make git worktrees for each of my different tasks these days, each task tends to have its own dedicated directory.
For this to reliably be available for Claude, I also add a permission to my user settings to allow terminal-notifier commands:
{
"permissions": {
"allow": [
"Bash(terminal-notifier:*)"
]
}
}
Another change I’ve made with this new configuration is that I have the notifications persist until I dismiss or click them. You can set this in System Preferences under Notifications > terminal-notifier
.
I know others have been building more… complex interfaces for managing lots of Claude instances, but I like to keep as close to the terminal as possible (as close to the actual Claude and its code/changeset as possible). With this new setup, I’m even more confident running handfuls of concurrent Claude coders. Each one gets its own notification queue and I can be sure of finding them in just a single click.
Reference
- Blog / Practicing
- code-snippets, ai, tools
-
Permalink to
2025.BLG.152
- Edit
← Previous | Next → |
Releasing gh-pr-staleness: GitHub CLI Extension for Commits Behind Target |