No description
Find a file
Robin L. M. Cheung, MBA 92b4c7539b build: shift to 2.0 MAJOR, auto-bump MINOR in CI, correct AppImage +x claim
Versioning rework for Google Play 3-field compatibility:

  old: version.txt = "0.2"   artifact = v0.2.<BUILD>
  new: version.txt = "2.0"   artifact = v2.1.<BUILD> (next build)
                             artifact = v2.2.<BUILD> (the one after)
                             ...

MAJOR stays at 2 until a human bumps it for a real milestone. MINOR is
now owned by CI and incremented by 1 on every successful build. The
"Read and bump version" step writes version.txt locally and emits a
'bumped=yes' output; the final step commits the new version.txt back
to the branch with a "[skip ci]" marker.

Infinite-loop guards (3 layers):
  1. Job-level `if:` filter skips builds triggered by [skip ci] commits
  2. Step-level grep on HEAD commit message prevents double-bumps even
     if a runner doesn't honor workflow-level [skip ci]
  3. `git diff --quiet` sanity check before pushing — nothing to push if
     version.txt wasn't actually modified

Push uses `secrets.GITHUB_TOKEN` (Forgejo auto-token) with the token
embedded in the HTTPS URL; no separate secret required.

Also: corrected the AppImage "+x stripped" wording on the site. Modern
Linux desktops often DO preserve the executable bit when the server
advertises application/vnd.appimage or when AppImageLauncher is
installed. The chmod step is now framed as a fallback, not a universal
requirement. BUILD_CONVENTIONS.md updated accordingly with the nginx
MIME-type snippet that enables the preserved-+x path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 22:35:24 -04:00
.forgejo/workflows build: shift to 2.0 MAJOR, auto-bump MINOR in CI, correct AppImage +x claim 2026-04-14 22:35:24 -04:00
DOCS docs: capture CI/CD hard-won learnings + bump version to 0.2.0 2026-04-11 02:00:11 -04:00
scripts fix(init-subdomain): correct nginx config heredoc escaping 2026-04-10 22:07:36 -04:00
site build: shift to 2.0 MAJOR, auto-bump MINOR in CI, correct AppImage +x claim 2026-04-14 22:35:24 -04:00
src/patchy-cnb Initial commit: Claude Desktop Linux repackaging build system 2026-04-10 19:21:04 -04:00
.gitignore docs: capture CI/CD hard-won learnings + bump version to 0.2.0 2026-04-11 02:00:11 -04:00
LICENSE-APACHE Initial commit: Claude Desktop Linux repackaging build system 2026-04-10 19:21:04 -04:00
LICENSE-MIT Initial commit: Claude Desktop Linux repackaging build system 2026-04-10 19:21:04 -04:00
Makefile build: MAJOR.MINOR.BUILD artifact naming + build timestamp + chmod +x 2026-04-14 22:28:30 -04:00
README.md Initial commit: Claude Desktop Linux repackaging build system 2026-04-10 19:21:04 -04:00
version.txt build: shift to 2.0 MAJOR, auto-bump MINOR in CI, correct AppImage +x claim 2026-04-14 22:35:24 -04:00

claude-desktop-linux

Builds Claude Desktop for Linux by repackaging the official Windows release. Supports both Debian/Ubuntu (apt) and Fedora/RHEL (dnf) systems.

Each build step saves its output to disk so you can inspect or modify the intermediate files — extracted installer, patched asar contents, compiled native stub — before continuing.


Quick start

# 1. Install system dependencies (Debian/Ubuntu)
sudo apt-get install p7zip-full imagemagick icoutils wget
sudo pnpm install -g electron          # or: npm install -g electron

# 1. Install system dependencies (Fedora/RHEL)
sudo dnf install p7zip p7zip-plugins ImageMagick icoutils wget
sudo pnpm install -g electron

# Also required: node, pnpm, cargo/rustc (see Dependencies section)

# 2. Build (all at once, or step by step)
make

# 3. Install
make install

# 4. Enable the Claude protocol handler (for Google login)
xdg-mime default claude-desktop.desktop x-scheme-handler/claude

Step-by-step workflow

Run steps individually to inspect intermediate files between each one:

