Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# CLAUDE.md

## Project Overview

Nix flake that runs Claude Desktop on Linux by repackaging the macOS build with JavaScript stubs for the native bindings.

## Building

```bash
nix build .#claude-desktop # Standard build
nix build .#claude-desktop-with-fhs # With FHS environment for MCP servers
nix run . # Build and run
```

## Architecture

The build process (`pkgs/claude-desktop.nix`):

1. Download macOS DMG
2. Extract with 7z (handles HFS+ despite warnings)
3. Extract and patch `app.asar`:
- Title bar: Enable native frames on Linux
- Platform detection: Add `linux-x64`/`linux-arm64` for Claude Code
- Origin validation: Allow `file://` protocol when unpackaged
- Tray icons: Theme-aware selection
- Window blur: Fix quick-submit focus
4. Replace `@ant/claude-native` with inline JS stubs
5. Repackage and wrap with Electron

## Updating Version

In `pkgs/claude-desktop.nix`:
1. Update `version`
2. Update `srcDmg.url` with new version/hash from filename
3. Update `srcDmg.hash` (run `nix-prefetch-url <url>` then `nix hash to-sri sha256:<hash>`)

## Packages

- `claude-desktop` - Standard build
- `claude-desktop-with-fhs` - FHS wrapper for MCP servers (npx, uvx, docker)
- `claude-desktop-shell` - FHS shell for MCP development
93 changes: 26 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,104 +4,63 @@ If you run into an issue with this build script, make an issue here. Don't bug A

# Claude Desktop for Linux (Nix)

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

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

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

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

This is a Nix flake for running Claude Desktop on Linux.

# Usage

To run this once, make sure Nix is installed, then run
To run once:

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

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

## Installation on NixOS with Flakes

Add the following to your `flake.nix`:
Add to your `flake.nix`:
```nix
inputs.claude-desktop.url = "github:k3d3/claude-desktop-linux-flake";
inputs.claude-desktop.inputs.nixpkgs.follows = "nixpkgs";
inputs.claude-desktop.inputs.flake-utils.follows = "flake-utils";
```

And then the following package to your `environment.systemPackages` or `home.packages`:
Then add to `environment.systemPackages` or `home.packages`:
```nix
inputs.claude-desktop.packages.${system}.claude-desktop
```

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).
For [MCP servers](https://modelcontextprotocol.io/quickstart/user) (`npx`, `uvx`, `docker`), use the FHS variant:
```nix
inputs.claude-desktop.packages.${system}.claude-desktop-with-fhs
```

## Other distributions

This repository only provides a Nix flake, and does not provide a package for e.g. Ubuntu, Fedora, or Arch Linux.

Other known variants:
- https://github.com/aaddrick/claude-desktop-debian - A debian builder for Claude Desktop
- https://aur.archlinux.org/packages/claude-desktop-bin - An Arch package for Claude Desktop
- https://github.com/wankdanker/claude-desktop-linux-bash - A bash-based Claude Desktop builder that works on Ubuntu and possibly other Debian derivatives

If anyone else packages Claude Desktop for other distributions, make an issue or PR and I'll link it here.

# How it works

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.

Despite there being no official Linux Claude Desktop release, the vast majority of the code is completely cross-platform.

With the exception of one library.

## `claude-native-bindings`

![image](https://github.com/user-attachments/assets/9b386f42-2565-441a-a351-9c09347f9f5f)

Node, and by extension Electron, allow you to import natively-compiled objects into the Node runtime as if they were regular modules.
These are typically used to extend the functionality in ways Node itself can't do. Only problem, as shown above, is that these objects
are only compiled for one OS.

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:

![image](https://github.com/user-attachments/assets/b2f1e72c-f763-45c0-8631-2de5555ae653)

There are many functions here for getting monitor/window information, as well as for controlling the mouse and keyboard.
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),
however I'm not a huge fan of this functionality existing in the first place.

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
small, it looked fairly easy to just wholesale reimplement it, using stubs for the functionality.

## `patchy-cnb`
## Other Distributions

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

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

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

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).
1. Extract `app.asar` from the macOS build
2. Patch title bar detection, platform checks, and tray icon handling
3. Replace `@ant/claude-native` Windows bindings with JavaScript stubs
4. Repackage with Linux Electron

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

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

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

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.
Claude Desktop itself is covered by [Anthropic's Consumer Terms](https://www.anthropic.com/legal/consumer-terms).
96 changes: 60 additions & 36 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,68 @@
flake-utils.url = "github:numtide/flake-utils";
};

outputs = {
self,
nixpkgs,
flake-utils,
}:
flake-utils.lib.eachSystem ["x86_64-linux" "aarch64-linux"] (system: let
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
};
in {
packages = rec {
patchy-cnb = pkgs.callPackage ./pkgs/patchy-cnb.nix {};
claude-desktop = pkgs.callPackage ./pkgs/claude-desktop.nix {
inherit patchy-cnb;
outputs =
{
self,
nixpkgs,
flake-utils,
}:
flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (
system:
let
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
};
claude-desktop-with-fhs = pkgs.buildFHSEnv {
name = "claude-desktop";
targetPkgs = pkgs:
with pkgs; [
docker
glibc
openssl
nodejs
uv
in
{
packages = rec {
claude-desktop = pkgs.callPackage ./pkgs/claude-desktop.nix { };

claude-desktop-with-fhs = pkgs.symlinkJoin {
name = "claude-desktop-with-fhs";
paths = [
claude-desktop
(pkgs.buildFHSEnv {
name = "claude-desktop-bwrap";
targetPkgs =
pkgs: with pkgs; [
docker
glibc
openssl
nodejs
uv
glib
gvfs
xdg-utils
];
runScript = "${claude-desktop}/bin/claude-desktop";
})
];
runScript = "${claude-desktop}/bin/claude-desktop";
extraInstallCommands = ''
# Copy desktop file from the claude-desktop package
mkdir -p $out/share/applications
cp ${claude-desktop}/share/applications/claude.desktop $out/share/applications/
postBuild = ''
rm -f $out/bin/claude-desktop
ln -sf $out/bin/claude-desktop-bwrap $out/bin/claude-desktop
'';
};

claude-desktop-shell = pkgs.buildFHSEnv {
name = "claude-desktop-shell";
targetPkgs =
pkgs: with pkgs; [
docker
glibc
openssl
nodejs
uv
glib
gvfs
xdg-utils
];
runScript = "bash";
};

# Copy icons
mkdir -p $out/share/icons
cp -r ${claude-desktop}/share/icons/* $out/share/icons/
'';
default = claude-desktop;
};
default = claude-desktop;
};
});
}
);
}
2 changes: 0 additions & 2 deletions patchy-cnb/.cargo/config.toml

This file was deleted.

Loading