[BUG] Claude Desktop (Linux) bundles a separate claude-code binary that diverges from standalone CLI — CLAUDE_CODE_LOCAL_BINARY override is dead code
Summary
Claude Desktop on Linux ships its own copy of claude-code under~/.config/Claude/claude-code/<version>/claude. This bundled binary is
updated separately from the standalone CLI (~/.local/bin/claude), so
users who maintain both end up with two different versions running depending
on entrypoint — the Desktop's embedded session uses the bundled (often older)
binary while the terminal uses the current one.
The env-var escape hatch intended to fix this (CLAUDE_CODE_LOCAL_BINARY) has
been present in app.asar since at least 1.8555.2 but is dead code:
the value is read as a bare expression and immediately discarded; the method
that would act on it (initLocalBinary()) is never invoked.
---
Affected version
- Claude Desktop: 1.9255.0 (Debian repack,
claude-desktop_1.9255.0-2.0.15_amd64.deb) - Standalone CLI: 2.1.152
- Bundled CLI under
~/.config/Claude/claude-code/: 2.1.149 (Desktop's own download) - Platform: Ubuntu 24.04.4 LTS, x86_64
---
Evidence
1. Two separate binaries, two separate versions
$ ls ~/.config/Claude/claude-code/
2.1.149/
$ ~/.config/Claude/claude-code/2.1.149/claude --version
claude-code 2.1.149
$ ~/.local/bin/claude --version
claude-code 2.1.152
2. CLAUDE_CODE_LOCAL_BINARY is read but never consumed (app.asar)
// constructor, verbatim from app.asar:
S.info(`[CCD] Initialized with version ${this.requiredVersion}`),
process.env.CLAUDE_CODE_LOCAL_BINARY // ← bare expression, value discarded
async initLocalBinary(A) {
try {
await HA.access(A, jA.constants.X_OK);
this.localBinaryPath = A;
S.warn(`[CCD] LOCAL OVERRIDE: Using local binary at ${A}`);
} catch {
S.error(`[CCD] LOCAL OVERRIDE: Binary not found or not executable at ${A}, …`);
}
}
initLocalBinary() is never called anywhere in the bundle. SettingCLAUDE_CODE_LOCAL_BINARY in ~/.config/environment.d/ has no observable
effect — the Desktop always falls through to the manifest-driven download flow.
3. Identical dead-code behaviour on Windows
Issue #59450 documented the exact same pattern on Windows (MSIX build
1.7196.0) and was incorrectly auto-closed as a duplicate of #42203
(which is about macOS env.PATH sandbox stripping — an unrelated issue).
The duplicate bot matched on surface keywords; the root cause is different.
#59450 should be re-opened or acknowledged here.
---
Impact
- Version skew: Desktop sessions silently run an older
claude-codethan
the terminal. Features/fixes available in the standalone CLI are invisible
inside the Desktop UI.
- No supported override: Users cannot pin Desktop to their system CLI.
The env-var override is documented nowhere officially, and even if users
discover it, it does nothing.
- Disk waste: Desktop downloads and stores its own versioned binaries
regardless of what is already installed.
---
Suggested fixes (in order of effort)
Option A — Wire up CLAUDE_CODE_LOCAL_BINARY (minimal)
Add the missing call in the constructor (or in the init path):
if (process.env.CLAUDE_CODE_LOCAL_BINARY) {
await this.initLocalBinary(process.env.CLAUDE_CODE_LOCAL_BINARY);
}
This activates the already-written plumbing and lets power users opt into
using their standalone CLI.
Option B — Desktop auto-detects an installed standalone CLI
On startup, if claude is resolvable on PATH (or at the canonical install
path ~/.local/bin/claude) and its version is ≥ the bundled version, use
it instead of downloading a separate copy. Fallback to the bundled/downloaded
binary only when no standalone CLI is present.
Option C — Desktop delegates claude update to the standalone CLI
Instead of managing its own download, Desktop could invoke claude update
on the standalone binary (same mechanism the CLI already uses) and then
symlink its version directory to the result.
---
Current workaround
While this is unresolved, the following script (claude-desktop-sync-cli)
bridges the gap by replacing Desktop's bundled binary with a symlink to the
standalone CLI:
#!/usr/bin/env bash
set -u
STANDALONE="${HOME}/.local/bin/claude"
CCD_DIR="${HOME}/.config/Claude/claude-code"
for vdir in "$CCD_DIR"/*/; do
bin="$vdir/claude"
[[ -e "$bin" ]] || continue
[[ -L "$bin" ]] && rm -f "$bin"
[[ -f "$bin" ]] && { cp -a "$bin" "${bin}.bak"; rm -f "$bin"; }
ln -s "$STANDALONE" "$bin"
touch "$vdir/.verified"
done
Run after every Desktop or CLI update (or wire into the .desktop Exec
line). The .verified marker touch is necessary because Desktop's startup
check expects it after any binary replacement.
Full write-up including the StartupWMClass GNOME issue (fixed upstream in
v2.0.15 of the Debian repack) at:
https://github.com/aaddrick/claude-desktop-debian/discussions/653
---
Written by Claude Opus 4.7 via Claude Code
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