An open API service indexing awesome lists of open source software.

https://github.com/omt-global/machete

Swiss army knife for macOS setup and maintenance.
https://github.com/omt-global/machete

automation dotfiles macos provisioning shell

Last synced: 27 days ago
JSON representation

Swiss army knife for macOS setup and maintenance.

Awesome Lists containing this project

README

          

# machete

```
_ _
_ __ ___ __ _ ___| |__ ___| |_ ___
| '_ ` _ \ / _` |/ __| '_ \ / _ \ __/ _ \
| | | | | | (_| | (__| | | | __/ || __/
|_| |_| |_|\__,_|\___|_| |_|\___|\__\___|
```

**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 bash` shenanigans.

## ⚠️ Command Safety

`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 setup` installs 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 sync` pulls the latest repo changes and re-runs setup for the active profile.
- `./machete snapshot` copies selected live machine state into this repository. Review `git diff` before committing so private paths, identities, or secrets do not become portable profile data.
- `./machete defaults` applies the shell commands in `defaults/macos-defaults.sh` to the current macOS user.
- `./machete schedule` installs a per-user `launchd` job that runs `sync` and `update` on a schedule.

Read-only inspection commands (safe to poke around with): `doctor`, `diff`,
`history`, `verify` without `--init`, and `audit`.

## πŸ› οΈ Install

You need [Go](https://go.dev/dl/) 1.21+ to build from source.

```bash
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.

## πŸ—ΊοΈ Commands

```
./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
```

## πŸ” How It Works

```
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.

## πŸš€ Quick Start

### On your current Mac (first time)

```bash
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 push
```

`setup`, `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.

### On a new Mac

```bash
git clone https://github.com/OMT-Global/machete.git
cd machete
./machete setup
```

Go make coffee. β˜• Come back to a fully provisioned machine.

### Day-to-day maintenance

```bash
./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//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:

```bash
./machete rollback snapshot/2026-04-22T09-30-00
```

## πŸ“‚ File Structure

```
machete/
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
```

## πŸ‘₯ Profiles

`machete` supports multiple machine profiles in one repo β€” perfect for
the "personal laptop vs. work laptop vs. that experimental media server"
situation.

- `default` keeps 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//`.
- `--profile ` works with `setup`, `snapshot`, `sync`, `doctor`, and `diff`.
- The last explicit `--profile` is stored in `~/.machete/profile` and reused on later commands.

```bash
mkdir -p profiles/base
./machete profile create work
./machete snapshot --profile work
./machete doctor # now uses the persisted work profile
./machete profile list
```

## πŸ“¦ Global Packages

`./machete snapshot` records user/global packages for:
- `npm -g` β†’ `packages/npm-global.txt`
- `pip install --user` β†’ `packages/pip-global.txt`
- `cargo 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.

## πŸ”— Dotfiles

Files in `dotfiles/` are **symlinked** (not copied) into `$HOME` by
`./machete setup`. This means:
- Editing `~/.zshrc` edits the repo file directly
- No manual syncing required
- `./machete snapshot` re-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 `.bak.` 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 `.gitconfig` and remove shell
> snippets that load local API tokens from the keychain or environment.

## βš™οΈ macOS Defaults

`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 defaults
- `developer`: minimal defaults plus fast keyboard, power-user Finder, Dock, and Activity Monitor settings
- `privacy`: 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.

## 🍺 Homebrew Services

`./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.

## ✏️ Editor Extensions

`./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.

## βœ… Requirements

- macOS (Intel or Apple Silicon)
- Git
- Go 1.21+ (to build the binary)
- Internet connection (for Homebrew)

## 🩹 Troubleshooting

- **Homebrew not found after install**: ensure `/opt/homebrew/bin` (Apple Silicon) or `/usr/local/bin` (Intel) is in your `PATH`.
- **Permission denied on `./machete`**: `chmod +x machete`.
- **`go: command not found` when running the wrapper**: install Go from [go.dev/dl](https://go.dev/dl/), or build elsewhere with `make build` and copy `dist/machete` over.
- **Symlink conflicts**: `./machete setup` backs up existing files to `.bak.` before symlinking.
- **Back out a setup run**: `./machete uninstall --dotfiles` shows which repo-managed symlinks would be removed; add `--apply` to perform the teardown. It does not uninstall Homebrew packages, clear caches, or restore shell history.

## πŸ”’ Privacy

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.

## πŸ“œ License

MIT. Use it, fork it, swing it around. Just don't blame us if you `rm -rf` something important. πŸͺ¦