_ _
_ __ ___ __ _ ___| |__ ___| |_ ___
| '_ ` _ \ / _` |/ __| '_ \ / _ \ __/ _ \
| | | | | | (_| | (__| | | | __/ || __/
|_| |_| |_|\__,_|\___|_| |_|\___|\__\___|
Hack your way through a fresh Mac. πͺ
machete is the swiss army knife for macOS setup and maintenance: snapshot
your current Mac into Git, restore it on a new machine in one command, and
keep everything in sync over time. No clicking through System Settings at
2am. No "I think I had a Homebrew formula for that." Just one binary, one
repo, one command.
π‘ Built as a single statically-linked Go binary. No bash dependency spaghetti, no
curl | sudo bashshenanigans.
machete is intentionally high-impact: it can install packages, symlink
files into $HOME, apply macOS defaults, start Homebrew services, and
rewrite tracked snapshots from the current machine state. Read what each
command does before pointing it at a machine you care about.
./machete setupinstalls or restores Homebrew packages, global packages, services, dotfile symlinks, and macOS defaults. Existing home files are backed up with timestamped names before symlinks are created../machete syncpulls the latest repo changes and re-runs setup for the active profile../machete snapshotcopies selected live machine state into this repository. Reviewgit diffbefore committing so private paths, identities, or secrets do not become portable profile data../machete defaultsapplies the shell commands indefaults/macos-defaults.shto the current macOS user../machete scheduleinstalls a per-userlaunchdjob that runssyncandupdateon a schedule.
Read-only inspection commands (safe to poke around with): doctor, diff,
history, verify without --init, and audit.
You need Go 1.21+ to build from source.
git clone https://github.com/OMT-Global/machete.git
cd machete
make build # builds dist/machete
make install # optional: copies dist/machete to /usr/local/bin/machete./machete at the repo root is a thin wrapper β it builds the Go binary
on first use and re-execs it for you, so you can just go.
./machete setup Bootstrap a new Mac: Xcode tools, Homebrew, global packages, services, dotfiles, defaults
./machete snapshot Export current state to the active profile or --profile target
./machete schedule Install a daily launchd agent that runs sync + update automatically
./machete track Add one or more home-directory files to dotfiles/ and symlink them back into $HOME
./machete untrack Remove one or more files from dotfiles/ and stop managing them
./machete uninstall Dry-run or apply a reversible teardown of machete-managed home dotfile symlinks
./machete services Start Homebrew services listed in defaults/brew-services.txt
./machete history List rollback snapshot tags, newest first
./machete rollback Restore the latest snapshot tag and re-apply setup
./machete verify Hash tracked files and compare them to the checksum baseline
./machete audit Scan $HOME and report new, changed, or missing files since the last snapshot baseline
./machete update Upgrade all Homebrew packages and clean up
./machete doctor Check what's installed, symlinked, and in sync for the active profile
./machete diff Compare tracked dotfiles and Brewfile for the active profile
./machete sync Pull latest repo changes and re-apply setup (idempotent)
./machete profile list
./machete profile create work
./machete defaults Apply macOS system preferences from defaults/macos-defaults.sh
./machete defaults --init
Create defaults/macos-defaults.sh with an interactive preset picker
Current Mac Git Repository New Mac
ββββββββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββββββ
β ./machete snapshot β ββββΊ β Brewfile β ββββΊ β ./machete setup β
β - brew bundle dump β β packages/ β β - Xcode CLI tools β
β - global pkg lists β β dotfiles/ β β - Homebrew β
β - copy dotfiles β β defaults/ β β - brew bundle β
β - brew services β β brew-services β β - global pkg restoreβ
β - defaults template β β macos-defaults β β - brew services β
β β β β β - symlink dotfiles β
β β β β β - apply defaults β
ββββββββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββββββ
One side captures, Git carries it, the other side restores. The boring, predictable, beautiful part is that both sides run the same binary.
git clone https://github.com/OMT-Global/machete.git
cd machete
./machete snapshot # captures the default profile in the repo root
./machete snapshot --with-extensions
./machete profile create work
./machete snapshot --profile work # captures a separate machine under profiles/work/
vim defaults/macos-defaults.sh # customize your system preferences
git status --short
git diff --stat
git add Brewfile dotfiles defaults packages profiles
git commit -m "snapshot: $(date +%Y-%m-%d)" && git pushsetup, snapshot, and sync quietly stash a rollback tag before they
touch state, named snapshot/YYYY-MM-DDTHH-MM-SS. If something goes
sideways, ./machete rollback puts you back where you were.
π΅οΈ Before committing a snapshot, inspect
git status --short,git diff --stat, and the full diff for private paths, API tokens, machine-local shell snippets, and personal identity fields that should stay out of a shared repo.
git clone https://github.com/OMT-Global/machete.git
cd machete
./machete setupGo make coffee. β Come back to a fully provisioned machine.
./machete doctor # see what's drifted
./machete diff # compare live state before snapshotting
./machete verify --init # record a checksum baseline
./machete verify # check tracked files against that baseline
./machete audit # full-home drift report since the last snapshot baseline
./machete schedule # install a daily sync + update launch agent
./machete doctor --profile work
./machete services # start saved Homebrew services
./machete update # upgrade all packages
./machete sync # pull latest + re-apply
./machete track .config/ghostty/config
./machete untrack .vimrc
./machete history # list rollback snapshots
./machete rollback # restore the newest snapshot and re-apply setup./machete verify --init records SHA256 checksums for the active profile's
tracked dotfiles and Brewfile in ~/.machete/checksums.sqlite. Later
./machete verify runs report NEW, CHANGED, or MISSING files and
exit non-zero when drift is found. Use ./machete verify --full --init
and ./machete verify --full for a broader $HOME scan.
./machete snapshot also refreshes a full-home audit baseline in the
background. ./machete audit compares the current filesystem against
that baseline, groups output into NEW FILES, CHANGED FILES, and
MISSING FILES, and exits non-zero when drift is found. Use --dir to
limit the report to a subtree, --since YYYY-MM-DD to filter recent
changes, and --export report.csv to write CSV output.
./machete schedule installs a per-user launchd plist in
~/Library/LaunchAgents/ and a small runner script in
~/.machete/schedule/<profile>/run.sh. By default it runs daily at
09:00 local time, calling ./machete sync and then ./machete update
for the active profile. Use --hour and --minute to change the schedule.
To restore a specific snapshot, pass its tag:
./machete rollback snapshot/2026-04-22T09-30-00machete/
machete # thin shell wrapper that builds + runs the Go binary
cmd/machete/ # Go entrypoint (main.go)
pkg/ # Go packages: brewfile, dotfiles, profiles, snapshot, ...
Makefile # build, install, test, clean
go.mod, go.sum # Go module definition
Brewfile # default-profile Homebrew packages
packages/ # default-profile global package snapshots
npm-global.txt
pip-global.txt
cargo-global.txt
vscode-extensions.txt # VS Code-compatible editor extensions (opt-in snapshot)
dotfiles/ # default-profile dotfiles, symlinked to $HOME by setup
.zshrc
.zprofile
.gitconfig
...
defaults/ # default-profile defaults
macos-defaults.sh
brew-services.txt
profiles/
base/
Brewfile
dotfiles/
work/
Brewfile
dotfiles/
packages/
defaults/
macos-defaults.sh
brew-services.txt
machete supports multiple machine profiles in one repo β perfect for
the "personal laptop vs. work laptop vs. that experimental media server"
situation.
defaultkeeps the existing flat repo layout for backward compatibility.- When
profiles/base/exists, it is always applied first and named profiles layer on top of it. - Named profiles live under
profiles/<name>/. --profile <name>works withsetup,snapshot,sync,doctor, anddiff.- The last explicit
--profileis stored in~/.machete/profileand reused on later commands.
mkdir -p profiles/base
./machete profile create work
./machete snapshot --profile work
./machete doctor # now uses the persisted work profile
./machete profile list./machete snapshot records user/global packages for:
npm -gβpackages/npm-global.txtpip install --userβpackages/pip-global.txtcargo installβpackages/cargo-global.txt
./machete setup restores each list when the corresponding tool is
available, and ./machete doctor reports drift if the live machine no
longer matches the saved snapshot.
Files in dotfiles/ are symlinked (not copied) into $HOME by
./machete setup. This means:
- Editing
~/.zshrcedits the repo file directly - No manual syncing required
./machete snapshotre-copies them if you add new dotfiles to track
To start tracking a new file, run ./machete track PATH. This copies
~/PATH into dotfiles/PATH and replaces the home file with a symlink
back into the repo. Machete refuses non-portable paths such as auth
state, sessions, caches, .env files, SSH/GitHub/AWS/Kubernetes
credentials, and filenames that look token-, cookie-, credential-,
session-, or secret-bearing. (Yes, we will save you from yourself.)
To stop tracking a file, run ./machete untrack PATH. If the home file
is still symlinked to the repo copy, machete converts it back into a
regular file before removing dotfiles/PATH.
To undo the machine-local dotfile install without touching the repo
copy, run ./machete uninstall --dotfiles for a dry run, then
./machete uninstall --dotfiles --apply to remove repo-managed symlinks
and restore the newest <file>.bak.<timestamp> backup when one exists.
./machete snapshot refreshes portable files already tracked under
dotfiles/ and skips any tracked path that matches the non-portable
denylist. On a brand-new repo with no tracked dotfiles yet, it still
seeds the default starter set (.zshrc, .zprofile, .gitconfig,
.gitignore_global, .vimrc) when those files exist.
π Before publishing or sharing a machete repo, template personal identity fields in dotfiles such as
.gitconfigand remove shell snippets that load local API tokens from the keychain or environment.
defaults/macos-defaults.sh is generated on first ./machete snapshot,
or any time with ./machete defaults --init.
The preset picker offers:
minimal: conservative Finder, dialog, and screenshot defaultsdeveloper: minimal defaults plus fast keyboard, power-user Finder, Dock, and Activity Monitor settingsprivacy: minimal defaults plus reduced ad personalization and web search leakage
After choosing a base preset, answer yes/no prompts to layer individual
settings. In non-interactive runs such as CI=true, machete skips
prompts and writes the safe minimal preset.
Edit it freely and re-run ./machete defaults to apply changes.
./machete snapshot writes currently running Homebrew services to
defaults/brew-services.txt. ./machete setup starts each saved
service after installing packages, and ./machete services can re-run
that step by itself.
If a saved service is not installed, machete prints a warning and skips
it. ./machete doctor reports saved services that are missing or not
running.
./machete snapshot --with-extensions writes extensions from the first
available VS Code-compatible CLI (code, cursor, or codium) to
packages/vscode-extensions.txt. When that file exists, ./machete setup installs each saved extension with the first available editor
CLI. If no supported editor CLI is installed, setup prints a warning
and continues. ./machete doctor reports extension drift only when
packages/vscode-extensions.txt exists.
- macOS (Intel or Apple Silicon)
- Git
- Go 1.21+ (to build the binary)
- Internet connection (for Homebrew)
- Homebrew not found after install: ensure
/opt/homebrew/bin(Apple Silicon) or/usr/local/bin(Intel) is in yourPATH. - Permission denied on
./machete:chmod +x machete. go: command not foundwhen running the wrapper: install Go from go.dev/dl, or build elsewhere withmake buildand copydist/macheteover.- Symlink conflicts:
./machete setupbacks up existing files to<file>.bak.<timestamp>before symlinking. - Back out a setup run:
./machete uninstall --dotfilesshows which repo-managed symlinks would be removed; add--applyto perform the teardown. It does not uninstall Homebrew packages, clear caches, or restore shell history.
Do not commit private keys, SSH configs, auth files, shell history,
session state, cache directories, local Claude/Codex worktrees, or
files that contain tokens, passwords, cookies, or machine-local secrets.
Keep local tool state such as .claude/ and .codex/ out of the repo
unless you have separated a small, portable scaffold from generated
runtime data.
The bootstrap docs under docs/bootstrap/ are maintainer/operator notes
for this repository. They are not required for normal public machete
usage.
MIT. Use it, fork it, swing it around. Just don't blame us if you rm -rf something important. πͺ¦