Acquiring good taste comes through using various things, discarding the ones you don't like and keeping the ones you do. if you never try various things, you will not acquire good taste.
And what I mean by taste here is simply the honed ability to distinguish mediocrity from excellence. This will be highly subjective, and not everyone's taste will be the same, but that is the point, you should NOT have the same taste as someone else.
Question the status quo, experiment, break things, do this several times, do this everyday and keep doing it.
My nix-darwin and NixOS configuration.
My daily driver is macOS because I prefer the Apple desktop environment. There are also a NixOS homelab server (running as a Proxmox VM) and NixOS VM setups mainly for experiments.
- Nix flakes provide a reproducible, pin-exact configuration shared across all machines.
- On macOS, nix-darwin manages system-level settings and packages declaratively.
- home-manager manages the user environment (dotfiles, packages, shell) across both macOS and NixOS hosts.
- Terminal: Rex
- Font: Berkeley Mono™ Typeface
- General zsh configuration:
- Prompt: Starship with a customized Pure prompt
- Theme: Catppuccin Macchiato (Blue accent wherever available)
- A number of handy aliases and functions and shell scripts
- Automatic shell proxy propagation from macOS settings
- Completion tuning: case-insensitive and partial-word matching (
hx h/m/zs→home/modules/zsh.nix); Tab twice for spelling corrections and approximate matches
- CLI apps of choice:
- Editor: Helix
- Shell History: Atuin
- File Manager: Yazi (invoke with
yfor shell integration) - Directory Navigation: zoxide
- fzf shell integration (config)
- CTRL-T - Full-screen file picker (streamed from
fd) with a file/directory preview; Tab to multi-select, CTRL-O to open the selection in$VISUAL - ALT-C - cd into the selected directory, with a tree preview
- In any fzf:
?toggles the preview, ALT-↑/↓ pages through it
- CTRL-T - Full-screen file picker (streamed from
- fzf-tab for fuzzy-searching zsh completion results, in the same Catppuccin theme, with context-aware previews:
- Files and directories (
cd,hx,bat,ls,mv, …): syntax-highlighted via lesspipe + bat, or anezatree - git:
deltadiffs foradd/diff/restore(untracked files show their contents), commits forshow/checkout/log manpages,docker(subcommand help, logs, images, inspect JSON),brew info, process details forkill, andsystemctl statuson Linux- Command names (tldr) and variable values (
echo $<Tab>) </>switch between completion groups
- Files and directories (
- Per-project environments: direnv + nix-direnv (cached devshells that survive GC)
- Git:
- TUI: lazygit (a quick starter video)
- Diffs: delta everywhere:
git, lazygit, and fzf-tab previews - Merges: mergiraf as a syntax-aware merge driver
- Secrets: agenix, decrypted with an identity held in 1Password via age-plugin-1p, so no private key on disk
- macOS: system and app preferences (Dock, Finder, keyboard, trackpad, Safari, third-party apps…) set declaratively via nix-darwin; GUI apps via Homebrew
Custom Zsh keybindings are configured in home/modules/shell/keys.zsh.
This is designed to work with default Ghostty macOS keybindings, or the iTerm2 Natural Text Editing keymappings preset.
Keybinding Reference
| Key Combo | Description |
|---|---|
Ctrl+U |
Delete everything to the left of the cursor |
Ctrl+X then Delete |
Delete entire line to the left of cursor |
Ctrl+B |
Jump to beginning of line |
Alt+Q |
Push aside current command line to type a new one (re-inserted on next prompt) |
Ctrl+X then Ctrl+_ |
Redo last undone edit |
Ctrl+X then Ctrl+E |
Edit current command line in $EDITOR |
Alt+V |
Show next key combo's terminal code and description |
Alt+Shift+S |
Prefix current/previous command with sudo |
Shell functions are defined in home/modules/shell/functions.zsh.
A non-exhaustive list:
Video & Media
burnsrt <input.mp4> <input.srt> <output.mp4>- Burn SRT subtitles into MP4 videoshrinkvid <input> <output> [bitrate]- Compress video (uses hardware acceleration on macOS)impaste > file.png- Output clipboard image data to stdoutfavicon <input.png>- Generate multi-size favicon.ico from an imagedirtypdf <input.pdf> <output.pdf>- Apply scanner effect to a PDF
Development & Git
gg <repo-url>- Clone repo and cd into itaic- Generate conventional commit message using LLMs from staged changese [file]- Edit file with$VISUAL, or open current directory if no arguments <pattern>- Search in files and visualize with Delta
Directory & File Management
take <dir>- Create directory and cd into it (equivalent tomkdir -p && cd)tt- Create and cd into a temporary directorycdls <dir>- Change to directory and list its contentsdecrypt_pdfs <password>- Decrypt all PDFs in current directory
Network & Diagnostics
t <host>- Traceroute with Trippy (auto-updates GeoIP database)tu <host>- UDP traceroute with Trippyhttps <domain> [port]- Show TLS certificate details (default port: 443)ttfb <url>- Measure Time To First Byte with curllistening [pattern]- List all processes listening on TCP portspingu <host>- Ping until success or cancelledlip <ip>- Lookup IP address detailsdns <domain>- Lookup IP address of domain's A record
Nix Utilities
nix-pkgdir <package>- Get the Nix store path for a packagenr <package> [args...]- Run a package from nixpkgs-unstable without installingns <pkg1> [pkg2...]- Start a shell with packages from nixpkgs-unstable
Commonly used commands in justfile
# Switch darwin configuration
just switch
# Updates all flake inputs
just update
# Updates one flake input
just update-input <flake-input-name>
# For more, run `just` to get all recipes.Installation instructions on a new macOS machine without Nix installed
Make sure the username aligns to the one specified in flake.nix (ale).
Full Disk Access has to be enabled for the terminal app via System Settings > Privacy & Security > Full Disk Access to overcome Could not write domain com.apple.universalaccess; exiting when applying user defaults.
xcode-select --install
# Install Homebrew (manages GUI apps)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install 1Password and login manually so credentials are present
brew install --cask 1password
# Clone the dotfiles
mkdir $HOME/.config
git clone https://github.com/birkhofflee/dotfiles $HOME/.config/dotfilesInstall Determinate Nix using the macOS package, then:
# Temporarily mitigate 'too many open files' issue
# @see https://github.com/NixOS/nix/issues/6557
ulimit -n 4096
# Pre-seed GitHub's SSH host key so the private secrets input doesn't stall
mkdir ~/.ssh
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
# Add the current user to trusted-users so --accept-flake-config is honoured,
# allowing Nix to use the binary caches declared in the flake's nixConfig.
echo "trusted-users = $USER" | sudo tee -a /etc/nix/nix.custom.conf
# Activate the configuration
nix run nixpkgs#nh -- darwin switch $HOME/.config/dotfiles --hostname AlexMBP --accept-flake-configApplying the home config on a generic Linux host (e.g. WSL)
On a non-NixOS distro only the user environment is managed, via a standalone home-manager configuration: homeConfigurations."ale@wsl" in flake.nix. It assumes x86_64-linux and the username ale (home at /home/ale); copy the output and adjust system / currentSystemUser for other boxes.
Compared to the other hosts it leaves out agenix secrets and the 1Password and Ghostty modules, and doesn't manage ~/.ssh/id_ed25519.pub so the host can keep its own key pair.
Install Determinate Nix (on WSL2, enable systemd in /etc/wsl.conf first), then:
curl -fsSL https://install.determinate.systems/nix | sh -s -- install
# Pre-seed GitHub's SSH host key so the private secrets input doesn't stall
mkdir -p ~/.ssh
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
# Add the current user to trusted-users so the flake's binary caches are honoured
# (otherwise e.g. Helix is compiled from source). Answer `y` to the trust prompts
# on the first switch.
echo "trusted-users = root $USER" | sudo tee -a /etc/nix/nix.custom.conf
sudo systemctl restart nix-daemon
# Activate the configuration
nix run nixpkgs#nh -- home switch github:birkhofflee/dotfiles -c ale@wsl --no-nom -- --refresh
# home-manager can't change the login shell outside NixOS
command -v zsh | sudo tee -a /etc/shells
chsh -s "$(command -v zsh)"Afterwards, nh is installed by the config itself, so updates are just nh home switch github:birkhofflee/dotfiles -c ale@wsl --no-nom -- --refresh.
Notes:
--refreshmakes Nix re-fetch the repo; otherwise agithub:flake ref is cached for up to an hour and a freshly pushed commit is silently ignored.--no-nomworks around nix-output-monitor#320 (nom 2.2.0 can't parse Determinate Nix's newer log events). The fix is merged upstream but unreleased; drop the flag once nixpkgs ships a newer nom.- If activation fails with
Existing file ... would be clobbered, move that file out of the way (or pass-b backup), after checking it isn't something the host needs.
Provisioning nixos-desktop-01 (NixOS desktop VM)
nixos-desktop-01 is a Proxmox KVM VM with GNOME DE. Remote desktop is provided by Gnome Remote Desktop on port 3389 (RDP).
List of RDP clients available on macOS
# Syncs working tree to nixos-server-01 and builds there (x86_64-linux).
just build-desktop-imagersync -avz /tmp/dotfiles-build/result/vzdump-qemu-nixos-desktop-01.vma.zst root@homelab-nuc:/var/lib/vz/dump/# SSH into homelab-nuc
# Assuming VM ID 201
# Stop the current VM
qm stop 201
# This creates (or replaces) VM 201 with our image.
# QEMU config is baked in. Starts the VM afterwards.
qmrestore /var/lib/vz/dump/vzdump-qemu-nixos-desktop-01.vma.zst 201 \
--unique true \
--storage local-lvm \
--force \
--start--unique true is required — the image has a zeroed MAC address by default.
Once the VM is up, it should be connected to Tailscale automatically (if the authkey given was valid).
If RDP fails somehow:
- RDP client-side config
use redirection server name:i:1may be required to connect. - On macOS, try to use Thincast Remote Desktop Client instead.
- SSH to the VM and check status using
sudo grdctl --system,ss -tlnp | grep 3389,sudo systemctl status gnome-rdp-setup gnome-remote-desktop
just switch-nixos-desktopHere are some reads you might find interesting:
- Faster and enjoyable ZSH (maybe)
- Comparison of ZSH frameworks and plugin managers
- fzf examples (fzf wiki)
- A simple dotfiles template to kick-start/bootstrap your zsh config
Some completions setups:
- https://github.com/mashehu/dotfiles/blob/236af8d7d71989f9755a6ea29ee66e33cbbce1f8/zshrc#L89-L105
- https://github.com/finnurtorfa/zsh/blob/master/completion.zsh
This project was heavily inspired by other open-source dotfiles. A non-exhaustive list:
- mitchellh/nixos-config
- malob/nixpkgs
- ahmedelgabri/dotfiles
- kornicameister/dotfiles
- Aloxaf/dotfiles
- paulmillr/dotfiles
- mashehu/dotfiles
- finnurtorfa/zsh
Credits are given in the source code where applicable.
This project is released under the MIT License.
