Personal macOS bootstrap + dotfiles + shell tooling in one place.
cd "$HOME/Projects/macforge"
./macforge setupThat command orchestrates all phases, saves progress, and can pause between phases.
- Runs in phases (
xcode_clt,homebrew,stow,backup,migrate_legacy,apply_dotfiles,brew_bundle,macos_defaults,iterm2). - Saves state at
~/.local/state/macforge/setup.state. - If interrupted, re-run the same command to resume.
- Prompts before moving to the next phase (use
--yesfor non-interactive mode).
./macforge help
./macforge phases
./macforge doctor
./macforge hooks
./macforge setup --yes
./macforge setup --from brew_bundle
./macforge setup --until apply_dotfiles
./macforge setup --reset-state
./macforge setup --with-optional-brewosx-conf/Brewfile: core baseline tools.osx-conf/Brewfile.optional: optional/legacy tools.- Optional tools are installed only with
--with-optional-brew(orMACFORGE_INSTALL_OPTIONAL_BREW=1).
macforge stows zsh/.zshrc to ~/.zshrc. The template sources osx-conf/load, which pulls in everything under osx-conf/{aliases,common,functions,optional}. Machine-local/private config belongs in ~/.config/macforge/secrets.zsh (sourced at the end of the stowed .zshrc if present).
Aliases for stack-specific tools (for example terraform, flutter, exercism, minikube, gigalixir) live in osx-conf/optional and only load when their command exists.
Keep secrets out of git and out of plaintext shell exports:
mkdir -p "$HOME/.config/macforge"
touch "$HOME/.config/macforge/secrets.zsh"
chmod 600 "$HOME/.config/macforge/secrets.zsh"Then place private exports in that file (for example API keys).
~/.gitconfig (stowed from git/.gitconfig) includes ~/.gitconfig-professional when the repo is under ~/Projects/. That professional file is not tracked in macforge — keep it as a local file per machine to avoid leaking a work email into a public repo:
cat > "$HOME/.gitconfig-professional" <<'EOF'
[user]
name = Your Name
email = you@work.example
signingkey = Your Name <you@work.example>
EOF~/.gitconfig-personal (for personal repos) stays tracked in macforge because its content is already intentionally public.
macforge is the source of truth for your config. To keep other machines in sync:
-
On the machine where you changed config: commit and push macforge (e.g.
git push). -
On each other machine: pull and re-run setup so symlinks and state are updated:
cd ~/Projects/macforge git pull ./macforge setup
After a git pull, running ./macforge setup skips phases already completed (state is in ~/.local/state/macforge/setup.state).
Install a pre-push hook that runs gitleaks:
./macforge hooksThe hook blocks push if potential secrets are detected in the outgoing commit range.