A coding-agent notification can be correct and still be badly timed. If Claude Code finishes while its terminal is frontmost, a full alert covers the response the user is already reading. Suppressing every alert from Terminal or VS Code is not the answer: another session may be waiting in a different window.
The condition has to be narrower: is the host application for this exact session frontmost right now? Agent Island v1.7.1 uses that check on macOS and Windows, holds the alert while the answer is already visible, and releases it when focus changes if the turn still needs attention.
Start with session identity, not an app allowlist
An allowlist such as “do not alert when Terminal is active” loses session identity. A user can have several terminals, editor-integrated CLIs, and background sessions at once. The foreground application only matters when it owns the CLI process whose working directory matches the waiting thread.
The released implementation follows this chain:
waiting thread
-> recorded working directory
-> matching claude or codex process
-> parent process chain
-> foreground application process
macOS reads process paths, working directories, and parent PIDs. Windows takes a process snapshot, matches claude, codex, node, or bun, reads the process working directory, and walks parent links to the foreground window's process. Both implementations cap the parent walk at 24 hops.
Hold, do not acknowledge
A suppressed alert is not a delivered alert. It is parked in a map keyed by provider, session identity, and turn identity. That distinction prevents two common bugs:
- marking a turn as notified even though the user never saw an alert;
- firing a stale alert after the user already replied.
When focus changes, the system re-checks the turn. It delivers only if reminders are still enabled, the turn is still in the needs-you set, and its delivery key is neither acknowledged nor delivered. If a fresh transcript scan shows that the user replied, the held entry is removed.
if exact_session_is_frontmost:
held[delivery_key] = waiting_turn
else:
deliver(waiting_turn)
on_focus_change:
for each held turn:
if no_longer_waiting: discard
else if exact_session_is_still_frontmost: keep holding
else: deliver once
Use event-driven timing at both edges
Agent Island already uses a one-second confirmation buffer before delivery. A transcript write can trigger a fresher scan during that window and cancel a turn the user has already answered. The frontmost hold adds another event boundary: application activation on macOS and EVENT_SYSTEM_FOREGROUND on Windows. There is no foreground polling loop.
This creates three chances to suppress noise without losing the handoff: cancel during the confirmation buffer, hold while the exact host is visible, and discard on the next state scan if the turn is no longer waiting.
Fail open when process ownership is unclear
Process ancestry is not always recoverable. A tmux session may be re-parented, a container can hide the relevant process, and permissions can block a working-directory read. In those cases the resolver returns false and the alert behaves normally. Missing one suppression is less damaging than silently losing a real handoff.
Path normalization also matters. On macOS, /tmp and /private/tmp can name the same location. On Windows, case and separator differences must not break a match. Windows also checks process creation times before following a parent link because recycled PIDs can otherwise lead into an unrelated process.
Tests for a focus-aware alert
- The exact session is frontmost: hold the alert.
- A different session in the same app is frontmost: deliver.
- The user switches away while the turn remains open: deliver once.
- The user replies before switching away: discard the held alert.
- The host cannot be resolved: fail open and deliver.
- Several subagents finish together: collapse the burst before applying focus logic.
- The app starts with old waiting turns: baseline history instead of replaying it.
What this does not prove
A foreground match does not prove the user read the response. It only proves that the application hosting the matching CLI is visible. The design suppresses an interruption under a narrow, reversible condition; it does not claim attention tracking.
The behavior described here is released in Agent Island v1.7.1. The macOS and Windows implementations are available in the public repository for inspection.