Automated setup and maintenance for macOS development environments using Ansible. This repository helps you quickly set up a new Mac or keep your existing setup up-to-date with a single command.
- 🚀 One-command setup for new Macs
- 🔄 Automated updates for all installed packages
- 🎯 Separate profiles for personal and work environments
- 🔐 Secure handling of API keys and private keys
- ✅ Idempotent operations - run safely multiple times
- 🛡️ Pre-flight validation and backup of existing configs
- 📦 Comprehensive toolset including modern AI tools
-
Clone this repository:
git clone https://github.com/your-username/mac-dev-setup.git cd mac-dev-setup -
Run the bootstrap script:
./new-mac.sh
-
Install everything:
make # For personal setup # OR make work # For work setup
Update all installed packages:
make update| Command | Description |
|---|---|
make |
Complete personal setup (all tools + personal apps) |
make work |
Complete work setup (essential tools only) |
make update |
Update all installed packages |
make check |
Dry run to preview changes |
make cli |
Install command-line tools only |
make gui |
Install GUI applications only |
make osx |
Configure macOS system preferences |
make dock |
Configure dock items |
make dotfiles |
Sync dotfiles from repository |
make fonts |
Install developer fonts |
make themes |
Install terminal themes |
make app-store |
Install Mac App Store apps |
make keys |
Install private keys (requires vault password) |
make gpg |
Configure GPG signing for git (auto-detects key) |
make gpg-setup |
Interactive YubiKey GPG key setup wizard |
- Languages: Node.js (via nvm), Go, Rust, Python, Deno
- Package Managers: Homebrew, npm, pnpm, yarn, cargo
- Version Control: Git, GitHub CLI, Sourcetree
- Containers: Docker, Colima, lazydocker
- Databases: PostgreSQL tools, Redis tools, TablePlus
- Terminals: iTerm2, Alacritty, Ghostty, WezTerm
- Shells: Zsh with Oh My Zsh, Starship prompt
- Multiplexers: tmux, Zellij
- Editors: Neovim, VS Code, Cursor
- CLI Tools: fzf, ripgrep, bat, eza, zoxide, and more
- AI Assistants: ChatGPT, Claude, Fabric AI
- AI Development: Ollama for local LLMs
- API Testing: Bruno, Postman, HTTPie
- Window Management: Karabiner Elements
- System Monitoring: Stats, glances, htop
- Security: SSH key management, GPG signing with YubiKey
- Productivity: Raycast, Obsidian, Fantastical
The setup includes comprehensive Git configuration with productivity-enhancing aliases and modern diff tools.
The following Git configurations are automatically applied:
- Editor: Neovim as default editor
- Pull strategy: Rebase by default
- Auto-prune: Fetch automatically prunes deleted remote branches
- Auto-setup remote: Automatically sets upstream on push
- Default branch:
mainfor new repositories - Diff tool: Difftastic for syntax-aware diffs
git co- checkoutgit br- branchgit ci- commitgit st- statusgit last- show last commitgit unstage- unstage filesgit lg- compact log with graph
git dlog- log with difftastic diffsgit dshow- show commit with difftasticgit ddiff- diff with difftasticgit dl- log with patches using difftasticgit ds- short alias for dshowgit dft- short alias for ddiff
git amend- amend last commit without editing messagegit undo- undo last commit, keeping changesgit wip- quick work-in-progress commitgit cleanup [N]- interactive rebase last N commits (default: 10)git fixup <commit>- create fixup commitgit recent- show recently worked branchesgit aliases- list all configured aliases
git branches- show all branches with tracking infogit gone- list branches whose remotes are gonegit prune-branches- delete branches whose remotes are gonegit main- checkout the main/master branch
git stash-all- stash including untracked filesgit pop- pop latest stash
git contributors- show contributor statisticsgit graph- pretty graph of commit historygit today- show your commits from todaygit yesterday- show your commits from yesterday
git untrack <file>- stop tracking filegit ignored- show ignored filesgit modified- list modified files only
git find <text>- search commit messagesgit who <file>- enhanced blame with move/copy detection
These aliases provide an interactive interface using fzf (fuzzy finder) with live previews, making git operations more visual and intuitive.
git fco- Fuzzy checkout branch - Search and checkout any branch (local or remote) with commit previewgit fcoc- Checkout any commit - Browse entire commit history and checkout with previewgit fbr- Branch switcher - Switch between local branches with commit history previewgit ftag- Tag browser - Browse and checkout tags with full diff preview
git fadd- Stage files interactively - Select files to stage with diff preview (supports multi-select with TAB)git funstage- Unstage files - Select staged files to unstage with previewgit fdiff- Diff browser - Select modified files to diff interactively
git fshow- Commit browser - Browse commits and show details with full diff previewgit flog- Log explorer - Browse and select multiple commits (returns commit SHAs)git fcherry- Cherry-pick commits - Select commits to cherry-pick with preview (multi-select with TAB)git ffix- Create fixup commits - Select target commit for fixup with previewgit frebase- Interactive rebase from point - Select commit to start interactive rebase from
git fstash- Stash browser - Browse stashes with full diff preview and apply selectedgit fbrm- Delete branches - Select branches to delete (supports multi-select with TAB)
git fgrep [pattern]- Grep in tracked files - Select file to search with bat preview, then grep for pattern
Tips for FZF aliases:
- Use
TABto multi-select items where supported - Use
Ctrl-CorESCto cancel without making changes - Type to fuzzy search through the list
- Arrow keys or
Ctrl-J/Kto navigate Enterto confirm selection
Edit defaults.yaml to customize which packages get installed:
cli_packages:
- your-favorite-cli-tool
gui_packages:
- your-favorite-app
gui_packages_personal: # Only installed with 'make'
- personal-only-app
gui_packages_work: # Only installed with 'make work'
- work-only-appUpdate the dotfiles_repo in defaults.yaml:
dotfiles_repo: https://github.com/yourusername/dotfiles.gitSensitive data is stored encrypted using Ansible Vault:
-
Create your vault file:
cp vars/api_keys.yml.example vars/api_keys.yml ansible-vault encrypt vars/api_keys.yml
-
Edit the vault:
ansible-vault edit vars/api_keys.yml
-
Install keys:
make keys
This setup supports signing git commits with a GPG key stored on a YubiKey for enhanced security. Multiple YubiKeys with different keys are supported - git automatically detects which YubiKey is currently inserted and uses the correct key.
- YubiKey with OpenPGP support (YubiKey 5 series recommended)
- GPG and YubiKey tools (installed automatically via
make cli)
-
Install prerequisites:
make cli
This installs
gnupg,pinentry-mac, andykman. -
Set up your GPG key on YubiKey:
make gpg-setup
This interactive wizard will:
- Check if your YubiKey is connected
- Detect existing GPG keys on the YubiKey
- Guide you through generating a new key or importing an existing one
-
Configure git to sign commits:
make gpg
This automatically:
- Detects your GPG key ID
- Configures git to use it for signing
- Enables commit signing by default
-
Add your public key to GitHub:
gpg --armor --export YOUR_KEY_ID
Copy the output and add it at: https://github.com/settings/keys
After setup, git commits are automatically signed. The 8-hour cache means you'll enter your YubiKey PIN once per workday.
# Test signing works
git commit --allow-empty -m "Test signed commit"
git log --show-signature -1
# Verify YubiKey is detected
gpg --card-statusImportant: Keys generated directly on a YubiKey cannot be extracted. Plan for backup BEFORE generating keys.
When running make gpg-setup and choosing to generate a new key:
- When asked "Make off-card backup of encryption key?", choose Yes
- GPG will create an encrypted backup file in
~/.gnupg/ - Store this backup securely (encrypted USB, password manager, safe)
To restore to a backup YubiKey:
# Import the backup key
gpg --import ~/.gnupg/sk_XXXXX.gpg
# Insert backup YubiKey
# Move the key to the new YubiKey
gpg --edit-key YOUR_KEY_ID
keytocard
# Select slot 1 for Signature, 2 for Encryption, 3 for Authentication
saveFor maximum flexibility with multiple YubiKeys:
# 1. Generate a master key on your computer (NOT on YubiKey)
gpg --full-generate-key
# Choose RSA (sign only), 4096 bits, set expiration
# 2. Add subkeys for signing, encryption, authentication
gpg --edit-key YOUR_KEY_ID
addkey # Add signing subkey
addkey # Add encryption subkey
addkey # Add authentication subkey
save
# 3. Export backup BEFORE moving to YubiKey
gpg --armor --export-secret-keys YOUR_KEY_ID > master-key-backup.asc
gpg --armor --export-secret-subkeys YOUR_KEY_ID > subkeys-backup.asc
# Store these securely!
# 4. Move subkeys to primary YubiKey
gpg --edit-key YOUR_KEY_ID
key 1 # Select first subkey
keytocard
key 1 # Deselect
key 2 # Select second subkey
keytocard
# Repeat for all subkeys
save
# 5. For backup YubiKey, reimport and repeat
gpg --delete-secret-keys YOUR_KEY_ID
gpg --import subkeys-backup.asc
# Insert backup YubiKey
gpg --edit-key YOUR_KEY_ID
# Move keys to backup YubiKey using keytocardWith the same key on both YubiKeys:
# Remove cached key stub and re-detect
gpg-connect-agent "scd serialno" "learn --force" /bye
# Or fully reset the agent
gpgconf --kill gpg-agent
gpg --card-statusWith different keys on each YubiKey:
This setup includes automatic key detection via a wrapper script (~/.local/bin/gpg-auto-sign). When you run make gpg, git is configured to use this wrapper which:
- Detects which YubiKey is currently inserted
- Reads the key ID from that YubiKey
- Uses that key for signing, regardless of what's in
user.signingkey
This means you can simply swap YubiKeys and git will automatically use the correct key - no manual switching required.
Note: You'll need to add each key's public key to GitHub separately at https://github.com/settings/keys
-
"No secret key" errors:
- Ensure your YubiKey is inserted
- Run
gpgconf --kill gpg-agentto restart the agent - Run
gpg --card-statusto verify YubiKey detection
-
PIN prompt doesn't appear:
- Ensure
pinentry-macis installed:brew list pinentry-mac - Check gpg-agent config includes
pinentry-program
- Ensure
-
Signing fails in terminal:
- Ensure
GPG_TTYis set:export GPG_TTY=$(tty) - Add this to your
.zshrcif not already present
- Ensure
The setup includes several safety features:
- Pre-flight checks: Validates system requirements before running
- Backup creation: Backs up existing SSH keys before modification
- Disk space check: Warns if disk space is low
- Internet connectivity: Verifies connection before downloading
- Dry run mode: Preview changes with
make check
-
"Homebrew not found" after new-mac.sh
- Restart your terminal or run:
source ~/.zshrc
- Restart your terminal or run:
-
"Permission denied" errors
- The makefile will prompt for sudo password when needed
- Some operations require admin access
-
App Store apps fail to install
- Ensure you're signed into the Mac App Store
- Run
mas signin your-apple-id@example.comfirst
-
Ansible Galaxy certificate errors
- We've removed the insecure
ignore_certssetting - If you have certificate issues, fix your system certificates
- We've removed the insecure
- Run with verbose output:
ansible-playbook local.yaml -vvv - Check specific task:
make cliormake gui - Validate syntax:
ansible-playbook local.yaml --syntax-check
.
├── makefile # Main interface for all commands
├── new-mac.sh # Bootstrap script for fresh installs
├── defaults.yaml # Package lists and configuration
├── local.yaml # Main Ansible playbook
├── update.yaml # Update playbook
├── ansible/
│ ├── tasks/ # Individual task files
│ └── templates/ # Configuration templates
└── vars/
└── api_keys.yml # Encrypted secrets (create this)
- Fork the repository
- Create a feature branch
- Test your changes with
make check - Submit a pull request
- macOS (tested on macOS 15.0 arm64)
- Internet connection
- Apple ID (for App Store apps)
This project is licensed under the MIT License - see the LICENSE file for details.
This setup is inspired by various dotfiles repositories and automation scripts from the developer community.