Add a Nix dev shell so Node and Rust match CI - #7
Conversation
Contributors currently assemble the Node and Rust toolchains by hand, so local versions drift from CI. On one machine here: Node 22.21.0 against CI's 22.22.3, and Homebrew cargo 1.92.0 against the 1.96.1 pinned in native/computer-use-broker/rust-toolchain.toml. The cargo gap is the one that bites, because `npm test` runs `cargo clippy --locked -- -D warnings` and clippy changes its lint set between releases, so a change can pass locally and fail CI on lint alone. `nix develop` now provides both, matching CI exactly on npm (10.9.8) and cargo (1.96.1), and differing only in Node patch (22.23.2 vs 22.22.3, both satisfying the >=22.19 engines constraint). The shell reads rust-toolchain.toml through rust-overlay rather than repeating the version, so bumping that file moves the shell with it and the two cannot drift. This adds no new version state to maintain. Deliberately out of scope: there is no package output. electron-builder, ad-hoc signing, notarization, and the FoundationModels framework all need the host Xcode and login keychain, which a Nix sandbox cannot reach. For the same reason the shell leaves DEVELOPER_DIR, SDKROOT, CC, and CXX unset so the host Xcode continues to drive every native build. Xcode and signing identities remain host requirements, as the README now states. Nothing existing changes: no CI edits, and the flake is opt-in. Anyone not using Nix is unaffected. Co-Authored-By: Claude Opus 5 <[email protected]>
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Nix flake —
flake.nixdeclares a macOS-only dev shell (arm64 and x86_64) with Node 22 from nixpkgs and Rust fromrust-toolchain.tomlviarust-overlay.flake.lockpins exact nixpkgs and rust-overlay revisions for byte-identical tool builds across contributors.DEVELOPER_DIR/SDKROOT/CC/CXXare deliberately left unset so the host Xcode drives native builds. - direnv integration —
.envrcauto-loads the flake oncdand watchesrust-toolchain.tomlso the shell reflects toolchain bumps without manual reloads. - Documentation — README adds a short paragraph and
nix developsnippet under Requirements, plus adirenv allowalternative. - Gitignore —
.direnv/entry keeps local direnv cache out of version control.
The flake reads the Rust version from the existing rust-toolchain.toml via fromRustupToolchainFile — no second copy to maintain. All changes are additive and opt-in; no existing code or CI configuration is modified.
DeepSeek Pro | 𝕏
Review findingsI do not think this is ready to merge yet.
The flake locking, Rust toolchain reuse, and direnv watch setup otherwise look well scoped and additive. |

Today each contributor installs Node and Rust by hand, so no two machines match. On my Mac, Homebrew had given me cargo 1.92.0. This repo asks for 1.96.1 — that number lives in
native/computer-use-broker/rust-toolchain.toml, the file rustup reads to decide which Rust version to use. The gap matters becausenpm testeventually runscargo clippy --locked -- -D warnings. In plain words, that command runs Clippy (the Rust linter), forces it to use exactly the dependency versions recorded inCargo.lockinstead of picking newer ones (--locked), and turns every warning into a hard failure (-D warnings). Clippy adds new lints in almost every Rust release, so a newer Clippy rejects code an older one accepted. The result is that a change can pass on my machine and fail CI, or pass CI and then break for the next contributor. It reads like a code bug, but it is a version bug — and you are the one who ends up working that out during review.This PR adds a Nix dev shell. Nix is a package manager that installs exact, pinned versions of tools into a temporary shell, without changing anything else on your Mac. A contributor runs one command,
nix develop, and lands in a shell holding the same tools CI uses: npm 10.9.8 and cargo 1.96.1, both exact matches. The detail that matters for you is thatflake.nixnever writes the Rust version down a second time. It callsrust-bin.fromRustupToolchainFileand hands it the path to your existingrust-toolchain.toml, so Nix reads the version out of the file you already maintain. Bump that file and the shell follows on its own — there is no second copy to forget. Xcode and your signing identities deliberately still come from the Mac, because the Swift helper builds against Apple's real SDK and Apple does not permit Nix to redistribute it. Nothing that exists today changes: no CI edits, no new scripts, 115 lines added and none modified. It is entirely opt-in, so if you never runnix develop, your setup behaves exactly as it does now.What each file does
flake.nix— declares the shell: Node 22 (yourenginesfield asks for >=22.19), plus Rust read from yourrust-toolchain.toml. It deliberately leavesDEVELOPER_DIR,SDKROOT,CC, andCXXunset so the host Xcode keeps driving every native build.flake.lock— records the exact nixpkgs and rust-overlay commits used, so two contributors resolve to byte-identical tool builds rather than "whatever was current that day"..envrc— optional. If you use direnv, the shell loads automatically when youcdinto the repo. It also watchesrust-toolchain.toml, because direnv otherwise only notices changes toflake.nixand would leave you in a stale shell after a toolchain bump..gitignore— one entry,.direnv/, the local cache direnv writes.README.md— documentsnix developbeneath the existing Requirements list.Verified on macOS (aarch64):
nix flake check,npm ci,npm run type-check,npm run lint, andnpm run test:computer-use:native(the fmt + test + Clippy gate) all pass inside the shell.One known gap, flagged honestly: Node resolves to 22.23.2 while CI pins 22.22.3. Both satisfy the
>=22.19requirement inpackage.json, and npm matches exactly at 10.9.8 because both Node versions bundle it. I chose not to force the exact patch, because pinning it needs a hand-written override that stops tracking nixpkgs and becomes the very maintenance burden this PR is trying to remove. Happy to change that if you would rather have it exact.🤖 Generated with Claude Code