dots

module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 11, 2026 License: Apache-2.0

README

dots

A brew-style dotfile package manager with taps, profiles, overlays, and cross-platform support. dots treats Git repos as package sources ("taps"), uses path aliases for portability, and supports symlink/copy/hardlink link strategies with platform-aware resolution.

Installation

Homebrew (macOS and Linux)
brew install jlrickert/formulae/dots

Shell completions for zsh, bash, and fish are installed automatically.

From source

Prerequisite: Go 1.25.0 or newer.

go install github.com/jlrickert/dots/cmd/dots@latest

If needed, add your Go bin directory to PATH:

export PATH="$(go env GOPATH)/bin:$PATH"
Precompiled binaries

Download from GitHub Releases.

Build from repo
git clone https://github.com/jlrickert/dots.git
cd dots
go build ./cmd/dots

Quick Start

Bootstrapping a fresh machine

Initialize dots and pull in your dotfiles repo in one command:

dots init --from git@github.com:you/dotfiles.git --path dots

This clones the repo as a tap and installs the dots package from it, which sets up dots' own configuration. From there you can apply a profile or install individual packages:

dots profile apply work
Bootstrapping without a repo

If you're starting fresh without an existing dotfiles repo:

dots init

This creates a default config at ~/.config/dots/config.yaml (Unix) or %APPDATA%\dots\config.yaml (Windows).

Adding Taps

Taps are Git repos that contain your dotfile packages. Register one with:

dots tap add personal git@github.com:you/dotfiles.git
dots tap add personal git@github.com:you/dotfiles.git --branch develop

Manage taps with:

dots tap list                # list registered taps
dots tap update              # update all taps
dots tap update personal     # update a specific tap
dots tap remove personal     # remove a tap

Installing Packages

A package is a directory inside a tap containing a Dotfile.yaml manifest and the config files it manages.

dots install personal/nvim
dots install personal/nvim --dry-run        # preview without changes
dots install personal/nvim --strategy copy  # override link strategy

Other package operations:

dots remove personal/nvim       # uninstall
dots upgrade personal/nvim      # upgrade to latest
dots upgrade --all              # upgrade everything
dots reinstall personal/nvim    # remove then reinstall

Discovering Packages

dots list                    # list installed packages
dots list --available        # list available (uninstalled) packages
dots search nvim             # search across all taps
dots browse personal         # list all packages in a tap
dots info personal/nvim      # show package details

Profiles

Profiles are named lists of packages that can be applied together:

dots profile create work
dots profile add work personal/zsh personal/nvim personal/git
dots profile apply work
dots profile switch personal   # switch to a different profile

Profiles support inheritance via extends and can be exported/imported:

dots profile export work > work-profile.yaml
dots profile import work-profile.yaml

Work Mode

Work mode points dots at your local repo checkout instead of its internal clone, so edits propagate immediately (with symlinks):

dots work on personal ~/code/dotfiles
dots work off personal
dots work status

Writing a Package Manifest

Each package needs a Dotfile.yaml in its directory:

package:
  name: nvim
  description: Neovim configuration
  version: 1.0.0
  tags: [editor, neovim]

links:
  init.lua: @config/nvim/init.lua
  lua/: @config/nvim/lua/

hooks:
  post_install: scripts/install-plugins.sh

platform:
  darwin:
    links:
      helpers/mac-clipboard.lua: @config/nvim/lua/clipboard.lua
  windows:
    links:
      helpers/win-clipboard.lua: @config/nvim/lua/clipboard.lua
    hooks:
      post_install: scripts/install-plugins.ps1

Link targets use path aliases for cross-platform portability:

Alias macOS / Linux Windows
@home $HOME %USERPROFILE%
@config $XDG_CONFIG_HOME (~/.config) %APPDATA%
@data $XDG_DATA_HOME (~/.local/share) %LOCALAPPDATA%
@cache $XDG_CACHE_HOME (~/.cache) %LOCALAPPDATA%\cache
@state $XDG_STATE_HOME (~/.local/state) %LOCALAPPDATA%\state
@bin ~/.local/bin %LOCALAPPDATA%\bin

Raw paths (without aliases) are relative to $HOME / %USERPROFILE%. Manifests always use forward slashes; dots normalizes to platform-native separators at resolution time.

Platform sections cascade in specificity order: base -> OS -> OS-arch. Maps deep-merge, scalars replace.

dots supports three strategies, configurable globally, per-platform, or per-package:

Strategy Behavior Edits propagate?
symlink (default) Symlink from target to source Instantly
copy Copy source to target No, run dots sync
hardlink Hardlink (same filesystem) Instantly

When using copy strategy, use dots sync to push changes:

dots sync personal/nvim    # sync one package
dots sync --all            # sync all copy-strategy packages

On Windows, dots auto-detects symlink capability and falls back to copy if unavailable.

Diagnostics

dots status    # overview: platform, config path, active profile, installed counts
dots doctor    # run diagnostic checks on config, taps, and links
dots diff personal/nvim   # show differences between source and installed files
dots which ~/.config/nvim/init.lua   # identify which package owns a file

Configuration

Config lives at ~/.config/dots/config.yaml (Unix) or %APPDATA%\dots\config.yaml (Windows):

core:
  link_strategy: symlink
  conflict_strategy: prompt
  backup: true

git:
  default_branch: main
  protocol: ssh

taps:
  personal:
    url: git@github.com:you/dotfiles.git
    branch: main

aliases:
  @nvim: @config/nvim
  @scripts: @home/scripts

platform:
  windows:
    link_strategy: copy

For the full design specification, see dots-design-v5.md.

Directories

Path Synopsis
cmd
dots command
pkg
cli

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL