[BUG] Windows: Claude Code computer use leaves the desktop window stuck always-on-top (cu-side-panel restore races with Win32 screenshot re-pin)

Status Open
Reported on v2.1.275
Maintainer reply None cached
Activity 8 comments · opened Sep 19, 2026

Preflight Checklist

  • [x] I have searched existing issues. Related reports exist (see below), but none identifies this trigger on Windows. This report is about the Claude Code computer-use tools stranding WS_EX_TOPMOST on the window that hosts Claude Code sessions.
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

This bug is caused by Claude Code's own computer-use tools. On Windows, Claude Code sessions run in a tab of the Claude desktop app. After a Claude Code session uses computer use (the mcp__computer-use__* tools that take screenshots and control the desktop), that window can stay always-on-top (WS_EX_TOPMOST) after the session gives control back.

After that, the window stays above every other application. Clicking or switching to another app does not bring that app in front of it. The only way to see other windows is to minimize Claude. Restarting the app fixes it for a while, but the next computer-use session can bring it back.

I checked this with GetWindowLong(GWL_EXSTYLE) on the main window (Chrome_WidgetWin_1, title Claude):

  • stuck: exstyle=0x00280108 (topmost bit 0x8 set)
  • normal: exstyle=0x00280100

In the app log, the last event before the stuck state is a normal computer-use dock/restore cycle. The app process had been running since 18:39, and the restore completed without errors:

2026-09-19 23:45:46 [info] mainView backgroundThrottling disabled (visible popouts: 0, glow: hidden, cu lock: held, boot: done)
2026-09-19 23:45:46 [info] [cu-glow] shown bounds={"x":0,"y":0,"width":1920,"height":1080}
2026-09-19 23:45:46 [info] [cu-side-panel] docked
2026-09-19 23:46:54 [info] [cu-side-panel] restored
2026-09-19 23:46:54 [info] mainView backgroundThrottling restored (visible popouts: 0, glow: hidden, cu lock: free, boot: done)

After this the main window still had WS_EX_TOPMOST, even though [cu-side-panel] restored had been logged.

Likely root cause (from reading the shipped app.asar, 2.2553.1.0)

This is the same save/restore pattern as the macOS report #91569, but on Windows. Two parts of the computer-use code both save and restore the always-on-top state:

1. [cu-side-panel] dock/restore saves the current always-on-top state when docking and puts it back when restoring:

// dock (on cuLockChanged with a holder)
V_i={bounds:e.getBounds(),minSize:o,wasAlwaysOnTop:e.isAlwaysOnTop() /*a*/, ...}
...W_i(e,!0)   // win32: e.setAlwaysOnTop(true,"screen-saver")
// restore (on cuLockChanged with no holder)
V_i=void 0, ... await H_i(e,n.bounds) /* ~220ms animation */,
!(b5!==t||e.isDestroyed())&&(... W_i(e,n.wasAlwaysOnTop) ...)

2. The Win32 screenshot wrapper (captureScreenshotWin32 path) records isAlwaysOnTop() for every BrowserWindow before a capture. In finally it re-pins any window that was topmost before:

for(let e of n) r.set(e.id,e.isContentProtected()), i.set(e.id,e.isAlwaysOnTop()), e.setContentProtection(!0);
await wx(50);
try { return await e() }
finally { for(let e of n) e.isDestroyed()|| (..., i.get(e.id)&&!e.isAlwaysOnTop()&&e.setAlwaysOnTop(!0,"screen-saver")) }

While the side panel is docked, the main window is always-on-top. A capture that starts before the restore and finishes after it therefore re-pins the main window at "screen-saver" level, which cancels the restore.

The problem then becomes permanent because of how part 1 works. The next computer-use dock records wasAlwaysOnTop: e.isAlwaysOnTop() as true, so every later restore applies setAlwaysOnTop(true,"screen-saver") again. Only a full app quit clears it.

A second, smaller race can start the same loop. If the CU lock is taken again during the ~220 ms restore animation, b5!==t skips W_i(e,false). The new dock then records wasAlwaysOnTop=true.

