My macOS setup — automated with a single command.
git clone <repo-url> ~/dotfiles && cd ~/dotfiles && ./setup.shThis runs four steps in order: installs packages (install.sh), creates symlinks (link.sh), configures git and runtimes (config.sh), and applies macOS settings (macos.sh). You can also run each step individually:
./setup.sh install # Install Homebrew packages and apps
./setup.sh link # Create symlinks for config files
./setup.sh config # Configure git and install runtimes
./setup.sh macos # Apply macOS system preferences~/dotfiles/
├── setup.sh # Orchestrator — runs everything
├── install.sh # Homebrew packages and casks
├── link.sh # Symlinks for config files
├── config.sh # Git config and language runtimes
├── macos.sh # macOS system preferences (defaults write)
├── .zshrc # Shell configuration
├── starship.toml # Prompt configuration
├── ghostty/config # Terminal configuration
├── .vimrc # Vim configuration
├── nvim/init.lua # Neovim configuration
├── pip.conf # Pip configuration
├── .gitignore
└── legacy/ # Previous configs (tmux, vim, alacritty, karabiner)
| Tool | Replaces | Purpose |
|---|---|---|
| Starship | Powerlevel10k | Cross-shell prompt, Rust-based, actively maintained |
| zsh-autosuggestions | Oh My Zsh plugin | Ghost text suggestions from history |
| fast-syntax-highlighting | Oh My Zsh plugin | Commands turn green/red as you type (faster than zsh-syntax-highlighting) |
| fzf | — | Fuzzy finder (unchanged, still the best) |
| fd | find | Fast file search, respects .gitignore |
| ripgrep | grep | Fast content search, respects .gitignore |
| bat | cat | Syntax highlighting, line numbers, git diff |
| eza | ls | Colors, icons, git status, tree view |
| zoxide | cd | Smarter directory jumping, learns your habits |
| delta | diff | Syntax-highlighted git diffs with line numbers |
| tealdeer | man | Community-driven simplified command examples (tldr) |
| yazi | Ranger + vifm | Terminal file manager, Rust-based, async, image preview |
| jq | — | JSON processor |
| git | Xcode CLT git | Latest version via Brew, updated more frequently |
| vim | macOS built-in vim | Latest version via Brew |
| Neovim | — | Modern vim fork, LSP/treesitter ready |
| uv | pip, virtualenv, pyenv | Python package/project manager, Rust-based, handles Python versions too |
| Ruff | flake8, black, isort | Python linter and formatter, Rust-based |
| fnm | nvm | Fast Node version manager, Rust-based, near-zero shell startup cost |
| App | Replaces | Purpose |
|---|---|---|
| Ghostty | Alacritty | Terminal emulator, native Metal rendering |
| VS Code | — | Code editor (unchanged) |
| Cursor | — | AI-native code editor (VS Code fork) |
| Chrome | — | Browser (unchanged) |
| Arc | — | Browser with spaces, split views, built-in tools |
| Raycast | Spotlight | Launcher, clipboard history, snippets, plugins |
| Shottr | Monosnap | Screenshots, OCR, annotations |
| Spotify | — | Music (unchanged) |
| Pearcleaner | Pretty Clean | Clean app uninstaller |
| Rectangle | — | Window manager with keyboard shortcuts |
| Obsidian | — | Markdown-based knowledge base |
| Docker Desktop or OrbStack | — | Container runtime (choose during install) |
- Vimium — keyboard-driven browsing
- uBlock Origin — ad blocker
- JSON Viewer Pro — JSON formatting and tree view
Dev runtimes — Installs latest LTS Node.js (via fnm) and latest stable Python (via uv) so you have working node/npm/npx and python out of the box. Add more versions anytime with fnm install 22 or uv python install 3.11.
Git — Prompts for user.name and user.email if not already configured. Sets init.defaultBranch to main. Configures delta as pager with line numbers and navigation.
Shell (.zshrc) — Bare zsh with no framework. Includes: cached completions via compinit, autosuggestions, fast syntax highlighting, Starship prompt, fzf integration with fd, zoxide for smart directory jumping, git aliases, eza/bat aliases, and the sshid helper function. Machine-specific secrets go in ~/.zshlocal (not committed).
Prompt (starship.toml) — Using Starship defaults. Customize after trying the stock experience.
Terminal (ghostty/config) — Using Ghostty defaults with MesloLGS Nerd Font at 14pt. Customize after trying the stock experience.
macOS (macos.sh) — System preferences automated via defaults write. Covers: Finder (show hidden files, path bar, list view), Dock (auto-hide, no recents, small icons), keyboard (fast repeat, F-keys as standard, fn → do nothing), trackpad (tap to click, 3-finger drag), screenshots (PNG to ~/Pictures), and more. See the file for the complete list.
After running setup.sh, configure these through System Settings:
- Keyboard → Modifier Keys: Make Caps Lock act as Ctrl
- Keyboard → Keyboard Shortcuts → Input Sources: Set
Cmd+Spaceto switch input source (language) - Keyboard → Keyboard Shortcuts → Mission Control: Disable
Ctrl+Up,Ctrl+Down,Ctrl+Left,Ctrl+Right— they interfere with terminal shortcuts - Mouse → More Gestures: Swipe between pages
- Raycast preferences: Confirm
Opt+Spaceas hotkey (should be set by default on first launch)
Terminal multiplexer: If Ghostty's built-in splits aren't enough, tmux is proven (old config in legacy/.tmux.conf). Zellij is the modern Rust-based alternative with sane defaults.
Neovim config: Consider a distribution like LazyVim or kickstart.nvim for a full IDE experience with LSP and treesitter. Old .vimrc is in legacy/.
Caps Lock → Ctrl/Escape: If you want Caps Lock to act as Ctrl when held and Escape when tapped (not just Ctrl), you'll need Karabiner-Elements back. Old config in legacy/karabiner/.