1- # clode: run Claude Code under Node
1+ # clode: Claude Code, everywhere
22
3- Claude Code used to ` npm install ` anywhere you had Node. Now it's
4- a binary-only distribution targeting only the most popular recent
5- operating systems and hardware platforms. Even older x86 (pre-AVX2)
6- no longer suffices.
3+ Claude Code ships as a binary-only distribution for a handful of popular
4+ platforms. clode re-bases it onto a small C runtime — txiki.js/QuickJS —
5+ and takes it everywhere else: macOS, musl-static Linux across eight
6+ architectures (x64 to s390x to loongarch64), NetBSD, FreeBSD, OpenBSD,
7+ DragonFly, OmniOS, Solaris — with more (Haiku, MidnightBSD, OpenIndiana,
8+ the BSDs on arm64) in the pipeline.
79
8- Clode fixes this. Anywhere you have Node, run the latest Claude Code.
10+ Two pieces:
911
10- ## Beware
12+ - ** clode** — the builder: one self-contained native binary per platform,
13+ needing no Node, no npm, nothing else on disk. The only thing we publish.
14+ - ** quaude** — the product it makes: the current Claude Code bundle,
15+ compiled to QuickJS bytecode and fused with a node-compatibility runtime
16+ into one native executable. Derived work: you fuse it locally, and it is
17+ never distributed.
1118
12- Clode is a hilarious hack that will inevitably stop working. It attempts
13- to be reasonably robust against many failure modes, but can't possibly
14- defend against all of them.
19+ ## Usage
1520
16- If you've been wishing you could run Claude Code directly on your weird
17- machine, use Clode while you still can.
21+ Grab ` clode-<version>-<platform> ` from Releases, then:
1822
19- ## Usage
23+ ``` sh
24+ ./clode-0.1.2-netbsd-amd64 build # fetch + extract + fuse -> ./quaude
25+ ./quaude # run it like `claude`
26+ ```
2027
21- Run ` clode ` anywhere you'd run ` claude ` .
28+ Every fuse self-verifies before reporting success: an offline canned
29+ Messages round-trip plus ` --quaude-attest ` manifest verification. `clode
30+ build` extracts from a Claude Code provider bundle — it finds an
31+ npm-installed one, or point ` CLODE_CLAUDE_BIN ` at it.
2232
23- On first run, it'll install its ` npm ` dependencies into a user-owned dir, fetch and postprocess the latest upstream, then launch it.
33+ The classic mode still works: with Node >= 24 on ` PATH ` , ` clode ` launches
34+ the extracted bundle directly under your host Node, anywhere you'd run
35+ ` claude ` . ` clode update ` keeps it current, and a daily changelog watch
36+ warns when an upstream change threatens the hack (` clode --clode-watch ` on
37+ demand; ` CLODE_NO_WATCH=1 ` off).
2438
25- Updating is much the same as you're used to, modulo the postprocessing. After
26- each ` clode update ` , a warn-only * signals* digest flags anything in the new
27- release's notes or bundle that bears on clode's ability to keep running the JS
28- under Node — e.g. a bundled-Bun-runtime bump, a raised Node floor, or new
29- "requires the native binary" gating. It never blocks the update; in a source
30- checkout it also writes a reviewable ` signals/<ver>.json ` snapshot. Override the
31- notes source with ` CLODE_CHANGELOG_URL ` (air-gapped/testing).
39+ Either way you'll live without: image/sharp, audio capture, computer-use,
40+ SQLite-backed bits, MSAL, runtime TypeScript, and anything else from
41+ ` Bun.* ` that's stubbed or missing.
3242
33- clode also watches for * concerning* upgrades on its own: about once a day a launch
34- fires a background, changelog-only check, and if a newer Claude Code carries
35- signals that bear on running under Node it prints a one-line notice next time you
36- start. Run ` clode --clode-watch ` to check on demand, or set ` CLODE_NO_WATCH=1 ` to
37- turn the automatic check off.
43+ ## Beware
3844
39- You'll have to live without:
45+ clode is a hilarious hack that will inevitably stop working. It attempts
46+ to be reasonably robust against many failure modes, but can't possibly
47+ defend against all of them.
4048
41- - image/sharp
42- - audio capture
43- - computer-use
44- - SQLite-backed bits
45- - MSAL
46- - runtime TypeScript
47- - anything else from ` Bun.* ` that's stubbed or missing
49+ If you've been wishing you could run Claude Code directly on your weird
50+ machine, use clode while you still can.
4851
4952## Installation
5053
51- ### Dependencies
52-
53- - ` node ` >= 24 and ` npm `
54- - ` ugrep ` >= 7.5.0, ` bfs ` >= 3.x (built with Oniguruma), and ` rg ` for fast searches
54+ From Releases: download, ` chmod +x ` , done. ` SHA256SUMS ` covers the native
55+ builders; every binary carries a SLSA provenance attestation
56+ (` gh attestation verify <file> --repo <owner/repo> ` ).
5557
56- The launcher itself is a Node program (` #!/usr/bin/env node ` ), so it needs ` node `
57- on ` PATH ` to start. An ES5-safe prologue prints a friendly "node too old" message
58- on an outdated node; a truly missing node yields ` env: node: not found ` .
58+ For the classic Node-launcher mode instead:
5959
60- Once you have those:
60+ - ` node ` >= 24 and ` npm ` (>= 20 suffices for ` clode build ` alone)
61+ - ` ugrep ` >= 7.5.0, ` bfs ` >= 3.x (built with Oniguruma), and ` rg ` for fast
62+ searches
6163
6264``` sh
6365npm pack
@@ -74,114 +76,27 @@ rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/clode"
7476
7577## Development
7678
77- ### Test dependencies
78-
79- - ` node ` >= 24 and ` npm ` (same as running clode)
80- - ` bats `
81- - on Linux (and anywhere ` node-pty ` has no prebuilt binary): a C/C++ toolchain
82- to compile it — ` python3 ` , ` make ` , and a C++ compiler (` g++ ` /` clang++ ` ). These
83- are the standard ` node-gyp ` build deps.
84-
85- The PTY/TUI tests drive clode under a pseudo-terminal via ` node-pty ` +
86- ` @xterm/headless ` . Those are declared in a separate ` test/package.json ` , and
87- ` npm test ` installs them automatically on first run. Because ` node-pty ` carries a
88- ** native** binary, the harness installs into a per-platform directory
89- (` test/.harness/<os>-<osver>-<arch>-node<major>/ ` ) rather than a shared
90- ` test/node_modules ` , so one machine's compiled binary can't clobber another's on a
91- shared/NFS workdir — ` NODE_PATH ` points the tests at the right one. These tests are
92- ** not optional** — the suite fails loudly rather than skipping if the harness can't
93- load.
94-
95- > ** First install compiles ` node-pty ` and can take a few minutes.** ` node-pty `
96- > ships prebuilt binaries only for macOS and Windows; on ** Linux** there is no
97- > prebuild, so ` npm install ` compiles it from source with ` node-gyp ` (hence the
98- > toolchain above). The very first build also downloads the Node C++ headers for
99- > your Node version, so it may sit "quiet" for a while — it is not hung. Later
100- > installs reuse the cached headers and finish in seconds.
101- >
102- > If you install with a package manager that blocks dependency build scripts by
103- > default (e.g. ** pnpm** or ** bun** ), the compile is skipped and ` node-pty ` loads
104- > with "no prebuilt binary"; approve its build script first (pnpm:
105- > ` pnpm approve-builds ` , or add it to ` onlyBuiltDependencies ` ; bun:
106- > ` trustedDependencies ` ). Plain ` npm ` runs the build script without prompting.
107-
108- > ** A bare ` npm install ` at the repo root is tolerated, but unnecessary.** The
109- > "fail-loud" tests (which assert clode dies with a clear message when a runtime dep
110- > like ` ws ` /` yaml ` /` semver ` is absent) are now isolated from the repo's own
111- > ` node_modules ` — they run their shim children from a temp copy outside the repo
112- > tree — so a populated root ` node_modules ` no longer makes them pass vacuously. You
113- > still don't need one: runtime deps install into a user-owned dir at runtime, and
114- > test-harness deps live under ` test/ ` .
115-
116- Run the whole suite:
117-
11879``` sh
11980npm test # offline suite (default; no network or login needed)
120- npm run test:online # also run the network/model tests (needs a logged-in ~/.claude)
121- ```
122-
123- Run a subset directly (run ` npm test ` once first — it installs the PTY/TUI harness
124- into ` test/.harness/<tag>/ ` and the rest resolve it via ` NODE_PATH ` ):
125-
126- ``` sh
127- node --test test/* .test.cjs # JS unit, module, and differential tests
128- bats test/ # launcher + integration tests
129- ```
130-
131- ### Building a single-file binary (SEA)
132-
133- clode can be packaged as a stand-alone [ Node SEA] ( https://nodejs.org/api/single-executable-applications.html ) —
134- one executable that embeds Node, the esbuilt launcher, and the runtime deps, so a
135- target machine needs neither ` node ` nor ` npm ` :
136-
137- ``` sh
138- node scripts/build-sea.mjs
139- ```
140-
141- The output is ` build/<os>-<osver>-<arch>-node<major>/clode ` (e.g.
142- ` build/darwin-25-arm64-node24/clode ` ). The build is self-provisioning: it installs
143- its own build tools (` esbuild ` , ` postject ` ) and stages the runtime deps on first run,
144- then caches them. On macOS it ad-hoc-signs the binary (required, or it won't launch).
145-
146- ** Use an official, non-stripped Node** ≥ 24 as the build node — a nodejs.org build,
147- or one from ` asdf ` /` nvm ` . The SEA embeds * whichever ` node ` runs the script* , so:
148-
149- - A ** stripped** node (some distro ` /usr/bin/node ` ) corrupts under ` postject ` and the
150- result segfaults at startup. The build's self-check catches this and explains it.
151- - A node that links ** non-system libraries** (e.g. a pkgsrc/Homebrew node pulling in
152- ` /opt/pkg/lib ` or ` /opt/homebrew ` dylibs) produces a binary that only runs where
153- those libraries exist. An official build links only the OS's own libraries, so the
154- binary is portable across machines of the same OS/arch.
155-
156- To embed a specific Node, run the script * with* that Node
157- (` ~/.asdf/installs/nodejs/24.18.0/bin/node scripts/build-sea.mjs ` ).
158-
159- Everything lands under a per-platform tag dir (the same tuple the test harness uses),
160- so builds for different OS/arch/Node coexist on a shared/NFS ` build/ ` tree without
161- colliding. Set ` CLODE_CLAUDE_BIN=/path/to/claude ` to have the build additionally boot
162- the real bundle once as a deep self-check.
163-
164- ### Fusing native binaries (` clode build ` )
165-
166- Two subcommands fuse stand-alone native binaries from the pinned txiki.js
167- runtime (` build/tjs/tjs ` , built by ` scripts/build-tjs.mjs ` ; override with
168- ` CLODE_TJS ` ). Both artifacts run with ** no Node at all** on the machine:
169-
170- ``` sh
171- clode build [--out PATH] # fuse a "quaude" (default ./quaude):
172- # the extracted Claude Code bundle compiled to
173- # quickjs bytecode + the node-shim runtime
174- clode build --self [--out PATH] # fuse a native clode builder (default ./clode-native):
175- # clode's own launcher + everything `clode build`
176- # needs, so the BUILDER itself needs no Node
81+ npm run test:online # also the network/model tests (needs a logged-in ~/.claude)
17782```
17883
179- ` clode build --self ` embeds the esbuilt launcher from the newest
180- ` build/*/clode-main.bundle.cjs ` (produce it with
181- ` node scripts/build-sea.mjs --bundle-only ` ; override with ` CLODE_MAIN_BUNDLE ` ).
182- The resulting ` ./clode-native ` answers ` --clode-version ` /` --clode-help ` and can
183- itself run ` clode-native build ` to fuse a quaude. Every fuse self-verifies
184- before reporting success (an offline canned Messages round-trip plus
185- ` --quaude-attest ` manifest verification for quaude; version/help smokes for the
186- builder). Fused binaries are derived work: they are fused locally and never
187- distributed.
84+ The PTY/TUI tests drive clode under a pseudo-terminal; the harness
85+ self-installs into ` test/.harness/<platform-tag>/ ` on first run. On Linux
86+ that first run compiles ` node-pty ` from source (needs ` python3 ` , ` make ` , a
87+ C++ compiler) and can sit quiet for a few minutes — it is not hung.
88+
89+ Building the pieces from source:
90+
91+ - ` node scripts/build-tjs.mjs ` — the pinned, patched txiki.js runtime
92+ (` build/tjs/tjs ` ). Pins in ` spike/quickjs/PINS.md ` ; portability fixups
93+ apply themselves with content verification.
94+ - ` clode build --self ` — fuse the native builder itself (embeds the
95+ esbuilt launcher from ` node scripts/build-sea.mjs --bundle-only ` and the
96+ pristine tjs template, so the result needs nothing on disk).
97+ - ` node scripts/build-sea.mjs ` — the transitional single-file
98+ [ Node SEA] ( https://nodejs.org/api/single-executable-applications.html )
99+ (the ` -node ` -tagged release assets; Windows's only path today). Run it
100+ with an official, non-stripped Node >= 24 — the SEA embeds whichever
101+ ` node ` runs the script, and a stripped or non-system-lib node produces a
102+ broken or non-portable binary.
0 commit comments