# Anthropic's official Claude Desktop for Linux (beta), repackaged from the .deb in # Anthropic's own apt repository: https://code.claude.com/docs/en/desktop-linux # # To update: pick the newest Filename/SHA256 pair from # https://downloads.claude.ai/claude-desktop/apt/stable/dists/stable/main/binary-amd64/Packages # and change version and sha256 below (the index's SHA256 is in hex, as here). # # Cowork also needs QEMU/KVM, the vhost_vsock module and OVMF firmware at the # Debian path it looks for; modules/nixos/apps.nix provides those. # # The Code tab runs Claude Code from the Nix store (claude-code.nix) rather than # a copy the app downloads, and Python tools use nixpkgs' uv rather than one it # downloads. After a version change, update claude-code.nix too: the build says # so if the app pins a different Claude Code. { lib, stdenv, callPackage, fetchurl, dpkg, asar, autoPatchelfHook, makeWrapper, wrapGAppsHook3, alsa-lib, at-spi2-atk, at-spi2-core, cairo, cups, dbus, expat, glib, gtk3, libdrm, libgbm, libglvnd, libnotify, libpulseaudio, libsecret, libuuid, libxkbcommon, libayatana-appindicator, nspr, nss, pango, pipewire, systemd, vulkan-loader, libx11, libxcomposite, libxdamage, libxext, libxfixes, libxrandr, libxtst, libxshmfence, libxcb, libseccomp, libcap_ng, xdg-utils, qemu_kvm, socat, bubblewrap, openssh, uv, }: let claude-code = callPackage ./claude-code.nix { }; in stdenv.mkDerivation (finalAttrs: { pname = "claude-desktop"; version = "2.42304.0"; src = fetchurl { url = "https://downloads.claude.ai/claude-desktop/apt/stable/pool/main/c/claude-desktop/claude-desktop_${finalAttrs.version}_amd64.deb"; sha256 = "74cd2ccc29d24165144e455cbc872c6cc2a24a263b83e73420e95f89166d4aa4"; }; nativeBuildInputs = [ dpkg asar autoPatchelfHook makeWrapper wrapGAppsHook3 ]; buildInputs = [ alsa-lib at-spi2-atk at-spi2-core cairo cups dbus expat glib gtk3 libdrm libgbm libnotify libpulseaudio libsecret libuuid libxkbcommon nspr nss pango pipewire systemd libx11 libxcomposite libxdamage libxext libxfixes libxrandr libxtst libxshmfence libxcb # The bundled virtiofsd (Cowork). libseccomp libcap_ng ]; # Loaded with dlopen at run time, so autoPatchelf can't see them. runtimeLibs = [ libglvnd libnotify libpulseaudio libayatana-appindicator pipewire systemd vulkan-loader ]; dontWrapGApps = true; unpackPhase = '' runHook preUnpack # Not dpkg-deb -x: the sandbox can't recreate chrome-sandbox's setuid bit. dpkg-deb --fsys-tarfile $src | tar -x --no-same-permissions --no-same-owner runHook postUnpack ''; installPhase = '' runHook preInstall mkdir -p $out/lib $out/bin cp -r usr/lib/claude-desktop $out/lib/ cp -r usr/share $out/ rm -rf $out/share/lintian # The setuid sandbox helper can't be setuid in the Nix store; Chromium uses # the user-namespace sandbox instead, which needs no helper. rm $out/lib/claude-desktop/chrome-sandbox # The app has an override for running a Claude Code that's already on disk # instead of downloading one; release builds compile out the part that # reads it. This puts it back, pointing at the store path. The app then # also leaves Claude Code updates alone: they come with this package. res=$out/lib/claude-desktop/resources asar extract $res/app.asar app pin=$(grep -l '"baseUrl":"https://downloads.claude.ai/claude-code-releases"' app/.vite/build/*.js) if ! grep -qF '{"version":"${claude-code.version}","manifest"' $pin; then echo "claude-desktop: the app pins another Claude Code than ${claude-code.version}; update claude-code.nix" >&2 exit 1 fi hook='process.env.CLAUDE_CODE_LOCAL_BINARY}async initLocalBinary(' if ! file=$(grep -lF "$hook" app/.vite/build/*.js); then echo "claude-desktop: the app's Claude Code override has changed; see the comment above" >&2 exit 1 fi substituteInPlace $file --replace-fail "$hook" \ 'this.localBinaryInitPromise=this.initLocalBinary("${lib.getExe claude-code}")}async initLocalBinary(' rm -r $res/app.asar $res/app.asar.unpacked asar pack app $res/app.asar --unpack '{*.node,github-mcp-server}' runHook postInstall ''; postFixup = '' makeWrapper $out/lib/claude-desktop/claude-desktop $out/bin/claude-desktop \ "''${gappsWrapperArgs[@]}" \ --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath finalAttrs.runtimeLibs} \ --prefix PATH : ${ lib.makeBinPath [ xdg-utils qemu_kvm socat bubblewrap openssh uv ] } ''; passthru = { inherit claude-code; }; meta = { description = "Claude desktop app (official Linux beta build)"; homepage = "https://claude.ai/download"; license = lib.licenses.unfree; mainProgram = "claude-desktop"; platforms = [ "x86_64-linux" ]; sourceProvenance = [ lib.sourceTypes.binaryNativeCode ]; }; })