Personal Linux workstation configuration managed with Nix, Home Manager, and a small set of explicit host-level scripts.
The day-to-day development setup is documented in DEVELOPMENT.org.
home.nixowns development and terminal packages, program configuration, session variables, Firefox policy, the declarative Noctalia base, and Home Manager links.niri/,foot/,herdr/, the shell/editor files, andurlsare copied bymake sync.- The host dependency scripts provision GUI applications, the Niri desktop runtime, networking, Bluetooth, audio, power, portals, and the firewall. Home Manager supplies the matching configuration without duplicating those packages in the Nix profile.
keyd.nixandbin/keyd-systemown a separate root Nix profile for the keyd daemon and its generated system configuration.- Noctalia keeps GUI changes in
~/.local/state/noctalia/settings.toml; those mutable values override the declarative defaults inhome.nix.
Install the distro-managed GUI applications, desktop runtime, and host services:
make install-system-deps-arch
# or, on Ubuntu 26.04:
make install-system-deps-ubuntu26Bootstrap Home Manager from the repository flake. Existing conflicting files
are preserved with the backup suffix on this first activation:
make prepareCheck that the expected workstation commands are available:
make doctorThe normal update cycle is:
make check
make sync
make switchmake sync copies repository-managed dotfiles and helper commands into their
live locations. It also links the shared manage-makefile and
tiger-style-java skills into the global Codex and Claude skill directories.
make switch applies the Home Manager configuration directly from this
repository through nix run home-manager/master and a path: flake reference.
It does not require a prior copy into ~/.config/home-manager.
Run both operations together when the final diff has already been reviewed:
make applymake prepare, make sync, make switch, and make apply do not install
host packages, change the firewall, deploy keyd, or restart the Niri session.
Niri uses stable workspace names instead of application-derived workspaces:
| Key | Workspace | Default role |
|---|---|---|
| Mod-1 | build | Primary editing and implementation |
| Mod-2 | debug | Tests, logs, and debugging |
| Mod-3 | review | Diffs, browsers, and review |
| Mod-4 | ops | Operations and system tools |
| Mod-5 | comm | Slack and communication |
| Mod-6 | write | Notes and Obsidian |
| Mod-7 | scratch | Temporary work on the laptop display |
The horizontal 27-inch display is the focus canvas for build, debug, and
review. The vertical display carries ops, comm, and write. The laptop
display carries scratch. Use Mod-Ctrl-1 through Mod-Ctrl-7 to move the
current column to a named workspace.
Important desktop bindings:
| Binding | Action |
|---|---|
Mod-T | Open Foot |
Mod-Shift-T | Open Herdr in Foot |
Mod-D | Toggle the Noctalia launcher |
Super-B | Toggle the Noctalia bar |
Mod-S | Open the Noctalia control center |
Mod-Ctrl-V | Open clipboard history |
Super-Alt-L | Lock the session |
Mod-Shift-/ | Show Niri’s full hotkey overlay |
Noctalia v5 owns the bar, launcher, wallpaper, notifications, clipboard history, lock screen, OSDs, and control center. Niri starts its daemon when the session begins. Foot is the default terminal, and Firefox is the default browser for HTML and HTTP(S) links.
After applying desktop configuration, restart the Niri session when a setting cannot be reloaded in place. Useful diagnostics:
niri validate -c niri/config.kdl
niri msg outputs
noctalia config validate
noctalia msg --help
journalctl --user -b | rg noctaliaThe expected host services are NetworkManager, Bluetooth, UPower, power-profiles-daemon, PipeWire/WirePlumber, GNOME Keyring Secret Service, polkit, and an XDG desktop portal. Check the persistent and user services with:
systemctl is-enabled NetworkManager bluetooth power-profiles-daemon ufw
systemctl --user status pipewire-pulse wireplumberHome Manager installs the keyd CLI. The daemon and generated
/etc/keyd/default.conf are built from the structured mappings in keyd.nix
and kept in a root Nix profile.
Caps Lock sends Escape when tapped and activates the navigation/editing layer
when held. Escape sends Caps Lock. The layer provides arrows, page movement,
Home/End, Delete, Backspace, Enter, Tab, and Shift. The Caps-layer a mapping
to Alt is intentionally disabled. AltGr retains the explicit accent and macro
mappings defined in keyd.nix.
Build and apply a generation explicitly:
make switch-keydThe first switch preserves an existing configuration as
/etc/keyd/default.conf.pre-nix. Roll back one generation with:
make rollback-keydInspect the live service and generated configuration with:
systemctl status keyd
readlink -f /etc/keyd/default.conf
keyd check /etc/keyd/default.confIf a bad mapping captures the keyboard, press Backspace+Escape+Enter to stop
keyd. The distribution-provided keyd package can be removed after confirming
that the service runs from the Nix profile.
make sync-bin installs rssadd and rssget into ~/.local/bin. rssadd
adds a URL and optional tags to the repository-managed Newsboat list, rejects
duplicates, sorts the file, and updates the live ~/.newsboat/urls copy.
rssget discovers feeds from a URL or the Wayland clipboard, uses Fuzzel when
several feeds are available, and delegates the selected feed to rssadd.
rssadd https://example.com/feed.xml "tech"
rssget https://example.com "tech"
rssget # use the current clipboard URLbin/cpu-throttle is a repository-local Intel P-state utility; it is not
installed by make sync. It uses sudo to switch to power-saver mode, disable
Turbo Boost, and cap performance at 60 percent. Disable restores Turbo Boost,
the 100 percent cap, and the balanced profile.
./bin/cpu-throttle status
./bin/cpu-throttle enable
./bin/cpu-throttle disableThe workstation toolset is grouped below. Development and terminal tools come from Home Manager; GUI applications and desktop runtime packages come from the distribution installers unless noted otherwise.
- Shell and navigation: Zsh, Starship, direnv with nix-direnv, zoxide, tmux, Herdr, nnn, fzf, plocate, tree, bat, eza, fd, ripgrep, ast-grep, jq, distro-managed yq, glow, tldr, and fastfetch.
- Files, downloads, and archives: wget, curl, aria2, HTTPie, Curlie, file, zip, xz, unzip, p7zip, zstd, GNU sed/tar/awk, and GnuPG.
- Monitoring and diagnostics: htop, btop, ncdu, duf, iotop, iftop, sysstat, lm_sensors, lsof, strace, ltrace, hyperfine, mtr, iperf3, dnsutils, ldns, socat, nmap, ipcalc, ethtool, pciutils, and usbutils.
- Development and review: Nix, Home Manager, Git, GitHub CLI, GitLab CLI, Difftastic, GNU Make, ShellCheck, shfmt, watchexec, mise, lazygit, lazydocker, Emacs, Neovim, VS Code, and Gum.
- Language tooling: JDT LS, google-java-format, Spring Boot CLI, clang-tools, ZLS, yaml-language-server, nixd, and rust-analyzer. Java projects obtain their JDK and build tools through Mise.
- Documentation and media: Hugo, Graphviz, TeX Live, and the distro-managed Obsidian, VLC, Xournal++, Pinta, Flameshot, and LocalSend.
- Privacy and secrets: Firefox, distro-managed KeePassXC, age, SOPS, Restic, Gitleaks, MAT2, and uBlock Origin plus KeePassXC-Browser Firefox extensions.
- Desktop runtime: distro-managed Niri, Noctalia, Foot, Fuzzel, wl-clipboard, and xwayland-satellite, plus the Nix-managed keyd CLI and Symbols Nerd Font glyph set.
- Small baseline utilities retained for direct use include
whichandcowsay.
The distribution-level installers add the GUI applications, desktop runtime,
services, portals, audio and Bluetooth stack, accessibility support, EGL/Mesa
dependencies, ddcutil, and UFW. They intentionally keep these host concerns
outside Home Manager.
Firefox installs uBlock Origin and KeePassXC-Browser from Mozilla Add-ons. In
KeePassXC, enable Browser Integration -> Firefox once, then pair the extension
with the unlocked database. KeePassXC owns its mutable settings and databases;
the distro owns the package and Home Manager owns the native-messaging
manifest.
Restic repositories are operator-selected. Initialize one on an external or remote mount, run a backup, verify it, and test a restore before depending on it:
restic -r /mnt/backup/restic init
restic -r /mnt/backup/restic backup "$HOME"
restic -r /mnt/backup/restic check --read-data
restic -r /mnt/backup/restic restore latest --target /tmp/restic-restoreDo not put the repository password in this repository. Restic prompts when no password source is configured. Back the password up separately from the Restic repository.
Create an age identity outside Git before adding SOPS-encrypted secrets to a
project. Back up the identity separately, use the printed public recipient in
that project’s .sops.yaml, and commit only SOPS-encrypted files:
install -d -m 0700 "$HOME/.config/sops/age"
age-keygen -o "$HOME/.config/sops/age/keys.txt"
chmod 0600 "$HOME/.config/sops/age/keys.txt"Scan committed history for secrets and make a metadata-cleaned copy before sharing a supported document or image:
make secrets-check
mat2 document.pdfThe host dependency installers configure UFW with default-deny inbound traffic, rate-limited SSH, and LocalSend on TCP/UDP port 53317. They preserve unrelated rules rather than resetting the firewall. Docker-published ports can bypass UFW; bind development services to loopback unless they are intentionally exposed.
VPN provider configuration, Tor routing, USBGuard, DNS proxies, and automated Restic credentials remain explicit operator choices rather than workstation defaults.
Show the available repository operations and the current Git state with:
make help
make statusRun make check after changing repository-managed configuration or scripts and
review the final diff before applying it. Do not use make sync or make
switch as validation commands: both change the live home environment.