Single binary, zero dependencies, one config file
- Zero dependencies — compiled binary, nothing else to install
- Cross-platform — macOS, Linux, Windows
- Interactive — run
dotand pick what you want from a checklist - Scriptable —
dot -i git -l zsh -vfor automation and LLMs - Install anything — brew, apt, pacman, paru, curl, cargo, any shell command
- Idempotent — run it twice, nothing breaks
- macOS defaults — export/import GUI app settings
curl -fsSL https://raw.githubusercontent.com/pablopunk/dot/main/scripts/install.sh | bashDownloads the latest binary to ~/.local/bin/dot.
irm https://raw.githubusercontent.com/pablopunk/dot/main/scripts/install.ps1 | iexDownloads the latest binary to %LOCALAPPDATA%\Programs\dot\dot.exe and adds it to your user PATH.
- Create a
dot.tomlin your dotfiles repo:
[zsh]
install.brew = "brew install zsh"
install.apt = "sudo apt install zsh"
link."zsh/.zshrc" = "~/.zshrc"
[git]
install.brew = "brew install git git-delta gh"
link."git/.gitconfig" = "~/.gitconfig"
postinstall = "gh auth login -p ssh -h github.com"
[neovim]
install.brew = "brew install neovim"
link."neovim/init.lua" = "~/.config/nvim/init.lua"- Run it:
dot # interactive checklist (default)
dot -i zsh -l git # scriptable: install zsh, link git
dot --list # list all components[component-name]
install.brew = "brew install thing" # any manager key works
install.apt = "sudo apt install -y thing"
install.any = "curl ... | sh" # fallback
uninstall.brew = "brew uninstall thing"
link."src/file" = "~/.dest/file" # single dest
link."src/file" = ["~/.a", "~/.b"] # multi dest
postinstall = "echo 'done'" # run after install
postlink = "chmod 600 ~/.file" # run after link
os = ["mac", "linux"] # restrict to OS
check = "binary-name" # detect if already installed
defaults."com.apple.dock" = "dock.plist" # macOS onlyNo hardcoded list. dot checks Bun.which(manager) for each key in your config and picks the first one available. any is always the last resort.
[mise]
install.brew = "brew install mise"
install.curl = "curl https://mise.run | sh" # picked if curl existscheck tells dot how to detect if a component is already installed. The interactive checklist shows ✓ for detected items.
[btop]
install.brew = "brew install btop"
check = "btop" # checks if binary is on PATH
[neovim]
install.brew = "brew install neovim"
check = "nvim" # binary name differs from package
[zed]
os = ["mac"]
install.brew = "brew install zed"
check = "test -d /Applications/Zed.app" # shell command, exit 0 = installedDot also auto-detects when all symlinks are already in place — no check needed for link-only components.
[dock]
os = ["mac"]
defaults."com.apple.dock" = "macos/dock.plist"
[finder]
os = ["mac"]
defaults."com.apple.finder" = "macos/finder.xml" # .xml = human-readabledot -e # export current defaults to files
dot -I # import saved defaults[vim]
install.brew = "brew install vim"
postinstall = "vim +PlugInstall +qall"
postlink = "echo 'linked'"dot --postinstall vim # run postinstall hook only
dot --postlink ssh # run postlink hook onlydot # interactive checklist (default)
dot --install # interactive install mode
dot --uninstall # interactive uninstall mode
dot --link # interactive link mode
dot --postinstall # interactive postinstall mode
dot -i zsh -i nvim -v # install zsh + nvim, verbose
dot -u zsh # uninstall zsh
dot -l git # link git files
dot --postinstall nvim # run postinstall hook
dot --postlink ssh # run postlink hook
dot -e # export macOS defaults
dot -I # import macOS defaults
dot --list # list all components
dot --dry-run -i nvim # preview without changes
dot --upgrade # self-upgrade binary
dot -h # help
dot --version # versionAll action flags are composable. Execution order is: uninstall → install → defaults → link → postinstall → postlink.
Fuzzy matching: dot -i nvim matches neovim too.
Output is silent by default — use -v for verbose. In a TTY, package managers get real stdin for interactive prompts. When piped, stdin is closed for non-interactive use.
[zsh]
install.brew = "brew install zsh"
link."zsh/.zshrc" = "~/.zshrc"
[git]
install.brew = "brew install git git-delta"
link."git/.gitconfig" = "~/.gitconfig"
[vim]
install.brew = "brew install vim"
link."vim/.vimrc" = "~/.vimrc"[tailscale]
install.brew = "brew install --cask tailscale"
install.pacman = "sudo pacman -S --noconfirm tailscale"
install.paru = "paru -S --noconfirm tailscale"
postinstall = """
if [[ "$(uname)" == "Linux" ]]; then
sudo systemctl enable --now tailscaled
fi
"""[ice]
os = ["mac"]
install.brew = "brew install ice"
defaults."com.jordanbaird.Ice" = "config/ice/Ice.xml"
[karabiner]
os = ["mac"]
install.brew = "brew install karabiner-elements"
link."config/karabiner/karabiner.json" = "~/.config/karabiner/karabiner.json"[xremap]
os = ["linux"]
install.cargo = "cargo install xremap --features hypr"
link."config/xremap/config.yml" = "~/.config/xremap/config.yml"git clone https://github.com/pablopunk/dot.git
cd dot
bun test # run tests
make build # compile binary
sudo make install| Feature | dot | GNU Stow | chezmoi | dotbot |
|---|---|---|---|---|
| Zero dependencies | yes | no | no | no |
| Single binary | yes | no | yes | no |
| Interactive TUI | yes | no | no | no |
| Package install | yes | no | yes | yes |
| macOS defaults | yes | no | no | no |
| Cross-platform | yes | yes | yes | yes |
| Dry run | yes | yes | yes | no |
MIT