From 3abf500bae76ab5f08063d6abbfaf17c30933822 Mon Sep 17 00:00:00 2001 From: larry <26318510+larry0x@users.noreply.github.com> Date: Fri, 17 Jul 2026 14:28:36 +0100 Subject: [PATCH 1/2] feat: add the mac development environment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A single buildEnv (mac/env.nix) installed into the user profile via `nix profile add`, providing the full development toolchain: stable Rust via fenix (including rustfmt — my projects format with stable now), node 24 + pnpm, python 3.14 + uv, mdbook with the katex and mermaid preprocessors, colima + the docker CLI/compose/buildx, the sops/age YubiKey stack, and general CLI utilities. Also unify the whole repo on a single nixpkgs input tracking nixos-unstable: the gaming PC moves from nixos-26.05 to the rolling branch, and the per-machine update recipes merge into one. Co-Authored-By: Claude Fable 5 --- .github/workflows/nix.yml | 6 +++ README.md | 14 ++--- flake.lock | 47 +++++++++++++++-- flake.nix | 22 ++++++-- justfile | 25 +++++++-- mac/README.md | 35 +++++++++++++ mac/env.nix | 107 ++++++++++++++++++++++++++++++++++++++ pc/README.md | 6 +-- 8 files changed, 242 insertions(+), 20 deletions(-) create mode 100644 mac/README.md create mode 100644 mac/env.nix diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 9f9a143..1ed0f3d 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -27,3 +27,9 @@ jobs: # that do not exist (typos) and values of the wrong type. - name: eval (NixOS option type check) run: nix eval .#nixosConfigurations.gaming.config.system.build.toplevel.drvPath + + # Same for the mac environment. Evaluation is system-agnostic (no import + # from derivation), so the aarch64-darwin derivation evaluates fine on + # this Linux runner without building anything. + - name: eval (mac dev env type check) + run: nix eval .#packages.aarch64-darwin.default.drvPath diff --git a/README.md b/README.md index 784b247..76d37fc 100644 --- a/README.md +++ b/README.md @@ -16,16 +16,18 @@ curl -fsSL https://install.determinate.systems/nix | sh -s -- install Open a new terminal afterwards so the shell picks up the Nix environment. -### 2. Install the language server, linters, and formatter +### 2. Install the development environment + +Clone this repo and install the [`mac/`](./mac/) environment into the user profile: ```sh -nix profile add \ - nixpkgs/nixos-26.05#nixd \ - nixpkgs/nixos-26.05#nixfmt \ - nixpkgs/nixos-26.05#statix \ - nixpkgs/nixos-26.05#deadnix +git clone https://github.com/larry0x/nix.git ~/workspace/larry0x/nix +cd ~/workspace/larry0x/nix +nix profile add . ``` +Among everything else, this provides the Nix tooling used to work on this repo: + - `nixd`: language server — completion, hover docs, and diagnostics for NixOS options - `nixfmt`: the official formatter - `statix`: lints for Nix anti-patterns diff --git a/flake.lock b/flake.lock index 6b753be..5cb72a0 100644 --- a/flake.lock +++ b/flake.lock @@ -1,25 +1,64 @@ { "nodes": { + "fenix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1784190100, + "narHash": "sha256-cE4wAMa3MDhnx+mH5Y72tM/VTSh5cS5S2q0w56XurJU=", + "owner": "nix-community", + "repo": "fenix", + "rev": "010b0647f8ebce9cd9e185773a7f9e422af1154a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1783148766, - "narHash": "sha256-uslt2pqShTIXDdAHRHv2QkYLsVdY8Oqwz0EA48/RSM8=", + "lastModified": 1784120854, + "narHash": "sha256-KesHgItiZPgGX740axSiQLcIQ8D24MDqNpkKYWIek8k=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a50de1b7d8a586adc18d2395c19de7d6058e6030", + "rev": "753cc8a3a87467296ddd1fa93f0cc3e81120ee46", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-26.05", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { + "fenix": "fenix", "nixpkgs": "nixpkgs" } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1784155628, + "narHash": "sha256-yLgQQpQJpNkqoNvYc93pr7HjpW2uOP6Y1sm/vQakEc4=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "7a5ecc88dbdfa13bac99fa4e0f38adcfdca1bb0a", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 6cf73b6..6720ecc 100644 --- a/flake.nix +++ b/flake.nix @@ -1,15 +1,31 @@ { - description = "Minimalist NixOS gaming machine"; + description = "Nix setup for my working and gaming computers"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05"; + # The rolling branch, so packages stay current instead of feature-freezing + # for six months at a time as the stable branches do. Despite the name, it + # only advances after Hydra CI passes — a CI-gated rolling release, not + # untested software. + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + # Rust toolchain for the mac environment, repackaging the official + # rust-lang binary releases under Nix pins. + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = - { nixpkgs, ... }: + { nixpkgs, fenix, ... }: { nixosConfigurations.gaming = nixpkgs.lib.nixosSystem { modules = [ ./pc/configuration.nix ]; }; + + packages.aarch64-darwin.default = import ./mac/env.nix { + pkgs = import nixpkgs { system = "aarch64-darwin"; }; + fenixPkgs = fenix.packages.aarch64-darwin; + }; }; } diff --git a/justfile b/justfile index 110ee0f..a191349 100644 --- a/justfile +++ b/justfile @@ -2,6 +2,8 @@ default: @just --list +# -------------------------------- Development --------------------------------- + # Format all Nix files in place fmt: nixfmt $(git ls-files '*.nix') @@ -11,15 +13,32 @@ lint: statix check . deadnix --fail . -# Type-check by evaluating the full NixOS system +# Type-check by evaluating the full NixOS system and the mac environment test: nix eval .#nixosConfigurations.gaming.config.system.build.toplevel.drvPath + nix eval .#packages.aarch64-darwin.default.drvPath + +# Update all flake inputs +update: + nix flake update + +# ------------------------------------- PC ------------------------------------- # Install NixOS for the first time -install: +pc-install: sudo nixos-generate-config --root /mnt --show-hardware-config > pc/hardware-configuration.nix sudo nixos-install --flake .#gaming --no-root-passwd # Rebuild NixOS -rebuild: +pc-rebuild: sudo nixos-rebuild switch --flake .#gaming + +# ------------------------------------ Mac ------------------------------------- + +# Install the mac dev environment into the user profile (first time only) +mac-add: + nix profile add . + +# Rebuild the mac dev environment after changing it +mac-upgrade: + nix profile upgrade --all diff --git a/mac/README.md b/mac/README.md new file mode 100644 index 0000000..fc96128 --- /dev/null +++ b/mac/README.md @@ -0,0 +1,35 @@ +# mac + +My macOS development environment: a single Nix profile providing every development tool, so that a fresh Mac replicates the full setup with one command. + +Layering rules: + +- Everything development-related lives here, in Nix. +- Homebrew is for non-development software only, e.g. GUI apps (casks). +- Stock macOS tools stay stock — notably git, which ships with the Xcode Command Line Tools. +- Claude Code uses its own self-updating native installer. +- No language-version managers (rustup, nvm, corepack): toolchains are pinned by `flake.lock`. + +## Install + +```sh +just mac-add +``` + +This installs `packages.aarch64-darwin.default` — one big `buildEnv` defined in [`env.nix`](./env.nix) — into the user profile. Make sure `~/.nix-profile/bin` is prepended to `PATH` ahead of Homebrew in `~/.zshrc`. + +## Update + +```sh +just update # bump the flake inputs +just mac-upgrade # rebuild the profile from the flake +``` + +Roll back with `nix profile rollback`. + +## Notes + +- `cargo` is a thin shim that accepts rustup-style `cargo +nightly …` invocations: the `+toolchain` argument is dropped, which is correct because rustfmt in this environment _is_ the nightly one, and everything else runs on the stable toolchain. +- mdbook and mdbook-mermaid come stock from nixpkgs; mdbook-katex is built from crates.io (nixpkgs' version is stale). The preprocessors may print a cosmetic "built against version X" warning when their locked mdbook libraries trail the mdbook binary — math and diagrams render fine regardless. +- The docker daemon is colima (`colima start`); the docker CLI, compose, and buildx come from this flake, with the compose/buildx plugins linked into `~/.docker/cli-plugins/`. +- coreutils are the GNU ones, unprefixed: they deliberately shadow the stock BSD `ls`, `date`, `stat`, etc. diff --git a/mac/env.nix b/mac/env.nix new file mode 100644 index 0000000..c111fc2 --- /dev/null +++ b/mac/env.nix @@ -0,0 +1,107 @@ +# My macOS development environment: a single buildEnv holding every +# development tool, installed into the user profile via `nix profile add` so +# that everything is available in every shell. + +{ pkgs, fenixPkgs }: +let + # ----------------------------------- Rust ----------------------------------- + + # The stable toolchain, pinned by flake.lock. There is deliberately no + # nightly anything here — my projects format with stable rustfmt. + rustToolchain = fenixPkgs.stable.withComponents [ + "cargo" + "clippy" + "rust-src" + "rustc" + "rustfmt" + ]; + + # ----------------------------------- Docs ----------------------------------- + + # mdbook and mdbook-mermaid come stock from nixpkgs. mdbook-katex must be + # built from source, because nixpkgs ships a stale version that predates + # mdbook 0.5. + # + # Nix builds honor each preprocessor crate's shipped Cargo.lock (unlike a + # bare `cargo install`, which re-resolves dependencies at install time), so + # the mdbook libraries they link are often slightly older than the mdbook + # binary calling them. Each such preprocessor then prints a one-line "built + # against version X" warning per mdbook run. This is cosmetic: KaTeX math + # and mermaid diagrams render fine regardless. + mdbook-katex = pkgs.rustPlatform.buildRustPackage rec { + pname = "mdbook-katex"; + version = "0.10.0-alpha"; + + src = pkgs.fetchCrate { + inherit pname version; + hash = "sha256-F6ozNlN8umagAWr+xeA61uf+QOae/y6VnyzWKDsFIhk="; + }; + + cargoHash = "sha256-LUHVGEvE22ITlmpuI+8qGBPTa7q8YssiLSfQnvGM4hw="; + doCheck = false; + }; +in +pkgs.buildEnv { + name = "dev"; + paths = [ + # Rust + rustToolchain + pkgs.rust-analyzer + pkgs.just + pkgs.taplo + pkgs.cargo-machete + pkgs.cargo-flamegraph + + # Docs + pkgs.mdbook + pkgs.mdbook-mermaid + mdbook-katex + + # JavaScript / TypeScript + pkgs.nodejs_24 + pkgs.pnpm + pkgs.typescript + pkgs.typescript-language-server + + # Python + pkgs.python314 + pkgs.uv + + # Containers (daemon = colima; no Docker Desktop, no OrbStack) + pkgs.colima + pkgs.docker-client + pkgs.docker-compose + pkgs.docker-buildx + + # Secrets / YubiKey + pkgs.sops + pkgs.age + pkgs.age-plugin-yubikey + pkgs.yubikey-manager + + # CLI utilities. coreutils is the GNU one, unprefixed — it deliberately + # shadows the stock BSD tools (ls, date, stat, …). + pkgs.coreutils + pkgs.bat + pkgs.eza + pkgs.starship + pkgs.fastfetch + pkgs.direnv + pkgs.gh + pkgs.jq + pkgs.yq-go + pkgs.ripgrep + pkgs.wget + pkgs.tokei + pkgs.websocat + pkgs.gitleaks + pkgs.zizmor + pkgs.wabt + + # Nix tooling + pkgs.nixd + pkgs.nixfmt + pkgs.statix + pkgs.deadnix + ]; +} diff --git a/pc/README.md b/pc/README.md index e467ade..5227b1d 100644 --- a/pc/README.md +++ b/pc/README.md @@ -153,8 +153,6 @@ Minimalist NixOS gaming machine ## Update ```sh -nix flake update nixpkgs -just rebuild +just update +just pc-rebuild ``` - -Updating only the `nixpkgs` input keeps the mac environment's inputs untouched. From 1274e2cfbb3aca486a8f3bffb959ccd980edb346 Mon Sep 17 00:00:00 2001 From: larry <26318510+larry0x@users.noreply.github.com> Date: Fri, 17 Jul 2026 14:40:27 +0100 Subject: [PATCH 2/2] docs: explain the hash, cargoHash, and doCheck fields Co-Authored-By: Claude Fable 5 --- mac/env.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mac/env.nix b/mac/env.nix index c111fc2..e66aa11 100644 --- a/mac/env.nix +++ b/mac/env.nix @@ -34,10 +34,18 @@ let src = pkgs.fetchCrate { inherit pname version; + + # Integrity hash of the source tarball; the fetch fails if crates.io + # ever serves different bytes for this name and version. hash = "sha256-F6ozNlN8umagAWr+xeA61uf+QOae/y6VnyzWKDsFIhk="; }; + # Same, for the vendored dependency tree (everything in the crate's + # Cargo.lock), which is fetched in a separate step so the build itself + # can run offline. cargoHash = "sha256-LUHVGEvE22ITlmpuI+8qGBPTa7q8YssiLSfQnvGM4hw="; + + # Skip the crate's own test suite; the released binary is all we need. doCheck = false; }; in