Instructions for AI coding agents working in this repository. Humans should
start with README. The guides in docs/ have the full details.
Personal dotfiles for four platforms. Application config files are shared across all of them; package management is not.
| Platform | Packages | Config files linked by |
|---|---|---|
NixOS WSL2 (nixos-wsl, the main machine) |
flake.nix + integrated Home Manager |
mkOutOfStoreSymlink in home/modules/ |
Native NixOS (nixos-native) |
flake.nix + integrated Home Manager |
mkOutOfStoreSymlink in home/modules/ |
| macOS | Brewfile |
GNU Stow |
| Arch Linux | pacman-packages.txt |
GNU Stow |
Nix is used only on NixOS. There is no nix-darwin, no standalone Home Manager configuration, and no ARM host.
| Path | What goes there |
|---|---|
flake.nix |
Inputs, the user name, overlays and package pins, mkSystem, checks, dev shell |
systems/common.nix |
NixOS settings shared by both hosts (Nix, user, zsh, base packages) |
systems/wsl/, systems/native/ |
Host-specific NixOS settings |
home/modules/*.nix |
Home Manager packages and config links, one topic per module |
home/modules/common.nix |
Imports the shared modules and defines the config.lib.dotfiles.link helper |
home/nixos-wsl.nix, home/nixos-native.nix |
Each host's extra imports and host-only packages |
<app>/.config/<app>/ |
The application's real config files (Stow package layout) |
bash/, zsh/ |
Shell startup files, linked directly into $HOME |
docs/ |
User documentation describing the current setup |
- Never change
system.stateVersionorhome.stateVersion. They select compatibility defaults, not the package release. - Keep application config hand-written and Stow-compatible. macOS and Arch
use the same files without Nix. Don't convert a config to Home
Manager-generated settings (
programs.git.settings,programs.zsh,programs.neovim,programs.<app>.settings, and so on). Link the repo files withconfig.lib.dotfiles.link "<path in repo>", as the existing modules do. - Home Manager's shell modules are off (
programs.zshandprograms.bashare not enabled). Options that inject into them, such asenableZshIntegrationorhome.shellAliases, do nothing.home.sessionVariablesonly reaches shells that sourcehm-session-vars.sh(bash/.bashrcdoes). Put environment variables, aliases and shell integrations inzsh/.zshenvorzsh/.zshrc, and mirror them inbash/.bashrc. - Shell files must run on NixOS, Arch and macOS, including macOS's bash
3.2. Guard optional tools with
command -v, and never reference/nix/storepaths. - Don't apply system changes unless the user asks. That covers
nixos-rebuild switch|boot|test,make switch|upgrade|clean|gc|setup-*,stow, and anything run withsudo. Note thatnixos-rebuild testdoes activate the configuration. - Don't update flake inputs unless asked. Never run a bare
nix flake update. Update only the named inputs (nix flake update <input>), and keepflake.lockchanges in the same commit as the change that needs them. - Never commit secrets. The
*.localoverride files (git/.config/git/config.local,zsh/.zshenv.local,bash/.bashrc.local) are gitignored on purpose. - Herdr writes into its linked config directory. Only
herdr/.config/herdr/config.tomlis tracked, and Herdr itself may edit it. Don't commit or revert changes there that you didn't make. - Neovim plugins are managed by lazy.nvim, not Nix. Don't hand-edit
nvim/.config/nvim/lazy-lock.json. Seenvim/.config/nvim/README.mdbefore changing the Neovim setup.
nixpkgs-azure-cliis a commit-pinned nixpkgs that deliberately does not follownixpkgs. Don't addinputs.nixpkgs.followsto it.copilotOverlayoverridesgithub-copilot-cli. A version bump must update the version and both platform hashes (x86_64-linuxandaarch64-linux).- Every other input follows
nixpkgs. Do the same for new inputs. - Add new package overrides as overlays in
mkSystem, so NixOS and Home Manager (useGlobalPkgs = true) see the same package. Record them indocs/EXAMPLE-VERSION-PINNING.md.
- The flake only sees files tracked by Git. Run
git addon a new file before evaluating or building. It doesn't need to be committed. - The NixOS hosts are
x86_64-linuxonly, but the checks, formatter and dev shell also coveraarch64-linux. Per-platform data such as URLs and hashes needs entries for both. - CI runs
deadnix --failandstatix. Remove module arguments (pkgs,config, ...) andletbindings you stop using. - Format Nix with
nixfmt(the flake's formatter), notnixpkgs-fmt. - List each package once. Don't add a package to Home Manager when it's in
environment.systemPackagesor when aprograms.<name>.enablemodule already installs it (for exampleprograms.gh,programs.gpg). systemd.user.startServices = "suggest"in the WSL home is intentional. It lets the bootstrap configuration activate before any user session exists.- The username is defined once as
userinflake.nixand reaches NixOS modules as theuserargument. The checkout path is/home/<user>/dotfiles. Don't rename either unless asked; seedocs/DEPLOYMENT.mdfor the places that still spell outuser3301.
- Put the files in
<app>/.config/<app>/. - Link the directory from the matching
home/modules/*.nixwithxdg.configFile."<app>".source = config.lib.dotfiles.link "<app>/.config/<app>";. - If the app is also used on macOS or Arch, add
<app>toSTOW_PACKAGESinMakefile, and its package toBrewfileorpacman-packages.txt. - Update the module table and Stow package lists in
docs/.
These commands mirror CI (.github/workflows/ci.yml) and need no sudo:
nix fmt <changed .nix files>
nix build --no-link \
.#checks.x86_64-linux.nix-quality \
.#checks.x86_64-linux.lua-format \
.#checks.x86_64-linux.zsh-syntax \
.#checks.x86_64-linux.bash-syntax
nix eval --raw '.#nixosConfigurations.nixos-wsl.config.system.build.toplevel.drvPath'
# CI doesn't evaluate the native host. Do it when you touch shared or native modules:
nix eval --raw '.#nixosConfigurations.nixos-native.config.system.build.toplevel.drvPath'Check the output for evaluation warning: lines as well as the exit code.
nix develop provides nixfmt, statix, deadnix, StyLua and nil.
- Commit subjects are imperative and sentence case, with no type prefix, for
example "Add kubectl and kubectx to dev-tools". The default branch is
master. - Pin GitHub Actions to a full commit SHA, with the version in a trailing
comment (
# v7.0.1). docs/describes the current setup. When you change behavior, packages, modules or pins, update the matching doc in the same change.