Declarative macOS configuration using nix-darwin and Home Manager with Flakes. This repository contains my personal dotfiles optimized for developer productivity with a focus on keyboard-first workflows.
# Apply configuration to current host
sudo nix run nix-darwin/master#darwin-rebuild -- switch --flake .#workstation
# Dry-run (see what would change)
sudo nix run nix-darwin/master#darwin-rebuild -- build --flake .#workstation
# Update inputs to latest versions
nix flake update
# Rollback to previous generation
sudo nix run nix-darwin/master#darwin-rebuild -- switch --rollbackThis repository uses a five-layer architecture for clear separation of concerns:
flake.nix (orchestration)
├── hosts/workstation/ → macOS with unstable nixpkgs (latest packages)
└── hosts/homelab/ → macOS 13 with stable nixpkgs (compatible packages)
├── default.nix → darwin system configuration
├── home.nix → Home Manager user configuration
└── homebrew.nix → Homebrew packages & casks
│
└── modules/
├── darwin/ → System-level settings (dock, keyboard, etc.)
├── home/ → Shell, git, SSH, development tools
└── programs/ → Self-contained GUI apps with config directories
Each program is self-contained with a standard structure:
modules/programs/neovim/
├── default.nix # Nix configuration (toggle, packages)
└── config/ # Live-editable configs (symlinked, no rebuild)
├── init.lua
├── lua/
└── plugins.lua
default.nixdefines the toggle (my.neovim.enable = true;) and importsconfig/directory is symlinked live (changes take effect immediately without rebuild)- This separates declarative configuration from live editing
Transform your keyboard into a comfort machine by holding letter keys to trigger modifiers. This eliminates pinky stretching to modifier keys—your fingers stay on the home row.
Home row mods are implemented across two keyboards and systems:
-
External Keyboard (ZMK Firmware)
- Device: Corne-ish Zen split keyboard
- Config:
zmk/config/corne-ish_zen.keymap - Implementation: ZMK keyboard firmware with home row mod behaviors
-
MacBook Built-in Keyboard (Karabiner)
- Device: Built-in MacBook keyboard
- Config:
modules/programs/karabiner/config/homerow.json - Implementation: Karabiner Elements dual-role keys
The MacBook keyboard uses Karabiner Elements for CACS (Command-Alt-Ctrl-Shift) home row mods:
Left-hand mods (home row):
A → Cmd (Command)
S → Alt (Option)
D → Ctrl (Control)
F → Shift
Right-hand mods (home row):
J → Shift
K → Ctrl (Control)
; → Cmd (Command)
Dual-role key behavior:
- Hold key = acts as modifier
- Tap key = types the letter normally
- Tap
A= typesa - Hold
A+ pressC=Cmd+C(copy) - Hold
D+ pressZ=Ctrl+Z(undo) - Hold
S+ pressTab=Alt+Tab(switch apps)
- Tap
The external Corne-ish Zen split keyboard uses ZMK firmware with layers for modifier access. See zmk/config/corne-ish_zen.keymap for detailed keymap configuration across QWERTY, LOWER, RAISE, and CONFIG layers.
| Application | Config Location | Purpose |
|---|---|---|
| zsh | modules/home/zsh/ |
Modern shell with async prompt |
| starship | zsh config | Fast, minimal prompt |
| kitty | modules/programs/kitty/config/ |
GPU-accelerated terminal |
| alacritty | modules/home/alacritty/ |
Cross-platform terminal |
| tmux | modules/home/tmux/config/ |
Terminal multiplexer |
| atuin | modules/home/atuin.nix |
Elegant shell history |
| Application | Config Location | Purpose |
|---|---|---|
| Neovim | modules/home/editor/ |
Extensible text editor |
| GitHub Copilot CLI | modules/programs/copilot/config/ |
AI coding assistant |
| Python/Node/.NET/Flutter | modules/home/*.nix |
Language toolchains |
| Application | Config Location | Purpose |
|---|---|---|
| AeroSpace | modules/programs/aerospace/config/ |
Tiling window manager |
| JankyBorders | modules/programs/borders/config/ |
Window borders decorator |
| SketchyBar | modules/programs/sketchybar/config/ |
Customizable status bar |
| Raycast | modules/home/raycast.nix |
App launcher & productivity |
| Maccy | modules/home/maccy.nix |
Clipboard manager |
| Application | Config Location | Purpose |
|---|---|---|
| Karabiner Elements | modules/programs/karabiner/config/ |
Key remapping (home row mods) |
| Application | Config Location | Purpose |
|---|---|---|
| Obsidian | modules/programs/obsidian/config/ |
Note-taking & knowledge base |
| ncspot | modules/home/ncspot/ |
Spotify CLI client |
| HTTPie | modules/home/httpie/ |
HTTP CLI client |
| git | modules/home/git/ |
Version control |
| ssh | modules/home/ssh/ |
Secure shell |
- Kubernetes:
modules/home/cloud-k8s/ - Netskope VPN:
modules/home/netskope.nix
This repository uses Git submodules (e.g. opencode/skills/obsidian-skills).
By default, git status only shows a vague (modified content) message when a
submodule has uncommitted changes, giving no indication of what actually changed
inside it.
diff.submodule = log is configured in modules/home/git.nix to make git status embed a diff summary directly in the output so you can see exactly which
files changed inside the submodule without having to cd into it.
$ git status
On branch nix-migration
Changes not staged for commit:
modified: opencode/skills/obsidian-skills (modified content)
Submodule opencode/skills/obsidian-skills contains modified content
--- a/opencode/skills/obsidian-skills
+++ b/opencode/skills/obsidian-skills
@@ -1 +1 @@
-Subproject commit 243259970868a2599486c859d040f295b986e24b
+Subproject commit 243259970868a2599486c859d040f295b986e24b-dirty
Submodule opencode/skills/obsidian-skills/skills/obsidian-cli is dirty
diff --git a/skills/obsidian-cli/SKILL.md b/skills/obsidian-cli/SKILL.md
index ec4a683..d5e6837 100644
--- a/skills/obsidian-cli/SKILL.md
+++ b/skills/obsidian-cli/SKILL.md
@@ -1,5 +1,5 @@
# Obsidian CLI Skill
-This skill enables interactions with Obsidian vaults via the Obsidian CLI (`obs`).
+This skill enables extended interactions with Obsidian vaults via the Obsidian CLI (`obs`).
It provides tools to read, create, search, and manage notes, tasks, and more.
This section is kept for historical context. These tools were used when this repository was for Arch Linux configuration.
I was maintaining a few dozen AUR packages for Arch Linux with a daily CI job checking for outdated packages:
aurpublish- Install githooks for package repositoryupdpkgsums- In-place update of checksumsnvchecker- Check for new versions (config)nvcmp- Compare version state files from nvcheckernvtake <pkg_name>- Accept the new version
Configuration lives in nvchecker/nvchecker.toml and is kept for archive purposes.
My daily driver is a 40% ortholinear split keyboard (Planck) that allows me to move keys towards my fingers, instead of moving my fingers to the keys. With this keyboard my fingers never travel more than a single key in any direction.
Combined with home row mods, this setup eliminates all hand movement for typing and hotkeys.
- Typeau .40 Planck Edition (site)
- OLKB Planck PCB Rev 6.1 (site)
- Matt3o /dev/tty keycaps with MT3 profile (site)
- Gateron Silent Clear switches (Linear | 4.0mm travel | 35g Actuation) (site)
- Krytox 205g0 lube for switches and stabilizers
- TX switch films 0.125mm (site)
- ZealPC Stabilizers v2 (site)
See the Features → Home Row Mods section above for detailed explanation and key mappings.