Skip to content

feat(desktop): keep Windows host in system tray - #7493

Open
Ivorisnoob wants to merge 20 commits into
pingdotgg:mainfrom
Ivorisnoob:feat/windows-desktop-tray
Open

feat(desktop): keep Windows host in system tray#7493
Ivorisnoob wants to merge 20 commits into
pingdotgg:mainfrom
Ivorisnoob:feat/windows-desktop-tray

Conversation

@Ivorisnoob

@Ivorisnoob Ivorisnoob commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Add a Windows system tray with Open and Quit actions.
  • Hide the desktop window on close while keeping the backend and remote connections running.
  • Preserve the graceful shutdown path for explicit Quit and updater-driven exits.
  • Enable close-to-background only after tray creation succeeds, preventing an inaccessible hidden app.
  • Add focused tray, window-close, and lifecycle coverage.
  • Document the Windows background behavior in the remote-access guide.

The independent Windows startup performance work is tracked in #7492.

Why

Closing the final T3 Code window on Windows previously exited the desktop host, stopping its backend and disconnecting paired remote clients. A tray-backed background mode keeps the host reachable while retaining an explicit, reliable way to quit completely.

UI Changes

T3 Code Windows system tray menu with Open T3 Code and Quit T3 Code actions

Related Issues

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Implemented with GPT-5.6-sol through the Codex harness in T3 Code.


Note

Medium Risk
Changes Windows quit/close semantics and couples lifecycle, tray, and update install recovery; mistakes could leave a hidden app running or fail to restore backends after a bad update install.

Overview
On Windows, closing the main window no longer exits the app when the system tray is active: a new DesktopTray service registers Open/Quit actions, enables DesktopWindow background mode only after tray setup succeeds, and DesktopLifecycle skips app.quit on window-all-closed while that mode is on.

DesktopWindow intercepts close to hide the window (including the connecting splash), calls prepareForQuit on real shutdown paths, and uses a creation mutex so backend-ready and activation cannot open duplicate main windows.

DesktopUpdates records backends that were running before install, and on failed or interrupted quit-and-install runs recoverInstallAction (restart those instances, wait for primary readiness, re-activate the window) while resetQuitPreparation restores close-to-background behavior. Updater before-quit permission is consumed once per event.

User docs for remote access note tray behavior on Windows.

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

Note

Add Windows system tray support with background mode and update install recovery

  • Adds the DesktopTray Context service, which on Windows creates a native tray with Open and Quit menu entries and enables DesktopWindow background mode while the tray exists; closing the window hides it instead of quitting, and tray click re-activates the window
  • Extends DesktopWindow with setBackgroundModeEnabled, isBackgroundModeEnabled, prepareForQuit, and resetQuitPreparation; closes on Windows are intercepted to hide the window when background mode is on, and a semaphore serializes main window creation to prevent duplicates under concurrent activation/readiness signals
  • Updates DesktopLifecycle so window-all-closed does not quit on non-mac platforms when background mode is enabled, and handleBeforeQuit now calls prepareForQuit synchronously and treats allowQuit as a one-time boolean
  • Adds recoverInstallAction in DesktopUpdates that restarts previously running backends, waits up to 60s for primary readiness, and re-activates the window after a failed or interrupted quit-and-install; resetInstallAction now clears quitting state and calls resetQuitPreparation
  • Risk: on Windows the close button no longer quits the app when the tray is active; handleBeforeQuit signature changed from a callback allowQuit: () => boolean to a plain boolean, and DesktopWindow interface gains four new methods that all stubs must implement

Macroscope summarized c585d17.

@github-actions github-actions Bot added the vouch:unvouched PR author is not yet trusted in the VOUCHED list. label Aug 19, 2026
@coderabbitai

coderabbitai Bot commented Aug 19, 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: c395f28d-4eca-41eb-9387-126e37bbba9d

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

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


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

@github-actions github-actions Bot added the size:L 100-499 changed lines (additions + deletions). label Aug 19, 2026
Comment thread apps/desktop/src/window/DesktopTray.ts Outdated
@macroscopeapp

macroscopeapp Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This adds a new Windows tray/background workflow and changes close, quit, startup, and updater recovery semantics across several production services. The cross-cutting native lifecycle and backend restart behavior warrants human validation despite focused test coverage.

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

@Ivorisnoob

Copy link
Copy Markdown
Contributor Author

On it

Comment thread apps/desktop/src/window/DesktopTray.ts Outdated
Comment thread apps/desktop/src/app/DesktopLifecycle.test.ts
Comment thread apps/desktop/src/window/DesktopTray.ts
@Ivorisnoob

Copy link
Copy Markdown
Contributor Author

PR does touch a lot of files here in my testing on windows in Dev and other modes it is working fine but its upto you guys to decide if we want this feature or not

Comment thread apps/desktop/src/window/DesktopWindow.ts
Comment thread apps/desktop/src/updates/DesktopUpdates.ts
Comment thread apps/desktop/src/updates/DesktopUpdates.ts Outdated

@macroscopeapp macroscopeapp 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.

Effect service conventions review of the tray work. The new DesktopTray service itself follows the canonical shape (subpath namespace imports, inline Context.Service interface, make then layer, all dependencies acquired with yield* Foo.Foo, scoped acquireRelease for the native handle, runPromiseWith only at the Electron callback boundary, and test-only Layer.succeed seams).

Two findings, both about failure modeling: the new failure paths report causes as Cause.pretty(...) text in a log annotation instead of a structured tagged error, which the conventions call out explicitly ("Define service failures with Schema.TaggedErrorClass and structured attributes" / "Do not copy ... arbitrary defect text into ... a parallel log payload. Preserve the exact underlying value only as cause").

Posted via Macroscope — Effect Service Conventions

Comment thread apps/desktop/src/window/DesktopTray.ts Outdated
Comment thread apps/desktop/src/updates/DesktopUpdates.ts Outdated

@macroscopeapp macroscopeapp 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.

One finding on the new tray service: DesktopTrayConfigurationError carries a single-value stage literal that duplicates the information already in the error tag. Everything else (namespace imports, Context.Service + inline interface, make/layer ordering, dependency acquisition via yield*, and the native-callback runPromiseWith boundary mirroring DesktopApplicationMenu.ts) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/desktop/src/window/DesktopTray.ts Outdated
@Ivorisnoob

Copy link
Copy Markdown
Contributor Author

only failing one is the marketing thing and im getting e mails about that LMAO

@Ivorisnoob

Copy link
Copy Markdown
Contributor Author

@StiensWout

Comment thread apps/desktop/src/updates/DesktopUpdates.ts

@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.

Reviewed by Cursor Bugbot for commit b16f4de. Configure here.

Comment thread apps/desktop/src/app/DesktopLifecycle.ts
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.

1 participant