Skip to content

[Bug]: Clicking a completed-thread notification does not reveal T3 Code on Linux #12500

Open

Description

@zytact

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/desktop

Steps to reproduce

  1. On Linux, enable system notifications for completed threads.
  2. Start a turn, then switch away from or minimize T3 Code before the turn completes.
  3. Wait for the "Thread completed" system notification.
  4. Click the notification.

Expected behavior

T3 Code should reveal and focus its desktop window, then open the completed thread.

Actual behavior

Clicking the notification does not bring T3 Code back to the foreground. The user remains in the current application.

The shipped renderer click handler closes the notification, calls window.focus(), and navigates to the thread route:

notification.addEventListener("click", () => {
  notification.close();
  window.focus();
  navigate({
    to: "/$environmentId/$threadId",
    params: { environmentId, threadId },
  });
});

On Linux, renderer window.focus() does not reveal or restore the Electron BrowserWindow. Navigation may happen inside the hidden window, but the application is not returned to the foreground. The click path needs to ask the desktop main process to reveal the window before or alongside navigation.

Impact

Minor bug or occasional failure

Version or commit

v0.0.43-nightly.20260918.1895

Environment

Fedora Linux 44, kernel 7.1.13-200.fc44.x86_64, GNOME on Wayland, T3 Code desktop nightly

Logs or stack traces

No error is shown.

Workaround

Manually return to T3 Code and select the completed thread.

Activity

  1. juliusmarminge commented on Sep 18, 2026

    @juliusmarminge
    Member

    Triage

    Confirmed against v0.0.43-nightly.20260918.1895 (994654198) and current main @ 4d36142c02. The click handler has not changed since #11481 / #11569. This is a real Linux desktop reveal miss, not a dead notification, not a navigation failure, and not the Windows toast-tag ticket.

    The filed handler is still what ships:

    notification.addEventListener("click", () => {
      notification.close();
      window.focus();
      void navigate({
        to: "/$environmentId/$threadId",
        params: { environmentId, threadId: thread.id },
      });
    });

    (apps/web/src/components/ThreadNotificationCoordinator.tsx)

    On Linux, especially GNOME/Wayland, renderer window.focus() does not restore or raise the Electron BrowserWindow. Navigation can still happen in the background window. The user stays in the other app.

    What the code does today

    1. System toasts are created in the renderer, not the desktop main process.

    ThreadNotificationCoordinator uses new Notification(...) when desktop notifications are on and the document is unfocused. There is no new Notification anywhere under apps/desktop. Electron maps the renderer Notification; the click stays in the renderer.

    2. The click path cannot ask the shell to reveal the window.

    DesktopBridge has badge helpers (setNotificationBadge, onNotificationBadgeClear) and no reveal / focus / showMain method (packages/contracts/src/ipc.ts). The click handler never calls desktopBridge.

    3. The desktop shell already knows how to reveal — other entry points use it.

    Path What it does
    desktop.window.activate dock / app.on("activate")
    second-instance electronWindow.reveal(mainWindow) (DesktopClerk.ts)
    SnapShot / t3 app activation desktopWindow.activate / reveal

    Thread-notification clicks never join that list.

    4. Even electronWindow.reveal() is a weak Linux raise today.

    Ordinary Linux reveal (apps/desktop/src/electron/ElectronWindow.ts):

    • restore() only if minimized
    • show() only if not visible
    • no moveTop()
    • no app.focus({ steal: true }) (macOS only)
    • no Win32 foreground helpers
    • then window.focus()

    If the window is already mapped but behind another app (the usual “switched away” case), reveal reduces to BrowserWindow.focus(), which Wayland compositors often ignore without an activation token. SnapShot already has compositor-specific activate(title) on Linux (LinuxSnapShot / Niri / KDE / Hyprland) because Electron focus is not enough there.

    5. Tests never exercise the click.

    ThreadNotificationCoordinator.test.tsx asserts that a background completion creates a "Thread completed" notification. It does not dispatch click or assert window.focus().

    Related, not duplicates

    Work Why it does not close this
    #11481 / #11569 Added opt-in toasts + badges. They introduced this click path; they did not give it a main-process reveal.
    #12289 Windows toast tag length. Delivery, not focus-on-click.
    #8316 Older Windows “notify while unfocused” work. Not Linux click-to-reveal.

    I did not find an existing issue for “notification click does not foreground the Linux desktop window.”

    Workaround

    Switch back to T3 Code yourself (taskbar / overview / Alt-Tab) and open the completed thread. There is no in-app control that makes the toast raise the window.

    Decision

    Accept.

    A change is not done for this issue until, on Linux desktop with system notifications enabled and the app unfocused or minimized:

    1. Clicking Thread completed (and the same handler for input / approval / failed) reveals and focuses the main window.
    2. The completed thread route still opens.

    Wiring the click to today’s ordinary reveal() is necessary but not sufficient on GNOME/Wayland if the window is already visible. The click has to go through the desktop main process, and Linux raise has to actually restore / show / move-to-top or use an activation token / compositor activate — not renderer window.focus() alone.

  2. added
    bugSomething is broken or behaving incorrectly.
    acceptedfeature request accepted
    via-triageFiled through npx t3 triage
    on Sep 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions