dot is a Unix-first dotfile manager written in Rust.
It is designed around a few defaults:
- top-level directories are packages
- symlink is the default target kind
.tmplfiles render automatically- state and render cache live in XDG directories, not in your repo
- planning is explicit and safe before mutation
dot init
dot plan [packages...]
dot apply [packages...]
dot status [packages...]
dot undeploy [packages...]
dot doctor [packages...]
Global flags:
--repo <path>
--host <name>
--verbose
--json
--yes
--overwrite-unmanaged
--overwrite-drift
--allow-privileged
--no-render-diff
With a Stow-style repo:
dotfiles/
zsh/
.zshrc
git/
.config/git/config.tmpl
assets/
wallpaper.png
dot plan maps those files to:
zsh/.zshrc->~/.zshrcgit/.config/git/config.tmpl->~/.config/git/configassets/wallpaper.png->~/.local/share/...only when you override it indot.toml
dot.toml is optional. If present, it lets you override targets, kinds, modes, and selectors.
[settings]
default_kind = "symlink"
render_suffix = ".tmpl"
collision_policy = "error"
[settings.conflicts]
unmanaged = "block"
managed = "block"
privileged = "skip_package"
merge_tool = "opendiff"
[variables]
email = "user@example.test"
[packages.git.files."git/.config/git/config.tmpl"]
target = "~/.config/git/config"
kind = "render"
[packages.assets.files."assets/wallpaper.png"]
target = "~/.local/share/wallpaper.png"
kind = "copy"
mode = "0644"
[packages.machine.files."machine/.config/app/config.toml"]
target = "~/.config/app/config.toml"
kind = "render"
when.os = ["linux", "macos"]
when.host = ["laptop", "desktop"]
[packages.git.files."git/.config/git/config.tmpl".conflicts]
managed = "merge"
[packages.machine.conflicts]
privileged = "apply"Conflict policy precedence is file -> package -> settings. Available actions are:
unmanaged = "block" | "overwrite" | "merge"managed = "block" | "overwrite" | "merge"privileged = "skip_package" | "apply"
planandapplyshare the same planner- replacements are first-class operations
- unmanaged targets and managed drift are governed by explicit conflict policy
--overwrite-unmanagedand--overwrite-driftare one-shot overrides--yesapplies both overwrite overrides for compatibility with confirmation-style workflows- merge-required conflicts print diff and merge-tool guidance without launching tools automatically
- packages that require privilege are skipped by default unless you pass
--allow-privileged - unreadable targets are surfaced as privileged inspection steps
applyrefuses to run when the planner reports validation errors
cargo fmt
cargo test