Skip to content

Commit 22cebe1

Browse files
committed
fix: use macOS DMG source with JS stubs, update to v1.1.1200
Major changes: - Switch from Windows installer to macOS DMG (more reliable extraction) - Replace Rust native bindings (patchy-cnb) with simple JavaScript stubs - Update to Claude Desktop v1.1.1200 - Add Linux platform detection for Claude Code - Fix tray icon theme detection for dark/light modes - Simplify build process (no Rust compilation needed) The previous Rust-based approach required compilation and had issues with the tray menu patches injecting 'await' outside async contexts, causing SyntaxError on startup. The JS stub approach matches what claude-desktop-debian uses and is simpler to maintain.
1 parent b2b040c commit 22cebe1

File tree

19 files changed

+376
-1752
lines changed

19 files changed

+376
-1752
lines changed

CLAUDE.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# CLAUDE.md
2+
3+
## Project Overview
4+
5+
Nix flake that runs Claude Desktop on Linux by repackaging the macOS build with JavaScript stubs for the native bindings.
6+
7+
## Building
8+
9+
```bash
10+
nix build .#claude-desktop # Standard build
11+
nix build .#claude-desktop-with-fhs # With FHS environment for MCP servers
12+
nix run . # Build and run
13+
```
14+
15+
## Architecture
16+
17+
The build process (`pkgs/claude-desktop.nix`):
18+
19+
1. Download macOS DMG
20+
2. Extract with 7z (handles HFS+ despite warnings)
21+
3. Extract and patch `app.asar`:
22+
- Title bar: Enable native frames on Linux
23+
- Platform detection: Add `linux-x64`/`linux-arm64` for Claude Code
24+
- Origin validation: Allow `file://` protocol when unpackaged
25+
- Tray icons: Theme-aware selection
26+
- Window blur: Fix quick-submit focus
27+
4. Replace `@ant/claude-native` with inline JS stubs
28+
5. Repackage and wrap with Electron
29+
30+
## Updating Version
31+
32+
In `pkgs/claude-desktop.nix`:
33+
1. Update `version`
34+
2. Update `srcDmg.url` with new version/hash from filename
35+
3. Update `srcDmg.hash` (run `nix-prefetch-url <url>` then `nix hash to-sri sha256:<hash>`)
36+
37+
## Packages
38+
39+
- `claude-desktop` - Standard build
40+
- `claude-desktop-with-fhs` - FHS wrapper for MCP servers (npx, uvx, docker)
41+
- `claude-desktop-shell` - FHS shell for MCP development

README.md

Lines changed: 26 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -4,104 +4,63 @@ If you run into an issue with this build script, make an issue here. Don't bug A
44

55
# Claude Desktop for Linux (Nix)
66