make fetch      # → assets/Claude-Setup-x64.exe       (browse: ls assets/)
make extract    # → build/extracted/                   (browse: ls build/extracted/lib/net45/)
make stub       # → build/patchy-cnb.node              (verify: file build/patchy-cnb.node)
make patch      # → build/app.asar.contents/           (edit JS here if needed)
make pack       # → dist/lib/claude-desktop/app.asar
make icons      # → dist/share/icons/
make desktop    # → dist/bin/claude-desktop + .desktop entry
make install    # → ~/.local/

After make patch you can freely edit any files in build/app.asar.contents/ before running make pack — no need to re-fetch or recompile the stub.


Directory layout

claude-desktop-linux/
├── Makefile                          ← all build logic
├── src/
│   └── patchy-cnb/                   ← Rust NAPI stub source
│       ├── Cargo.toml
│       ├── package.json
│       └── src/lib.rs
├── LICENSE-MIT
└── LICENSE-APACHE

Generated at build time (gitignored):
├── assets/
│   └── Claude-Setup-x64.exe          ← make fetch   (persists across clean)
├── build/
│   ├── extracted/                    ← make extract (inspectable)
│   ├── app.asar.contents/            ← make patch   (modifiable before pack)
│   └── patchy-cnb.node               ← make stub
└── dist/                             ← make desktop (final installable tree)
    ├── bin/claude-desktop
    ├── lib/claude-desktop/app.asar
    └── share/

Updating to a new Claude Desktop version

Anthropic's download URL embeds both the version number and a build hash — no auto-discovery is available. When a new release ships:

  1. Find the new URL (check community repos such as aaddrick/claude-desktop-debian or k3d3/claude-desktop-linux-flake)
  2. Edit the three lines at the top of Makefile:
    CLAUDE_VERSION := <new-version>
    CLAUDE_HASH    := <new-hash>
    CLAUDE_SHA256  := <new-sha256>
    
  3. Rebuild:
    make distclean && make
    

Make targets

Target Description
make / make all Full build (default)
make fetch Download installer to assets/ (idempotent, SHA256-verified)
make extract Unpack exe + nupkg → build/extracted/
make stub Compile Rust NAPI stub → build/patchy-cnb.node
make patch Extract asar, inject stub + i18n → build/app.asar.contents/
make pack Repack patched asar → dist/
make icons Extract + convert app icons → dist/share/icons/
make desktop Create .desktop entry + launcher → dist/
make install Copy dist/~/.local/
make clean Remove build/ and dist/ (keeps assets/)
make distclean Remove everything including assets/
make help List all targets with descriptions

Dependencies

Tool Install
7za apt: p7zip-full / dnf: p7zip p7zip-plugins
node nodejs.org or nvm
pnpm curl -fsSL https://get.pnpm.io/install.sh | sh -
electron pnpm install -g electron
cargo / rustc rustup.rs
wrestool / icotool apt: icoutils / dnf: icoutils
magick / convert apt: imagemagick / dnf: ImageMagick
wget system

How it works

The Windows installer is a Squirrel package. 7z extracts it to get the .nupkg, which is extracted again to get app.asar and the raw resources.

app.asar is Electron's archive format. The patching step:

  1. Extracts it to build/app.asar.contents/ (fully browsable)
  2. Replaces claude-native-binding.node (a Windows-only native module) with the Linux stub compiled from src/patchy-cnb/src/lib.rs
  3. Copies tray icons and i18n JSON files into place
  4. Repacks the archive

The stub (patchy-cnb) implements the same NAPI interface that Claude Desktop expects — keyboard simulation, mouse control, window info, monitor info — but as Linux no-ops. This lets the app start cleanly on Linux while logging any native calls to stdout.


Notes

  • Wayland: Global shortcuts and some native features require X11. Wayland support is limited by the stub's no-op implementation.
  • Disk space: build/ can reach several hundred MB during extraction.
  • Modifying the app: edit files in build/app.asar.contents/ after make patch, then run make pack — no re-fetch or re-compile needed.

License

Dual-licensed under the MIT license and the Apache License (Version 2.0). See LICENSE-MIT and LICENSE-APACHE for details.

The Claude Desktop application itself is covered by Anthropic's Consumer Terms.