Skip to content

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.

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.

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.

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.

FeatureDescription
Homebrew formulae and casksBoth kinds of package, captured from what is already installed when you first set up.
SetsGroup packages, files, and shell fragments; each machine activates the ones it needs.
Assembled shell configYour .zshrc is concatenated from shell/*.zsh fragments of every active set.
Secrets, never storedA 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 appSee what differs, review a diff, and apply with a click. Setup runs from here too.
Hourly background checkA status line tells you when something drifted, without opening anything.
Nothing applied unaskedEvery change is reported first. A hand-edited file is a question, not a casualty.

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.