Modern dotfiles with a clean convention-over-configuration approach.
Fork of Zach Holman's dotfiles with modern CLI tools, Oh My Zsh, and Tokyo Night theming.
- macOS: Xcode Command Line Tools (
xcode-select --install),git,make - Linux (Debian/Ubuntu):
sudo apt install build-essential curl file git
Homebrew/Linuxbrew will install GNU Stow and the rest of the toolchain automatically.
git clone https://github.com/ratulotron/dotfiles.git ~/.dotfiles
cd ~/.dotfiles
make install
make stow
make check- Run
make installfirst so Homebrew/Linuxbrew can install GNU Stow (and the rest of the toolchain). - Then run
make stowto create the symlinks. - Finally run
make checkto verify Stow can restow cleanly without changes.
Simple patterns for automatic symlinking:
Stow mirrors the package layout into $HOME. Place files exactly where you want them to land:
topic/.filename → ~/.filename
git/.gitconfig→~/.gitconfigzsh/.zshrc→~/.zshrc
Mirror the .config tree beneath each package:
topic/.config/<tool>/ → ~/.config/<tool>/
atuin/.config/atuin/→~/.config/atuin/helix/.config/helix/→~/.config/helix/
Place the file under .config with the desired relative path:
topic/.config/<filename> → ~/.config/<filename>
starship/.config/starship.toml→~/.config/starship.toml
Files in bin/ are added directly to $PATH.
# Main operations
dot # git pull + install + stow
dot install # run all installers
dot update # same as `dot`
dot stow # restow packages
dot check # dry-run restow + legacy link check
# Maintenance
dot clean # Unstow everything
dot edit # Open dotfiles in $EDITOR
dot help # Show commands- Modern CLI tools:
bat,fd,ripgrep,eza,git-delta,zoxidereplacing old Unix utilities - Development setup: Node.js, Python, Go, Docker, PostgreSQL
- macOS optimized: Ghostty terminal, developer-friendly system defaults
- Shell enhancements: Oh My Zsh, Atuin history sync, 50+ aliases, smart completions
- Tokyo Night theming: Consistent colors across all tools
- Explicit shell loading: 6-phase init order (Homebrew → PATH → config → init → compinit → completions)
The dotfiles use Oh My Zsh as the shell framework. It's installed automatically by zsh/install.sh along with two community plugins:
- zsh-autosuggestions – fish-like command suggestions
- zsh-syntax-highlighting – real-time syntax highlighting
The plugin list lives in zsh/omz-config.zsh. Themes are disabled because Starship handles the prompt (see starship/.config/starship.toml).
To add or remove plugins, edit the plugins=( ... ) array in zsh/omz-config.zsh and reload with source ~/.zshrc or open a new terminal.
Tools are installed in this order of preference:
- Homebrew - CLI utilities and system tools (cross-platform via Linuxbrew)
- Mise - Language runtimes with version management
- Topical
install.shscripts - Last resort for tools not available elsewhere
CLI utilities like bat, fd, ripgrep, eza, git-delta are managed by Homebrew for simplicity. Language runtimes (node, python, go) are managed by Mise for per-project version control.
Avoid maintaining a giant per-tool table in this README.
- Policy is the source of truth: install precedence is brew -> mise -> topical install script.
- Canonical locations are:
Brewfile/Mac.Brewfilemise/.config/mise/config.toml- topical
<topic>/install.shscripts
- Only update README when workflow/policy changes, not for every package bump.
Keep shared defaults in this repo, and put host-specific/secrets in untracked local files.
- Use
~/.localrcfor secrets and machine-only env vars. - Prefer local mise overrides in
~/.config/mise/config.local.tomlfor machine-specific runtime/tool differences. - Use
~/.gitconfig.localfor personal Git identity (name, email). - Use
~/.gitconfig.machinefor machine-only Git settings (credential helpers, SSH URL rewrites). - Do not commit office-only, personal-only, or WSL-only overrides into shared topic files.
Edit mise/.config/mise/config.toml, add the tool under [tools], then run:
mise install- Modern CLI:
bat,eza,fd,ripgrep,git-delta,zoxide,dust,duf,bottom,procs,sd,xh,tealdeer - Dev tools:
jq,yq,just,gh,aws-sso-cli,lazygit,starship,helix - System:
git,stow,mise,wget,tree,htop - Containers/DevOps:
docker,docker-compose,docker-credential-helper,colima,ctop,dive,lazydocker - Security:
detect-secrets,pre-commit,shellcheck,shfmt - Terminal & Navigation:
zellij,broot
- Apps: Ghostty, VS Code, Bitwarden, Obsidian, Slack, Discord, Spotify, Chrome, Zen
- Languages: Node.js, Python, Go
- Ecosystem tools:
uv,ruff,pnpm,pyright(npm backend),gopls,goimports,dlv,claude-code,copilot
make check # Dry-run stow and detect legacy links
dot check # Same as above via the wrapper
dot help # Show all available commandsCommon fixes:
- Broken symlinks:
dot clean && dot stow - Missing packages:
dot install - Outdated system:
dot update - Toolchain drift:
mise install
If an app keeps generating a file (for example ~/.config/atuin/atuin-receipt.json), do not manage that file in shared dotfiles.
- Add the path/pattern to the package's
.stow-local-ignore. - Remove the tracked file from the repo package.
- Restow so only intended files remain linked.
Example:
# 1) ignore in package
echo '\\.config/atuin/atuin-receipt\\.json' >> atuin/.stow-local-ignore
# 2) remove from repo package
rm -f atuin/.config/atuin/atuin-receipt.json
# 3) restow
make stowNotes:
- Keep machine-specific/secrets out of shared dotfiles (
~/.localrc, local configs). - If the target file already exists as a real file,
make stownow backs up common conflicts to~/.dotfiles-backup/<timestamp>/before linking.
CI runs a smoke suite on macOS and Linux to prevent precedence and shell breakage:
- Shell syntax validation for
install.shand*.zshfiles shellcheckforinstall.shscripts- Install precedence invariant check in
Makefile(homebrew -> mise -> topic installers) make checkstow dry-run integrity check
MIT License. Fork it, use it, improve it.
- bin/: global scripts (including
dot) - topic/: topical configuration (e.g.
git,zsh)- path.zsh: exports PATH entries or environment variables for that topic
- init.zsh: initializes the tool (e.g.
atuin/init.zshrunsatuin init) - .config/: config files (stowed to
~/.config) - .file: dotfiles (stowed to
~/.file) - install.sh: installation script
- Makefile: management commands
Use the topical path.zsh/init.zsh files for tool-specific setup so the shared zsh/.zshrc can stay lightweight. Optional tools (Docker completions, uvx, Atuin, etc.) are always wrapped in existence checks to keep shells happy on both macOS and Linux.