Skip to content

Add OS notifications when an agent needs an approval#122

Open
germanescobar wants to merge 1 commit into
mainfrom
approval-notifications
Open

Add OS notifications when an agent needs an approval#122
germanescobar wants to merge 1 commit into
mainfrom
approval-notifications

Conversation

@germanescobar

Copy link
Copy Markdown
Owner

What

Agents that block on a tool/plan approval were only surfaced through the per-turn, per-session SSE in the sessions route. That stream only reaches the client currently watching that session — so if the user was on another session or had the app backgrounded (exactly when an alert is useful), they got no signal.

This adds an app-wide notification path for needs_input (approval) transitions, raising an OS notification.

How

  • server/lib/session-runtime.ts — module EventEmitter + RuntimeNotification type + onRuntimeNotification(listener) subscriber. recordPendingApproval emits a needs_input event (sessionId, projectId, worktreeId, provider, toolName, requestId) the moment an agent blocks.
  • server/index.ts — new GET /api/events SSE endpoint bridging emitter events to any connected renderer, with a 15s heartbeat and clean unsubscribe on disconnect. Independent of which session view is mounted.
  • client/src/lib/useApprovalNotifications.ts — opens one EventSource("/api/events") for the app lifetime, raises an OS Notification, suppresses the alert when the target session is already foreground and focused (document.hasFocus()), dedupes per session via tag, and on click focuses the window (controller.showWindow()) and opens the session.
  • client/src/App.tsx — wires the hook in, passing the foreground session id and routing clicks through the existing handleSelectSession.

Scope

First cut is approval/needs-input only, notifications only (no dock badge). The emitter is generic, so "turn finished" / "errors" can be added later as a one-line emit at the completion path plus a kind in the hook — no new plumbing.

Notes

  • Electron grants the Notification API implicitly; a plain browser build requests permission on mount and no-ops if denied.

Test plan

  • Server typecheck clean (tsc -p server/tsconfig.json)
  • Client builds clean (vite build)
  • sessions.test.ts 16/16 pass
  • Manual: trigger a Claude plan/tool approval while viewing a different session → OS notification fires; clicking opens the session

🤖 Generated with Claude Code

Agents that block on a tool/plan approval were only surfaced through the
per-turn, per-session SSE, so the user got no signal while viewing another
session or with the app backgrounded — exactly when it matters.

Add an app-wide notification path:
- session-runtime emits a `needs_input` RuntimeNotification when an agent
  records a pending approval, via a module EventEmitter.
- New `GET /api/events` SSE endpoint bridges those events to the renderer,
  independent of which session view is mounted.
- `useApprovalNotifications` opens one EventSource for the app lifetime and
  raises an OS Notification, suppressing the alert when the target session is
  already foreground and focused. Clicking focuses the window and opens it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant