The goal of this repository is to manage distinct systems using a single Git repository and Flake:
- MacBook Pro 14 (macOS): Hostname
mbp-14. Uses nix-darwin for system-level configuration (including hostname management) and Home Manager (as a module) for user tools and dotfiles. - HP Z2 Mini G1a (NixOS): Hostname
z2-mini. Uses NixOS for system configuration and Home Manager (as a module) for user configuration.
Key Philosophy: "Write once, run everywhere" for user tools (Neovim, Zsh, Git, etc.), while keeping system-specific configurations (disk mounts, networking, macOS settings) separate.
This repository uses a modular structure to maximize code reuse:
.
├── .envrc # Direnv configuration (auto-loads dev shell)
├── lefthook.yml # Git hooks (formatting, linting)
├── flake.nix # Entry point for all systems
├── flake.lock
├── modules/
│ └── home/
│ ├── default.nix # Imports all common modules
│ ├── core.nix # Shells, Git, common packages
│ ├── neovim.nix # Neovim config
│ └── gui.nix # GUI tools (Ghostty, etc.)
├── hosts/
│ ├── mbp-14/ # macOS specific configs (MacBook Pro 14)
│ │ ├── configuration.nix# System-level config (nix-darwin)
│ │ └── home.nix # macOS-specific home overrides
│ └── z2-mini/ # NixOS specific configs (HP Z2 Mini G1a)
│ ├── configuration.nix# System-level config
│ ├── hardware-configuration.nix
│ └── home.nix # NixOS-specific home overrides
The flake.nix produces two types of outputs:
nixosConfigurations: For thez2-minimachine.darwinConfigurations: For thembp-14machine.
Concept:
- Shared Inputs: Both systems share
nixpkgsversions viaflake.lock. - NixOS (
z2-mini): Implements Home Manager as a system module for atomic updates. - macOS (
mbp-14): Implements nix-darwin with Home Manager as a system module for atomic updates.
modules/home/core.nix: Contains the bulk of user configuration (Packages, Shells, Git, etc.).- Host Specifics:
home.usernameandhome.homeDirectoryare defined inhosts/<machine>/home.nixto allow portability.
- YubiKey SSH Guide: Instructions for setting up FIDO2-based SSH authentication for passwordless, secure access to remote machines.
Use darwin-rebuild to update both system and user configurations.
# From local source
$ sudo darwin-rebuild switch --flake .#mbp-14
# Directly from GitHub (useful for bootstrapping)
$ sudo nix run nix-darwin -- switch --flake github:wjkoh/nix-config#mbp-14# From local source
$ sudo nixos-rebuild switch --flake .#z2-mini
# Directly from GitHub
$ sudo nixos-rebuild switch --flake github:wjkoh/nix-config#z2-mini- Single Source of Truth: Change configuration once, propagate to all machines.
- Shared Lockfile: Ensures identical tool versions across macOS and Linux.
- Atomic Updates: On NixOS, system and user configs update synchronously.
After applying the configuration, some manual steps are required:
- macOS (
mbp-14): Tailscale is installed automatically via the Mac App Store. Open the app to authenticate. - NixOS (
z2-mini): Tailscale is managed as a system service. Runsudo tailscale upto authenticate.
On both systems, you must authenticate manually to use gcloud and application
default credentials:
$ gcloud auth login
$ gcloud auth application-default loginTo enhance productivity, several modern CLI replacements and aliases are configured:
| Command | Alias To | Description |
|---|---|---|
man |
tldr |
Displays concise cheat sheets instead of full manuals. |
df |
duf |
Disk Usage/Free - a better df with colors and graphs. |
du |
gdu |
Disk Usage Analyzer - a fast, interactive du alternative. |
cat |
bat |
A cat clone with syntax highlighting and Git integration. |
ls |
eza |
A modern, maintained replacement for ls. |
On z2-mini, Zellij is configured to start automatically upon SSH login to
ensure persistent sessions.
Escape Hatch: If you need to bypass Zellij (e.g., if it's crashing or you need a clean shell), use the following command to log in:
ssh -t z2-mini "ZELLIJ=1 zsh -l"Note: The original commands are available via standard paths or by unaliasing if strictly needed.
This repository uses Lefthook for git hooks to ensure code quality. We chose Lefthook (over pre-commit) and markdown-oxide (over marksman) to avoid introducing Python or .NET dependencies into the environment. The hooks run automatically inside the development shell:
- Pre-commit:
nix-fmt: Formats all.nixfiles usingalejandra.check-yaml: Lints all YAML files.
- Pre-push:
nix-flake-check: Runsnix flake checkto enforce dependency constraints.
To keep the system minimal, we strictly enforce that no .NET runtime
(dotnet) is included in the system closure. This is checked automatically via
nix flake check (which runs on git push).
To verify manually:
$ nix flake checkIf dotnet is found in the dependency graph, the check will fail and print the
dependency path.