# NousResearch/hermes-agent · Linux/WSL desktop window controls missing or broken

## Open now

- Nothing open on GitHub.

Multiple bug reports and fix attempts addressing missing or broken native window controls (minimize, maximize, close) on Linux desktop environments including Wayland, WSLg, X11/XWayland, and with titleBarStyle hidden or overlay configurations. The work spans Electron 40+ compatibility, renderer-drawn fallbacks, and related titlebar layout concerns.

## TL;DR

- 11 member(s): 0 open issue(s), 4 closed issue(s), 0 open PR(s), 2 merged PR(s), 5 PR(s) closed without merging.
- A fix was merged to main in PR #53989. Verify it addresses your case.
- **Recommended:** read PR #53989 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `partially_resolved` · deciding PR(s): `pr-113247`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_PARTIAL`): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text.
- Members outside that structural core may belong to a different underlying problem.
- Pairwise link density `0.18`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #53514: \[Bug\]: Linux desktop: no close button when titleBarStyle is hidden
- #53690: Linux (X11/XWayland): Electron 40+ window frame missing with titleBarStyle: "hidden"
- #54294: \[Bug\]: Desktop (Linux/Wayland): Native window controls (minimize/maximize/close) are missing
- #57614: \[Bug\] Desktop (WSL/WSLg): no minimize/maximize/close buttons (companion to #53514)

## Prior & competing PRs

- **#53989: fix(desktop): restore window controls on plain Linux (min/max/close)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `apps/desktop/electron/main.cjs`, `apps/desktop/electron/titlebar-overlay-width.cjs`, `apps/desktop/electron/titlebar-overlay-width.test.cjs`, `scripts/release.py`
  - fix hunks:
  - `apps/desktop/electron/main.cjs`

    ```diff
    @@ -534,9 +534,10 @@ function getTitleBarOverlayOptions() {
         return { height: TITLEBAR_HEIGHT }
       }
     
    -  // Windows + WSLg paint WCO natively; plain Linux disables it (frameless hidden
    -  // titlebar still applies).
    -  if (!IS_WINDOWS && !IS_WSL) {
    +  // WSLg paints WCO via the RDP host's own min/max/close, so requesting
    +  // an Electron overlay there just leaves a dead gap. Plain Linux (KDE,
    +  // GNOME) can use the native overlay — let it through.
    +  if (!IS_WINDOWS && IS_WSL) {
         return false
       }
     
    ```

    ```diff
    @@ -3788,7 +3789,7 @@ function getWindowButtonPosition() {
     }
     
     function getNativeOverlayWidth() {
    -  return computeNativeOverlayWidth({ isWindows: IS_WINDOWS, isWsl: IS_WSL })
    +  return computeNativeOverlayWidth({ isWindows: IS_WINDOWS, isWsl: IS_WSL, isMac: IS_MAC })
     }
     
     function getWindowState() {
    ```
  - `apps/desktop/electron/titlebar-overlay-width.cjs`

    ```diff
    @@ -1,11 +1,24 @@
    -// Pre-layout fallback for WCO right-edge reservation (--titlebar-tools-right).
    -// Live width comes from navigator.windowControlsOverlay in the renderer.
    +'use strict'
     
     const OVERLAY_FALLBACK_WIDTH = 144
     
    -/** @param {{ isWindows?: boolean, isWsl?: boolean }} opts */
    -function nativeOverlayWidth({ isWindows = false, isWsl = false } = {}) {
    -  return isWindows || isWsl ? OVERLAY_FALLBACK_WIDTH : 0
    +/**
    + * Static pre-layout reservation (px) for the right-side native window-controls
    + * overlay (min/max/close). Only a FALLBACK — once laid out the renderer reads
    + * the exact width from navigator.windowControlsOverlay
    + * (use-window-controls-overlay-width.ts) and uses this value only when the WCO
    + * API is unavailable.
    + *
    + * macOS uses traffic lights positioned via trafficLightPosition, not a WCO
    + * overlay, so it reserves nothing here. Every other desktop platform now paints
    + * the Electron overlay (Windows, WSLg, and plain Linux KDE/GNOME), so they all
    + * reserve the fallback width.
    + *
    + * @param {{ isWindows?: boolean, isWsl?: boolean, isMac?: boolean }} opts
    + */
    +function nativeOverlayWidth({ isWindows = false, isWsl = false, isMac = false } = {}) {
    +  if (isMac) return 0
    +  return OVERLAY_FALLBACK_WIDTH
     }
     
     module.exports = { OVERLAY_FALLBACK_WIDTH, nativeOverlayWidth }
    ```
  - `apps/desktop/electron/titlebar-overlay-width.test.cjs`

    ```diff
    @@ -18,10 +18,17 @@ test('WSLg paints the same WCO, so it reserves the same fallback width', () => {
       assert.equal(nativeOverlayWidth({ isWsl: true }), OVERLAY_FALLBACK_WIDTH)
     })
     
    -test('plain Linux and macOS reserve nothing', () => {
    -  assert.equal(nativeOverlayWidth({ isWindows: false, isWsl: false }), 0)
    -  assert.equal(nativeOverlayWidth(), 0)
    -  assert.equal(nativeOverlayWidth({}), 0)
    +test('plain Linux paints the WCO too, so it reserves the fallback width', () => {
    +  // Regression #53185: re-enabling the overlay on plain Linux (KDE/GNOME)
    +  // without reserving its width left the native min/max/close buttons painting
    +  // on top of the app's right-edge titlebar tools.
    +  assert.equal(nativeOverlayWidth({ isWindows: false, isWsl: false }), OVERLAY_FALLBACK_WIDTH)
    +  assert.equal(nativeOverlayWidth(), OVERLAY_FALLBACK_WIDTH)
    +  assert.equal(nativeOverlayWidth({}), OVERLAY_FALLBACK_WIDTH)
    +})
    +
    +test('macOS uses traffic lights, not a WCO overlay, so it reserves nothing', () => {
    +  assert.equal(nativeOverlayWidth({ isMac: true }), 0)
     })
     
     test('the fallback width is a sane positive pixel value', () => {
    ```
  - `scripts/release.py`

    ```diff
    @@ -70,6 +70,7 @@
         "[redacted:email]": "uperLu",  # PR #50958 salvage (rename plugins/cron → plugins/cron_providers; #50872)
         "[redacted:email]": "yusekiotacode",  # PR #48706 salvage (anthropic OAuth login token endpoint → platform.claude.com; #45250/#49821)
         "[redacted:email]": "s010mn",  # PR #29221 salvage (ollama-cloud reasoning_effort xhigh→max)
    +    "[redacted:email]": "chriswesley4",  # PR #53185 salvage (re-enable titleBarOverlay on plain Linux; missing min/max/close regression)
         "[redacted:email]": "jeeves-assistant",  # PR #50771 (computer-use CuaDriver vision capture routing)
         "[redacted:email]": "ScotterMonk",  # PR #50145 salvage (cron output truncation: adapter-aware chunking, #50126)
         "[redacted:email]": "TutkuEroglu",  # PR #50481 salvage (AGENTS.md stale token-lock adapter path)
    ```
