dot

vizie's NixOS desktop: Hyprland, CachyOS kernel and gaming tweaks

206 lines5239 bytesNix
1# Anthropic's official Claude Desktop for Linux (beta), repackaged from the .deb in
2# Anthropic's own apt repository: https://code.claude.com/docs/en/desktop-linux
3#
4# To update: pick the newest Filename/SHA256 pair from
5# https://downloads.claude.ai/claude-desktop/apt/stable/dists/stable/main/binary-amd64/Packages
6# and change version and sha256 below (the index's SHA256 is in hex, as here).
7#
8# Cowork also needs QEMU/KVM, the vhost_vsock module and OVMF firmware at the
9# Debian path it looks for; modules/nixos/apps.nix provides those.
10#
11# The Code tab runs Claude Code from the Nix store (claude-code.nix) rather than
12# a copy the app downloads, and Python tools use nixpkgs' uv rather than one it
13# downloads. After a version change, update claude-code.nix too: the build says
14# so if the app pins a different Claude Code.
15{
16 lib,
17 stdenv,
18 callPackage,
19 fetchurl,
20 dpkg,
21 asar,
22 autoPatchelfHook,
23 makeWrapper,
24 wrapGAppsHook3,
25 alsa-lib,
26 at-spi2-atk,
27 at-spi2-core,
28 cairo,
29 cups,
30 dbus,
31 expat,
32 glib,
33 gtk3,
34 libdrm,
35 libgbm,
36 libglvnd,
37 libnotify,
38 libpulseaudio,
39 libsecret,
40 libuuid,
41 libxkbcommon,
42 libayatana-appindicator,
43 nspr,
44 nss,
45 pango,
46 pipewire,
47 systemd,
48 vulkan-loader,
49 libx11,
50 libxcomposite,
51 libxdamage,
52 libxext,
53 libxfixes,
54 libxrandr,
55 libxtst,
56 libxshmfence,
57 libxcb,
58 libseccomp,
59 libcap_ng,
60 xdg-utils,
61 qemu_kvm,
62 socat,
63 bubblewrap,
64 openssh,
65 uv,
66}:
67
68let
69 claude-code = callPackage ./claude-code.nix { };
70in
71stdenv.mkDerivation (finalAttrs: {
72 pname = "claude-desktop";
73 version = "2.42304.0";
74
75 src = fetchurl {
76 url = "https://downloads.claude.ai/claude-desktop/apt/stable/pool/main/c/claude-desktop/claude-desktop_${finalAttrs.version}_amd64.deb";
77 sha256 = "74cd2ccc29d24165144e455cbc872c6cc2a24a263b83e73420e95f89166d4aa4";
78 };
79
80 nativeBuildInputs = [
81 dpkg
82 asar
83 autoPatchelfHook
84 makeWrapper
85 wrapGAppsHook3
86 ];
87
88 buildInputs = [
89 alsa-lib
90 at-spi2-atk
91 at-spi2-core
92 cairo
93 cups
94 dbus
95 expat
96 glib
97 gtk3
98 libdrm
99 libgbm
100 libnotify
101 libpulseaudio
102 libsecret
103 libuuid
104 libxkbcommon
105 nspr
106 nss
107 pango
108 pipewire
109 systemd
110 libx11
111 libxcomposite
112 libxdamage
113 libxext
114 libxfixes
115 libxrandr
116 libxtst
117 libxshmfence
118 libxcb
119 # The bundled virtiofsd (Cowork).
120 libseccomp
121 libcap_ng
122 ];
123
124 # Loaded with dlopen at run time, so autoPatchelf can't see them.
125 runtimeLibs = [
126 libglvnd
127 libnotify
128 libpulseaudio
129 libayatana-appindicator
130 pipewire
131 systemd
132 vulkan-loader
133 ];
134
135 dontWrapGApps = true;
136
137 unpackPhase = ''
138 runHook preUnpack
139 # Not dpkg-deb -x: the sandbox can't recreate chrome-sandbox's setuid bit.
140 dpkg-deb --fsys-tarfile $src | tar -x --no-same-permissions --no-same-owner
141 runHook postUnpack
142 '';
143
144 installPhase = ''
145 runHook preInstall
146
147 mkdir -p $out/lib $out/bin
148 cp -r usr/lib/claude-desktop $out/lib/
149 cp -r usr/share $out/
150 rm -rf $out/share/lintian
151
152 # The setuid sandbox helper can't be setuid in the Nix store; Chromium uses
153 # the user-namespace sandbox instead, which needs no helper.
154 rm $out/lib/claude-desktop/chrome-sandbox
155
156 # The app has an override for running a Claude Code that's already on disk
157 # instead of downloading one; release builds compile out the part that
158 # reads it. This puts it back, pointing at the store path. The app then
159 # also leaves Claude Code updates alone: they come with this package.
160 res=$out/lib/claude-desktop/resources
161 asar extract $res/app.asar app
162 pin=$(grep -l '"baseUrl":"https://downloads.claude.ai/claude-code-releases"' app/.vite/build/*.js)
163 if ! grep -qF '{"version":"${claude-code.version}","manifest"' $pin; then
164 echo "claude-desktop: the app pins another Claude Code than ${claude-code.version}; update claude-code.nix" >&2
165 exit 1
166 fi
167 hook='process.env.CLAUDE_CODE_LOCAL_BINARY}async initLocalBinary('
168 if ! file=$(grep -lF "$hook" app/.vite/build/*.js); then
169 echo "claude-desktop: the app's Claude Code override has changed; see the comment above" >&2
170 exit 1
171 fi
172 substituteInPlace $file --replace-fail "$hook" \
173 'this.localBinaryInitPromise=this.initLocalBinary("${lib.getExe claude-code}")}async initLocalBinary('
174 rm -r $res/app.asar $res/app.asar.unpacked
175 asar pack app $res/app.asar --unpack '{*.node,github-mcp-server}'
176
177 runHook postInstall
178 '';
179
180 postFixup = ''
181 makeWrapper $out/lib/claude-desktop/claude-desktop $out/bin/claude-desktop \
182 "''${gappsWrapperArgs[@]}" \
183 --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath finalAttrs.runtimeLibs} \
184 --prefix PATH : ${
185 lib.makeBinPath [
186 xdg-utils
187 qemu_kvm
188 socat
189 bubblewrap
190 openssh
191 uv
192 ]
193 }
194 '';
195
196 passthru = { inherit claude-code; };
197
198 meta = {
199 description = "Claude desktop app (official Linux beta build)";
200 homepage = "https://claude.ai/download";
201 license = lib.licenses.unfree;
202 mainProgram = "claude-desktop";
203 platforms = [ "x86_64-linux" ];
204 sourceProvenance = [ lib.sourceTypes.binaryNativeCode ];
205 };
206})