Travis 44cd5a6c24 fix: forward userSelectedFolders[0] as sharedCwdPath on cowork spawn (#412) (#436)
* fix: forward userSelectedFolders[0] as sharedCwdPath on cowork spawn (#412)

The cowork-vm-service daemon already honors a `sharedCwdPath` field on
the spawn IPC payload with priority over `cwd` (resolveWorkDir in
scripts/cowork-vm-service.js:500), but the upstream Electron app never
populates it on Linux backends. Every spawn arrives with only
`cwd=/sessions/{name}`, so the daemon derives the host path from
mountMap heuristics (PRs #389/#392/#411 cover the symptoms).

Patch 12 threads the user-selected folder through three sites so the
daemon receives the host path explicitly:

  12a. At `this.getVMSpawnFunction({...})` config assembly, inject
       `sharedCwdPath: SESSION.userSelectedFolders?.[0]` alongside the
       existing mount config.
  12b. At the Kyr() -> VMClient.spawn() call, forward
       `SESSION.sharedCwdPath` as a new 13th positional argument.
  12c. In the spawn() method body, accept a new trailing parameter
       and set it on the IPC payload with a `VAR && (I.sharedCwdPath=VAR)`
       guard matching the existing setter chain.

All three sub-patches detect prior application and no-op on re-run
(idempotent). If any site fails to match on a future upstream, the
daemon-side fallback from #392 keeps cwd resolution working — the
daemon workarounds in #389/#392/#411 remain as safety nets.

Verified against app.asar extracted from Claude-Setup-x64.exe for
version 1.3109.0. All three edits apply, output parses cleanly, a
second run is a no-op.

Co-Authored-By: Claude <claude@anthropic.com>

* refactor: simplify Patch 12 block

Reduce Patch 12 (#412) by 25 lines without changing the patched
output:

- 12a: use extractBlock('{') directly on the getVMSpawnFunction
  argument and splice before its closing '}', removing the
  inverted backward walk over the parenthesised block.
- 12a: replace the exec-until-null loop with matchAll + last
  element to read the session-var name.
- 12c: replace the whole.replace().replace() + code.replace(whole)
  reassembly chain with an index-based splice using
  spawnMatch.index.
- 12c: drop the unneeded .split('') on the letter bag and inline
  newArgList.
- Trim the prologue comment to match the density of Patches 1-10.

Patched index.js is byte-identical against the 1.3109.0 fixture
and the three idempotency log lines still fire on re-run.

Co-Authored-By: Claude <claude@anthropic.com>

* fix: address aaddrick's review — robust 12a anchor, 12b uniqueness assertion

Two fixes from PR #436 review:

1. **12a: drop fragile backscan, route through this.sessions.get().**
   The previous `VAR.userSelectedFolders` backscan returned 10 matches
   across 4 distinct vars (t, se, Ke, We) in the v1.3109.0 window —
   last-match landed on `t` by coincidence, and `We` in particular is
   a for-loop variable one upstream re-order away from becoming the
   new "last". Swap to the canonical accessor the class already uses:
   `this.sessions.get(sessionId)?.userSelectedFolders?.[0]`. The
   sessionId var is extracted from the config's first field
   `{sessionId:VAR` — scoped to the config block, 100% guaranteed
   present, immune to unrelated references leaking in.

2. **12b: matchAll + uniqueness assertion.** The previous code used
   `code.match()` which silently took the first hit if a second
   upstream call site ever appeared. Switch to `matchAll` with
   `length === 1` assertion; WARN-and-skip on anything else so a
   wrong-site forwarding becomes detectable instead of silent.

3. **Drop misleading ordering comment in 12c.** The "12c before 12b
   so property name is fixed" note was wrong — the property name is
   a hardcoded string literal in both sub-patches, so the ordering
   is cosmetic.

Verified: dry-run still applies all three patches on 1.3109.0 source,
output passes `node --check`, the three sharedCwdPath edits are
byte-stable across runs (the non-idempotency in Patch 9 is
pre-existing and orthogonal).

Co-Authored-By: Claude <claude@anthropic.com>

---------

Co-authored-by: Claude <claude@anthropic.com>
2026-04-19 12:25:29 -04:00
2025-04-03 10:41:13 -04:00
2026-04-13 03:17:43 +00:00

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 for Arch Linux, and a Nix flake for NixOS.

Note: This is an unofficial build script. For official support, please visit Anthropic's website. For issues with the build script or Linux implementation, please open an issue in this repository.


⚠️ EXPERIMENTAL: Cowork Mode Support Cowork mode is enabled by default in this build with a pluggable isolation backend:

Backend Isolation Requirements
bubblewrap (default) Namespace sandbox bwrap installed and functional
host (fallback) 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.

KVM status: The KVM/QEMU backend code exists but is non-functional — VM file downloads are disabled on Linux to prevent a checksum loop (#337). The backend code remains for potential future use.


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

Screenshots

Claude Desktop running on Linux

Global hotkey popup

Installation

Add the repository for automatic updates via apt:

# 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).

Add the repository for automatic updates via dnf:

# 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 package is available on the AUR and is automatically updated with each release.

# 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:

# 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:

# 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

Download the latest .deb, .rpm, or .AppImage from the Releases page.

Building from Source

See docs/BUILDING.md for detailed build instructions.

Configuration

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.

Troubleshooting

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.

Acknowledgments

This project was inspired by k3d3's claude-desktop-linux-flake and their Reddit post about running Claude Desktop natively on Linux.

Special thanks to:

  • k3d3
    • Original NixOS implementation
    • Native bindings insights
  • emsi
    • Title bar fix
    • Alternative implementation approach
  • leobuskin for the Playwright-based URL resolution approach
  • yarikoptic
    • Codespell support
    • Shellcheck compliance
  • IamGianluca for build dependency check improvements
  • ing03201 for IBus/Fcitx5 input method support
  • ajescudero for pinning @electron/asar for Node compatibility
  • delorenj for Wayland compatibility support
  • Regen-forest for suggesting Gear Lever as AppImageLauncher replacement
  • niekvugteveen for fixing Debian packaging permissions
  • speleoalex for native window decorations support
  • imaginalnika for moving logs to ~/.cache/
  • richardspicer for the menu bar visibility fix on Linux
  • jacobfrantz1
    • Claude Desktop code preview support
    • Quick window submit fix
  • janfrederik for the --exe flag to use a local installer
  • MrEdwards007 for discovering the OAuth token cache fix
  • lizthegrey for version update contributions
  • mathys-lopinto
    • AUR package
    • Automated deployment
  • pkuijpers for root cause analysis of the RPM repo GPG signing issue
  • dlepold for identifying the tray icon variable name bug with a working fix
  • Voork1144
    • Detailed analysis of the tray icon minifier bug
    • Root-cause analysis of the Chromium layout cache bug
    • Direct child setBounds() fix approach
  • sabiut
    • --doctor diagnostic command
    • SHA-256 checksum validation for downloads
    • Post-build integration tests for deb, rpm, and AppImage artifacts
  • milog1994
    • Popup detection
    • Functional stubs
    • Wayland compositor support
  • 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
  • chukfinley for experimental Cowork mode support on Linux
  • CyPack for orphaned cowork daemon cleanup on startup
  • IliyaBrook for fixing the platform patch for Claude Desktop >= 1.1.3541 arm64 refactor
  • MichaelMKenny
    • Diagnosing the $-prefixed electron variable bug
    • Root cause analysis and workaround
  • daa25209 for detailed root cause analysis of the cowork platform gate crash and patch script
  • noctuum
    • CLAUDE_MENU_BAR env var with configurable menu bar visibility
    • Boolean alias support
  • typedrat
    • NixOS flake integration with build.sh
    • node-pty derivation
    • CI auto-update
    • Fixing the flake package scoping regression
  • 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
  • joekale-pp for adding --doctor support to the RPM launcher
  • ecrevisseMiroir for the bwrap backend sandbox isolation with tmpfs-based minimal root
  • arauhala for detailed root cause analysis of the NixOS isPackaged regression
  • cromagnone for confirming the VM download loop on bwrap installs with detailed logs that disproved the initial triage
  • aHk-coder for diagnosing the hardcoded minified variable crash in the cowork smol-bin patch
  • RayCharlizard
    • Detailed analysis of the self-referential .mcpb-cache symlink ELOOP bug
    • Fixing auto-memory path translation on HostBackend
  • reinthal for fixing the NixOS build breakage caused by the nixpkgs nodePackages removal
  • gianluca-peri
    • Reporting the GNOME quit accessibility issue
    • Confirming tray behavior with AppIndicator
  • 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
  • hfyeh for diagnosing the Ubuntu 24.04 AppArmor unprivileged-userns block on Cowork bwrap and contributing the AppArmor profile workaround

Sponsorship

If this project is useful to you, consider sponsoring on GitHub.

License

The build scripts in this repository are dual-licensed under:

The Claude Desktop application itself is subject to Anthropic's Consumer Terms.

Contributing

Contributions are welcome! By submitting a contribution, you agree to license it under the same dual-license terms as this project.

Description
No description provided
Readme 10 GiB
Languages
TypeScript 46.6%
Shell 40.5%
JavaScript 11.4%
Nix 0.9%
Python 0.6%