7-
Supports MCP!
8-
![image](https://github.com/user-attachments/assets/93080028-6f71-48bd-8e59-5149d148cd45)
7+
This is a Nix flake for running Claude Desktop on Linux with proper desktop integration.
98

10-
Supports the Ctrl+Alt+Space popup!
11-
![image](https://github.com/user-attachments/assets/1deb4604-4c06-4e4b-b63f-7f6ef9ef28c1)
9+
## Features
1210

13-
Supports the Tray menu! (Screenshot of running on KDE)
11+
- MCP server support
12+
- Ctrl+Alt+Space popup
13+
- System tray integration
14+
- GNOME/Wayland desktop integration
1415

15-
![image](https://github.com/user-attachments/assets/ba209824-8afb-437c-a944-b53fd9ecd559)
16+
## Usage
1617

17-
This is a Nix flake for running Claude Desktop on Linux.
18-
19-
# Usage
20-
21-
To run this once, make sure Nix is installed, then run
18+
To run once:
2219

2320
```bash
2421
NIXPKGS_ALLOW_UNFREE=1 nix run github:k3d3/claude-desktop-linux-flake --impure
2522
```
2623

27-
The "unfree" part is due to the fact that Claude Desktop is not an open source application, and thus, Nix's licensing rules
28-
are dictated by the application itself, not the build script used to build the application.
24+
The "unfree" flag is required because Claude Desktop itself is proprietary.
2925

3026
## Installation on NixOS with Flakes
3127

32-
Add the following to your `flake.nix`:
28+
Add to your `flake.nix`:
3329
```nix
3430
inputs.claude-desktop.url = "github:k3d3/claude-desktop-linux-flake";
3531
inputs.claude-desktop.inputs.nixpkgs.follows = "nixpkgs";
3632
inputs.claude-desktop.inputs.flake-utils.follows = "flake-utils";
3733
```
3834

39-
And then the following package to your `environment.systemPackages` or `home.packages`:
35+
Then add to `environment.systemPackages` or `home.packages`:
4036
```nix
4137
inputs.claude-desktop.packages.${system}.claude-desktop
4238
```
4339

44-
If you would like to run [MCP servers with Claude Desktop](https://modelcontextprotocol.io/quickstart/user) on NixOS, use the `claude-desktop-with-fhs` package. This will allow running MCP servers with calls to `npx`, `uvx`, or `docker` (assuming docker is installed).
40+
For [MCP servers](https://modelcontextprotocol.io/quickstart/user) (`npx`, `uvx`, `docker`), use the FHS variant:
4541
```nix
4642
inputs.claude-desktop.packages.${system}.claude-desktop-with-fhs
4743
```
4844

49-
## Other distributions
50-
51-
This repository only provides a Nix flake, and does not provide a package for e.g. Ubuntu, Fedora, or Arch Linux.
52-
53-
Other known variants:
54-
- https://github.com/aaddrick/claude-desktop-debian - A debian builder for Claude Desktop
55-
- https://aur.archlinux.org/packages/claude-desktop-bin - An Arch package for Claude Desktop
56-
- https://github.com/wankdanker/claude-desktop-linux-bash - A bash-based Claude Desktop builder that works on Ubuntu and possibly other Debian derivatives
57-
58-
If anyone else packages Claude Desktop for other distributions, make an issue or PR and I'll link it here.
59-
60-
# How it works
61-
62-
Claude Desktop is an Electron application. That means the majority of the application is inside an `app.asar` archive, which usually contains minified Javascript, HTML, and CSS, along with images and a few other things.
63-
64-
Despite there being no official Linux Claude Desktop release, the vast majority of the code is completely cross-platform.
65-
66-
With the exception of one library.
67-
68-
## `claude-native-bindings`
69-
70-
![image](https://github.com/user-attachments/assets/9b386f42-2565-441a-a351-9c09347f9f5f)
71-
72-
Node, and by extension Electron, allow you to import natively-compiled objects into the Node runtime as if they were regular modules.
73-
These are typically used to extend the functionality in ways Node itself can't do. Only problem, as shown above, is that these objects
74-
are only compiled for one OS.
75-
76-
Luckily enough, because it's a loadable Node module, that means you can open it up yourself in node and inspect it - no decompilation or disassembly needed:
77-
78-
![image](https://github.com/user-attachments/assets/b2f1e72c-f763-45c0-8631-2de5555ae653)
79-
80-
There are many functions here for getting monitor/window information, as well as for controlling the mouse and keyboard.
81-
I'm not sure what exactly these are for - my best guess is something unreleased related to [Computer Use](https://docs.anthropic.com/en/docs/build-with-claude/computer-use),
82-
however I'm not a huge fan of this functionality existing in the first place.
83-
84-
As for how to move forward with getting Claude Desktop working on Linux, seeing as how the API surface area of this module is relatively
85-
small, it looked fairly easy to just wholesale reimplement it, using stubs for the functionality.
86-
87-
## `patchy-cnb`
45+
## Other Distributions
8846

89-
The result of that is a library I call `patchy-cnb`, which uses NAPI-RS to match the original API with stub functions.
90-
Turns out, the original module also used NAPI-RS. Neat!
47+
- [claude-desktop-debian](https://github.com/aaddrick/claude-desktop-debian) - Debian/Ubuntu
48+
- [AUR package](https://aur.archlinux.org/packages/claude-desktop-bin) - Arch Linux
49+
- [claude-desktop-linux-bash](https://github.com/wankdanker/claude-desktop-linux-bash) - Ubuntu/Debian (bash-based)
9150

92-
From there, it's just a matter of compiling `patchy-cnb`, repackaging the app.asar to include the newly built Linux module, and
93-
making a new Electron build with these files.
51+
## How it Works
9452

95-
# License
53+
Claude Desktop is an Electron app. The macOS DMG is extracted, patched for Linux compatibility, and repackaged:
9654

97-
The build scripts in this repository, as well as `patchy-cnb`, are dual-licensed under the terms of the MIT license and the Apache License (Version 2.0).
55+
1. Extract `app.asar` from the macOS build
56+
2. Patch title bar detection, platform checks, and tray icon handling
57+
3. Replace `@ant/claude-native` Windows bindings with JavaScript stubs
58+
4. Repackage with Linux Electron
9859

99-
See [LICENSE-MIT](LICENSE-MIT) and [LICENSE-APACHE](LICENSE-APACHE) for details.
60+
The native binding stubs provide no-op implementations for Windows-specific features (window effects, input emulation, etc.) that aren't needed on Linux.
10061

101-
The Claude Desktop application, not included in this repository, is likely covered by [Anthropic's Consumer Terms](https://www.anthropic.com/legal/consumer-terms).
62+
## License
10263

103-
## Contribution
64+
Build scripts are dual-licensed under MIT and Apache 2.0. See [LICENSE-MIT](LICENSE-MIT) and [LICENSE-APACHE](LICENSE-APACHE).
10465

105-
Unless you explicitly state otherwise, any contribution intentionally submitted
106-
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
107-
additional terms or conditions.
66+
Claude Desktop itself is covered by [Anthropic's Consumer Terms](https://www.anthropic.com/legal/consumer-terms).

flake.nix

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,68 @@
66
flake-utils.url = "github:numtide/flake-utils";
77
};
88

9-
outputs = {
10-
self,
11-
nixpkgs,
12-
flake-utils,
13-
}:
14-
flake-utils.lib.eachSystem ["x86_64-linux" "aarch64-linux"] (system: let
15-
pkgs = import nixpkgs {
16-
inherit system;
17-
config.allowUnfree = true;
18-
};
19-
in {
20-
packages = rec {
21-
patchy-cnb = pkgs.callPackage ./pkgs/patchy-cnb.nix {};
22-
claude-desktop = pkgs.callPackage ./pkgs/claude-desktop.nix {
23-
inherit patchy-cnb;
9+
outputs =
10+
{
11+
self,
12+
nixpkgs,
13+
flake-utils,
14+
}:
15+
flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (
16+
system:
17+
let
18+
pkgs = import nixpkgs {
19+
inherit system;
20+
config.allowUnfree = true;
2421
};
25-
claude-desktop-with-fhs = pkgs.buildFHSEnv {
26-
name = "claude-desktop";
27-
targetPkgs = pkgs:
28-
with pkgs; [
29-
docker
30-
glibc
31-
openssl
32-
nodejs
33-
uv
22+
in
23+
{
24+
packages = rec {
25+
claude-desktop = pkgs.callPackage ./pkgs/claude-desktop.nix { };
26+
27+
claude-desktop-with-fhs = pkgs.symlinkJoin {
28+
name = "claude-desktop-with-fhs";
29+
paths = [
30+
claude-desktop
31+
(pkgs.buildFHSEnv {
32+
name = "claude-desktop-bwrap";
33+
targetPkgs =
34+
pkgs: with pkgs; [
35+
docker
36+
glibc
37+
openssl
38+
nodejs
39+
uv
40+
glib
41+
gvfs
42+
xdg-utils
43+
];
44+
runScript = "${claude-desktop}/bin/claude-desktop";
45+
})
3446
];
35-
runScript = "${claude-desktop}/bin/claude-desktop";
36-
extraInstallCommands = ''
37-
# Copy desktop file from the claude-desktop package
38-
mkdir -p $out/share/applications
39-
cp ${claude-desktop}/share/applications/claude.desktop $out/share/applications/
47+
postBuild = ''
48+
rm -f $out/bin/claude-desktop
49+
ln -sf $out/bin/claude-desktop-bwrap $out/bin/claude-desktop
50+
'';
51+
};
52+
53+
claude-desktop-shell = pkgs.buildFHSEnv {
54+
name = "claude-desktop-shell";
55+
targetPkgs =
56+
pkgs: with pkgs; [
57+
docker
58+
glibc
59+
openssl
60+
nodejs
61+
uv
62+
glib
63+
gvfs
64+
xdg-utils
65+
];
66+
runScript = "bash";
67+
};
4068

41-
# Copy icons
42-
mkdir -p $out/share/icons
43-
cp -r ${claude-desktop}/share/icons/* $out/share/icons/
44-
'';
69+
default = claude-desktop;
4570
};
46-
default = claude-desktop;
47-
};
48-
});
71+
}
72+
);
4973
}

patchy-cnb/.cargo/config.toml

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)