feat(nix): add a flake that builds Moli - #140
Open
athul-22 wants to merge 2 commits into
Open
Conversation
Moli could not be built with Nix at all, so packaging it for nixpkgs had no starting point. Add a flake exposing the CLI, a dev shell, and a formatter. Four things about this workspace need handling before a sandboxed build works, and each is commented where it is worked around: - The vendored `v8` crate downloads a prebuilt static library from its build script. `RUSTY_V8_ARCHIVE` is copied rather than downloaded when it is not an http(s) URL, so a fixed-output `fetchurl` satisfies it. Building V8 from source is not an option: the vendored tree is prebuilt-only and rejects `V8_FROM_SOURCE`. - The pinned curl-rust fork carries libcurl as a git submodule. Only the `fetchCargoVendor` path behind `cargoHash` passes `--fetch-submodules`, so `cargoLock` cannot be used here; it leaves the submodule empty and the static libcurl build fails. - That same fork locates brotli's C headers by scanning `$CARGO_HOME` and a `vendor/` directory beside its own manifest, neither of which exists in the Nix vendor layout, so `preBuild` links the vendored brotlic-sys crate into a path the scan reaches. - `moli-protocol` derives the binary revision by shelling out to git, and vergen's `fail_on_error` makes a missing repository fatal in a way `VERGEN_IDEMPOTENT` cannot soften. Rather than carry a git repository into the sandbox, emit the revision the flake already knows. `stylo` also needs Python at build time for its property tables, and `bindgen` needs libclang. Tests are disabled in the sandbox: the suite binds loopback HTTP servers and drives a full browser runtime. Verified on aarch64-darwin: `nix build`, `nix run`, `nix flake check`, and `nix fmt` all succeed, and the resulting binary fetches a live page. The V8 archive hashes for the other three platforms were taken from the published release assets, but only aarch64-darwin was built here. Refs lexmount#118
There was a problem hiding this comment.
Pull request overview
Adds initial Nix support for building, running, developing, and formatting Moli.
Changes:
- Adds a four-platform Nix flake and locked nixpkgs input.
- Packages the Rust CLI with sandbox-compatible V8 and native dependency handling.
- Documents Nix usage and provides a development shell and formatter.
Reviewed changes
Copilot reviewed 4 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
.gitignore |
Ignores Nix build result links. |
README.md |
Documents Nix commands. |
flake.lock |
Pins nixpkgs. |
flake.nix |
Defines packages, shells, and formatter. |
nix/package.nix |
Packages the Moli CLI. |
nix/shell.nix |
Defines the Rust development shell. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| packages = forEachSystem (pkgs: rec { | ||
| moli = pkgs.callPackage ./nix/package.nix { | ||
| src = self; | ||
| revision = self.rev or self.dirtyRev or "unknown"; |
Comment on lines
+3
to
+27
| cargo, | ||
| cargo-nextest, | ||
| clippy, | ||
| cmake, | ||
| perl, | ||
| pkg-config, | ||
| python3, | ||
| rustc, | ||
| rustPlatform, | ||
| rustfmt, | ||
| }: | ||
|
|
||
| mkShell { | ||
| # A dev shell is not sandboxed, so the `v8` build script can fetch its own | ||
| # prebuilt archive. Only the native toolchain has to be provided here. | ||
| packages = [ | ||
| cargo | ||
| cargo-nextest | ||
| clippy | ||
| cmake | ||
| perl | ||
| pkg-config | ||
| python3 | ||
| rustc | ||
| rustfmt |
athul-22
added a commit
to athul-22/moli
that referenced
this pull request
Aug 21, 2026
Review on lexmount#140 caught two problems. `self.dirtyRev` is `<commit>-dirty`, so building from a dirty worktree embedded a non-hex revision and made `Browser.getVersion` report a value that violates the 40/64-digit hex contract asserted in `moli-protocol/src/version.rs`. The `"unknown"` fallback for a source that is not a git tree broke the same contract. Strip the suffix and fall back to git's all-zero commit sentinel instead, so every path yields 40 hex digits. The dev shell also relied on two undeclared host tools: `moli-protocol` derives its revision with vergen-gitcl under `fail_on_error`, and the vendored `v8` downloader shells out to Deno or `curl` — the slim tree carries no `tools/download_file.py` fallback. Without either tool `cargo build` failed inside the advertised shell. Add git and curl. Verified on aarch64-darwin: with the worktree dirty the flake emits VERGEN_GIT_SHA=46d3761, matching `git rev-parse HEAD`; the clean, dirty, and non-git branches each yield 40 hex digits; the dev shell derivation carries git 2.55.0 and curl 8.21.0 alongside the existing toolchain; and `nix fmt` is a no-op on both files. Refs lexmount#118 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review on lexmount#140 caught two problems. `self.dirtyRev` is `<commit>-dirty`, so building from a dirty worktree embedded a non-hex revision and made `Browser.getVersion` report a value that violates the 40/64-digit hex contract asserted in `moli-protocol/src/version.rs`. The `"unknown"` fallback for a source that is not a git tree broke the same contract. Strip the suffix and fall back to git's all-zero commit sentinel instead, so every path yields 40 hex digits. The dev shell also relied on two undeclared host tools: `moli-protocol` derives its revision with vergen-gitcl under `fail_on_error`, and the vendored `v8` downloader shells out to Deno or `curl` — the slim tree carries no `tools/download_file.py` fallback. Without either tool `cargo build` failed inside the advertised shell. Add git and curl. Verified on aarch64-darwin: with the worktree dirty the flake emits VERGEN_GIT_SHA=46d3761, matching `git rev-parse HEAD`; the clean, dirty, and non-git branches each yield 40 hex digits; the dev shell derivation carries git 2.55.0 and curl 8.21.0 alongside the existing toolchain; and `nix fmt` is a no-op on both files. Refs lexmount#118
athul-22
force-pushed
the
feat/nix-flake
branch
from
August 21, 2026 20:22
3bfb89e to
10f0a01
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #118.
Moli could not be built with Nix at all, so packaging it for nixpkgs had no starting point. This adds a flake that builds the CLI, plus a dev shell and a formatter.
Scope
This is the buildable foundation, not the nixpkgs submission itself —
search.nixos.orgneeds a separate PR against NixOS/nixpkgs.nix/package.nixis deliberately split fromflake.nixand takessrc,version, andrevisionas arguments, so it can be lifted into nixpkgs with afetchFromGitHubsrc and no rewrite. Happy to follow up with that submission if you want it.What a sandboxed build runs into
Four things in this workspace block a Nix build. Each is commented where it is worked around, because none of them is guessable from the outside:
The vendored
v8crate downloads a prebuilt static library from its build script, and Nix builds have no network. There is no source-build escape hatch — the vendored tree is prebuilt-only and explicitly rejectsV8_FROM_SOURCE. The way through is thatdownload_filecopies rather than downloads whenRUSTY_V8_ARCHIVEis not anhttp(s):URL, so a fixed-outputfetchurlsatisfies it. The V8 src bindings are already vendored undervendor/v8-146.9.0/gen/, so nothing else is fetched.The pinned curl-rust fork carries libcurl as a git submodule. This one is a trap:
cargoLockusesimportCargoLock, which callsfetchgitwithoutfetchSubmodules, so the submodule arrives empty and thestatic-curlbuild fails. Only thefetchCargoVendorpath behindcargoHashpasses--fetch-submodules.cargoHashis therefore mandatory here, and switching tocargoLocklater would silently break the build.That same fork locates brotli's C headers by scanning
$CARGO_HOMEand avendor/directory beside its own manifest. Neither exists in the Nix vendor layout, sopreBuildlinks the vendoredbrotlic-syscrate into a path that scan reaches.moli-protocolderives the binary revision by shelling out to git, and a Nix source tree has no.git. vergen'sfail_on_errormakes that fatal in a wayVERGEN_IDEMPOTENTcannot soften (gitclreturns the error before ever consulting the idempotent flag). Rather than carry a git repository into the sandbox,postPatchemits the revision the flake already knows — which is more accurate than what a tarball build would produce.Beyond those,
styloneeds Python at build time for its property tables, andbindgenneeds libclang viarustPlatform.bindgenHook.doCheck = false: the suite binds loopback HTTP servers and drives a full browser runtime, neither of which the sandbox can host.Testing
Verified on aarch64-darwin:
nix buildsucceedsnix run .#moli -- --versionworksnix flake checkpassesnix fmtruns clean and is idempotentrobots.txt-disallowed URLOnly aarch64-darwin was actually built. The V8 archive hashes for the other three platforms come from downloading and hashing the published release assets, so they are real values rather than placeholders, but those builds are unverified. If CI or a Linux user hits something, I would expect it in the
curl-sysorstylonative-dependency area rather than in the V8 wiring.nixfmtformats files rather than directories, soformatteris a small wrapper that walks the tree; a barepkgs.nixfmtmakesnix fmtfail.