Add an nvim Module that configures Neovim declaratively through nixvim, wired as a flake input and consumed as its home-manager module. Options, globals, keymaps, and plugin settings are typed Nix; the colorscheme call and two autocmds live in modules/nvim/config.lua via extraConfigLua. Plugins come from nixpkgs (no plugin manager, no runtime cloning); git, ripgrep, and fd are provided from Nix; treesitter grammars are built by Nix so no runtime compiler is needed. Functionally matches the previous config (plugins, keymaps, options, the nord colorscheme, markdown conceal, the Neogit blame toggle), verified headless against the generated init.
5.5 KiB
5.5 KiB
dotfiles-nixos
One flake that builds every machine the user owns.
The domain model (Host, Module, Skeleton, Auto-loader, Enable convention, overlays) lives in .claude/CONTEXT.md; the current deliverable's spec is .claude/spec/laptop-mvi.md.
Conventions
- In-file comments describe only the current content and behaviour of the file they sit in.
Do not write comments about history ("used to be X", "now moved here"), about how a value is consumed in other files, or that justify the choice against alternatives.
Never reference agent-facing state (anything under
.claude/orCLAUDE.md) from a code comment: that state is not part of understanding the code. A reader looking at only that file should find every comment accurate and self-contained. - Comments posted to Gitea (pull requests, issues, reviews) go out under the operator's account, so sign every one to make clear the author is the agent, not the operator.
End the comment with a
— Claudesign-off. (A dedicated bot account may replace this later; until then, the sign-off is the only marker.)
Gotchas
- Nix on the dev host needs experimental features passed per-command.
This repo is developed on
neogaiawhile it still runs CachyOS (the migration target), where Nix is the distro package at/usr/bin/nixin multi-user daemon mode. The system/etc/nix/nix.confdoes not enable flakes, so exportNIX_CONFIG="experimental-features = nix-command flakes"(or pass--extra-experimental-features 'nix-command flakes') for every command. - The dev user is a non-trusted daemon client (
nix store inforeportsTrusted: 0). You cannot add substituters from the CLI, so rely on what the flake/config declares (e.g. the chaotic cache is wired by the chaotic module, not a CLI flag). Caveat that bites when a Host actually selects the CachyOS kernel: the substituters anix buildfetches from are the daemon's (/etc/nix/nix.conf), not thenix.settingsof the config being built — those only govern the built system. This dev host's/etc/nix/nix.confhas nosubstituters/trusted-substituterslines, so building a toplevel whoseboot.kernelPackagesislinuxPackages_cachyoscompiles the kernel (and rustc bootstrap, etc.) from source instead of hittingnyx-cache. To build such a Host here, first addextra-substituters = https://nyx-cache.chaotic.cx/andextra-trusted-public-keys = nyx-cache.chaotic.cx:dJxTrgMC3V3cFfyIiBQDQorG6k1LsqurH/srpMSq7qk=to/etc/nix/nix.conf(sudo) andsudo systemctl restart nix-daemon.nix evalof the kernel version does not trigger this — only a real build does. - If
/nix/storeis missing ornix-daemonis inactive after a fresh Nix install, initialise it withsudo systemd-tmpfiles --create nix-daemon.conf && sudo systemctl enable --now nix-daemon.socket. - The primary build/verify seam for any Host is
nix flake check, which buildschecks.x86_64-linux.<host>(the system toplevel); cheap targeted checks usenix eval .#nixosConfigurations.<host>.config.... - chaotic-nyx must not follow our
nixpkgs, and its packages are built against chaotic's own pinned nixpkgs (its overlay defaults toonTopOf = "flake-nixpkgs", the cache-friendly path). That is what lets thenyx-cache.chaotic.cxbinary cache hit instead of compiling the CachyOS kernel from source; the tradeoff is that chaotic packages do not see ourunstable/stableoverlays. - The remote is self-hosted Gitea (
git.alexion.dev); the forge CLI istea(loginaxi), andghis not installed. - nixpkgs
vimPlugins.nord-nvimisshaunsingh/nord.nvim(norequire("nord").setup()); the config wantsgbprod/nord.nvim, which is packaged asvimPlugins.gbprod-nord. - nixpkgs
vimPlugins.nvim-treesittertracks the rewrittenmainbranch: there is norequire("nvim-treesitter.configs").setup{ensure_installed,highlight,indent}. Under nixvim, useplugins.treesitterwithhighlight.enable/indent.enableandgrammarPackages = with config.programs.nixvim.plugins.treesitter.package.builtGrammars; [ ... ]— the module's ownpackage.builtGrammars, notpkgs.vimPlugins.nvim-treesitter.*(whose query files can mismatch). The module targets the main branch and enables features via neovim-native APIs (vim.treesitter.start(),require'nvim-treesitter'.indentexpr()). - Neovim is configured via nixvim (flake input
nixvim, consumed asinputs.nixvim.homeModules.nixvimadded tohome-manager.sharedModules, config underhome-manager.users.<user>.programs.nixvim).nixvim.inputs.nixpkgs.follows = "nixpkgs"is set; nixvim then emits a benign eval warning that its pinned nixpkgs differs from the followed one — builds and runs fine, do not "fix" it by dropping the follows. - To reference the nixvim-built package's own attrs (e.g. treesitter
builtGrammars) inside our NixOS module, givehome-manager.users.<user>the module-function form (hm: { programs.nixvim = { ... hm.config.programs.nixvim... }; }), since the outerconfigis the NixOS config, not the home-manager one. - Verifying a nixvim change headless:
programs.nixvim.build.package's wrapper has no-u, so running$OUT/bin/nvimloads the caller's~/.config/nvim(the dev host's real config), not the built config — silently. To exercise the built config, launch with-u "$(nix build --no-link --print-out-paths .#…programs.nixvim.build.initFile)"and a scratchHOME/XDG_CONFIG_HOME.conceallevelis window-local: set it withopt_local/vim.wo, nevervim.bo[buf](which errors).