macOS dotfiles and full machine bootstrap for a fresh install.
Running setup.sh once on a clean machine will:
- Install Homebrew and upgrade any existing packages
- Install rbenv, the latest stable Ruby, and the
kamalgem - Install CLI tools (fish, fzf, ripgrep, ag, nvim, mas, libpq, …) and GUI apps via Homebrew casks into
/Applications(Firefox, Ghostty, Slack, 1Password, OrbStack, Linear, Notion, Bruno, Postgres, and more) - Install Run.app (launcher) into
/Applicationsfrom the bundledrun/Run.dmg— it's not on Homebrew - Install Mac App Store apps via
mas - Symlink all configs into place (see below)
- Apply a comprehensive set of
defaults writesettings for macOS (Dock with only the apps that are installed, Finder, keyboard, trackpad, screenshots, Bluetooth audio, Spotlight, Dictation, menu bar clock) - Set Firefox as the default browser (if it's installed)
- Set the desktop wallpaper
- Configure login items. Like the Dock, they only include apps that are installed
| File/Dir | Symlinked to |
|---|---|
nvim/ |
~/.config/nvim |
fish/ |
~/.config/fish |
ghostty/ |
~/.config/ghostty |
claude/ |
~/.claude |
gitconfig |
~/.gitconfig |
gitmessage |
~/.gitmessage |
herdr/config.toml |
~/.config/herdr/config.toml |
run/config, run/urls |
~/.config/run/config, ~/.config/run/urls |
irbrc |
(manually placed) |
pryrc |
(manually placed) |
git clone https://github.com/timhogg/dots ~/dots
cd ~/dots
./setup.shThe script asks for your sudo password once at the start (Homebrew's installer, .pkg casks like Krisp, App Store apps, and adding fish to /etc/shells need it). Homebrew resets sudo's cached login whenever a brew command first needs root, so instead of relying on that cache the script hands sudo the password through a SUDO_ASKPASS helper. The password sits in a private temp file and is deleted as soon as the last step that needs root is done. Homebrew goes in /opt/homebrew.
Every section and app runs, with no per-step questions. The only other prompts are the SSH key passphrase, the gh login, and whether to reboot at the end.
Most steps are idempotent — re-running is safe. A re-run re-applies everything, including rebuilding the Dock and login items.
Neovim (nvim/) — entry point is nvim/init.lua. Plugins managed by lazy.nvim, all defined in nvim/lua/plugins.lua. LSP servers (ruby-lsp, typescript-language-server, lua-language-server, elixir-ls) auto-installed by Mason on first launch.
Fish (fish/config.fish) — key aliases: m = nvim, c = claude, be = bundle exec, gs/ga/gc/gp = git shortcuts. h (fish/functions/h.fish) starts herdr with a space for every directory in ~/work, skipping ones that already have a space.
Ghostty (ghostty/config) — TokyoNight Night theme, 0.85 background opacity, non-blinking block cursor.
herdr (herdr/config.toml) — agent multiplexer, installed via Homebrew. Dracula theme, prefix ctrl+\ (nvim's \ leader plus ctrl, so it doesn't swallow \ in panes). cmd+shift+left/right switch herdr tabs (taken over from Ghostty, whose own tabs still switch with cmd+shift+[/]). cmd+shift+up/down step through spaces (Ghostty unbinds its own prompt-jump on those keys so they reach herdr) and shift+option+up/down through agents. cmd+k clears the focused pane (Ghostty's own cmd+k clear is unbound). cmd+t opens a new herdr tab right away, without asking for a name (Ghostty's own cmd+t new tab is unbound). cmd+w closes the active herdr tab (Ghostty's own cmd+w close is unbound).
Run (run/config, run/urls) — launcher app, installed from run/Run.dmg since it's not on Homebrew. Owns the Cmd+Space hotkey, so setup.sh disables Spotlight's Cmd+Space/Cmd+Shift+Space shortcuts.
- Create the file or directory here (e.g.
dots/foo/config) - Add a symlink step to the
symlinkssection ofsetup.sh:rm -rf $HOME/.config/foo && ln -s $HOME/dots/foo $HOME/.config/foo
- Commit both the config and the updated
setup.sh