macOS · bash 3.2 · chezmoi · one curl

dotforge
Your Mac, forged exactly once.

From bare macOS to fully configured dev machine in a single command. Homebrew, dotfiles, SSH keys, CLI tools, macOS defaults — all automated. No manual steps. Reproducible. Yours to fork.

  • 17 commands
  • 6 feature flags
  • 4 archetypes
  • 3 scanners

The problem

New Mac. Twenty hours of clicking. Every. Single. Time.

You get a new MacBook. You spend the next two days reinstalling Xcode CLT, re-downloading Homebrew, hunting for your .zshrc, regenerating SSH keys, copying them to GitHub, Bitwarden, and three servers, reconfiguring macOS defaults you forgot you'd changed, and wondering why nvm broke again. It's not setup — it's archaeology.

dotforge collapses that two-day ritual into one curl command. A single bootstrap.sh setup drives chezmoi to apply your entire dotfiles repo — Brewfile, macOS defaults, SSH keys from Bitwarden, login items, CLI globals — across any number of Macs. After that, dot doctor keeps you in sync. You configure your machine once. dotforge reproduces it forever.

How it works

One entry point. Seven hooks (6 run_onchange + 1 run_once_before).

bootstrap.sh setup orchestrates everything — Xcode CLT, brew, chezmoi init, interactive prompts — then fires chezmoi apply, which runs 6 run_onchange hooks plus 1 run_once_before hook. After that, the dot CLI lives at ~/.local/bin/dot for day-to-day operations.

Install

One curl. Fresh Mac ready.

Requires macOS, an internet connection, and your Bitwarden vault (for SSH keys). Works on a brand-new Mac with only bash and curl available.

New Mac — curl installer

curl -fsSL https://raw.githubusercontent.com/roman-dubovik/dotforge/main/docs/install.sh | bash

Installs Xcode CLT, Homebrew, git, clones repo, then runs bootstrap.sh setup.

Git clone fallback

git clone https://github.com/roman-dubovik/dotforge ~/dotforge && cd ~/dotforge && ./bootstrap.sh setup

If you prefer to inspect the repo first.

After first install — on any Mac

dot setup

Alias for bootstrap.sh setup once dotforge is on your $PATH.

Verify

dot doctor

8 read-only sync checks. All green = you're fully in sync.

Commands

19 commands across two layers.

bootstrap.sh handles the heavy lifting — full setup, update, sync, customization. The dot CLI lives on your $PATH for daily operations after first install.

bootstrap.sh — orchestration layer
bootstrap.sh setup Full bootstrap: Xcode CLT → brew → chezmoi init → prompts → apply
bootstrap.sh update git pull + chezmoi apply — keeps existing install in sync
bootstrap.sh sync Promote local brew + /Applications into canonical Brewfile
bootstrap.sh customize Interactive Brewfile section picker + toggle feature flags
bootstrap.sh add-key Upload SSH keys to Bitwarden vault
bootstrap.sh scan-cli Scan globally-installed CLIs → cli-globals.txt
bootstrap.sh scan-macos Capture macOS defaults → macos-defaults.txt
bootstrap.sh scan-autostart Scan login items → login-items.txt
bootstrap.sh doctor 8 read-only sync checks (same as dot doctor)
bootstrap.sh fork Personalize-for-own-account flow — replaces remote origin
bootstrap.sh browse Interactive walkthrough of all available commands
dot — daily operations layer
dot setup Alias for bootstrap.sh setup — use after dot is on $PATH
dot doctor 8 read-only sync checks, colorized output
dot apply [--dry-run] [--enable=X] [--disable=Y] chezmoi apply + before/after doctor delta. Toggle feature flags via --enable/--disable (CSV or repeated)
dot snapshot scan-cli + scan-login + scan-macos → commit to repo
dot pull [--resolve=MODE] fetch + merge + chezmoi apply + dot doctor. MODE = abort (default, ff-only) | ours | theirs | interactive
dot status [--fetch] Read-only divergence report: ahead/behind, working tree, scanner outputs, doctor summary
dot features List all six feature flags with value, source (state.toml / chezmoi.toml / default), and sync status
dot version / dot help Version info and command reference

Roadmap

Shipped and what's coming.

Shipped

  • Plan 1 — Foundation · Xcode CLT, Homebrew, chezmoi dotfiles, SSH, Claude config, fork flow
  • Plan 1.5 — Toolchains · oh-my-zsh, p10k, nvm, pnpm, maestro, macOS defaults baseline
  • Slice 1 — doctor · 8 read-only sync checks
  • Slice 2a — dot CLI · chezmoi-managed shim, doctor / help / version
  • Slice 2b — Archetypes · 4 Brewfile profiles prompted on init
  • Slice 2c — apply / snapshot / pull · loop-closing trio
  • Slice 2d — Feature flags · 6 flags + scan-macos capture + bats tests
  • Slice 2e — Programmatic toggles · dot apply --enable/--disable, dot features, state.toml as single source of truth (note: local_llm flag deferred — see next)
  • Plan 3 MVP — Multi-machine reconciliation · dot status + dot pull --resolve=ours/theirs/interactive/abort

What's next

  • Plan 3b — Full three-way merge · Auto-merge divergent scanner outputs against the common ancestor, beyond the ours/theirs strategy
  • local_llm flag · Ship a seventh feature flag for local LLM tooling (ollama + models); blocked on choosing the Brewfile bundle
  • App-specific configs · Raycast, IDE settings, Hammerspoon, Rectangle
  • Linux / Windows · macOS-only by design — no plans to port
  • Browser / app logins · Limited by Apple platform constraints

View full ROADMAP.md →