Personal dotfiles, managed in three layers:
- Nix (
nix/) — system configuration and packages, pinned byflake.lockand applied with a rebuild. Fully reproducible. - Stow (
stow/) — dotfiles symlinked into$HOMEwith GNU Stow. Changes take effect immediately, no rebuild needed. - Package tools — CLI tools installed by their own package managers
(currently
uvfor Python,denofor npm). Nix declares which tools and installs missing ones on rebuild, but versions are unpinned and upgraded manually.
Note
- This requires having Nix installed. See the Nix README.
- The
flake.nixis designed to set up the machine based on its hostname.
# Rebuild system + packages + dotfiles (reproducible, uses flake.lock)
sudo darwin-rebuild switch --flake ~/.dotfiles#"$(hostname -s)" # macOS
sudo nixos-rebuild switch --flake ~/.dotfiles#"$(hostname -s)" # NixOS
# Update ALL flake inputs, then rebuild
nix flake update
# Update only the unstable-pinned inputs, then rebuild
nix flake update nixpkgs-unstable nix-darwin home-manager-unstable llm-agents dotfiles
# Clean up old Nix generations, keeping the last 5 days for rollback safety
sudo nix-collect-garbage --delete-older-than 5dNote
On macOS, home-manager's per-user activation can silently fail to apply (a
known upstream launchctl asuser flakiness). The rebuild self-heals this: a
guard in nix/shared/system/darwin.nix verifies the activation landed and
retries it, failing loudly otherwise. See CLAUDE.md for manual
verification and recovery.
Dotfiles are managed with GNU Stow, not Nix.
Note
The darwin-rebuild and nixos-rebuild commands will run stow as well.
- Edit files in
stow/directory and run stow - Changes are immediately active (no rebuild needed)
# Apply dotfiles (no Nix rebuild needed)
cd ~/.dotfiles/stow
stow --target="$HOME" --restow --no-folding --adopt shared "$(uname -s)"--adopt absorbs any real file that has replaced a managed symlink into the
repo instead of aborting; review the result with git diff before committing.
The shell entrypoint is stow/shared/.zshrc, which sources
stow/shared/.zshrc_user. The user file loads the shell configuration chain:
shell/exports.sh— PATH (includingshell/bin/utils), globals, env varsshell/aliases.sh— shell aliasesshell/sourcing.sh— tool initialization, plugins, completions
See Project config for details on shell initialization, direnv, and per-project tooling.
Note
I'm not happy with how this is designed, see dotfiles#202.
CLI tools that come from language ecosystems rather than nixpkgs are declared
in Nix (see nix/shared/home/package-tools.nix) but installed by their native
package manager. A rebuild installs anything missing; upgrades are manual:
uv tool upgrade --all # Python tools (uv)
npm-tools-upgrade # npm tools (deno)LLM agent CLIs (claude-code, opencode,...) are the exception: they are plain Nix
packages from the llm-agents flake input, upgraded via
nix flake update llm-agents + rebuild.
- Neovim ⌨️
- My Neovim config - uses
vim.pack - Minimalistic config
- My Neovim config - uses
- Workflows 🌊
- Fonts
- Host-specific documentation
- rpi5-homelab - requires custom installation procedure