- **#113247: fix(desktop): working WSLg window controls and native Wayland launch**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `apps/desktop/electron/entry.ts`, `apps/desktop/electron/main.ts`, `apps/desktop/electron/preload.ts`, `apps/desktop/electron/titlebar-overlay-width.test.ts`, `apps/desktop/electron/titlebar-overlay-width.ts`, `apps/desktop/electron/window-chrome-events.test.ts`, `apps/desktop/electron/window-chrome-events.ts`, `apps/desktop/electron/window-controls.test.ts`, `apps/desktop/electron/window-controls.ts`, `apps/desktop/electron/wslg-launch-process.test.ts`, `apps/desktop/electron/wslg-launch-process.ts`, `apps/desktop/electron/wslg-launch.test.ts`, `apps/desktop/electron/wslg-launch.ts`, `apps/desktop/scripts/bundle-electron-main.mjs`, `apps/desktop/src/app/contrib/wiring.tsx`, `apps/desktop/src/app/shell/wslg-window-controls.test.tsx`, `apps/desktop/src/app/shell/wslg-window-controls.tsx`, `apps/desktop/src/global.d.ts`, `website/docs/user-guide/desktop.md`
- **#53326: fix(desktop): enable titleBarOverlay on Linux for Electron 40+**. closed without merge
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#53989`
- **#53528: fix(desktop): add Linux close fallback when no titlebar overlay**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `97640fd9adf532d6ce4ebc63ec817137ba685157`, `#53514`, `#53326`
- **#64505: fix(desktop): renderer-drawn WSLg window controls, zoom-restore coordinator, work-area snap**. closed without merge
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#70803`, `#70803`
- **#70803: fix(desktop): WSLg window controls + GPU crash-loop fallback**. closed without merge
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#113247`
- **#71754: fix(desktop): request window controls overlay on WSLg (#57614)**. closed without merge
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#113247`

## Fix status

- Merged to main in PR #53989 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-09-17`.
- Subsystem: `apps/desktop`
