Introduction
dotfix keeps several Macs in sync: the Homebrew packages you have installed, your shell configuration, and your application config files. Everything lives in one Git repository you own, grouped into sets that each machine activates as it needs them.
It comes as a command-line tool and a menubar app. Both drive exactly the same steps — use whichever suits the moment.
Why it exists
Section titled “Why it exists”A second Mac starts out as a week of small annoyances: the formula you forgot to install, the alias that only exists on the other machine, the config file you edited once and never copied over. The usual answer is a dotfiles repository full of shell scripts that nobody dares to touch.
dotfix takes the declarative route instead. You describe what a machine should have; dotfix reports what differs and changes only what you approve. Nothing is applied behind your back, and a file you edited by hand is never silently overwritten.
The idea in one minute
Section titled “The idea in one minute”Your repository holds sets. A set is a named bundle — core, web, work — containing packages, files, and shell fragments. Each machine lists the sets it wants in machines/<name>.toml.
That single indirection is what makes several Macs practical: your laptop can take core and web, the desktop core and work, and neither needs to know about the other’s tools.
Three states, not two
Section titled “Three states, not two”Most sync tools compare two things: what you want, and what is there. dotfix compares three — what the repository wants, what is installed right now, and what dotfix itself last applied.
The third one is what tells an intentional local change apart from an incoming one. A package you installed by hand is an invitation to adopt it, not drift to be wiped out. A file you edited yourself is a decision dotfix reports rather than reverts.
Features
Section titled “Features”| Feature | Description |
|---|---|
| Homebrew formulae and casks | Both kinds of package, captured from what is already installed when you first set up. |
| Sets | Group packages, files, and shell fragments; each machine activates the ones it needs. |
| Assembled shell config | Your .zshrc is concatenated from shell/*.zsh fragments of every active set. |
| Secrets, never stored | A config file can reference a secret by name. The value comes from the macOS Keychain, 1Password, or an age-encrypted file at render time — dotfix never holds it. |
| Menubar app | See what differs, review a diff, and apply with a click. Setup runs from here too. |
| Hourly background check | A status line tells you when something drifted, without opening anything. |
| Nothing applied unasked | Every change is reported first. A hand-edited file is a question, not a casualty. |
Tech stack
Section titled “Tech stack”dotfix is written in Rust. The menubar app is built with Tauri 2 and a React frontend; the command-line tool and the app share one engine, so both behave identically. It runs on macOS 13 and later, on Apple silicon and Intel.
Next steps
Section titled “Next steps”- Install dotfix on your Mac.
- Set up your first machine and build the repository from what you already have.
- Add another Mac to the same repository.