A repository to bootstrap a fresh macOS environment. Includes essential apps, coding configurations, and post-install setup steps.
Download and run bootstrap.sh. The script will prompt for credentials interactively.
# Simple (script prompts for all values):
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/handshou/dotfiles/HEAD/bootstrap.sh)"
# Or pre-set variables (script prompts if not set):
STRAP_GIT_NAME="handshou" \
STRAP_GIT_EMAIL="handshou@users.noreply.github.com" \
STRAP_GITHUB_USER="handshou" \
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/handshou/dotfiles/HEAD/bootstrap.sh)"
# For work account, also set:
STRAP_GIT_NAME_WORK="your-work-name" \
STRAP_GIT_EMAIL_WORK="your-work@users.noreply.github.com" \
STRAP_GITHUB_USER_WORK="your-work-username"- Prompts for git credentials (personal + optional work)
- Generates SSH keys (ed25519) for personal and work GitHub accounts
- Installs Homebrew
- Checks out dotfiles via bare git repo to
~/.cfg - Installs packages from Brewfile
- Initializes neovim submodule
- Applies macOS defaults via
scripts/macos-setup.sh - Runs headless neovim plugin install
- Displays post-install checklist
After bootstrap completes, follow these 9 steps:
- SSH keys - Add to GitHub:
cat ~/.ssh/id_ed25519.pub - nvim submodule -
config submodule update --init --recursive - Neovim plugins - Open nvim and run
:Lazy sync - Alacritty - Run
alacritty migrateif needed - skhd - Start service:
/opt/homebrew/bin/skhd --start-service - yabai - Requires partial SIP disable (see bootstrap output for instructions)
- Tmux plugins -
prefix + Ito install TPM plugins - Node.js - Install via nvm:
nvm install --lts - Restart terminal - Apply shell configuration changes
# Show dotfiles status
config status
# Pull latest changes
config pull
# Add and commit changes
config add <file>
config commit -m "message"
config pushconfig config --local status.showUntrackedFiles noconfig remote set-url origin git@github.com:handshou/dotfiles.gitbrew install --cask claude-codeBy default, Enter submits. To use Enter for newline and require Cmd+Enter to submit:
claude config set --global preferredSubmitKey "cmd+enter"claude
# Follow prompts to authenticate with Anthropic| Name | Repo | Location |
|---|---|---|
| Nvim Config | init.lua | .config/nvim |
config submodule update --init --recursive
config submodule update --remote --mergeconfig submodule add <clone address> <directory>Applies opinionated system preferences via defaults write. Backs up your
current defaults to ~/Desktop/macos-defaults-<timestamp>.txt first.
| Section | Configures |
|---|---|
| UI/UX | Dark mode + graphite accent, metric units, save-to-disk default, instant window resize |
| Trackpad/Keyboard | Tap-to-click, fastest key repeat, full keyboard tab nav, autocorrect off |
| Finder | Hidden files, all extensions, list view, folders-first sort, no .DS_Store on network/USB |
| Dock & Mission Control | Auto-hide menu bar + dock, no recent apps, all 4 hot corners disabled, Ctrl+1..9 → Switch to Desktop N |
| Plain-text compose, no animations, newest-first, no remote content | |
| Spotlight | Custom indexing order — apps and conversion first, fonts/messages/contacts/etc. off |
| Networking | Auto-DHCP for Ethernet, ProtonVPN auto-connect on boot |
| TextEdit | Plain text mode, UTF-8 |
| Transmission | Encryption required, blocklist auto-update, peer limits, prevent sleep |
| Magnet | Clears default hotkeys (keeps center/restore/maximize) |
| iTerm2 | Imports tokyonight-storm theme |
Run manually after edits:
sh ~/scripts/macos-setup.sh
killall cfprefsd Dock Finder # apply changes immediatelyPackages are split into three Brewfiles. Bootstrap installs Brewfile automatically and prompts for optional bundles.
| File | Description | Install |
|---|---|---|
Brewfile |
Core development tools and daily apps | Auto |
Brewfile.work |
Work packages (Slack, MS Office, GCloud) | Prompted |
Brewfile.optional |
Photography, media, games | Prompted |
Manual install after bootstrap:
brew bundle --file=Brewfile.work
brew bundle --file=Brewfile.optional| App | Description |
|---|---|
| neovim | Editor |
| node, deno, pnpm | JavaScript runtimes |
| python@3.11 | Python |
| rustup, goenv | Language version managers |
| tmux, tpm | Terminal multiplexer |
| ripgrep, fzf, tree, chafa | CLI utilities |
| pgcli | Database tools |
| stylua | Lua formatter |
| yabai, skhd-zig | Window management |
| App | Description |
|---|---|
| iterm2, alacritty | Terminals |
| firefox, zen | Browsers |
| alfred, obsidian | Productivity |
| claude-code | AI assistant |
| figma | Design |
| 1password, 1password-cli | Password manager |
| protonvpn | VPN |
| karabiner-elements | Keyboard remapping |
| hiddenbar, stats | Menu bar utilities |
| font-hack-nerd-font | Nerd font |
| App | Description |
|---|---|
| docker, docker-compose | Containers |
| supabase | Database |
| slack | Work communication |
| visual-studio-code | Editor |
| microsoft-word/excel/powerpoint | Office suite |
| postman | API testing |
| google-cloud-sdk | GCloud CLI |
| pulumi | Infrastructure as code |
| trello (App Store) | Project management |
| App | Description |
|---|---|
| rawtherapee, gimp | Photography/image editing |
| subler, transmission | Media tools |
| love | Game engine |
| hazel | Automation |
| discord, telegram | Communication |
| App | ID |
|---|---|
| Things 3 | 904280696 |
| Magnet | 441258766 |
| Dropover | 1355679052 |
| 1password for Safari | 1569813296 |
| Keys for Safari | 1494642810 |
| Vinegar | 1591303229 |
| Baking Soda | 1601151613 |
| Refined GitHub | 1519867270 |
| DeArrow | 6451469297 |
| Wappalyzer | 1520333300 |
Apps not available via Homebrew:
| App | Source |
|---|---|
| Cider 2 | https://cidercollective.itch.io/cider |
| Photo Mechanic | https://home.camerabits.com/ (commercial) |
Using test to check file conditionals. Read more with man test.
Some apps will regress.
1Password issues.
- Bootstrap now auto-runs
scripts/macos-setup.shafter Brewfile install - Added Ctrl+1..9 → Switch to Desktop N hotkeys to macos-setup.sh
- Removed
nodefrom Brewfile (use nvm-managed node instead) - Added
tag.gpgsign = trueandgpg.ssh.allowedSignersFileto gitconfig - Switched hardcoded
/Users/hpaths in dotfiles to~/$HOMEfor portability - Removed leftover Windsurf PATH entries from .zshrc
- Split Brewfile into core, work, and optional bundles
- Added interactive prompts in bootstrap for optional package installs
- Removed darktable from Brewfile
- Added 9-step post-install checklist with detailed SIP disable instructions
- Migrated from koekeishiya/skhd to jackielii/skhd-zig
- Updated nvim config for neovim 0.12 (removed lsp-zero, use native LSP)
- Added global caps_lock to left_control in Karabiner
- Fixed TPM path in tmux.conf (hardcoded /opt/homebrew)
- Added brew shellenv to .zshrc
- Removed discontinued apps: Effortless, Omnivore, Duolingo, Wireless@SG
- Removed unavailable brew packages: codex, overlayed
- Added Zen browser, rawtherapee to Brewfile
- Initial bootstrap script with interactive prompts
- Dual SSH key support (personal + work GitHub accounts)