Packages, not just
dotfiles.

Your shell config is only half the story — the other half is the CLI tools it expects to find. dotstate tracks packages per profile and installs what's missing in one command.

How it works

A package is a tuple: a name, a manager (how to install it), and optionally a binary name (how to detect it, if different from the package name — e.g. Homebrew's ripgrep ships rg). Each profile keeps its own list. Inheritance applies: a child profile automatically includes its parent's packages.

Supported managers

Homebrew

macOS and Linux. brew must be on the $PATH.

Cargo

Rust packages from crates.io. cargo install <pkg>.

npm

Global npm packages. npm install -g <pkg>.

pip

Python packages. pip install --user <pkg>.

apt · dnf · pacman

System packages on common Linux distributions.

Custom

Any shell command. Use for tools with bespoke installers (mise, rustup, nvm, …).

Adding a package

From the TUI, open Packages, choose a manager, and type the name. From the command line:

# Interactive — prompts for manager and binary name:
$ dotstate packages add

# Or inline:
$ dotstate packages add -n ripgrep -m brew -b rg
$ dotstate packages add -n eza -m cargo
$ dotstate packages add -n prettier -m npm

Checking what's missing

On a fresh machine, check everything the current profile expects:

$ dotstate packages check
→ brew  · ripgrep (rg)     ✓ installed
→ cargo · eza              ✗ missing
→ npm   · prettier         ✓ installed
→ 1 package missing.

Installing in bulk

install only touches packages that are actually missing — it's safe to run repeatedly.

$ dotstate packages install
→ cargo install eza
→ done · 1 package installed.

Custom packages

When a tool doesn't fit a standard manager, register a custom package with its own install command and a detection command:

$ dotstate packages add \
    -n mise -m custom \
    --install-command  "curl https://mise.run | sh" \
    --existence-check  "command -v mise"

The existence check is anything that exits 0 when the tool is present. The install command is run in a subshell — not interpreted by your login shell — so there's no shell-injection surface.

Security note. dotstate never runs install commands automatically. You explicitly opt in by running dotstate packages install. Before install, the exact commands that will run are printed, and you can cancel.

Next

See the CLI reference for all package commands, or profiles for how per-profile package lists inherit.