From ebad39adab212ab4e26f9a98befa0048c7eea710 Mon Sep 17 00:00:00 2001 From: sommerfeld Date: Wed, 13 May 2026 13:43:24 +0100 Subject: feat(nix): hybrid setup with flakes + direnv for per-project dev shells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Install Nix (multi-user daemon) on Arch and wire up direnv so any project can declare its toolchain in a flake.nix and get a hermetic dev shell on cd. No NixOS, no home-manager, no migration off paru/chezmoi — just one new package manager scoped to project dev shells. - meta/nix.txt: nix from extra repo - meta/dev.txt: direnv (general-purpose, not nix-specific) - systemd-units/system/nix.txt: nix-daemon.socket (socket-activated) - etc/nix/nix.conf: enable flakes + nix-command, trusted-users=@wheel, auto-optimise-store, keep-outputs/derivations so direnv envs survive GC - dot_config/direnv/direnvrc: load nix-direnv 3.1.1 via source_url with pinned sha256 (not packaged for Arch; refusing -git AUR) - dot_config/nix/templates/{flake.nix,dev/}: flake template usable via 'nix flake init -t ~/.config/nix/templates' - dot_config/zsh/dot_zshrc: 'eval "$(direnv hook zsh)"' --- dot_config/direnv/direnvrc | 14 ++++++++++++++ dot_config/nix/templates/dev/dot_envrc | 1 + dot_config/nix/templates/dev/flake.nix | 29 +++++++++++++++++++++++++++++ dot_config/nix/templates/flake.nix | 13 +++++++++++++ dot_config/zsh/dot_zshrc | 3 +++ etc/nix/nix.conf | 21 +++++++++++++++++++++ meta/dev.txt | 1 + meta/nix.txt | 16 ++++++++++++++++ systemd-units/system/nix.txt | 3 +++ 9 files changed, 101 insertions(+) create mode 100644 dot_config/direnv/direnvrc create mode 100644 dot_config/nix/templates/dev/dot_envrc create mode 100644 dot_config/nix/templates/dev/flake.nix create mode 100644 dot_config/nix/templates/flake.nix create mode 100644 etc/nix/nix.conf create mode 100644 meta/nix.txt create mode 100644 systemd-units/system/nix.txt diff --git a/dot_config/direnv/direnvrc b/dot_config/direnv/direnvrc new file mode 100644 index 0000000..40bfc86 --- /dev/null +++ b/dot_config/direnv/direnvrc @@ -0,0 +1,14 @@ +# Global direnv runtime config. +# +# Loads nix-direnv on demand. nix-direnv is NOT packaged for Arch and we +# refuse to depend on -git AUR packages, so we fetch the loader from +# upstream pinned by version + content hash. direnv caches it under +# $XDG_CACHE_HOME/direnv/, so the network fetch happens exactly once +# per pin bump. +# +# To upgrade: bump the version in the URL and replace the sha256 with +# the new one. direnv prints the expected hash on mismatch. +if ! has nix_direnv_version || ! nix_direnv_version 3.1.1; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.1.1/direnvrc" \ + "sha256-p+fzQdrms/hDa7g+soShAybJNo4bN4SIAeSfqNKgD5I=" +fi diff --git a/dot_config/nix/templates/dev/dot_envrc b/dot_config/nix/templates/dev/dot_envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/dot_config/nix/templates/dev/dot_envrc @@ -0,0 +1 @@ +use flake diff --git a/dot_config/nix/templates/dev/flake.nix b/dot_config/nix/templates/dev/flake.nix new file mode 100644 index 0000000..84b3179 --- /dev/null +++ b/dot_config/nix/templates/dev/flake.nix @@ -0,0 +1,29 @@ +{ + description = "Project dev shell"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = { self, nixpkgs }: + let + systems = [ "x86_64-linux" "aarch64-linux" ]; + forAllSystems = nixpkgs.lib.genAttrs systems; + in + { + devShells = forAllSystems (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = pkgs.mkShell { + packages = with pkgs; [ + # Add per-project tools here. + # Example: nodejs_22 python313 cargo gcc + ]; + + shellHook = '' + # Per-project env setup (printed once on shell entry). + ''; + }; + }); + }; +} diff --git a/dot_config/nix/templates/flake.nix b/dot_config/nix/templates/flake.nix new file mode 100644 index 0000000..dc4cf2d --- /dev/null +++ b/dot_config/nix/templates/flake.nix @@ -0,0 +1,13 @@ +{ + description = "Personal flake templates. Use: nix flake init -t ~/.config/nix/templates#"; + + outputs = { self }: { + templates = { + dev = { + path = ./dev; + description = "Generic per-project dev shell with direnv .envrc"; + }; + default = self.templates.dev; + }; + }; +} diff --git a/dot_config/zsh/dot_zshrc b/dot_config/zsh/dot_zshrc index f516495..e8fca42 100644 --- a/dot_config/zsh/dot_zshrc +++ b/dot_config/zsh/dot_zshrc @@ -353,6 +353,9 @@ compdef l=lsd la=lsd lt=lsd export GPG_TTY=$TTY gpg-connect-agent updatestartuptty /bye &>/dev/null +# ── direnv (per-project env via .envrc; nix-direnv loaded from direnvrc) ───── +eval "$(direnv hook zsh)" + # ── Zoxide (smart directory jumping) ────────────────────────────────────────── # z foo → jump to frecency-ranked dir matching "foo" # zi → interactive picker with fzf diff --git a/etc/nix/nix.conf b/etc/nix/nix.conf new file mode 100644 index 0000000..eb24511 --- /dev/null +++ b/etc/nix/nix.conf @@ -0,0 +1,21 @@ +# /etc/nix/nix.conf — daemon-wide Nix config. +# Managed by chezmoi (etc/nix/nix.conf in dotfiles). + +# Enable `nix` CLI (vs legacy nix-* commands) and flakes. +experimental-features = nix-command flakes + +# Wheel users may configure extra substituters / import paths without +# the daemon prompting. Safe on a single-user laptop. +trusted-users = root @wheel + +# Hard-link identical store paths to save disk after large builds. +auto-optimise-store = true + +# Keep build outputs and derivations alive even when only referenced +# from GC roots like direnv envs. Without these, `nix store gc` would +# drop dev-shell deps and force a re-download next `cd` into a project. +keep-outputs = true +keep-derivations = true + +# Lift the default 64 MiB download buffer; reduces stalls on big closures. +download-buffer-size = 524288000 diff --git a/meta/dev.txt b/meta/dev.txt index bca1348..5f26ad7 100644 --- a/meta/dev.txt +++ b/meta/dev.txt @@ -1,6 +1,7 @@ android-tools curl difftastic +direnv git-absorb git-delta github-cli diff --git a/meta/nix.txt b/meta/nix.txt new file mode 100644 index 0000000..e5c4bb4 --- /dev/null +++ b/meta/nix.txt @@ -0,0 +1,16 @@ +# Nix package manager (multi-user daemon mode). +# +# Used purely for hermetic per-project dev shells via `nix develop` + +# direnv `use flake`. Not a replacement for paru/pacman, not home-manager, +# not NixOS — just a sandboxed second package manager that gives every +# project a reproducible toolchain pinned in its own flake.lock. +# +# Pairs with: +# - systemd-units/system/nix.txt (enables nix-daemon.socket) +# - etc/nix/nix.conf (flakes, trusted-users=@wheel, GC roots) +# - dot_config/direnv/direnvrc (loads nix-direnv; pinned via source_url) +# - dot_config/nix/templates/ (flake templates: nix flake init -t ~/.config/nix/templates) +# +# nix-direnv itself is not packaged for Arch — it's loaded at runtime via +# direnv's source_url with a content hash, so no extra package needed. +nix diff --git a/systemd-units/system/nix.txt b/systemd-units/system/nix.txt new file mode 100644 index 0000000..de99aaa --- /dev/null +++ b/systemd-units/system/nix.txt @@ -0,0 +1,3 @@ +# Nix builder daemon — socket-activated, idle-friendly. +# The .service spawns on first client connect; the .socket is what gets enabled. +nix-daemon.socket -- cgit v1.3.1