Getting started: your first hour¶
This tutorial takes a brand-new Mac from nothing to a fully managed development environment, then shows you the everyday loop that keeps it healthy. It is learning-oriented: follow it top to bottom and you will end with a verified setup and the muscle memory for the daily commands.
Allow roughly an hour — most of that is unattended package and runtime installation. Every command below maps to a real script in the repo, and the output snippets are illustrative of what you will see.
What you need first
A Mac running macOS 12 (Monterey) or later, an internet connection, and a
GitHub account. You do not need Homebrew, Xcode, or any developer tools
installed yet — bootstrap.sh installs them for you.
Step 1 — Clone the repo¶
Clone into ~/dotfiles (the path every script assumes):
No git yet?
A fresh Mac may not have git. Running any git command triggers Apple's
"command line developer tools" installer — accept it, wait for it to finish,
then re-run the clone. bootstrap.sh also installs the full Xcode Command
Line Tools in Step 1 below.
Step 2 — Run bootstrap¶
Kick off the one-time setup:
bootstrap.sh runs a 14-step setup: Xcode Command Line Tools, Homebrew,
packages (brew bundle), fzf shell integration, an SSH signing key, GitHub CLI
auth, mise runtimes, Yarn via Corepack, Rust via rustup, git-lfs, dotfile
symlinks (it calls install.sh), optional work configs, and macOS defaults.
The first-run profile picker¶
Because this is a genuine first run (no --profile flag, no DOTFILES_PROFILE
environment variable, no saved profile file, and an interactive terminal),
bootstrap greets you with the profile picker before doing anything:
This machine has no saved profile yet — pick one:
1) personal (default) — full GUI Mac: core + GUI apps/casks + macOS defaults
2) work — personal plus the work overlay & work configs
3) minimal — core CLI + runtimes + core dotfiles only
4) server — headless macOS: core CLI + runtimes, no GUI
Profile [1-4 or name, Enter = personal]:
For your first personal Mac, press Enter to accept personal. You can type
a number (1–4) or a name (personal, work, minimal, server). The
choice is persisted to ~/.config/dotfiles/profile so that update.sh,
verify.sh, and status.sh all agree on this machine's profile afterward.
Skipping the picker
Pass the profile up front to bypass the prompt entirely:
bash ~/dotfiles/bootstrap.sh --profile work. See the
Adopt a profile tutorial and the
Profiles reference for the full precedence rules.
The component summary¶
Right after the profile is resolved, bootstrap prints a banner and a summary of
exactly what this profile will set up — derived from profile_component_summary
so it always matches what the steps actually do:
🚀 dotfiles bootstrap — macOS developer setup
─────────────────────────────────────────────────
Machine Brad's MacBook Pro
Date Mon Jun 16 2026 09:00
Profile personal
─────────────────────────────────────────────────
This profile sets up
Runtimes (mise) yes
Core CLI + dotfiles yes
Package overlay core + GUI (Brewfile.personal)
GUI apps + dotfiles yes
Work configs no
macOS defaults yes
─────────────────────────────────────────────────
Use this as a sanity check: if the profile line or the component rows are not
what you expected, Ctrl-C now and re-run with the right --profile.
What to expect during the steps¶
A few steps are interactive or long-running:
- Pre-flight check — validates the system first. Critical errors abort the run; warnings prompt you to continue (auto-continuing after 10 seconds).
- SSH key for commit signing — if you have no
~/.ssh/id_ed25519, bootstrap generates one, copies the public key to your clipboard, and pauses with instructions to add it to GitHub as a Signing Key athttps://github.com/settings/ssh/new. Press Enter once you have added it. - GitHub CLI auth — if
ghis installed but not logged in, it runsgh auth login. - Runtimes via mise — installing runtimes can take 5–10 minutes (compiling from source). It prompts before installing and auto-continues after 10s.
When everything finishes you will see:
🎉 Bootstrap complete in 18m 42s
─────────────────────────────────────────────────
Next steps
1. Edit ~/.zshrc.local with machine-specific config
2. Open a new terminal (or: source ~/.zshrc)
3. Keep everything current: bash ~/dotfiles/update.sh
Preview without changing anything
Curious before you commit? bash ~/dotfiles/bootstrap.sh --dry-run walks
through every step and the component preview without installing a thing (and
without persisting a profile or showing the picker). See
Dry-Run & Pre-flight.
Step 3 — Open a new shell¶
The dotfiles set up zsh, the starship prompt, and dozens of tools. Pick up the new configuration by opening a new terminal tab, or reload in place:
You should now have a starship prompt and aliases like dotstatus available.
Step 4 — Verify the setup¶
Confirm the environment is healthy with the read-only health check:
verify.sh covers nine areas: symlinks, required tools, stale backups, the
SSH key, git-lfs, mise runtimes, dotfiles git health, Brewfile drift, and the
git config include. A clean run ends with:
Only broken symlinks are treated as an error (exit 1); everything else is a
non-blocking warning. If you see warnings, the message tells you how to fix
them — for example missing: <tool> — run: bash ~/dotfiles/bootstrap.sh.
For an even faster look, use the status snapshot (aliased to dotstatus):
🩺 dotfiles status
─────────────────────────────────────────────────
Profile personal
Repo ~/dotfiles
Branch main (clean)
Upstream in sync
─────────────────────────────────────────────────
No update.status yet — run: bash ~/dotfiles/update.sh
dotstatus shows the active profile, the repo's git state, and the result of
the last update.sh run. Right after bootstrap there is no update status yet —
that is expected.
Step 5 — The daily loop¶
From here on, one command keeps everything current:
update.sh runs seven self-healing steps: pull the dotfiles
(git pull --rebase --autostash), re-run install.sh to pick up new symlinks,
upgrade Homebrew, upgrade mise runtimes, update Rust, update Ruby gems, and
finally run verify.sh. An individual step failing never aborts the run —
failures are collected and reported at the end:
After an update, dotstatus reflects the last run:
Make it automatic
Schedule a daily run with launchd:
bash ~/dotfiles/scripts/setup-scheduler.sh (runs at 9 AM). See
Usage & lifecycle
for scheduler options and per-machine defaults.
You're set up¶
You now have a verified environment and the everyday loop:
bash ~/dotfiles/update.sh— pull, re-symlink, upgrade, verify.dotstatus— a quick read-only snapshot.bash ~/dotfiles/verify.sh— the full health check on demand.
Where to next¶
- Set up a work laptop — the guided
work-profile flow with corporate configs, secrets, and commit signing. - Adopt a profile on an existing machine — switch profiles without re-bootstrapping.
- Profiles reference — how profiles gate every component.
- Usage & lifecycle — the complete command and flag reference.