Any other short-lived pin that is active when a dock or capture takes its snapshot can also start the loop. One example is the Windows focus_desktop path, which pins the window and unpins it on a 100 ms timer (#93228).

What Should Happen?

When computer use gives control back, the main window should never be left WS_EX_TOPMOST. Suggestions:

  • Don't treat a temporary pin as the window's real state. The side panel should remember the user-intended state, which is always false on Windows today, not isAlwaysOnTop().
  • In the screenshot wrapper, skip re-pinning the main window. Or re-pin only if the window is still docked (V_i set).
  • On side-panel restore, always call setAlwaysOnTop(false) on Windows unless the user turned always-on-top on.

Steps to Reproduce

  1. On Windows 11, use Claude Code in the Claude desktop app (Code tab) with computer use enabled.
  2. Ask Claude to do a task that uses computer use (screenshots and clicks), and let it finish so control is released. The log shows [cu-side-panel] docked → restored.
  3. Repeat a few times.
  4. At some point, the Claude window stays above all other apps after restored. GetWindowLong(hwnd, GWL_EXSTYLE) & 0x8 is non-zero.
  5. Later computer-use sessions keep it topmost until the app is fully quit, including from the tray.

It happens intermittently, because it depends on timing.

Workaround

Clearing the bit fixes it for that window, and the app does not set it again on its own (until the next computer-use session sets it again):

SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

For now, I run a small watchdog. Once per second, it clears WS_EX_TOPMOST on the main Claude window unless the last [cu-side-panel] line in %LOCALAPPDATA%\Claude\Logs\main.log is docked.

Claude Model

Opus

Is this a regression?

I don't know

Claude Code Version

2.1.275 (Claude Code), Claude desktop app 2.2553.1.0 x64 (Microsoft Store / MSIX)

Platform

Anthropic API

Operating System

Windows 11 Pro 10.0.26200

Terminal/Shell

Other (Claude desktop app, Code tab)

Additional Information

Related:

  • #91569: same wasAlwaysOnTop save/restore pattern in the computer-use side panel, on macOS
  • #93228: Windows, focus_desktop 100 ms pin/unpin (closed by the bot as "not Claude Code")
  • #95264, #89467, #88093, #87895, #85891: same symptom on Windows, no root cause identified

View original on GitHub ↗

3 Comments

dstepnov-cloud · 24 days ago

Confirming this on a newer build and in a different configuration than the original report, plus two data points that may help narrow it down.

Environment

| Item | Value |
|---|---|
| Claude Desktop | 2.2553.1 |
| Electron | 44.2.0 |
| Node | 24.20.0 |
| Platform | win32, x64 |
| Session type | cloud session linked to a local Windows machine over the remote-devices bridge (not a local-only session) |
| Computer-use grants | AutoCAD 2024 (tier full), Google Chrome (tier read) |
| Screenshot filtering | mask |
| Observed | 2026-09-20 / 2026-09-21 |

Reproduction

Extended computer-use automation driving a desktop application (AutoCAD 2024): alternating
computer_screenshot, computer_batch (click / type / key / zoom) and computer_open_application
calls, with the side panel opening and closing repeatedly during the task.
Volume, approximate: 30–40 screen captures over ~90 minutes in a single session.

After that, the main window rendered above all other applications and stayed there. Other
applications were reachable only by minimising the Claude window.

Data point 1 — clearing WS_EX_TOPMOST externally does not work

The watchdog approach suggested earlier in this thread had no effect here:

Add-Type -Name W -Namespace N -MemberDefinition '[DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr h,IntPtr a,int x,int y,int cx,int cy,uint f);'
$h = (Get-Process claude | Where-Object MainWindowHandle -ne 0 | Select-Object -First 1).MainWindowHandle
[N.W]::SetWindowPos($h, [IntPtr]-2, 0,0,0,0, 0x0013)   # HWND_NOTOPMOST

The call targets the handle Windows reports as MainWindowHandle. The window that is actually
pinned appears to be a different top-level window of the same process, and/or the style is
re-applied immediately. A per-MainWindowHandle workaround is therefore not reliable.

Escalation ladder actually observed:

| Action | Result |
|---|---|
| Switching focus to another application | no change |
| SetWindowPos(HWND_NOTOPMOST) on MainWindowHandle | no change |
| Closing the window (app keeps running in tray) | no change |
| Full Exit (process termination) + relaunch | cleared |

Since close-to-tray does not clear it, the stuck state survives in the process, not in the
window instance. That also means the only working remedy terminates the running session.

Data point 2 — foreground stealing during automation causes wrong-target input

Separate from z-order: during the same task the Claude Desktop window repeatedly raised itself
to the foreground while the target application was mid-operation. Recorded consequences:

  • Clicks issued at coordinates computed from the preceding screenshot landed on the Claude

Desktop window instead of the target application, because the foreground window changed
between the screenshot and the click.

  • Text sent through the clipboard paste path (computer_type) was delivered to the wrong

window. In AutoCAD this started an unintended PASTECLIP command, which then blocked the
command line and required several recovery steps before automation could continue.

  • Steps had to be re-issued. Approximate overhead in this session: **10–15 wasted tool calls,

on the order of 20–30% of the computer-use calls made**.

(The two counts above are estimates from the session log, not instrumented measurements.)

This is arguably the more serious half of the problem. An agent driving a desktop application
cannot rely on "frontmost window at screenshot time" still being frontmost at click time if the
host application can raise itself asynchronously. The failure is silent — input goes somewhere
else and the agent only discovers it from the next screenshot.

Requests

  1. Serialise access to the always-on-top state between the screenshot path and the side-panel

dock/restore path, so the style cannot persist beyond the operation that required it.

  1. Add a user-facing setting to disable always-on-top for the main window (also requested in

#89467). At present the only remedy is a full Exit, which ends the running session.

  1. During computer-use automation, suppress asynchronous raising of the Claude Desktop window,

or surface foreground-window changes to the agent so stale-coordinate input can be detected
rather than silently misdelivered.

wilsonbuilt78-glitch · 23 days ago

Same fault here on Windows 11 (desktop app 2.2553.1): the main window stays always-on-top after any computer-use session. PowerToys Win+Ctrl+T does not clear it.

One-click workaround for non-developers until this is fixed. Save the text below as Unpin Claude.cmd on the Desktop and double-click it whenever the window is stuck. It clears the topmost flag on every visible window owned by a claude process and changes nothing else. Confirmed working here. The pin returns after the next computer-use session, so run it again then.

@echo off
powershell -NoProfile -ExecutionPolicy Bypass -Command "iex (((Get-Content -Raw -LiteralPath '%~f0') -split '(?m)^:PSSTART\r?\n',2)[1])"
exit /b
:PSSTART
$src = @'
using System;
using System.Runtime.InteropServices;
public static class ClaudeUnpin {
  delegate bool EnumProc(IntPtr h, IntPtr l);
  [DllImport("user32.dll")] static extern bool EnumWindows(EnumProc cb, IntPtr l);
  [DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
  [DllImport("user32.dll")] static extern bool IsWindowVisible(IntPtr h);
  [DllImport("user32.dll")] static extern int GetWindowLong(IntPtr h, int i);
  [DllImport("user32.dll")] static extern bool SetWindowPos(IntPtr h, IntPtr after, int x, int y, int cx, int cy, uint flags);
  public static int Run(int[] pids) {
    int n = 0;
    EnumWindows(delegate(IntPtr h, IntPtr l) {
      uint pid; GetWindowThreadProcessId(h, out pid);
      if (Array.IndexOf(pids, (int)pid) >= 0 && IsWindowVisible(h) && (GetWindowLong(h, -20) & 8) != 0) {
        SetWindowPos(h, new IntPtr(-2), 0, 0, 0, 0, 0x13);
        n++;
      }
      return true;
    }, IntPtr.Zero);
    return n;
  }
}
'@
Add-Type -TypeDefinition $src
$ids = @(Get-Process -Name claude -ErrorAction SilentlyContinue | ForEach-Object { $_.Id })
if ($ids.Count -eq 0) { Write-Host 'Claude is not running.' }
else {
  $n = [ClaudeUnpin]::Run([int[]]$ids)
  if ($n -gt 0) { Write-Host "Unpinned $n Claude window(s)." } else { Write-Host 'No pinned Claude window found.' }
}
Start-Sleep -Seconds 2

Workaround written with Claude.

israelins85 · 18 days ago

Also reproduces on macOS, so this doesn't seem to be Windows-only.

The Claude Desktop main window got stuck always-on-top right after a session where Claude controlled my computer (computer use). Before that session the window behaved normally; after it ended, the main window kept rendering above every other app even when another window had focus.

OS: macOS 26.6.2 (25G83)
Claude Desktop: 2.9939.2 (d3e504), built 2026-09-24
Workaround: quitting Claude and opening it again fixes it.

Showing cached comments. Read the full discussion on GitHub ↗