Skip to content

feat(desktop): notify on turn completion while unfocused on Windows - #8316

Closed
Pleko-script wants to merge 6 commits into
pingdotgg:mainfrom
Pleko-script:feat/desktop-win-turn-notification
Closed

feat(desktop): notify on turn completion while unfocused on Windows#8316
Pleko-script wants to merge 6 commits into
pingdotgg:mainfrom
Pleko-script:feat/desktop-win-turn-notification

Conversation

@Pleko-script

@Pleko-script Pleko-script commented Aug 26, 2026

Copy link
Copy Markdown

Agents finish while the user is in another window, and nothing tells them. Issue #780 asked for completion notifications, and the earlier attempts (#976, #1780, #4003, #5821) were closed for being too broad or for tracking completion state that went stale across reseeds.

This is the smallest slice that works, built on the existing awareness foundation. The renderer derives phases from the thread-shell atoms with resolveThreadAwarenessPhase, the same ladder AgentAwarenessRelay uses for mobile push, and reports a turn that moved from running (or waiting on approval or input) to completed over one new optional DesktopBridge.notifyAgentTurnCompleted method. The Electron main process owns the whole gate (win32, no focused window, Notification.isSupported()) and shows one silent toast with the thread title. No agent output crosses the bridge.

What keeps it quiet when it should be:

  • A thread's first observation never notifies, so hydration and reconnect stay silent for work that was already done.
  • A phase arms a notification only while its environment connection reports live. Cached and resynchronizing snapshots never arm, so a thread cached as running that finished while the app was closed stays silent when the fresh snapshot loads. Arming is sticky across active phases, so a completion replayed on reconnect still notifies.
  • "starting" never arms a notification, because a booting session projects a transient completed ("ready" before the first turn, the phantom AgentAwarenessRelay defers server-side).
  • Transient null projections carry the last phase forward instead of breaking the chain.
  • The phase map is the duplicate guard, so one completion notifies once.

The liveness source pairs the shell list with a reference-stable boolean projection per environment, so shell updates that change neither shells nor liveness never rerun the collector.

Deliberately out of scope (each is a small follow-up): a settings toggle (Windows per-app notification settings are the off switch for now), macOS and Linux, click-to-focus, sounds, approval and input notifications. One semantic is inherited from the shared phase ladder and matches mobile push today. Interrupted turns with a completedAt stamp read as completed.

Verified with 24 targeted tests via vp test run (transition detection, liveness arming, source-atom emission stability, duplicate suppression, hydration seeding, the boot transient, per-environment keys, platform, focus and support gating, throw safety), scoped typecheck over shared, contracts, web and desktop, targeted lint, and vp fmt --check. I also exercised the real path on a Windows 11 machine through the dev app with remote debugging. The bridge call returned false while the window was focused and true after minimizing, and this toast appeared:

Native Windows toast shown by the dev app

The dev build attributes the toast to "Electron" because dev has no installed Start Menu shortcut. Installed builds carry com.t3tools.t3code (set in DesktopAppIdentity and the packaging appId), so they show the T3 Code name and icon.

Built with Claude Fable 5 on Claude Code, with a Codex (GPT) review pass.

🤖 Generated with Claude Code


Note

Low Risk
Additive optional bridge API and Windows-only notification gating; no auth or sensitive data on the wire, with behavior covered by extensive unit tests.

Overview
Adds Windows-only, unfocused desktop toasts when an agent turn finishes, without sending agent output across the IPC bridge.

The renderer tracks thread awareness phases (same ladder as mobile push via newly exported resolveThreadAwarenessPhase) and calls an optional desktopBridge.notifyAgentTurnCompleted({ threadTitle }) when a thread moves from an armed active phase to completed. Arming respects environment live connection state, ignores first-seen completions, skips the session-boot starting phantom, and dedupes via a per-thread phase map.

The Electron main process implements ElectronNotification with shouldShowAgentTurnNotification gating (win32, no focused window, Notification.isSupported()), showing a silent Agent finished toast with the thread title. New IPC channel desktop:notify-agent-turn-completed is wired through handlers, preload, and DesktopBridge in contracts; main.tsx starts the subscriber on app boot.

Includes targeted unit tests for gating and transition logic plus user docs for Windows notification settings.

Reviewed by Cursor Bugbot for commit c78efca. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Windows desktop notifications for agent turn completion when unfocused

  • Adds ElectronNotification service that shows a silent "Agent finished" notification on win32 only when no window is focused and Electron reports notification support; all other platforms and focused states return false
  • Registers a notifyAgentTurnCompleted IPC channel and exposes it through the preload bridge so the renderer can request a notification with a thread title and receive a boolean result
  • Adds web-side monitoring in startDesktopAgentTurnNotifications that tracks thread awareness phases, arms only live-environment threads, deduplicates completions, and skips threads already completed at startup
  • Exports resolveThreadAwarenessPhase from packages/shared/src/agentAwareness.ts so the web collector can reuse existing phase resolution
  • Behavioral Change: notifications fire only on unfocused Windows desktops; macOS, Linux, focused windows, and older bridge builds without notifyAgentTurnCompleted are silently skipped. DesktopBridge.notifyAgentTurnCompleted is optional, so non-browser or older desktop environments no-op at startup

Macroscope summarized c78efca.

The renderer detects active-to-completed phase transitions from the
existing awareness projection and reports them over one optional bridge
method; the Electron main process owns the win32, window-focus, and
support gate and shows a silent native toast titled "Agent finished"
with the thread title as the body.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bbdf7f6f-a859-45d4-939a-fdf73ce6361b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 26, 2026
Comment thread docs/user/desktop-notifications.md Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a9f0dcd. Configure here.

Comment thread apps/web/src/desktopAgentTurnNotifications.ts
@macroscopeapp

macroscopeapp Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces an enabled-by-default Windows desktop notification workflow spanning renderer state tracking, IPC/preload wiring, and Electron native notifications. Its cross-process runtime behavior and product-default impact exceed the scope of an auto-approvable bounded change.

You can add or adjust custom eligibility rules. Learn more.

Pleko-script and others added 5 commits August 27, 2026 02:00
Cold start hydrates thread shells from the persisted cache before the
authoritative snapshot loads, so a thread cached as running that finished
while the app was closed read as a fresh completion and toasted. A phase
now arms a notification only when observed while its environment shell is
live, with arming sticky across active phases so a reconnect that replays
running to completed still notifies once.

The liveness source pairs the shell list with a reference-stable boolean
projection per environment, so snapshot updates that change neither shells
nor liveness do not rerun the collector.

Also corrects the documented Windows notification settings path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Superseded by #11481 (opt-in thread notifications and sounds for browser/desktop on main). Closing as superseded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants