These are my dotfiles. There are many like them, but these are mine.
I'm reinventing the wheel with this dotfile management solution. There are many tools that do what I need and much more. But that's just it. I want a tool that does exactly what I need and no more. I also relish the learning opportunity.
The bare git repo approach is indeed elegant, but I have two gripes. You have to use an alias instead of using the git command (like config diff); and it doesn't allow you to store a README in the repo directory. I don't want to clutter my home with helper files that are specific to dotfile management.
Dotbot was attractive--in fact, my solution is based on my cursory understanding of its philosophy--but I want to do things MY WAY dammit.
The essence of my solution is this. Load up src/dotfiles/ with all of your dotfiles, named and organized exactly as you want them to appear relative to $HOME (~/). Add a reference to that filepath in the config file. Then install to create symlinks automatically.
Simply clone the repo and run make setup.
git clone https://github.com/taylorvance/dotfiles.git && cd dotfiles && make setup
This will install required CLI tools (nvim, git, tmux, zsh, etc.), sync the vendored plugin submodules, and create symlinks in your home directory for everything located in src/dotfiles/ and configured in config. If there are any conflicts*, your original files will be backed up in .backups/ with full path preservation.
Zsh and tmux plugins are vendored as commit-pinned git submodules under vendor/ (reached via tracked symlinks at src/dotfiles/.zsh/plugins and src/dotfiles/.tmux/plugins), so nothing on your machine executes unreviewed upstream HEAD. make bump-plugins upgrades them interactively: it fetches upstream commits, lists them for audit, and only checks them out after you confirm.
Installation is idempotent, which is a word that dotfile authors love to flaunt.
* If the file has already been installed/symlinked, it will be skipped. You will not lose local changes to installed files.
Before deploying changes to your actual system, test them safely in Docker:
make doctor # Fast local validation, no Docker
make test # Run all tests in Docker
make test-shell # Interactive debuggingAll tests passing? ✓ Safe to deploy! See tests/README.md for detailed testing documentation.
Run make help to see all available commands:
Setup & Management:
make setup- Complete bootstrap: install tools + sync submodules + create symlinks + git hooksmake install- Install required + recommended CLI tools (prompts before optional language tools)make link- Sync plugin submodules + create symlinks (no tool installation)make bump-plugins- Update vendored plugins interactively (fetch, audit, confirm, checkout)make unlink- Remove all dotfile symlinksmake status- Show installation status of tools and dotfilesmake doctor- Validate repo wiring and script syntax without touching$HOMEmake shellcheck- Lint all shell scripts (requires shellcheck)make adopt F=.path- Copy an existing$HOMEpath intosrc/dotfiles/, add it toconfig, and preview linkingmake restore- Restore files from a backup directorymake macos- Apply macOS system preferences (defaultsdeviations from stock; no-op elsewhere)
Testing (safe - runs in Docker, never touches your system):
make test- Run all tests in Dockermake test-shell- Interactive debugging shellmake test-clean- Remove Docker test artifacts
- Place the dotfile in
src/dotfiles/exactly as it should appear relative to your own home directory. In other words, pretendsrc/dotfiles/is~/.
|-- dotfiles
|-- src
|-- dotfiles
|-- .my-whole-directory
| |-- file1.cfg
| |-- file2.cfg
|-- .config
| |-- nvim
| |-- init.vim
|-- .zshrc
- Add a line to
config. You can link specific files or whole directories.
.my-whole-directory
.config/nvim
.zshrc
- Test your changes:
make test
Or adopt an existing file from your home directory:
make adopt F=.config/tool/config.toml
make linkCore tools are nvim, git, tmux, zsh, curl/wget, unzip, and build tools where needed. The installer also attempts to install recommended CLI tools (fzf, zoxide, eza, fd, ripgrep, delta, atuin, bat, starship, lazygit, tree-sitter, gh with the gh-dash extension) and development tools (mise for node — global versions live in ~/.config/mise/config.toml — plus python3), but the shell config is designed to degrade gracefully when optional tools are missing.
e- Git-aware editor wrapper with composable filtersproj- tmux session managertmp- Quick temporary workspace creatorclean- Remove common dependency/cache directoriesenvsync- Compare.envfiles against their sample counterpartsgit-prune-branches- Remove stale local git branchesgit-prune-worktrees- Remove synced git worktreessysinfo- Quick system information summary
Each script documents itself — run it with -h for full usage.
ytaudio and ytvideo download media through yt-dlp; both also require
ffmpeg. Install them with your package manager (for example, brew install yt-dlp ffmpeg). If either dependency is missing, the commands print this
instruction instead of attempting a download.
- zsh - Vi mode, custom prompt, modern CLI integrations, graceful fallbacks
- nvim - lazy.nvim plugin manager
- git - Common aliases, delta diff integration
- tmux -
C-Spaceprefix, vim-like navigation - agents - Shared guidance and skills under
.agents, exposed through client-specific discovery adapters where required
dotfiles/
├── src/ # All source code
│ ├── install-tools.sh # Tool installation script
│ ├── check-tools.sh # Tool verification script
│ ├── doctor.sh # Local repo/config validator
│ ├── adopt.sh # Adopt existing home files into src/dotfiles/
│ ├── symlink-manager.sh # Symlink management (install/uninstall/status/restore)
│ └── dotfiles/ # Your actual dotfiles
│ ├── .agents/ # Canonical shared agent guidance and skills
│ ├── .claude/ # Claude-specific config and shared-skill adapters
│ ├── .codex/ # Codex discovery adapter for shared AGENTS.md
│ ├── .config/
│ ├── .local/bin/
│ ├── .tmux/plugins # -> vendor/tmux
│ ├── .zsh/plugins # -> vendor/zsh
│ ├── .zshrc
│ ├── .tmux.conf
│ └── .gitconfig
├── tests/ # Comprehensive test suite
│ ├── docker/ # Docker infrastructure (Alpine test image, Ubuntu dev image)
│ ├── unit/ # Unit tests
│ ├── integration/ # Integration tests
│ ├── test-runner.sh # Test orchestration
│ └── README.md # Testing documentation
├── vendor/ # Vendored plugin submodules (zsh/, tmux/), commit-pinned
├── archive/ # Retired configs kept for reference (not linked)
├── .backups/ # Auto-generated backups
│ └── 2025-01-20_10-30-45_12345/
│ └── .zshrc # Your original files
├── config # Paths to symlink
├── Makefile # Command interface
├── AGENTS.md # Repository guidance for coding agents
├── CLAUDE.md # AI assistant instructions
└── README.md # This file
When you run make setup, files that would be overwritten are automatically backed up to .backups/ with full path preservation. Each backup is in a timestamped directory (format: YYYY-MM-DD_HH-MM-SS_PID) so you never lose data.
Use make restore to interactively restore from any backup.
config is a text file that lists which files/directories to symlink. One path per line, relative to both src/dotfiles/ and ~/. Empty lines and lines beginning with # are ignored.
Specific files: .config/nvim/init.vim links that file at ~/.config/nvim/init.vim while leaving the rest of ~/.config/nvim intact.
Whole directories: .config/nvim links the entire directory at ~/.config/nvim/.
Note: When linking a directory, any existing files in ~/ at that path will be backed up. To maintain untracked files in a directory, configure specific files instead of the whole directory.
All of the content specific to my setup is in src/dotfiles/ and config. To start fresh:
- Empty out
src/dotfiles/andconfig - Add your own dotfiles to
src/dotfiles/ - Reference them in
config - Run
make doctorandmake testto verify - Run
make setupto deploy
This is a personal dotfiles repo, but the testing infrastructure could be useful for others. Feel free to adapt the test suite for your own dotfiles!