Skip to content

Rebuilding a Machine from Scratch

How to wipe a machine and rebuild it from this repository. The shape is the same on every platform; only three things differ — how the machine gets erased, what has to exist before install.sh can run, and which bookends the automation deliberately refuses because they need a secret, an interactive sign-in, or a freshly generated identity.

Every tool and config here is reproducible from this repo plus a package manager. What is genuinely at risk is the machine-local state that no repo holds, which is why the capture step comes first.

The shape

  1. Capture the machine-local state, while the old system is still alive.
  2. Wipe and reinstall the OS.
  3. Install git with the system package manager — the one bootstrap dependency.
  4. Clone this repo over HTTPS. No SSH key exists yet on a fresh machine.
  5. Restore the captured state.
  6. ./install.sh --machine NAME, which installs the CLI and stops.
  7. dotfiles apply --machine NAME, which is the install proper.
  8. Verify, then do the manual steps.

Capture what no git repo holds

safekeep takes dated, tagged snapshots of exactly this; safekeep --help covers the verbs and safekeep tags list says what a given tag would bring back.

Getting the capture set right is the hard part, because what dies in a wipe is unobvious. dotfiles machines requirements answers the half the repo can prove — every value and file a machine needs that apply will never write — and --safekeep emits those files as [[back_up_paths]] blocks to paste straight into the config, each tagged dotfiles.

That is a floor and not the set. It covers what is declared, which is by definition narrower than what is worth keeping: ~/.env below its # OVERRIDES marker is hand-written and exists nowhere else, the repo registry the trust variant's repos_registry points at is hand-edited and generated by nothing, and credentials, SSH keys and anything under ~/.config that was authored rather than deployed are all outside the register entirely. Anything found that way and worth checking forever belongs in required_files:, which is what makes dotfiles check report it on every machine from then on.

Confirm the destination survives the wipe: a snapshot inside the machine you are about to erase is not a backup. On WSL that means a Windows or network path, not somewhere under the distro's own filesystem.

Seed phrases are the exception to all of this. Record them offline, restore-test each wallet on a different machine before wiping, and never let a seed pass through a networked tool.

Restore before the install, not after

The env resource regenerates ~/.env from the manifest at Stage.ENVIRONMENT, the first stage of the walk, preserving everything below the # OVERRIDES marker. Restore first and the managed half is rebuilt against the current manifest while the hand-edits and secrets survive intact.

Restore afterwards and you reinstate the old machine's generated half — a stale MACHINE and stale flags — by which point every stage has already run on defaults. src/dotfiles/resources/env.py records why it is first: everything below it reads the file, and MACHINE is what selects the manifest, so a run that starts from the wrong one resolves the wrong machine entirely and ignores every flag override for its whole length.

macOS

Apple Silicon and T2 Intel Macs reset cleanly without a Recovery reinstall: System Settings → General → Transfer or Reset → Erase All Content and Settings. Have the Apple ID password ready; the reset clears Activation Lock as part of the flow.

Xcode Command Line Tools is the bootstrap dependency, being where git comes from. The apply self-bootstraps Homebrew and everything after it.

xcode-select --install

Arch Linux

Do a base install, ensure git and sudo are present, then run install.sh and the apply it prints. The installer owns everything above the base system, including the AUR helper.

WSL — the restricted machine

Measure the firewall and build the offline bundle before the wipe. Both need the old box alive and networked, and neither is recoverable afterwards (Restricted Networks covers the machinery). Re-measure rather than trusting an old reading — the blocked set has twice been wrong in the direction of carrying tools that were never actually blocked.

Rebuild by registering the new Ubuntu rootfs as the distro. Get the bundle onto the new WSL filesystem and install from there rather than across a mounted drive; --offline unpacks it into the cache itself, so nothing needs unpacking by hand. Where a remote is configured, dotfiles bundle download fetches it onto the new filesystem in one command and there is nothing to carry at all.

./install.sh --machine wsl-work-workstation --offline
dotfiles plan  --machine wsl-work-workstation --offline
dotfiles apply --machine wsl-work-workstation --offline

--offline belongs on all three, and on the plan for a reason of its own: every read verb measures upstream unless told not to, so a bare plan here asks GitHub about every declared release, fetches every plugin clone and refreshes a copy of the apt index — none of which this box can reach. --offline measures against the staged bundle instead, and --cached is the same decline where there is no bundle.

The plan in between matters most on this box, where a run started without one has sat on a blocked cargo download having never said what it meant to fetch.

Neither of the last two lines needs the bootstrap again. A bundle that arrives later — a newer one carried over to a machine already built — is unpacked by the next apply --offline, which stages the newest archive in the download cache, ./ or ~/ unless that archive is the one already staged. dotfiles bundle stage unpacks without installing, for looking at a bundle before it lands.

This box replicates nothing between machines. Every directory the fleet shares that way is absent here. A tool depending on one is either off the manifest or configured differently, which is a property of the machine rather than something the install detects.

Verify

dotfiles plan        # symlink, package and flag drift in one place
dotfiles packages check   # declared but not installed
syncer check         # repos the registry expects, against what is on disk

Open the editor and confirm plugins loaded without errors. dotfiles apply is idempotent, so anything that failed can be fixed and the whole thing re-run without going near the bootstrap again.

After the install

Generate a new SSH key rather than carrying the old one forward, and re-authorize it — a fresh key forces the pruning of dead authorizations. Restore wallets from their seeds, and sign into the applications holding their own credentials.

File sync needs peering, not just installation: each side has to add the other and agree to share each folder, so configure both ends.