[FEATURE] Per-tab focus-aware notifications — hook payload lacks terminal/tab identifier
Problem
When Claude Code runs in a terminal with multiple tabs (drop-down terminals like ddterm, gnome-terminal, kitty tabs, Windows Terminal, tmux, etc.), the Notification and Stop hooks have no way to determine whether the current Claude session is in the foreground tab.
Use case
I want a desktop popup (notify-send, osascript, BurntToast) to fire only when the specific tab running this Claude session is not in foreground. If I'm staring at it, the popup is noise; if I'm on another tab (even of the same terminal app), I want the popup.
This is what terminals supporting OSC 9 / OSC 99 (Ghostty, kitty, iTerm2) provide automatically — the terminal itself delivers the notification and is focus-aware. Everything VTE-based (gnome-terminal, ddterm, Tilix) and Windows Terminal is stuck with the terminal_bell ASCII beep.
Why building it via the Notification hook is currently impossible
- Hook payload contains
session_idbut no information that ties the hook to a specific OS-level window/tab. - Hooks run with
PPID=1and no controlling TTY, sops -o tty=doesn't help (see #30910). - The session title that Claude Code already writes to the terminal tab via OSC 0/2 is not in the payload (see #15461, #16917, #19083).
- Querying the OS only tells you "is the terminal app focused", not "is this PTY the active tab". On a drop-down terminal with N tabs, the window is focused but you can't tell which tab is shown.
Workaround: a 3-part hack involving CLAUDE_TTY_MARKER env vars, ps -Eww scans, and writing escape sequences to /dev/$TTY (described in #30910). It works but is fragile and per-user.
And even without multi-tab, notifications are a mess
Set aside the multi-tab case. Even with a single Claude Code session in a single terminal window, getting a usable focus-aware desktop notification requires:
- A terminal that implements OSC 9 / OSC 99 (a small subset: kitty, iTerm2, Ghostty, Windows Terminal partial). Otherwise:
- A custom
Notificationhook that callsnotify-send/osascript/BurntToast, plus a way to detect "is the terminal currently focused?" — which is entirely platform-specific: - Linux X11:
xdotool getactivewindowworks. - Linux Wayland: nothing native works. You need to install a GNOME Shell extension (
focused-window-dbus@flexagoon.com,window-calls@domandoman.xyz, …) just to query the active window via D-Bus, becauseorg.gnome.Shell.Evalis gated and the X11 tools fail under Wayland without XWayland window listing.wmctrl -lreturns empty. - macOS:
osascript -e 'tell application "System Events" to ...'. - Windows: PowerShell + WMI, or AutoHotkey, or BurntToast with custom Window-ID matching.
So the user has to write a per-OS, per-terminal, per-window-manager focus-detection routine just to get the equivalent of what kitty / Ghostty give for free via OSC 99.
The setting preferredNotifChannel only covers a small set of terminals (iterm2, iterm2_with_bell, terminal_bell, kitty, ghostty, notifications_disabled). Anything else falls back to terminal_bell (a beep, not a desktop popup) and there is no built-in cross-terminal "send desktop notification" path. A preferredNotifChannel: desktop (cross-platform, focus-aware using what the WM/OS exposes) would close most of this gap.
Proposed Solution
Two things would go a long way:
- Include in the hook JSON payload any one of:
session_title— the auto-generated topic Claude Code already sets as the terminal tab title (cheap; matches_NET_WM_NAME/ D-Bus active-window queries).parent_tty/terminal_pid— the TTY or PID of the originating foreground process before the orphaning, so hooks can correlate to OS-level "which PTY is the foreground job of the focused terminal".- A stable
terminal_window_idrecorded at session attach.
- A built-in cross-terminal
desktopnotification channel that handles the OS-level focus detection internally, instead of leaving every user to reimplement it.
Related closed issues (all autoclosed for inactivity, never implemented)
- #15461 — Expose Session Name to All Extension Points
- #16917 — Include session title in hook input JSON (closed as duplicate of #15461)
- #19083 — Add
terminal_titleto hook JSON payload for session identification (closed as duplicate) - #30910 — Expose parent TTY path to hooks via environment variable
- #15029, #15267 — related (session name in statusLine)
- #7460 — Add inactivity-based notification delay
- #104 — More configurable
preferredNotifChannel(run an arbitrary script)
This has been requested repeatedly for almost a year. Tracking it under one open issue would help.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