Declarative workstation configuration for macOS and Linux using Nix, Home Manager, nix-darwin, and nix-homebrew.
New machine? Start with the first-time setup guide to choose the personal or company profile, check prerequisites, clone the stable branch, and verify the first login. The personal Nix outputs are configured for this repository's owner; the company profile takes the device's own account details.
Use the separate Company Mac profile for work. It brings over the current Mac's Pure/LazyVim preferences while separating work Git identity, history, editor state, and local settings. It uses standalone Home Manager and does not import the personal nix-darwin module or its GUI apps.
Do not activate darwinConfigurations.macbook on a company device. Supply the
company Mac's own username and home directory explicitly as described in the
guide. Work Git name/email are validated and written locally during activation;
they are not evaluated into the Nix store.
The Nix/Home Manager configuration and isolated company Mac profile are merged
into main. Use main for installation and dev for integrating changes.
- CI evaluates the personal Linux/macOS outputs and both work Mac architectures.
- Native Apple Silicon CI builds the personal nix-darwin system package without activating it.
- Native x86_64 and ARM64 Linux CI runners rehearse the personal module twice in disposable home directories.
- Native Apple Silicon and Intel macOS CI runners rehearse the work profile twice in disposable home directories, including its Git guards.
make verifychecks source and behavior in disposable home directories.- The legacy shell/Python installer remains available for the company profile.
These checks do not establish successful activation on a real workstation. Complete the device checks below before retiring compatibility paths.
| Layer | Responsibility |
|---|---|
| Nix flake | Pins configuration inputs in flake.lock |
| Home Manager | User packages, shell configuration, tmux, Neovim, and home-directory state |
| nix-darwin | macOS system integration |
| nix-homebrew | Existing Homebrew installation and declarative GUI casks |
| Legacy installer | Company profile fallback when Nix is unavailable |
| Path | Purpose |
|---|---|
flake.nix |
Defines macOS and Linux configuration outputs |
flake.lock |
Pins nixpkgs, Home Manager, nix-darwin, and nix-homebrew |
nix/home.nix |
Shared Home Manager configuration |
nix/darwin.nix |
Apple Silicon macOS configuration |
config/nvim/ |
Neovim configuration managed by Home Manager |
docs/NIX.md |
Migration details, ownership map, and rollout notes |
.github/workflows/nix.yml |
Nix evaluation and configuration validation |
The macOS configuration targets Apple Silicon and is exposed as:
.#macbook
Use main for the personal Mac configuration. For a company device, follow the
separate Company Mac profile instead:
git switch main
git pull --ff-only
nix flake check
sudo nix run nix-darwin/nix-darwin-26.05#darwin-rebuild -- \
switch --flake .#macbookDuring the first activation, Home Manager backs up conflicting managed files using the .hm-backup suffix.
The migration intentionally does not remove unlisted Homebrew software. Existing formulae and casks remain in place while the Nix configuration is proven on the workstation.
After nix-darwin is installed:
sudo darwin-rebuild switch --flake .#macbooknix flake update
nix flake check
sudo darwin-rebuild switch --flake .#macbookReview flake.lock before committing an input update.
Standalone Home Manager outputs are provided for both common architectures.
nix run home-manager/release-26.05 -- \
switch -b hm-backup --flake .#linux-x86_64nix run home-manager/release-26.05 -- \
switch -b hm-backup --flake .#linux-aarch64Home Manager currently owns:
- zsh
- Oh My Zsh
- zsh autosuggestions and syntax highlighting
- Powerlevel10k
- tmux
- tmux plugins
- Neovim configuration
~/.pylintrc- core CLI and development packages
On macOS, nix-darwin and nix-homebrew additionally manage system integration and selected GUI casks.
The repository is the source of truth. Prefer changing the declarative configuration first and then rebuilding the workstation from it.
The normal direction is:
Git repository
↓
Nix / Home Manager
↓
workstation
Avoid treating the workstation as the authoritative copy of managed configuration.
Update dev, then create a short-lived branch:
git switch dev
git pull
git switch -c codex/my-config-changeUse a focused branch name such as:
config/tmux-copy-mode
config/add-ripgrep
config/add-vscode
config/nvim-lsp
Common changes belong in these locations:
| Change | Edit |
|---|---|
| CLI/development package | nix/home.nix |
| zsh configuration | nix/home.nix |
| tmux configuration/plugins | nix/home.nix |
| Neovim configuration | config/nvim/ |
| macOS/Homebrew cask | nix/darwin.nix |
| Nix inputs | flake.nix and generated flake.lock |
| README content | README.template |
For files owned by Home Manager, edit the repository source rather than the installed path in $HOME. For example, change config/nvim/ instead of directly modifying ~/.config/nvim/.
nix flake checkFor a formatting pass:
nix fmt
nix flake checkDuring the migration, the legacy repository checks remain useful as an additional regression gate:
make verifysudo darwin-rebuild switch --flake .#macbookTest the affected tools after the rebuild. For shell or terminal changes, start a fresh shell and tmux session rather than relying only on the current process.
If the configuration needs another adjustment, edit the repository again and rerun the rebuild. Do not commit a configuration that has only passed static evaluation but has not been exercised on the workstation when the change affects runtime behavior.
git status
git diff
git diff --check
git add --patch
git commit -m "Configure <change>"
git push -u origin HEADReview flake.lock carefully whenever it changes. A package/configuration edit should not unexpectedly rewrite input revisions.
Open a pull request from the change branch into dev. After CI and the
commit-specific agent review pass, merge it into dev.
The change promotion path is:
config/* or feature branch
↓
dev
↓
real workstation validation
↓
main
main contains the stable source definition. A merge or passing CI does not
replace runtime validation on the affected workstation.
Prefer nixpkgs for command-line and development tools.
Add the package to home.packages in nix/home.nix:
home.packages = with pkgs; [
jq
ripgrep
];Then validate and rebuild:
nix flake check
sudo darwin-rebuild switch --flake .#macbookGUI applications that are intentionally kept in Homebrew belong in the cask list in nix/darwin.nix:
homebrew.casks = [
"rectangle"
"visual-studio-code"
];Then rebuild with the same darwin-rebuild command.
Nix does not automatically export workstation changes back into Git.
If software or configuration is changed directly on the host, decide whether that change should be permanent. If it should, translate it into the appropriate repository configuration and rebuild.
For example, after a manual:
brew install --cask visual-studio-codeadd the cask to nix/darwin.nix, run nix flake check, rebuild, and commit the declarative change.
The same rule applies to manually installed CLI tools, shell changes, tmux changes, and managed dotfiles. A manual host change is temporary until it is represented in the repository.
Before pushing a workstation change, this is a useful audit sequence:
git status
git diff
nix flake check
sudo darwin-rebuild switch --flake .#macbookThen verify the affected behavior and commit the source configuration.
Homebrew is not being removed.
It remains useful for macOS GUI software while command-line and development tooling moves toward nixpkgs. The current migration uses:
homebrew.onActivation.cleanup = "none";That prevents the first activation from deleting Homebrew software that has not yet been classified into the Nix configuration.
Once the migration is proven, the remaining Homebrew inventory can be reviewed and either moved into Nix, retained as a cask, or removed.
Run the Nix checks locally with:
nix flake check
nix fmtCI also evaluates the complete Linux Home Manager configuration and Apple Silicon nix-darwin system derivation.
The existing repository quality gates remain active during the migration:
make verifyThose checks cover:
- checkmake
- shellcheck
- luacheck
- pyright
- unit tests
- integration tests
When Nix is unavailable on an approved company device, follow the identity setup in Company Mac setup before running:
make dependencies
make install-work
make verify-installmake install also selects the company profile. These commands do not restore
the personal Nix configuration. Retain previous Nix generations and Home Manager
backups for recovery, and review them before restoring files.
Do not delete the legacy installer, its package inventories, or its compatibility tests until the relevant device installation has been verified.
The source migration is merged. Personal Mac activation remains a separate verification step, with these completion criteria:
darwin-rebuild switch --flake .#macbooksucceeds on the real Mac.- zsh starts normally.
- tmux loads its expected plugins and bindings.
- Neovim starts with the existing configuration.
- expected CLI development tools are available.
- Homebrew GUI applications remain intact.
- a second rebuild completes cleanly and demonstrates idempotence.
After that, the legacy shell/Python installer and obsolete package inventory files can be removed in a separate cleanup change.
main— stable configurationdev— integration branchcodex/*— short-lived feature branches merged intodev