Skip to content

Repository files navigation

dotfiles

Declarative personal setup for Apple Silicon macOS using nix-darwin, Home Manager, nix-homebrew, and Homebrew casks. A standalone Linux Home Manager configuration is also included.

Nix packages and configuration are pinned by flake.lock. Homebrew casks are intentionally used for self-updating GUI applications, so their exact versions are not pinned. Secrets and private machine data never belong in this repository.

Bootstrap a Mac

During Setup Assistant, create the first macOS account with the short name gwku and enable FileVault. Store its recovery key somewhere secure and outside this repository. Then run:

xcode-select --install
git clone https://github.com/gwku/dotfiles.git ~/development/dotfiles
cd ~/development/dotfiles
./install.sh gkmp

After the installer succeeds, continue with the complete POST-INSTALL.md checklist. It covers the first restart, Mac App Store and Bitwarden sign-in, SSH, privacy approvals, developer credentials, SDKs, application data, code-managed macOS policy, and final verification.

The installer:

  1. installs Determinate Nix when necessary;
  2. verifies that the configured macOS account exists;
  3. uses the nix-darwin revision pinned by this flake;
  4. activates nix-darwin and Home Manager.

The installer front-loads macOS administrator authentication and keeps that authorization alive during the build. If Xcode command-line tools are missing, it starts Apple's installer and asks you to rerun after it finishes. If the Bitwarden CLI is already configured but locked, its unlock also happens before the long switch starts. Once preflight is complete, the Nix/Homebrew activation itself is non-interactive.

End-to-end bootstrap is not completely unattended: Mac App Store applications require an Apple ID sign-in and the separate command below, and a clean machine still needs one-time Bitwarden desktop/CLI login and SSH-agent setup after activation. FileVault enrollment belongs in Setup Assistant because it creates credential-bound recovery material; the runtime test verifies that it remains enabled.

After signing into the Mac App Store, restore the declared App Store applications:

./scripts/install-mas-apps.sh

This installs Amphetamine, HP Smart, Keynote, Microsoft Word, Numbers, Pages, Todoist, and WireGuard. It is deliberately separate from activation so a clean VM build never needs Apple ID credentials.

This repository standardises on Determinate Nix. Its official nix-darwin module prevents nix-darwin from trying to replace the Determinate-managed daemon and declares the additional Nix settings used by this setup.

Bootstrap Linux

The Linux target manages the user environment with standalone Home Manager; it is not a complete NixOS system configuration. On an x86-64 Linux machine, install Nix if the machine does not already provide it, then run:

curl --proto '=https' --tlsv1.2 -sSf -L \
  https://install.determinate.systems/nix | sh -s -- install
git clone https://github.com/gwku/dotfiles.git ~/development/dotfiles
cd ~/development/dotfiles
nix run path:.#home-manager -- switch --flake path:.#gwku@workstation
./scripts/smoke-test.sh

On NixOS, use the existing system Nix installation and start with the clone. The same Home Manager target can be imported into a future NixOS system configuration if system-level NixOS management is added later.

Maintenance and updates

These commands are not a daily routine. Normal computer use requires no Nix maintenance. Run them only after changing or pulling this repository, when deliberately updating pinned dependencies, or when troubleshooting.

# Test changes without activating them
./scripts/check.sh gkmp

# Apply repository changes to this Mac
./scripts/switch.sh gkmp

# Periodically update pinned Nix inputs, test, and then apply
nix flake update
./scripts/check.sh gkmp
./scripts/switch.sh gkmp

# Troubleshooting: inspect or roll back to an older Mac generation
darwin-rebuild --list-generations
sudo darwin-rebuild --switch-generation <generation>

Fish provides a few optional abbreviations:

  • drs applies this Mac's configuration (macOS only);
  • hms applies the standalone Home Manager configuration (Linux only);
  • nfu updates the repository's pinned Nix inputs;
  • nfc checks the repository's flake.

The abbreviations use the repository at ~/development/dotfiles, so they work from any directory. Updating inputs can change many package versions; review flake.lock, run the checks, and switch only when you intend to upgrade.

