777genius/claude-notifications-go

Ghostty focus is not fail-closed: a stale terminal ID falls back to cwd/AXDocument and focuses the wrong tab; app-level `terminals` enumeration is also unreliable

Open

#116 opened on Jul 16, 2026

View on GitHub
 (0 comments) (0 reactions) (0 assignees)Go (100 forks)auto 404
bughelp wanted

Repository metrics

Stars
 (759 stars)
PR merge metrics
 (PR metrics pending)

Description

Follow-up to #113/#114/#115, same setup (macOS Tahoe, Ghostty 1.3.1, ~12 concurrent Claude Code sessions, most sharing one cwd). Two related findings from a week of running a locally patched build, with the fix we've verified in production.

1. The focus chain silently degrades to "wrong tab" instead of "no-op"

focusGhosttyWindowWithOptions tries exact terminal-ID focus, then falls back to cwd matching, then to window-level AXDocument + activateByPID. Every step down that ladder loses precision:

  • A stale terminal ID (session resumed via claude --resume, or a handed-off session) fails the ID step, then cwd matching can't disambiguate shared-cwd tabs, and the AXDocument fallback raises an arbitrary same-cwd window.
  • A headless session (cron/CI, or a session living on another machine) has no tab at all — the click still activates the app and lands on whatever tab is frontmost.

From the user's perspective both cases are "the notification lied to me": the click confidently focused a tab that has nothing to do with the notification. A click that does nothing is strictly better than one that focuses the wrong session.

Fix we run locally (happy to PR):

  • When a terminal ID was provided and by-ID focus fails → return the error; no cwd fallback, no AXDocument, no app activation.
  • At send time, when no trustworthy terminal ID exists for the session → build the notification without any click action (no -execute, no -activate).

2. App-level terminals enumeration misses windows; iterate windows→tabs→terminals

ghosttyFocusByIDAppleScript and the cwd-matching script iterate the app-level terminals element. We observed states where that enumeration returned a small subset of actual terminals (in the extreme, 1 of 12 — notably while a second Ghostty process instance was alive, e.g. spawned via ghostty -e …; with two processes sharing the bundle ID, all Apple events route to one arbitrary instance). Explicit nesting is more robust and costs nothing:

repeat with w in windows
  repeat with tb in tabs of w
    repeat with t in (terminals of tb)
      ...

Also worth adding an explicit activate after focus tfocus alone selects the tab but doesn't reliably bring the app forward when Ghostty is backgrounded or the tab lives on another Space.

Related operational note for other multi-session users who land here: if clicks suddenly stop working across all sessions, check for a second Ghostty process (ps -axo pid=,comm= | grep Ghostty.app). Any ghostty -e-style helper instance hijacks AppleScript for the whole bundle ID until it exits. (macOS pgrep -f is a trap for this check — it matches environment strings.)

We've been running all of the above (fail-closed focus + explicit iteration + activate) for a fleet of ~12 sessions with zero wrong-tab focuses since. Can open a PR for whichever parts you'd take.

Contributor guide