Requirements
dots runs on macOS and Linux. It's a single static binary — no runtime dependencies, no OpenSSL, no keychain.
| Requirement | Details |
|---|---|
| OS | macOS or Linux |
| Package manager | Homebrew, apt, or dnf (auto-detected) |
| git | Required for install and updates |
Installation
Run this in your terminal to set up dots:
curl -fsSL https://raw.githubusercontent.com/CtrlUserKnown/dots/main/install.sh | sh
Or clone and build from source (requires a Rust toolchain):
git clone https://github.com/CtrlUserKnown/dots ~/.dots
cd ~/.dots
cargo build --release
Installer flags
| Flag | Purpose |
|---|---|
--branch <name> | Install from a specific branch (default main) |
--version <tag> | Pin to a specific release tag |
--dir <path> | Install to a custom directory (default ~/.dots) |
What the installer does
- Clones the repo to
~/.dots(or updates it if already present) - Downloads a prebuilt binary from releases, falling back to
cargo build --release - Puts
dotson your PATH via~/.dots/bin - Runs
dots initto create default config
Project structure
dots is a Cargo workspace with two crates.
| Crate | Role |
|---|---|
crates/dots | Main binary: CLI, TUI screens, installer, symlink engine, config, premade assets |
crates/tui-core | Shared TUI chrome — header/footer/description bars, theme, flash messages |
Key modules
| Module | Purpose |
|---|---|
main.rs | CLI parsing (clap) and command dispatch |
symlinks.rs / links.rs | Symlink engine and links.toml manifest |
packages.rs | Dependency table and shell plugin list |
installer.rs | Package manager detection and premade config application |
aliases.rs | Alias parsing, CRUD, built-in vs user sources |
network.rs | Live network monitor for the dashboard |
update.rs | Update checks and pulls |
config/ | Settings, personal layer, profile import/export |
tui/ | Dashboard and per-screen views |
Interactive TUI
Run dots with no arguments to open the interactive terminal UI. It's built on ratatui with shared chrome provided by the tui-core crate.
Dashboard
The main screen is a 2-column grid of 6 panes:
| Pane | Shows | Drills into |
|---|---|---|
| Symlinks | Link status (ok / missing / broken / wrong target) | Health |
| Tools | Dependencies installed vs missing | Health |
| Plugins | Shell plugin status | Health |
| Configs | Premade app config state | Health |
| Update | Newer version available? | Update |
| Network | Live network status (latency, name, DNS, VPN) | Informational |
Screens
- Health — detailed view behind Symlinks / Tools / Plugins / Configs; repair links and install missing tools
- Aliases — browse built-in and user aliases; add, edit, or remove your own
- Profile — export/import your personal configuration
- Theme — pick a Ghostty theme from installed themes
- Settings — toggle update checks, greeting, developer mode, set update frequency
- Update — check for and apply updates
Navigation
| Input | Action |
|---|---|
hjkl / arrow keys | Move focus |
Enter | Select / drill into pane |
Esc | Go back |
q | Quit |
1-4 | Open Aliases / Profile / Theme / Settings |
Ctrl+C | Quit (any screen) |
| Scroll wheel | Vertical navigation |
| Left-click | Focus and open dashboard pane |
CLI reference
Every TUI action is also available as a subcommand.
| Command | Description |
|---|---|
dots health [--fix] | Check and repair all declared symlinks, tools, and plugins |
dots update | Open update screen |
dots install <name> | Install a single dependency |
dots install --all | Install all missing Required dependencies |
dots install --optional | Install all missing Optional dependencies |
dots aliases list | List all aliases (built-in + user) |
dots aliases add <name> <value> | Add a user alias |
dots aliases remove <name> | Remove a user alias |
dots premade list | List available premade configs |
dots premade apply <app> | Apply a bundled config |
dots link add <source> <target> | Adopt a file/dir and symlink it |
dots link list | List declared links and their status |
dots link apply | Create or repair all declared links |
dots link remove <target> | Remove a declared link |
dots profile generate [path] | Export your setup to personal.json |
dots profile import <path> | Import a personal.json from a local file |
dots profile import-git <spec> | Import from GitHub (user/repo/path/to/file.json) |
dots init [--quiet] | Initialize config (idempotent) |
dots --version | Print version |
Aliases
dots manages shell aliases from two sources:
- Built-in — defined in
~/.dots/src/zsh/zsh/.aliases(read-only) - User — defined in
~/.personal/aliases.zsh(read/write)
User aliases are sourced after built-in ones so your definitions win. Manage them from the TUI Aliases screen or the CLI.
Settings
Settings live in ~/.dots/settings.toml under a [dots] table. Edit directly or manage from the TUI Settings screen.
| Key | Type | Default | Description |
|---|---|---|---|
update_check | bool | true | Enable/disable periodic update checks |
update_frequency | int (minutes) | 1440 | How often to check (1440 = daily) |
greeting | bool | true | Show the greeting banner |
developer_mode | bool | false | Enable developer features |
theme | string | "" | Selected theme name |
Unknown keys are ignored and missing keys fall back to defaults. A malformed file logs a warning and falls back to defaults.
The ~/.personal overlay
~/.personal/config.toml uses the same schema. Any keys it sets override the base settings — useful for per-machine tweaks.
Managing symlinks
Declare which files should be symlinked in ~/.dots/links.toml, and dots creates and repairs them.
Explicit links
[[link]]
source = "~/dotfiles/starship.toml"
target = "~/.config/starship.toml"
Stow-style folding
Mirror package subdirectories of dir into target, GNU Stow style.
[stow]
dir = "~/dotfiles"
target = "~"
packages = ["nvim", "git"]
ignore = [".DS_Store", "*.bak", "README.md"]
Link statuses
| Status | Meaning |
|---|---|
ok | Symlink exists and points where it should |
missing | Nothing exists at the target |
broken | Symlink exists but its destination is gone |
not a link | A real file/dir sits at the target instead |
wrong target | Symlink points somewhere other than declared |
Existing files are backed up to timestamped *.bak.<date> backups before symlinks are created.
Dependencies
dots manages a single cross-platform dependency list organized in three tiers.
| Tier | Installed by | Examples |
|---|---|---|
| Required | dots install --all |
git, eza, bat, fd, fzf, fastfetch, zoxide |
| Optional | dots install --optional |
neovim, herdr, btop, lazygit, yazi, carapace |
| Dev | dots install <name> |
java, go, lua, maven, cmake, gcc, ripgrep, shellcheck, gh, docker, nmap, ffmpeg |
Package manager detection: brew → apt → dnf. Per-platform names are resolved automatically (e.g. fd is fd-find on apt/dnf).
Shell plugins
The Plugins pane tracks these by path existence:
zsh-autosuggestionszsh-syntax-highlightingzsh-history-substring-searchfzf-tab
Premade configs
dots ships starter configs compiled into the binary — always available offline.
| App | Description |
|---|---|
ghostty | Catppuccin Mocha theme + sensible defaults |
neovim | Minimal init.lua (lazy.nvim bootstrap) |
opencode | AI terminal config |
dots premade list
dots premade apply ghostty
Existing files are backed up before writing.
Profiles
A profile is a portable snapshot of your setup stored as personal.json.
# Export on current machine
dots profile generate ~/personal.json
# Import on a new machine
dots profile import-git you/dotfiles/personal.json
dots install --all
dots health
Profiles record settings, theme, installed packages, and per-app config. Imports are validated before applying.
Updating
dots checks for updates periodically when update_check is enabled, respecting the update_frequency interval.
Modes
- Normal mode — compares current tag against latest
v*release tag - Developer mode — compares against upstream branch tip, reports commits behind
Applying an update
Runs git pull --ff-only in ~/.dots then re-repairs all symlinks. Local edits block the update (fast-forward only).
dots update # open the update screen
dots --version # check current version
Testing
dots has unit tests in every module, integration tests via assert_cmd, and a shell integration test.
cargo test --all
cargo clippy --all -- -D warnings
cargo fmt --all -- --check
bash tests/integration/test_setup.sh
CI runs on Linux and macOS via GitHub Actions. A container-based test environment lives in test-env/.