The Homebrew declaration is exhaustive: activation runs an explicit, non-zapping brew bundle cleanup --force, so formulae and casks removed from the declaration are also removed from the machine while their user data is preserved. Close Homebrew-managed applications before switching.

On an existing Mac, first complete a successful switch. Then remove the privileged leftovers that Homebrew cannot own:

./scripts/finish-current-mac-cleanup.sh

The script moves obsolete Docker launch daemons and privileged helpers to the Trash, asks macOS to garbage-collect extensions, and tells you if a reboot is needed. It never deletes the archive directly.

Testing

Run the non-activating checks first:

nix flake check path:. --all-systems --no-build
nix build path:.#darwinConfigurations.gkmp.system

For a clean-machine test on Apple Silicon:

./scripts/test-vm.sh --switch --stop-after

The VM test installs Determinate Nix, builds the full configuration, performs a real switch, and runs the runtime smoke tests. It is still important to test a fresh VM rather than relying only on a previously mutated dotfiles-test VM.

After activation, run:

./scripts/smoke-test.sh

SSH without secrets in Git

Bitwarden is the source of truth for private SSH keys and private host metadata. Home Manager:

  • points OpenSSH at the Bitwarden desktop SSH-agent socket;
  • installs bw-ssh-sync;
  • includes the generated ~/.ssh/config.bitwarden;
  • synchronizes metadata in the switch preflight, prompting before the build when the CLI is logged in but locked.

Private keys are never written by Nix or bw-ssh-sync. The sync command writes only public-key selector files under ~/.ssh/bitwarden/ and Host blocks generated from Bitwarden custom fields.

First setup on a Mac

  1. Open the Bitwarden desktop application, sign in, enable its SSH agent, and allow Bitwarden to remain open in the background.
  2. Log the CLI into the same account once with bw login.
  3. Run bw-ssh-sync. If the CLI vault is locked, it prompts to unlock it for that command.
  4. Verify the agent and a configured host:
ssh-add -L
ssh -G github.com

Every native Bitwarden SSH item is offered by the desktop agent automatically; there is no hardcoded key list in this repository. Host aliases require metadata because a key alone cannot reveal its hostname, username, or port.

Bitwarden SSH item metadata

Add a Text custom field named ssh_config to any SSH item that needs one or more host aliases. Use {{identity_file}} where the generated public selector belongs:

Host example
  HostName example.internal
  User deploy
  Port 22
  IdentityFile {{identity_file}}
  IdentitiesOnly yes

Run bw-ssh-sync after adding or changing an item. The command discovers all SSH items dynamically, validates each public-key fingerprint, regenerates the config atomically, and removes stale generated selector files. Custom fields such as source_path, public_key_comment, and host_aliases are retained as provenance but are not required at runtime.

scripts/switch.sh prompts for bw unlock before building when the CLI is logged in but locked. Home Manager activation always uses the non-interactive mode, preserving the last generated configuration when the CLI is locked or has never logged in. The repository contains neither secret blobs nor vault credentials.

State restored outside Nix

Nix does not reproduce credentials, application databases, or cloud accounts. Follow the ordered POST-INSTALL.md checklist after a clean bootstrap. UNMANAGED.md explains why that state remains external. Important examples include:

  • enabling Bitwarden's desktop SSH agent and running bw-ssh-sync;
  • AWS, Kubernetes, GitHub CLI, GPG, and Stripe authentication;
  • Android SDK platforms, system images, and accepted licences;
  • application sign-ins and synced IDE/editor settings;
  • network/peripheral enrollment and a credential-bound Time Machine destination.

Public Cursor extensions, Shopify CLI 4.5.2, and Google Lighthouse 13.4.1 are pinned by the flake. Cursor's bundled anysphere.* extensions continue to ship with Cursor itself.

Home Manager uses the backup suffix .hm-backup when taking over an existing file. Inspect those backups after the first successful switch and remove them only after confirming the managed replacement works.

Hosts

  • gkmp — Apple Silicon MacBook
  • workstation — x86-64 Linux placeholder

About

Declarative personal macOS and Linux setup with Nix, nix-darwin, Home Manager, and Homebrew.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages