Files
claude-desktop-debian/README.md

203 lines
10 KiB
Markdown
Raw Normal View History

# Claude Desktop for Linux
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.
**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.
---
> **⚠️ EXPERIMENTAL: Cowork Mode Support**
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
> Cowork mode is **enabled by default** in this build. It uses Anthropic's native VM images with a pluggable isolation backend:
>
> | Backend | Isolation | Requirements |
> |---------|-----------|-------------|
> | **KVM** (preferred) | Full VM via QEMU/KVM | `/dev/kvm`, `qemu-system-x86_64`, `/dev/vhost-vsock`, `socat`, `virtiofsd` |
> | **bubblewrap** (fallback) | Namespace sandbox | `bwrap` installed and functional |
> | **host** (last resort) | None — runs directly on host | No additional requirements |
>
> The best available backend is auto-detected at startup. Run `claude-desktop --doctor` to check which backend will be used and which dependencies are missing.
>
> **Note:** The bubblewrap backend mounts your home directory as read-only (only the project working directory is writable). The host backend provides no isolation — use it only if you understand the security implications.
---
## Features
- **Native Linux Support**: Run Claude Desktop without virtualization or Wine
- **MCP Support**: Full Model Context Protocol integration
Configuration file location: `~/.config/Claude/claude_desktop_config.json`
- **System Integration**:
- Global hotkey support (Ctrl+Alt+Space) - works on X11 and Wayland (via XWayland)
- System tray integration
- Desktop environment integration
2025-04-03 01:27:06 -04:00
### Screenshots
<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>
<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>
## Installation
2025-01-17 11:17:57 +01:00
### Using APT Repository (Debian/Ubuntu - Recommended)
Add the repository for automatic updates via `apt`:
```bash
# Add the GPG key
curl -fsSL https://aaddrick.github.io/claude-desktop-debian/KEY.gpg | sudo gpg --dearmor -o /usr/share/keyrings/claude-desktop.gpg
# Add the repository
echo "deb [signed-by=/usr/share/keyrings/claude-desktop.gpg arch=amd64,arm64] https://aaddrick.github.io/claude-desktop-debian stable main" | sudo tee /etc/apt/sources.list.d/claude-desktop.list
# 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`).
### Using DNF Repository (Fedora/RHEL - Recommended)
Add the repository for automatic updates via `dnf`:
```bash
# Add the repository
sudo curl -fsSL https://aaddrick.github.io/claude-desktop-debian/rpm/claude-desktop.repo -o /etc/yum.repos.d/claude-desktop.repo
# Install
sudo dnf install claude-desktop
```
Future updates will be installed automatically with your regular system updates (`sudo dnf upgrade`).
### 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.
### 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 ];
})
];
};
};
}
```
### Using Pre-built Releases
2025-01-17 11:17:57 +01:00
Download the latest `.deb`, `.rpm`, or `.AppImage` from the [Releases page](https://github.com/aaddrick/claude-desktop-debian/releases).
### Building from Source
See [docs/BUILDING.md](docs/BUILDING.md) for detailed build instructions.
2025-04-03 01:27:06 -04:00
## Configuration
2025-04-03 01:27:06 -04:00
Model Context Protocol settings are stored in:
```
~/.config/Claude/claude_desktop_config.json
```
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
## 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.
For additional troubleshooting, uninstallation instructions, and log locations, see [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md).
2025-04-03 01:27:06 -04:00
## Acknowledgments
2025-04-03 01:27:06 -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
Special thanks to:
- **k3d3** for the original NixOS implementation and native bindings insights
- **[emsi](https://github.com/emsi/claude-desktop)** for the title bar fix and alternative implementation approach
- **[leobuskin](https://github.com/leobuskin/unofficial-claude-desktop-linux)** for the Playwright-based URL resolution approach
- **[yarikoptic](https://github.com/yarikoptic)** for codespell support and shellcheck compliance
- **[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
- **[jacobfrantz1](https://github.com/jacobfrantz1)** for Claude Desktop code preview support and quick window submit fix
- **[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
- **[lizthegrey](https://github.com/lizthegrey)** for version update contributions
- **[mathys-lopinto](https://github.com/mathys-lopinto)** for the AUR package and automated deployment
- **[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
- **[Voork1144](https://github.com/Voork1144)** for detailed analysis of the tray icon minifier bug, root-cause analysis of the Chromium layout cache bug, and the direct child `setBounds()` fix approach
- **[sabiut](https://github.com/sabiut)** for the `--doctor` diagnostic command
- **[milog1994](https://github.com/milog1994)** for Linux UX improvements including popup detection, functional stubs, and Wayland compositor support
- **[jarrodcolburn](https://github.com/jarrodcolburn)** for passwordless sudo support in container/CI environments
- **[chukfinley](https://github.com/chukfinley)** for experimental Cowork mode support on Linux
- **[IliyaBrook](https://github.com/IliyaBrook)** for fixing the platform patch for Claude Desktop >= 1.1.3541 arm64 refactor
- **[MichaelMKenny](https://github.com/MichaelMKenny)** for diagnosing the `$`-prefixed electron variable bug with root cause analysis and workaround
- **[daa25209](https://github.com/daa25209)** for detailed root cause analysis of the cowork platform gate crash and patch script
- **[noctuum](https://github.com/noctuum)** for the `CLAUDE_MENU_BAR` env var with configurable menu bar visibility and boolean alias support
- **[typedrat](https://github.com/typedrat)** for the NixOS flake integration with build.sh, node-pty derivation, and CI auto-update
- **[cbonnissent](https://github.com/cbonnissent)** for reverse-engineering the Cowork VM guest RPC protocol and fixing the KVM startup blocker
## Sponsorship
Anthropic doesn't publish release notes for Claude Desktop. Each release here includes AI-generated notes that analyze code changes between versions. I wrote up how that process works if you're curious: [Generating Real Release Notes from Minified Electron Apps](https://nonconvexlabs.com/blog/generating-real-release-notes-from-minified-electron-apps).
The analysis runs against Claude's API. Costs vary a lot depending on how big the update is. Recent releases have run between **$3.36 and $76.16 per release**.
If this project is useful to you, consider [sponsoring on GitHub](https://github.com/sponsors/aaddrick) to help cover those costs.
## License
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))
The Claude Desktop application itself is subject to [Anthropic's Consumer Terms](https://www.anthropic.com/legal/consumer-terms).
## Contributing
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.