7.5 KiB
Building from Source
build.sh downloads Anthropic's official Claude Desktop Linux .deb, optionally patches its app.asar, and repackages the official application tree as a .deb, .rpm, or AppImage.
git clone https://github.com/aaddrick/claude-desktop-debian.git
cd claude-desktop-debian
# Build with the auto-detected format for your distro
./build.sh
# Or pick a format explicitly
./build.sh --build deb
./build.sh --build rpm
./build.sh --build appimage
The default format is detected from the host distribution:
| Distribution family | Default format |
|---|---|
Debian, Ubuntu, Mint (/etc/debian_version) |
deb |
| Fedora, RHEL, CentOS | rpm |
| NixOS | nix (currently a stub — see Nix below) |
| Anything else (including Arch) | appimage |
Prerequisites
The official .deb is unpacked with ar + tar instead of dpkg-deb, so rpm-family and Arch hosts can build too. Per format:
| Needed for | Commands |
|---|---|
| Every format | wget, ar (binutils), tar, xz, zstd |
--build deb |
dpkg-deb (dpkg-dev) |
--build rpm |
rpmbuild (rpm-build) |
--build appimage |
appimagetool — downloaded into build/ automatically when not on PATH |
| The asar patch stage | Node.js v20+ — a local v20.18.1 is downloaded into build/ when the system Node is missing or too old; @electron/asar is npm-installed into build/ |
On Debian- and RPM-family hosts, build.sh offers to install the missing system packages via apt/dnf (check_dependencies in scripts/setup/dependencies.sh). On other distros it lists what to install manually.
Build flags
From parse_arguments in scripts/setup/detect-host.sh:
./build.sh [--build deb|rpm|appimage|nix] [--clean yes|no]
[--deb /path/to/claude-desktop.deb] [--arch amd64|arm64]
[--release-tag TAG] [--source-dir /path] [--test-flags]
| Flag | Default | Effect |
|---|---|---|
-b, --build |
auto-detected | Output format: deb, rpm, appimage, or nix. |
-c, --clean |
yes |
Remove intermediate files in build/ after packaging. --clean no keeps them for inspection. |
-d, --deb |
download | Use a locally downloaded official .deb instead of fetching the pinned one. The SHA256 pin check is skipped for local files. |
-a, --arch |
uname -m |
Override the target architecture (amd64 or arm64) for cross-building — repackaging the official .deb is arch-independent, so an amd64 host can produce an arm64 package. |
-r, --release-tag |
unset | Release tag (e.g. v3.0.0+claude1.18286.0); the wrapper version is extracted and appended to the package version (1.18286.0-3.0.0). Used by CI. |
-s, --source-dir |
repo root | Path to the repo root for scripts and assets, for out-of-tree invocations. |
--test-flags |
off | Parse flags, print the results, and exit without building. |
How the official .deb is resolved
The build never scrapes a download page — it pulls a pinned artifact from Anthropic's official APT pool:
scripts/setup/official-deb.shpinsOFFICIAL_DEB_VERSION(currently1.18286.0) plus a per-architecture pool path and SHA256 againsthttps://downloads.claude.ai/claude-desktop/apt/stable.- The download is verified against the pinned SHA256 before extraction.
ar+tarextractdata.tar.*andcontrol.tar.*(zst/xz/gz all handled); the app tree must land atusr/lib/claude-desktopor the build aborts with an upstream-layout error.- The package version is read from the extracted control file; a mismatch against the pin is a warning, not a failure.
Depends:andRecommends:are read from the official control file and re-emitted verbatim into our packages — the contract differs per arch (arm64 recommends a different qemu stack than amd64), and re-emitting tracks upstream automatically.
The pins are bumped automatically: the check-claude-version workflow polls the official APT Packages index, rewrites the OFFICIAL_DEB_* pins in scripts/setup/official-deb.sh, updates the CLAUDE_DESKTOP_VERSION repo variable, and pushes a v{REPO_VERSION}+claude{VERSION} tag that triggers the release build.
To build a version before the automation catches it, download the .deb from the official pool yourself and pass --deb /path/to/claude-desktop_VERSION_ARCH.deb.
The patch stage (patch-zero contract)
active_patches in scripts/patches/app-asar.sh lists every asar patch still active. The default verdict for any patch is delete: when the array is empty, the official app.asar ships byte-identical — it is never extracted or repacked. Two patches currently survive:
patch_quick_window(scripts/patches/quick-window.sh) — KDE-gated blur/focus workaround so the main window reappears after a Quick Entry submit (Electron stale-focus bug on Plasma).patch_org_plugins_path(scripts/patches/org-plugins.sh) — adds acase "linux"to the upstream org-plugins platform switch, which only handles darwin/win32; without it MDM org plugins are silently dead on Linux (filed upstream).
Two build-time tripwires grep the pristine app.asar on every build and fail loudly if upstream flips behavior we deleted patches for: apt_channel_pending (AU-1 — the marker that keeps the official autoupdater dormant while the APT channel is pending) and menuBarEnabled:!0 (MB-1 — the settings default that keeps the menu bar on).
When patches do run, the repack preserves upstream's app.asar.unpacked set exactly and aborts if the sets diverge.
Installing the built package
For .deb packages (Debian/Ubuntu)
sudo apt install ./claude-desktop-unofficial_VERSION_ARCHITECTURE.deb
# Or: sudo dpkg -i ./claude-desktop-unofficial_VERSION_ARCHITECTURE.deb
# If you encounter dependency issues:
sudo apt --fix-broken install
For .rpm packages (Fedora/RHEL)
sudo dnf install ./claude-desktop-unofficial-VERSION-1.ARCH.rpm
# Or: sudo rpm -i ./claude-desktop-unofficial-VERSION-1.ARCH.rpm
For AppImages
# Make executable
chmod +x ./claude-desktop-unofficial-*.AppImage
# Run directly
./claude-desktop-unofficial-*.AppImage
# Or integrate with your system using Gear Lever
Note: AppImage login requires proper desktop integration. Use Gear Lever or manually install the generated .desktop file to ~/.local/share/applications/.
Automatic updates: AppImages downloaded from GitHub releases include embedded update information and work with Gear Lever for automatic updates. Locally-built AppImages can be configured manually in Gear Lever.
Nix
The derivation (nix/claude-desktop.nix) repackages the official .deb: fetchurl from the official APT pool, autoPatchelfHook over the bare co-located tree, no nixpkgs Electron. The FHS output (nix/fhs.nix, the flake default) additionally provides MCP runtime dependencies and OVMF firmware at Cowork's hardcoded probe paths.
nix build .#claude-desktop
nix build .#claude-desktop-fhs
Build-verified on x86_64; runtime on real NixOS and the aarch64 leg are open validation items (owner @typedrat). Design contract, SRI auto-bump anchors, and a no-NixOS testing recipe: docs/learnings/nix.md.
Two facts about the --build nix path that hold on this branch: build.sh --build nix requires --deb (it never downloads inside the sandbox), and it stops after the patch stage — the Nix derivation is expected to handle installation itself.