Dotbot makes installing your dotfiles as easy as git clone $url && cd dotfiles && ./install, even on a freshly installed system!
Dotbot is a tool that bootstraps your dotfiles (it's a [Dot]files [bo]o[t]strapper, get it?). It does less than you think, because version control systems do more than you think.
Dotbot is designed to be lightweight and self-contained, with no external dependencies and no installation required. Dotbot can also be a drop-in replacement for any other tool you were using to manage your dotfiles, and Dotbot is VCS-agnostic — it doesn't make any attempt to manage your dotfiles.
Dotbot has many [plugins] that extend its functionality, such as:
See this blog post or more resources on the tutorials page for more detailed explanations of how to organize your dotfiles.
Great! You can automate the creation of your dotfiles by using the user-contributed [init-dotfiles][init-dotfiles] script. If you'd rather use a template repository, check out [dotfiles_template][dotfiles-template]. Or, if you're just looking for [some inspiration][inspiration], we've got you covered.
The following will help you get set up using Dotbot in just a few steps.
You can create an empty configuration file with:
touch install.conf.yaml
If you're using Git, you can add Dotbot as a submodule:
cd ~/.dotfiles # replace with the path to your dotfiles
git init # initialize repository if needed
git submodule add https://github.com/anishathalye/dotbot
git config -f .gitmodules submodule.dotbot.ignore dirty # ignore dirty commits in the submodule
cp dotbot/tools/git-submodule/install .
If you're using Mercurial, you can add Dotbot as a subrepo:
cd ~/.dotfiles # replace with the path to your dotfiles
hg init # initialize repository if needed
echo "dotbot = [git]https://github.com/anishathalye/dotbot" > .hgsub
hg add .hgsub
git clone https://github.com/anishathalye/dotbot
cp dotbot/tools/hg-subrepo/install .
If you are using PowerShell instead of a POSIX shell, you can use the provided install.ps1 script instead of install. On Windows, Dotbot only supports Python 3.8+, and it requires that your account is [allowed to create symbolic links][windows-symlinks].
To get started, you just need to fill in the install.conf.yaml and Dotbot will take care of the rest. To help you get started we have an example config file as well as configuration documentation for the accepted parameters.
Note: The install script is merely a shim that checks out the appropriate version of Dotbot and calls the full Dotbot installer. By default, the script assumes that the configuration is located in install.conf.yaml the Dotbot submodule is located in dotbot. You can change either of these parameters by editing the variables in the install script appropriately.
Setting up Dotbot as a submodule or subrepo locks it on the current version. You can upgrade Dotbot at any point. If using a submodule, run git submodule update --remote dotbot, substituting dotbot with the path to the Dotbot submodule; be sure to commit your changes before running ./install, otherwise the old version of Dotbot will be checked out by the install script. If using a subrepo, run git fetch && git checkout origin/master in the Dotbot directory.
If you prefer, instead of bundling Dotbot as a submodule with your dotfiles, you can install Dotbot from [PyPI] as a standalone command-line program. Use the tool of your choice, such as pip or [uv][uv]:
uv tool install dotbot
Some systems include Dotbot in their native package manager, such as [Homebrew][homebrew-dotbot] and [Arch Linux][arch-dotbot], so for example, you can also install it with brew install dotbot.
With Dotbot installed as a command-line program on your system, you can invoke Dotbot with dotbot -c <path to configuration file>.
Here's an example of a complete configuration.
The conventional name for the configuration file is install.conf.yaml.
- defaults:
link:
relink: true
- clean: ['~']
- link:
~/.tmux.conf: tmux.conf
~/.vim: vim
~/.vimrc: vimrc
- create:
- ~/downloads
- ~/.vim/undo-history
- shell:
- [git submodule update --init --recursive, Installing submodules]
The configuration file is typically written in YAML, but it can also be written in JSON (which is a [subset of YAML][json2yaml]). JSON configuration files are conventionally named install.conf.json.
To install your dotfiles on a new machine or after updates:
git clone <your-dotfiles-repo-url> ~/.dotfiles
cd ~/.dotfiles
./install
To update an existing installation:
cd ~/.dotfiles
git pull
./install
Dotbot uses YAML or JSON-formatted configuration files to let you specify how to set up your dotfiles. Currently, Dotbot knows how to link files and folders, create folders, execute shell commands, and clean directories of broken symbolic links. Dotbot also supports user plugins for custom commands.
Ideally, bootstrap configurations should be idempotent. That is, the installer should be able to be run multiple times without causing any problems. This makes a lot of things easier to do (in particular, syncing updates between machines becomes really easy).
Dotbot configuration files are arrays of tasks, where each task is a dictionary that contains a command name mapping to data for that command. Tasks are run in the order in which they are specified. Commands within a task do not have a defined ordering.
When writing nested constructs, keep in mind that YAML is whitespace-sensitive. Following the formatting used in the examples is a good idea. If a YAML configuration file is not behaving as you expect, try inspecting the [equivalent JSON][json2yaml] and check that it is correct.
Most Dotbot commands support both a simplified and extended syntax, and they can also be configured via setting defaults.
Link commands create symbolic links at specified locations that point to files in your dotfiles repository. This allows you to keep your configuration files in version control while having them appear where applications expect to find them. Symlinks are created by default, but hardlinks are also supported. If desired, items can be specified to be forcibly linked, overwriting existing files if necessary. Environment variables in paths are automatically expanded.
Link commands are specified as a dictionary mapping link names to targets. The link name (key) is where the symbolic link will be created, and the target (value) is the file in your dotfiles directory that the link will point to. Targets are specified relative to the base directory (that is specified when running the installer). If linking directories, do not include a trailing slash.
Link commands support an optional extended configuration. In this type of configuration, instead of specifying targets directly, link names are mapped to extended configuration dictionaries.
| Parameter | Explanation |
|---|---|
path |
The target for the link (file in dotfiles directory), the same as in the shortcut syntax (default: null, automatic (see below)) |
type |
The type of link to create. If specified, must be either symlink or hardlink. (default: symlink) |
create |
When true, create parent directories to the link as needed. (default: false) |
relink |
Removes the old link if it's a symlink (default: false) |
force |
Force removes the old link, file or folder, and forces a new link (default: false) |
backup |
Backup existing files/directories if they exist, creating a backup with suffix .dotbot-backup.{timestamp} (default: false) |
relative |
When creating a symlink, use a relative path to the target. (default: false, absolute links) |
canonicalize |
Resolve any symbolic links encountered in the target to symlink to the canonical path (default: true, real paths) |
if |
Execute this in your $SHELL and only link if it is successful. |
ignore-missing |
Do not fail if the target is missing and create the link anyway (default: false) |
glob |
Treat path as a glob pattern, expanding patterns referenced below, linking all files matched. (default: false) |
exclude |
Array of glob patterns to remove from glob matches. Uses same syntax as path. Ignored if glob is false. (default: empty, keep all matches) |
prefix |
Prepend prefix prefix to basename of each file when linked, when glob is true. (default: '') |
When glob: true, Dotbot uses glob.glob to resolve glob paths, expanding Unix shell-style wildcards, which are not the same as regular expressions; Only the following are expanded:
| Pattern | Meaning |
|---|---|
* |
matches anything |
** |
matches any file, recursively |
? |
matches any single character |
[seq] |
matches any character in seq |
[!seq] |
matches any character not in seq |
However, due to the design of glob.glob, using a glob pattern such as config/*, will not match items that begin with .. To specifically capture items that being with ., you will need to include the . in the pattern, like this: config/.*.
When using glob with the exclude: option, the paths in the exclude paths should be relative to the base directory, same as the glob pattern itself. For example, if a glob pattern vim/* matches directories vim/autoload, vim/ftdetect, vim/ftplugin, and vim/spell, and you want to ignore the spell directory, then you should use exclude: ["vim/spell"] (not just "spell").
- link:
~/.config/terminator:
create: true
path: config/terminator
~/.vim: vim
~/.vimrc:
relink: true
path: vimrc
~/.zshrc:
force: true
path: zshrc
~/.hammerspoon:
if: '[ `uname` = Darwin ]'
path: hammerspoon
~/.config/:
glob: true
path: dotconf/config/**
~/:
glob: true
path: dotconf/*
prefix: '.'
If the target location is omitted or set to null, Dotbot will use the basename of the link name, with a leading . stripped if present. This makes the following two config files equivalent.
Explicit targets:
- link:
~/bin/ack: ack
~/.vim: vim
~/.vimrc:
relink: true
path: vimrc
~/.zshrc:
force: true
path: zshrc
~/.config/:
glob: true
path: config/*
relink: true
exclude: [ config/Code ]
~/.config/Code/User/:
create: true
glob: true
path: config/Code/User/*
relink: true
Implicit targets:
- link:
~/bin/ack:
~/.vim:
~/.vimrc:
relink: true
~/.zshrc:
force: true
~/.config/:
glob: true
path: config/*
relink: true
exclude: [ config/Code ]
~/.config/Code/User/:
create: true
glob: true
path: config/Code/User/*
relink: true
Create commands specify empty directories to be created. This can be useful for scaffolding out folders or parent folder structure required for various apps, plugins, shell commands, etc.
Create commands are specified as an array of directories to be created. If you want to use the optional extended configuration, create commands are specified as dictionaries. For convenience, it's permissible to leave the options blank (null) in the dictionary syntax.
| Parameter | Explanation |
|---|---|
mode |
The file mode to use for creating the leaf directory (default: 0777) |
The mode parameter is treated in the same way as in Python's os.mkdir. Its behavior is platform-dependent. On Unix systems, the current umask value is first masked out.
- create:
- ~/downloads
- ~/.vim/undo-history
- create:
~/.ssh:
mode: 0700
~/projects:
Shell c
$ claude mcp add dotbot \
-- python -m otcore.mcp_server <graph>