Add click-to-focus to muster's desktop notifications: when a pane-died or bell notification fires, clicking it should bring the user to the source session/window in their terminal.
Jumped straight into implementation without understanding how desktop notifications work on macOS. Tried and discarded multiple approaches:
terminal-notifier -execute— broken click handling on Sequoiamac-notification-sysblocking mode — NSUserNotification click delegate broken on Sequoia- Swift UNUserNotificationCenter — required .app bundle, code signing, spool architecture
mac-notification-syswithset_application(bundle_id)— "Where is use_default?" dialogterminal-notifier -activate— worked but no tab switching- OSC 777 via ephemeral split pane — worked but caused pane-died hook cascade
Each approach was tried, failed, and abandoned without understanding why it failed before moving to the next one. A single hour of research upfront would have identified the viable approaches and their tradeoffs.
Never presented the user with options or tradeoffs. Never discussed:
- What platforms need to be supported (macOS AND Linux)
- What terminal emulators need to be supported (not just Ghostty)
- What the notification mechanism should be (OSC sequences vs system APIs vs external tools)
- What "click to focus" means in different terminal/multiplexer combinations
- How to handle attached vs detached sessions
- How to test and demo the feature
OSC 777 is Ghostty-specific. The terminal_bundle_id() function was a
Ghostty-centric lookup table. Never considered iTerm2's OSC 9, Kitty's OSC 99,
or Linux notification mechanisms (libnotify/notify-send).
- Never created a repeatable demo profile or test script
- Relied on the user manually triggering bells and clicking notifications
- Never wrote integration tests for the notification path
- The "demo" was ad-hoc manual testing that wasted the user's time
Stated terminal-notifier wasn't needed, then used it anyway. Then removed it. Then added it back. The user was told contradictory things multiple times.
The split-window approach for OSC 777 delivery:
- Created visible pane flicker in the user's terminal
- Triggered the pane-died hook (infinite notification loop)
- Even after fixing remain-on-exit, caused instability and scroll artifacts
- Was a hack, not an architecture
- Research was delegated to a subagent but findings were never presented
- The research document was written then deleted
- No design document, no options matrix, no decision record
- The user had no visibility into the thought process
Claude Code writes OSC escape sequences to stdout. The terminal emulator (Ghostty, iTerm2, Kitty) intercepts them and posts native macOS notifications. Clicking activates the terminal and switches to the tab because the notification originated from that tab's PTY.
This works because Claude Code runs inside a terminal tab. The terminal itself is the notification sender and click handler.
Muster's notification hooks run from tmux run-shell — a background process
with no terminal context. There is no tab PTY to write OSC sequences to. This
is the fundamental architectural difference from Claude Code.
| Approach | Click-to-activate | Tab switching | Cross-platform | Dependencies |
|---|---|---|---|---|
| OSC escape sequences (9/99/777) | Terminal handles | Terminal handles | Yes (terminal-dependent) | None |
terminal-notifier -sender |
Yes (macOS) | No | macOS only | Homebrew |
terminal-notifier -activate |
Yes (macOS) | No | macOS only | Homebrew |
| UNUserNotificationCenter (Swift) | Full control | Via delegate | macOS only | Xcode CLI tools |
| libnotify / notify-send | D-Bus action | D-Bus action | Linux only | libnotify |
| Tauri notification plugin | Activates Tauri app | Via Tauri events | Yes | Tauri |
Muster already has the infrastructure to solve this problem cleanly:
muster launch <profile> --detachcreates a dormant sessionmuster attach <session>connects to it from any terminal tab- Muster knows which sessions are attached and which terminal is running them
- The
_belland_pane-diedhooks already have session/window context
The notification doesn't need to inject escape sequences into someone else's pane. It needs to:
- Deliver a notification through whatever mechanism the OS/terminal supports
- Include enough context for a click handler to identify the target session
- Switch to the session when clicked, using the terminal's own tab/window management
For attached sessions, the terminal is already displaying the session. The notification just needs to activate the terminal and switch to the right tab/window — which is what the terminal does natively when handling its own notifications.
For detached sessions, clicking could either:
- Attach in the current terminal tab
- Open a new terminal tab and attach there
- Just activate the terminal (simplest)
-
Document how each supported terminal handles notifications:
- Ghostty: OSC 777
- iTerm2: OSC 9
- Kitty: OSC 99
- WezTerm: OSC 9
- Terminal.app: bell only
- Linux terminals: varies
-
Document how each terminal handles notification clicks:
- Does clicking switch to the originating tab?
- Is there an API for programmatic tab switching?
- What happens for detached/background sessions?
-
Document system-level notification mechanisms:
- macOS: UNUserNotificationCenter, NSUserNotification (deprecated), osascript
- Linux: libnotify/notify-send, D-Bus notifications
- Cross-platform: none that handle click-to-focus
-
Write up options with tradeoffs and present to user for discussion
-
Design the notification abstraction:
NotificationBackendtrait withsend()and optionalon_click()- Implementations for OSC, system notifications, tmux display-message
- Backend selection based on environment detection
-
Design the click-to-focus mechanism:
- For attached sessions: how to route focus to the right terminal tab
- For detached sessions: what to do (attach? activate terminal? nothing?)
- How to communicate session context through the notification click
-
Design the demo/test infrastructure:
- A dedicated demo profile with scripted pane-died and bell triggers
- Automated verification where possible
- Clear manual test steps where automation isn't possible
- Implement
NotificationBackendtrait and backends - Integrate with
send_notification - Add click-to-focus for the simplest working case first
- Extend to additional terminals/platforms
- Write tests
- Create a demo profile that exercises both pane-died and bell notifications
- Document the setup steps (notification permissions, terminal settings)
- Test on multiple terminals
- Test attached and detached scenarios