2025-08-04 19:13:40 -04:00
# Claude Desktop for Linux
2025-04-05 20:15:38 -04:00
2026-02-26 18:48:52 -08:00
This project provides build scripts to run Claude Desktop natively on Linux systems. It repackages the official Windows application for Linux distributions, producing `.deb` packages (Debian/Ubuntu), `.rpm` packages (Fedora/RHEL), distribution-agnostic AppImages, an [AUR package ](https://aur.archlinux.org/packages/claude-desktop-appimage ) for Arch Linux, and a Nix flake for NixOS.
2025-04-05 20:15:38 -04:00
2025-08-04 19:18:59 -04:00
**Note:** This is an unofficial build script. For official support, please visit [Anthropic's website ](https://www.anthropic.com ). For issues with the build script or Linux implementation, please [open an issue ](https://github.com/aaddrick/claude-desktop-debian/issues ) in this repository.
2025-04-05 20:15:38 -04:00
2026-02-16 14:16:44 -05:00
---
2026-04-23 18:10:33 -04:00
> **⚠️ APT migration notice (April 2026)**
feat: KVM/bwrap isolation backends for cowork mode (#269)
* feat: add KVM/bwrap isolation backends for cowork mode
Refactor cowork-vm-service.js from monolithic VMManager into a pluggable
backend architecture with three isolation levels:
- HostBackend: direct execution on host (existing Phase 1 behavior)
- BwrapBackend: bubblewrap namespace sandbox (PID/mount isolation)
- KvmBackend: full QEMU/KVM VM with vsock, virtiofs, QMP monitor
Backend auto-detected at startup (KVM > bwrap > host) or overridden
via COWORK_VM_BACKEND env var. Shared helpers extracted for env
filtering, arg cleanup, command resolution, and work dir handling.
Also:
- Add Cowork Mode section to --doctor diagnostics with per-tool
checks and distro-specific install hints
- Update Patch 4 to extract real win32 file entries for linux
bundle manifest (enables app download infrastructure)
- Update handover documentation for Phase 2/3 architecture
Co-Authored-By: Claude <claude@anthropic.com>
* fix: correct KvmBackend vsock port, direction, and kernel cmdline
The guest sdk-daemon connects TO the host (CID=2), not the other way
around. Confirmed via disassembly of the guest binary: the vsock port
is 51234 (0xC822), matching the Hyper-V GUID in the Windows service.
- Change VSOCK_GUEST_PORT from 2222 to 51234
- Reverse socat bridge: VSOCK-LISTEN (host listens) instead of
VSOCK-CONNECT (host connecting to guest)
- Add bridge server to accept persistent guest connection and route
events/responses via callback map
- Fix kernel cmdline: root=LABEL=cloudimg-rootfs (matches fstab)
Co-Authored-By: Claude <claude@anthropic.com>
* fix: patch VM download to use disk-backed temp dir on Linux
Linux systems often mount /tmp as a small tmpfs (3-4GB). The VM
rootfs download decompresses to ~9GB, causing ENOSPC. Patch the
app's mkdtemp("wvm-") call to use the bundle directory (on real
disk) instead of os.tmpdir() on Linux.
Uses regex-based dynamic variable extraction to remain
version-agnostic across minified code changes.
Co-Authored-By: Claude <claude@anthropic.com>
* fix: handle stale cowork socket (ECONNREFUSED) on Linux
Stale sockets from previous sessions give ECONNREFUSED instead of
ENOENT, bypassing the retry loop and auto-launch entirely. Fix:
- Expand ENOENT check in retry loop to include ECONNREFUSED on Linux
- Add cleanup_stale_cowork_socket() to launcher scripts (all formats)
that removes dead sockets before Electron starts
- Increase tmpdir patch search window from 1000 to 2000 chars
Co-Authored-By: Claude <claude@anthropic.com>
* fix: preserve DNS resolution inside bwrap sandbox
On systems using systemd-resolved, /etc/resolv.conf is a symlink to
/run/systemd/resolve/stub-resolv.conf. The bwrap --tmpfs /run option
wiped this out, breaking DNS resolution inside the sandbox and
preventing the spawned Claude process from reaching the API.
Bind-mount the resolved /run/systemd/resolve/ directory back into
the sandbox as read-only to restore DNS.
Co-Authored-By: Claude <claude@anthropic.com>
* fix: harden cowork isolation and build patches
- Remove broken _setupEventForwarding (events already flow through
_handleGuestData); the second bridge connection was silently ignored
- Mount $HOME read-only in bwrap sandbox; only workDir and explicit
mounts are writable (prevents writes to ~/.ssh, ~/.gnupg, etc.)
- Scope Patch 4 win32 extraction to actual win32:{} block via brace
counting to avoid crossing into darwin/linux sections
- Set _qmpAvailable flag on QMP timeout instead of silently continuing
- Wrap CID allocation at 65535 to prevent unbounded growth
- Use execFileSync instead of execSync('which ...') in detectBackend
- Coerce response ID to String for Map lookup in _handleGuestData
- Use non-greedy [\s\S]*? in Patch 6 regex for nested brace robustness
- Update patch count threshold from 4 to 5 after adding Patch 8
- Add age-based fallback for stale socket cleanup when socat is missing
- Use indexOf-based splice in Patch 8 instead of string.replace()
- Extract shared resolveSdkBinary helper to deduplicate SDK resolution
- Remove dead retryFuncRe/retryFuncMatch variables from Patch 6
Co-Authored-By: Claude <claude@anthropic.com>
* fix: address security and correctness issues from code review
- Replace execSync string interpolation with execFileSync for qemu-img
calls to eliminate shell injection risk
- Add path validation to readFile in both LocalBackend and KvmBackend
to restrict reads to within the user's home directory
- Fix QMP _sendQmpCommand timer leak by clearing timeout on success
- Fix _pendingCallbacks.delete() to use String(msg.id) matching the
String(msg.id) used in the .get() lookup
- Extract FORWARDED_EVENTS constant, cleanup helper, extractBlock
helper, and consolidate doctor tool checks (from simplifier pass)
Co-Authored-By: Claude <claude@anthropic.com>
* docs: update README cowork notice with isolation backends and doctor info
Co-Authored-By: Claude <claude@anthropic.com>
---------
Co-authored-by: Claude <claude@anthropic.com>
2026-02-28 21:13:09 -05:00
>
2026-04-23 18:10:33 -04:00
> The APT/DNF repo moved to `pkg.claude-desktop-debian.dev` (#493) — binaries are now served from GitHub Releases via a Cloudflare Worker so they don't hit the 100 MB per-file push cap on `gh-pages`. **DNF users are unaffected.** APT users on the legacy `aaddrick.github.io` sources.list will see a scheme-downgrade error on `apt update`. [One-line `sed` fix](#migrating-from-the-old-aaddrickgithubio-url).
2026-02-16 14:16:44 -05:00
---
2025-08-04 19:13:40 -04:00
## Features
2025-04-05 20:15:38 -04:00
2025-08-04 19:13:40 -04:00
- **Native Linux Support**: Run Claude Desktop without virtualization or Wine
2026-01-05 19:54:43 -05:00
- **MCP Support**: Full Model Context Protocol integration
2025-08-04 19:13:40 -04:00
Configuration file location: `~/.config/Claude/claude_desktop_config.json`
2026-01-05 19:54:43 -05:00
- **System Integration**:
- Global hotkey support (Ctrl+Alt+Space) - works on X11 and Wayland (via XWayland)
2025-08-04 19:13:40 -04:00
- System tray integration
- Desktop environment integration
2025-04-03 01:27:06 -04:00
2025-08-04 19:13:40 -04:00
### Screenshots
2024-12-26 11:08:01 -05:00
2026-02-16 19:47:44 -05:00
<p align="center">
<img src="https://raw.githubusercontent.com/aaddrick/claude-desktop-debian/main/docs/images/claude-desktop-screenshot1.png" alt="Claude Desktop running on Linux" />
</p>
2024-12-26 11:08:01 -05:00
2026-02-16 19:47:44 -05:00
<p align="center">
<img src="https://raw.githubusercontent.com/aaddrick/claude-desktop-debian/main/docs/images/claude-desktop-screenshot2.png" alt="Global hotkey popup" />
</p>
2024-12-26 11:08:01 -05:00
2025-08-04 19:13:40 -04:00
## Installation
2025-01-17 11:17:57 +01:00
2026-01-24 11:06:05 -05:00
### Using APT Repository (Debian/Ubuntu - Recommended)
2026-01-24 08:53:57 -05:00
Add the repository for automatic updates via `apt` :
```bash
# Add the GPG key
2026-04-23 16:12:05 -04:00
curl -fsSL https://pkg.claude-desktop-debian.dev/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/claude-desktop.gpg
2026-01-24 08:53:57 -05:00
# Add the repository
2026-04-23 16:12:05 -04:00
echo "deb [signed-by=/usr/share/keyrings/claude-desktop.gpg arch=amd64,arm64] https://pkg.claude-desktop-debian.dev stable main" | sudo tee /etc/apt/sources.list.d/claude-desktop.list
2026-01-24 08:53:57 -05:00
# Update and install
sudo apt update
sudo apt install claude-desktop
```
Future updates will be installed automatically with your regular system updates (`sudo apt upgrade` ).
2026-01-24 11:06:05 -05:00
### Using DNF Repository (Fedora/RHEL - Recommended)
Add the repository for automatic updates via `dnf` :
```bash
# Add the repository
2026-04-23 16:12:05 -04:00
sudo curl -fsSL https://pkg.claude-desktop-debian.dev/rpm/claude-desktop.repo -o /etc/yum.repos.d/claude-desktop.repo
2026-01-24 11:06:05 -05:00
# Install
sudo dnf install claude-desktop
```
Future updates will be installed automatically with your regular system updates (`sudo dnf upgrade` ).
2026-04-23 16:12:05 -04:00
#### Migrating from the old `aaddrick.github.io` URL
If you installed claude-desktop before April 2026, your repo config points at `https://aaddrick.github.io/claude-desktop-debian` . That URL now auto-redirects to `pkg.claude-desktop-debian.dev` — DNF follows the redirect transparently, but **apt refuses it as a security downgrade ** , so `apt update` fails. Update your sources list to the new URL:
```bash
# APT (Debian/Ubuntu)
sudo sed -i 's|https://aaddrick\.github\.io/claude-desktop-debian|https://pkg.claude-desktop-debian.dev|g' \
/etc/apt/sources.list.d/claude-desktop.list
sudo apt update
# DNF (Fedora/RHEL) — optional refresh; the old URL still works but pointing directly at the new host is cleaner
sudo curl -fsSL https://pkg.claude-desktop-debian.dev/rpm/claude-desktop.repo \
-o /etc/yum.repos.d/claude-desktop.repo
```
Background: binaries for recent releases are no longer committed to the `gh-pages` branch — `.deb` files grew past GitHub's 100 MB per-file cap (#493 ). The new URL is fronted by a small Cloudflare Worker that serves the existing metadata directly and 302-redirects package downloads to the corresponding GitHub Release asset. Bandwidth and package bytes still come from GitHub; the Worker just handles the routing.
2026-02-08 14:33:18 -05:00
### Using AUR (Arch Linux)
The [`claude-desktop-appimage` ](https://aur.archlinux.org/packages/claude-desktop-appimage ) package is available on the AUR and is automatically updated with each release.
```bash
# Using yay
yay -S claude-desktop-appimage
# Or using paru
paru -S claude-desktop-appimage
```
The AUR package installs the AppImage build of Claude Desktop.
2026-02-26 18:48:52 -08:00
### Using Nix Flake (NixOS)
Install directly from the flake:
```bash
# Basic install
nix profile install github:aaddrick/claude-desktop-debian
# With MCP server support (FHS environment)
nix profile install github:aaddrick/claude-desktop-debian#claude -desktop-fhs
```
Or add to your NixOS configuration:
```nix
# flake.nix
{
inputs.claude-desktop.url = "github:aaddrick/claude-desktop-debian";
outputs = { nixpkgs, claude-desktop, ... }: {
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
modules = [
({ pkgs, ... }: {
nixpkgs.overlays = [ claude-desktop.overlays.default ];
environment.systemPackages = [ pkgs.claude-desktop ];
})
];
};
};
}
```
2025-08-04 19:13:40 -04:00
### Using Pre-built Releases
2025-01-17 11:17:57 +01:00
2026-01-24 10:59:53 -05:00
Download the latest `.deb` , `.rpm` , or `.AppImage` from the [Releases page ](https://github.com/aaddrick/claude-desktop-debian/releases ).
2024-12-26 11:08:01 -05:00
2025-08-04 19:13:40 -04:00
### Building from Source
2024-12-26 11:08:01 -05:00
2026-02-16 19:45:40 -05:00
See [docs/BUILDING.md ](docs/BUILDING.md ) for detailed build instructions.
2025-04-03 01:27:06 -04:00
2025-08-04 19:13:40 -04:00
## Configuration
2025-04-03 01:27:06 -04:00
2025-08-04 19:13:40 -04:00
Model Context Protocol settings are stored in:
```
~/.config/Claude/claude_desktop_config.json
```
2024-12-26 11:08:01 -05:00
2026-02-16 19:45:40 -05:00
For additional configuration options including environment variables and Wayland support, see [docs/CONFIGURATION.md ](docs/CONFIGURATION.md ).
2025-03-29 02:31:42 -04:00
2025-08-04 19:13:40 -04:00
## Troubleshooting
feat: KVM/bwrap isolation backends for cowork mode (#269)
* feat: add KVM/bwrap isolation backends for cowork mode
Refactor cowork-vm-service.js from monolithic VMManager into a pluggable
backend architecture with three isolation levels:
- HostBackend: direct execution on host (existing Phase 1 behavior)
- BwrapBackend: bubblewrap namespace sandbox (PID/mount isolation)
- KvmBackend: full QEMU/KVM VM with vsock, virtiofs, QMP monitor
Backend auto-detected at startup (KVM > bwrap > host) or overridden
via COWORK_VM_BACKEND env var. Shared helpers extracted for env
filtering, arg cleanup, command resolution, and work dir handling.
Also:
- Add Cowork Mode section to --doctor diagnostics with per-tool
checks and distro-specific install hints
- Update Patch 4 to extract real win32 file entries for linux
bundle manifest (enables app download infrastructure)
- Update handover documentation for Phase 2/3 architecture
Co-Authored-By: Claude <claude@anthropic.com>
* fix: correct KvmBackend vsock port, direction, and kernel cmdline
The guest sdk-daemon connects TO the host (CID=2), not the other way
around. Confirmed via disassembly of the guest binary: the vsock port
is 51234 (0xC822), matching the Hyper-V GUID in the Windows service.
- Change VSOCK_GUEST_PORT from 2222 to 51234
- Reverse socat bridge: VSOCK-LISTEN (host listens) instead of
VSOCK-CONNECT (host connecting to guest)
- Add bridge server to accept persistent guest connection and route
events/responses via callback map
- Fix kernel cmdline: root=LABEL=cloudimg-rootfs (matches fstab)
Co-Authored-By: Claude <claude@anthropic.com>
* fix: patch VM download to use disk-backed temp dir on Linux
Linux systems often mount /tmp as a small tmpfs (3-4GB). The VM
rootfs download decompresses to ~9GB, causing ENOSPC. Patch the
app's mkdtemp("wvm-") call to use the bundle directory (on real
disk) instead of os.tmpdir() on Linux.
Uses regex-based dynamic variable extraction to remain
version-agnostic across minified code changes.
Co-Authored-By: Claude <claude@anthropic.com>
* fix: handle stale cowork socket (ECONNREFUSED) on Linux
Stale sockets from previous sessions give ECONNREFUSED instead of
ENOENT, bypassing the retry loop and auto-launch entirely. Fix:
- Expand ENOENT check in retry loop to include ECONNREFUSED on Linux
- Add cleanup_stale_cowork_socket() to launcher scripts (all formats)
that removes dead sockets before Electron starts
- Increase tmpdir patch search window from 1000 to 2000 chars
Co-Authored-By: Claude <claude@anthropic.com>
* fix: preserve DNS resolution inside bwrap sandbox
On systems using systemd-resolved, /etc/resolv.conf is a symlink to
/run/systemd/resolve/stub-resolv.conf. The bwrap --tmpfs /run option
wiped this out, breaking DNS resolution inside the sandbox and
preventing the spawned Claude process from reaching the API.
Bind-mount the resolved /run/systemd/resolve/ directory back into
the sandbox as read-only to restore DNS.
Co-Authored-By: Claude <claude@anthropic.com>
* fix: harden cowork isolation and build patches
- Remove broken _setupEventForwarding (events already flow through
_handleGuestData); the second bridge connection was silently ignored
- Mount $HOME read-only in bwrap sandbox; only workDir and explicit
mounts are writable (prevents writes to ~/.ssh, ~/.gnupg, etc.)
- Scope Patch 4 win32 extraction to actual win32:{} block via brace
counting to avoid crossing into darwin/linux sections
- Set _qmpAvailable flag on QMP timeout instead of silently continuing
- Wrap CID allocation at 65535 to prevent unbounded growth
- Use execFileSync instead of execSync('which ...') in detectBackend
- Coerce response ID to String for Map lookup in _handleGuestData
- Use non-greedy [\s\S]*? in Patch 6 regex for nested brace robustness
- Update patch count threshold from 4 to 5 after adding Patch 8
- Add age-based fallback for stale socket cleanup when socat is missing
- Use indexOf-based splice in Patch 8 instead of string.replace()
- Extract shared resolveSdkBinary helper to deduplicate SDK resolution
- Remove dead retryFuncRe/retryFuncMatch variables from Patch 6
Co-Authored-By: Claude <claude@anthropic.com>
* fix: address security and correctness issues from code review
- Replace execSync string interpolation with execFileSync for qemu-img
calls to eliminate shell injection risk
- Add path validation to readFile in both LocalBackend and KvmBackend
to restrict reads to within the user's home directory
- Fix QMP _sendQmpCommand timer leak by clearing timeout on success
- Fix _pendingCallbacks.delete() to use String(msg.id) matching the
String(msg.id) used in the .get() lookup
- Extract FORWARDED_EVENTS constant, cleanup helper, extractBlock
helper, and consolidate doctor tool checks (from simplifier pass)
Co-Authored-By: Claude <claude@anthropic.com>
* docs: update README cowork notice with isolation backends and doctor info
Co-Authored-By: Claude <claude@anthropic.com>
---------
Co-authored-by: Claude <claude@anthropic.com>
2026-02-28 21:13:09 -05:00
Run `claude-desktop --doctor` for built-in diagnostics that check common issues (display server, sandbox permissions, MCP config, stale locks, and more). It also reports cowork mode readiness — which isolation backend will be used, and which dependencies (KVM, QEMU, vsock, socat, virtiofsd, bubblewrap) are installed or missing.
2026-02-28 15:47:37 -05:00
For additional troubleshooting, uninstallation instructions, and log locations, see [docs/TROUBLESHOOTING.md ](docs/TROUBLESHOOTING.md ).
2025-04-03 01:27:06 -04:00
2025-08-04 19:13:40 -04:00
## Acknowledgments
2025-04-03 01:27:06 -04:00
2025-08-04 19:13:40 -04:00
This project was inspired by [k3d3's claude-desktop-linux-flake ](https://github.com/k3d3/claude-desktop-linux-flake ) and their [Reddit post ](https://www.reddit.com/r/ClaudeAI/comments/1hgsmpq/i_successfully_ran_claude_desktop_natively_on/ ) about running Claude Desktop natively on Linux.
2025-04-03 01:27:06 -04:00
2025-08-04 19:13:40 -04:00
Special thanks to:
2026-04-12 15:19:11 -04:00
- **k3d3**
- Original NixOS implementation
- Native bindings insights
- **[emsi ](https://github.com/emsi/claude-desktop )**
- Title bar fix
- Alternative implementation approach
2026-01-05 17:35:53 -05:00
- **[leobuskin ](https://github.com/leobuskin/unofficial-claude-desktop-linux )** for the Playwright-based URL resolution approach
2026-04-12 15:19:11 -04:00
- **[yarikoptic ](https://github.com/yarikoptic )**
- Codespell support
- Shellcheck compliance
2026-02-08 14:33:18 -05:00
- **[IamGianluca ](https://github.com/IamGianluca )** for build dependency check improvements
- **[ing03201 ](https://github.com/ing03201 )** for IBus/Fcitx5 input method support
- **[ajescudero ](https://github.com/ajescudero )** for pinning @electron/asar for Node compatibility
- **[delorenj ](https://github.com/delorenj )** for Wayland compatibility support
- **[Regen-forest ](https://github.com/Regen-forest )** for suggesting Gear Lever as AppImageLauncher replacement
- **[niekvugteveen ](https://github.com/niekvugteveen )** for fixing Debian packaging permissions
- **[speleoalex ](https://github.com/speleoalex )** for native window decorations support
- **[imaginalnika ](https://github.com/imaginalnika )** for moving logs to `~/.cache/`
- **[richardspicer ](https://github.com/richardspicer )** for the menu bar visibility fix on Linux
2026-04-12 15:19:11 -04:00
- **[jacobfrantz1 ](https://github.com/jacobfrantz1 )**
- Claude Desktop code preview support
- Quick window submit fix
2026-02-08 14:33:18 -05:00
- **[janfrederik ](https://github.com/janfrederik )** for the `--exe` flag to use a local installer
- **[MrEdwards007 ](https://github.com/MrEdwards007 )** for discovering the OAuth token cache fix
fix(lifecycle): hide main window to tray on close, Linux (#451)
* fix(lifecycle): hide main window to tray on close, Linux (#448)
Electron's default window-all-closed handler quits the app on
Linux. The existing tray icon and Ctrl+Q patches keep the app
reachable while a window is alive, but as soon as the last
window is closed (stray click on X, or a sign-out flow that
closes mainWindow) the app exits and the tray goes with it —
taking any in-app schedulers / MCP servers / cron tasks
(/schedule skill) down silently until the user re-launches.
Intercept BrowserWindow.close on main windows (not popups;
Quick Entry and About already dismiss via hide(), never emit
close) and preventDefault + hide unless app is in a real quit
path. The quit path is detected via before-quit: Ctrl+Q, tray
Quit, cmd+Q, SIGTERM and app.quit() from anywhere all emit
before-quit, which arms app._quittingIntentionally so the
close handler lets the window actually close.
Gated by CLOSE_TO_TRAY, default on. Set CLAUDE_QUIT_ON_CLOSE=1
to restore the Electron-default behaviour.
Fixes #448
Co-Authored-By: Claude <claude@anthropic.com>
* fix(frame-fix-wrapper): drop superseded globalShortcut Ctrl+Q
Removes the globalShortcut.register('CommandOrControl+Q') block
that #484 superseded with the per-window
webContents.on('before-input-event') listener. Auto-merging main
into this branch left both registrations in place, which would
re-introduce the AZERTY physical-keycode grab and system-wide
shortcut steal that #484 fixed. The focus-scoped listener
already covers the original #321 hidden-menu-bar use case.
Also updates the close-to-tray comment to reference the new
listener path instead of the removed global shortcut.
Co-Authored-By: Claude <claude@anthropic.com>
* docs(readme): credit lizthegrey for close-to-tray contribution
Co-Authored-By: Claude <claude@anthropic.com>
---------
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: aaddrick <aaddrick@gmail.com>
2026-04-28 15:16:56 -07:00
- **[lizthegrey ](https://github.com/lizthegrey )**
- Version update contributions
- Close-to-tray on Linux to keep in-app schedulers, MCP servers, and the tray icon alive across window close
fix(autostart): route openAtLogin through XDG Autostart on Linux (#450)
* fix(autostart): route openAtLogin through XDG Autostart on Linux (#128)
Electron's app.getLoginItemSettings()/setLoginItemSettings() are
no-ops on Linux (electron/electron#15198), so the "Run on startup"
toggle never persists and isStartupOnLoginEnabled() returns
undefined, failing the IPC handler's typeof === 'boolean' check.
Intercept both calls in frame-fix-wrapper.js and back them with
~/.config/autostart/claude-desktop.desktop, which is honoured by
GNOME/KDE/XFCE/Cinnamon/MATE/LXQt (XDG Autostart spec). Also
coerce executableWillLaunchAtLogin (Windows-only in Electron,
undefined on Linux) to a boolean so the IPC handler stops
throwing.
Fixes #128
Co-Authored-By: Claude <claude@anthropic.com>
* fix(autostart): address review — APPIMAGE runtime target, XDG_CONFIG_HOME, StartupWMClass (#128)
Addresses review comments on #450:
- Resolve Exec= and Icon= at toggle time via process.env.APPIMAGE
so AppImage users (who don't have claude-desktop on $PATH unless
integrated via AppImageLauncher) get an autostart entry that
launches the actual .AppImage bundle instead of a broken binary
reference. escapeExecArg() handles Desktop Entry Exec escaping
(quote + backslash-escape reserved chars).
- Honour $XDG_CONFIG_HOME when set and non-empty, falling back to
~/.config only otherwise. Home-manager and dotfile users who
relocate the config root were getting the entry dropped in the
wrong place silently.
- Add StartupWMClass=Claude to the generated entry, matching the
value set by scripts/packaging/{deb,rpm}.sh, so DEs group the
autostarted window with user-launched instances under a single
taskbar/dock item. Drop Categories= per review guidance
(autostart parsers ignore it).
- Comment why opts.path is intentionally ignored: process.execPath
points at the electron binary, not the launcher shim that sets
ELECTRON_FORCE_IS_PACKAGED / ozone flags / orphan cleanup —
honouring opts.path would write a broken autostart entry.
The "removed" log placement (review item 4) is already inside the
inner try, so unlinkSync throwing ENOENT short-circuits before the
log runs. Left as-is.
Co-Authored-By: Claude <claude@anthropic.com>
* docs(readme): credit lizthegrey for XDG Autostart contribution
Co-Authored-By: Claude <claude@anthropic.com>
---------
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: aaddrick <aaddrick@gmail.com>
2026-04-28 16:02:47 -07:00
- "Run on startup" persistence on Linux via XDG Autostart, fixing the toggle that would silently revert
2026-04-12 15:19:11 -04:00
- **[mathys-lopinto ](https://github.com/mathys-lopinto )**
- AUR package
- Automated deployment
2026-02-08 14:33:18 -05:00
- **[pkuijpers ](https://github.com/pkuijpers )** for root cause analysis of the RPM repo GPG signing issue
- **[dlepold ](https://github.com/dlepold )** for identifying the tray icon variable name bug with a working fix
2026-04-12 15:19:11 -04:00
- **[Voork1144 ](https://github.com/Voork1144 )**
- Detailed analysis of the tray icon minifier bug
- Root-cause analysis of the Chromium layout cache bug
- Direct child `setBounds()` fix approach
- **[sabiut ](https://github.com/sabiut )**
- `--doctor` diagnostic command
- SHA-256 checksum validation for downloads
2026-04-12 15:23:10 -04:00
- Post-build integration tests for deb, rpm, and AppImage artifacts
2026-04-12 15:19:11 -04:00
- **[milog1994 ](https://github.com/milog1994 )**
- Popup detection
- Functional stubs
- Wayland compositor support
- **[jarrodcolburn ](https://github.com/jarrodcolburn )**
- Passwordless sudo support in container/CI environments
- Identifying the gh-pages 4GB bloat fix
- Identifying the virtiofsd PATH detection issue on Debian
- Detailed analysis of the CI release pipeline failure caused by runner kills during compare-releases
- Diagnosing the session-start hook sudo blocking issue with three solution approaches
2026-02-16 14:09:43 -05:00
- **[chukfinley ](https://github.com/chukfinley )** for experimental Cowork mode support on Linux
2026-05-01 05:09:41 +02:00
- **[CyPack ](https://github.com/CyPack )**
- Orphaned cowork daemon cleanup on startup
- `COWORK_VM_BACKEND` documentation, Cowork troubleshooting sections, and unknown-value warning in `--doctor`
fix: update Linux tray icon in place on OS theme change (#515)
* fix: update Linux tray icon in place on OS theme change
Avoids a StatusNotifierItem re-registration race on KDE Plasma
where the old SNI remains registered when the new one appears,
resulting in two tray icons side by side until session logout.
`patch_tray_menu_handler` already bounds the race with a 250 ms
delay after `tray.destroy()`, but that's not enough on all setups
(reproduced on Fedora 43 KDE Plasma 6.6.4 + Wayland). Widening the
delay just moves the goalposts; the race is structural.
Fix: inject a fast-path before the existing destroy+recreate block
in the tray rebuild function. When the tray already exists and
isn't being disabled, update its icon and context menu in place
via `setImage` + `setContextMenu` — the existing StatusNotifierItem
stays registered, no DBus re-registration, no race. The slow path
(destroy + delay + re-create) is kept for the initial creation and
the tray-disable cases where it's unavoidable.
All five minified locals needed by the fast-path (tray function,
tray variable, electron module, menu function, icon path const,
menuBarEnabled flag) are extracted dynamically; the idempotency
guard re-keys off the post-rename `setImage(...)` sequence.
Triggered in KDE System Settings by any of Appearance → Colors /
Plasma Style / Global Theme, which all fire the same
`nativeTheme.on('updated')` signal.
Follow-up to #491. The broader submenu work from that PR stays
parked on features/change-icon-color pending the scope discussion
in #492; this PR ships only the duplicate-tray-icon fix that
@aaddrick asked to split out.
Co-Authored-By: Claude <claude@anthropic.com>
* fix(tray): tighten in-place patch extraction guards
Drop the redundant `electron_var_re_local` local — `electron_var_re`
is already a sourced global from `_common.sh` with the same value.
Replace the silent `head -1` on `enabled_var` extraction with an
explicit count-and-bail. The grep matches `const X=fn("menuBarEnabled")`
across the whole file; today there's exactly one site (inside the
tray function), but if upstream ever ships a second the previous
code would silently bind to whichever the minifier emitted first.
Bail loudly with a count diagnostic instead.
Verified on the live 1.3883.0 build asar: all five extractions
resolve (`Nh`/`wAt`/`t`/`e`) — note the symbol drift vs. the
build-reference's `fh`/`CZe`. Fast-path injects, JS validates,
idempotent re-run confirmed, duplicate-icon repro gone on Nobara
KDE Plasma 6 (Wayland) under Appearance → Colors / Plasma Style /
Global Theme.
Co-Authored-By: Claude <claude@anthropic.com>
* docs(readme): credit @IliyaBrook for tray duplicate-icon fix
Co-Authored-By: Claude <claude@anthropic.com>
---------
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: aaddrick <aaddrick@gmail.com>
2026-04-27 16:19:36 +03:00
- **[IliyaBrook ](https://github.com/IliyaBrook )**
- Fixing the platform patch for Claude Desktop >= 1.1.3541 arm64 refactor
- Fixing the duplicate tray icon on OS theme change with an in-place `setImage` /`setContextMenu` fast-path that avoids the KDE Plasma SNI re-registration race
2026-04-12 15:19:11 -04:00
- **[MichaelMKenny ](https://github.com/MichaelMKenny )**
- Diagnosing the `$` -prefixed electron variable bug
- Root cause analysis and workaround
2026-02-25 06:16:05 -05:00
- **[daa25209 ](https://github.com/daa25209 )** for detailed root cause analysis of the cowork platform gate crash and patch script
2026-04-12 15:19:11 -04:00
- **[noctuum ](https://github.com/noctuum )**
- `CLAUDE_MENU_BAR` env var with configurable menu bar visibility
- Boolean alias support
- **[typedrat ](https://github.com/typedrat )**
- NixOS flake integration with build.sh
- node-pty derivation
- CI auto-update
- Fixing the flake package scoping regression
- **[cbonnissent ](https://github.com/cbonnissent )**
- Reverse-engineering the Cowork VM guest RPC protocol
- Fixing the KVM startup blocker
- Fixing RPC response id echoing for persistent connections
- Configurable bwrap mount points via a dedicated Linux config file
2026-03-19 08:03:35 -04:00
- **[joekale-pp ](https://github.com/joekale-pp )** for adding `--doctor` support to the RPM launcher
2026-03-20 11:44:29 -04:00
- **[ecrevisseMiroir ](https://github.com/ecrevisseMiroir )** for the bwrap backend sandbox isolation with tmpfs-based minimal root
2026-03-20 11:51:16 -04:00
- **[arauhala ](https://github.com/arauhala )** for detailed root cause analysis of the NixOS `isPackaged` regression
2026-03-22 22:51:00 -04:00
- **[cromagnone ](https://github.com/cromagnone )** for confirming the VM download loop on bwrap installs with detailed logs that disproved the initial triage
2026-03-25 06:50:00 -04:00
- **[aHk-coder ](https://github.com/aHk-coder )** for diagnosing the hardcoded minified variable crash in the cowork smol-bin patch
2026-04-12 15:44:41 -04:00
- **[RayCharlizard ](https://github.com/RayCharlizard )**
- Detailed analysis of the self-referential `.mcpb-cache` symlink ELOOP bug
- Fixing auto-memory path translation on HostBackend
2026-04-22 21:44:05 -04:00
- Fixing the `ion-dist` static asset copy for the `app://` protocol handler
2026-04-01 04:42:27 -04:00
- **[reinthal ](https://github.com/reinthal )** for fixing the NixOS build breakage caused by the nixpkgs `nodePackages` removal
2026-04-12 15:19:11 -04:00
- **[gianluca-peri ](https://github.com/gianluca-peri )**
- Reporting the GNOME quit accessibility issue
- Confirming tray behavior with AppIndicator
2026-04-18 19:28:22 -05:00
- **[martin152 ](https://github.com/martin152 )** for detailed diagnosis and a complete patch for three launcher cleanup bugs: `cleanup_orphaned_cowork_daemon` self-match, `cleanup_stale_cowork_socket` socat dependency no-op, and the same self-match in `--doctor`
2026-04-19 01:12:13 -05:00
- **[hfyeh ](https://github.com/hfyeh )** for diagnosing the Ubuntu 24.04 AppArmor unprivileged-userns block on Cowork bwrap and contributing the AppArmor profile workaround
2026-04-21 08:26:21 -04:00
- **[davidamacey ](https://github.com/davidamacey )** for identifying and fixing the XRDP GPU compositing blank-window issue on remote desktop sessions
2026-04-21 16:33:59 -05:00
- **[pb3ck ](https://github.com/pb3ck )** for diagnosing the Cowork `CLAUDE_CODE_OAUTH_TOKEN` env-strip bug with a working reference diff
2026-04-21 18:51:14 -04:00
- **[aJV99 ](https://github.com/aJV99 )** for exporting `GDK_BACKEND=wayland` in native Wayland mode to fix XWayland fallback blur on HiDPI displays
2026-04-27 18:20:46 +05:00
- **[Andrej730 ](https://github.com/Andrej730 )**
- Quick-window regex readability refactor (`String.raw` + `escapeRegExp` helper)
- Fixing the visibility-function regex break on Claude Desktop 1.3883.0 (#495 )
2024-12-26 11:08:01 -05:00
2026-02-24 00:44:48 -05:00
## Sponsorship
2026-04-19 02:34:00 -04:00
If this project is useful to you, consider [sponsoring on GitHub ](https://github.com/sponsors/aaddrick ).
2026-02-24 00:44:48 -05:00
2025-08-04 19:13:40 -04:00
## License
2024-12-26 11:08:01 -05:00
2025-08-04 19:13:40 -04:00
The build scripts in this repository are dual-licensed under:
- MIT License (see [LICENSE-MIT ](LICENSE-MIT ))
- Apache License 2.0 (see [LICENSE-APACHE ](LICENSE-APACHE ))
2024-12-26 11:08:01 -05:00
2025-08-04 19:13:40 -04:00
The Claude Desktop application itself is subject to [Anthropic's Consumer Terms ](https://www.anthropic.com/legal/consumer-terms ).
2024-12-26 11:08:01 -05:00
2026-04-20 17:29:17 -04:00
## Privacy
This repository uses an automated triage bot that sends issue contents to Anthropic's API for classification and investigation when you file a bug report or feature request. The bot reads the issue body, title, and any referenced related issues; it does not follow URLs, execute code blocks, or read content outside the triggering issue.
Do not include credentials, tokens, personal data, or anything you wouldn't put on a public issue tracker. If you post sensitive content and then edit it out, the bot's original read is preserved as a run artifact for audit — GitHub's UI hides the edit, but the bot's view of what you wrote is recoverable by maintainers.
Full design and data inventory: [`docs/issue-triage/README.md` ](docs/issue-triage/README.md ).
2025-08-04 19:13:40 -04:00
## Contributing
2024-12-26 11:08:01 -05:00
2025-08-09 21:58:44 -04:00
Contributions are welcome! By submitting a contribution, you agree to license it under the same dual-license terms as this project.