My dotfiles for my NixOS setup: the dotfiles root. This repo holds the
files; it does not place them. Home-manager, in the
NixOS config, wires them into $HOME.
Each top-level dir is one application's package. Its tree mirrors where the
files appear under $HOME:
<pkg>/.config/<app>/... → ~/.config/<app>/...
Which paths are actually linked is the link set, declared in
homes/modules/dotfiles.nix: a shared layer every host gets, plus a
per-host layer on top. A file here that no entry names is not linked anywhere;
adding a package means adding an entry there and rebuilding once.
The links are out-of-store symlinks: ~/.config/<app> resolves to this
directory, not to a copy in the Nix store. Editing a file here takes effect
immediately, with no rebuild, and applications that rewrite their own config
keep working. That is deliberate — store copies were considered and rejected
for machines I sit at, so don't "fix" it. See the NixOS config's
ADR-0001 for the reasoning and the
glossary for the terms.
This directory must exist at ~/dots before the first rebuild. Syncthing
is what puts it there. Nix cannot verify it: if it is missing, the rebuild
succeeds anyway, every link dangles silently, and the applications fail
obscurely (defaults, or errors reading their config) rather than loudly.
| Pkg | App | Linked | Notes |
|---|---|---|---|
fish |
fish shell | ~/.config/fish/ |
Vi keys, zoxide-shadowed cd, FZF widgets, custom yt_chat / yt_summarize functions wrapping the claude CLI. |
niri |
niri Wayland compositor | ~/.config/niri/, plus ~/.config/niri-host.kdl |
config.kdl includes split files under dms/ (binds, outputs, windowrules, …). Driven by DMS. Each host gets its own host/<host>.kdl (layout, touchpad) at the canonical name niri-host.kdl. |
DankMaterialShell |
DMS niri shell | ~/.config/DankMaterialShell/ |
Settings, themes, plugin metadata. |
nvim |
Neovim | ~/.config/nvim/ |
LazyVim base. User plugins in lua/plugins/, config in lua/config/. |
wezterm |
WezTerm | ~/.config/wezterm/ |
wezterm.lua loads keys.lua and sets color_scheme = "dank-theme" from colors/dank-theme.toml. |
herdr |
herdr agent multiplexer | config.toml only |
See note below. |
git |
git | config and ignore only |
The directory takes git's runtime state (credential store, gitk), so the two files are linked alone. |
qutebrowser |
qutebrowser | ~/.config/qutebrowser/, plus userscripts/ |
Multi-file config split across appearance, privacy, filepicker, binds, search_engines. Themes under themes/. Only userscripts/ is linked under ~/.local/share/qutebrowser, whose history and caches stay out of here. See deps below. |
mpv |
mpv | ~/.config/mpv/ |
mpv.conf + input.conf. |
Directories are linked whole unless they hold runtime state, because an application that saves by writing a temp file and renaming it over the target destroys a file-level link.
Note
~/.config/herdr/ is also herdr's runtime state dir (*.sock, session.json, logs), so only config.toml is linked rather than the whole directory.
syncthing/— Shared.stglobalignoreacross all Syncthing folders/hosts. Not in the link set; placed by hand per Syncthing folder — seesyncthing/README.md.helium/— Browser extension settings (vimiumc), imported by hand in the browser rather than linked.wallpapers/— Wallpapers, stored as lossless JPEG XL in Git LFS (needsgit-lfs;.githooks/pre-pushuploads them). DMS points at them directly via its savedwallpaperPath, so nothing links them.docs/— Written for agents working in this repo, not symlinked anywhere.agents/says where issues live and how the triage labels and domain docs are read;adr/records decisions that are hard to reverse..claude/— Repo-specific Claude Code skills, one per package. The global ignore drops/.claudewholesale, so.gitignorere-includesskills/on its own..githooks/— Pre-commit syntax/format checks for staged configs (stylua,fish -n,niri validate, …). Enable once per clone withgit config core.hooksPath .githooks.screenshots/— Preview images.
Config directories are linked whole, so anything an application writes at runtime lands here too. That is contained with ignore rules rather than by linking individual files:
- git —
.gitignore, sogit statusreports only what is authored here. - Syncthing —
syncthing/.dotsignore, so each host keeps its own copy instead of receiving the other's.
Both lists must stay in step. The load-bearing case is
niri/.config/niri/dms/outputs.kdl: DMS regenerates it from the compositor's
live outputs, so syncing it hands the laptop the desktop's monitor layout.
| qutebrowser (everforest) | menu |
|---|---|
![]() |
![]() |
Detach videos (download + play locally):
Bitwarden:
- rofi
- tldextract
- pyperclip
- bitwarden-cli
Note
Bitwarden setup still flaky — slow, doesn't autofill on many sites. Testing rbw workaround
Adblock:
- adblock
- Run
:adblock-updatein qutebrowser to refresh lists.
Spellcheck (en-US):
"$(find "$(nix-store --query --outputs "$(which qutebrowser)")" -iname 'dictcli.py' | head -1)" install en-US
