skills/dotfiles/SKILL.md
Dotfile management with stow, chezmoi, yadm, or git bare repo for configuration sync across machines. Use when user asks to "manage dotfiles", "sync configs", "setup dotfiles", "backup shell config", "organize config files", "bootstrap new machine", "stow packages", "chezmoi template", "git bare repo dotfiles", "XDG directories", "shell startup files", "gitconfig aliases", "tmux config", or manage any ~/. configuration files.
npx skillsauth add 1mangesh1/dev-skills-collection dotfilesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Manage and sync configuration files across machines.
| Tool | Complexity | Symlinks | Templates | Encryption | Multi-machine | |------|-----------|----------|-----------|------------|---------------| | Git bare repo | Low | No (actual files) | No | No | Manual | | GNU Stow | Low | Yes | No | No | Manual | | chezmoi | Medium | No (copies) | Yes | Yes | Built-in | | yadm | Medium | No (actual files) | Yes (Jinja) | Yes (GPG) | Built-in |
No dependencies, no symlinks. Home directory is the work tree.
git init --bare $HOME/.dotfiles
alias dot='git --git-dir=$HOME/.dotfiles --work-tree=$HOME'
dot config --local status.showUntrackedFiles no
echo "alias dot='git --git-dir=\$HOME/.dotfiles --work-tree=\$HOME'" >> ~/.zshrc
dot add ~/.zshrc ~/.gitconfig
dot commit -m "Add shell and git config"
dot remote add origin [email protected]:user/dotfiles.git
dot push -u origin main
# Clone to new machine
git clone --bare [email protected]:user/dotfiles.git $HOME/.dotfiles
alias dot='git --git-dir=$HOME/.dotfiles --work-tree=$HOME'
dot checkout
# If conflicts: back up existing files, then checkout again
dot checkout 2>&1 | grep -E "^\s+" | xargs -I{} mv {} {}.bak
dot checkout
dot config --local status.showUntrackedFiles no
brew install stow # macOS
apt install stow # Debian/Ubuntu
mkdir -p ~/dotfiles && cd ~/dotfiles && git init
Each top-level folder is a "package" mirroring home directory structure:
~/dotfiles/
├── zsh/
│ └── .zshrc
├── git/
│ └── .gitconfig
├── nvim/
│ └── .config/nvim/
│ └── init.lua
├── tmux/
│ └── .tmux.conf
└── scripts/
└── .local/bin/
└── backup.sh
cd ~/dotfiles
stow zsh # symlink: ~/.zshrc -> ~/dotfiles/zsh/.zshrc
stow */ # stow all packages
stow -D zsh # unstow (remove symlinks)
stow -R zsh # restow (unstow then stow — use after restructuring)
stow -t /etc/nginx nginx # target a different directory
stow -n -v zsh # dry run with verbose output
# If target exists, stow refuses. Back up first:
mv ~/.zshrc ~/.zshrc.bak && stow zsh
# Or adopt existing files into stow dir (overwrites stow version):
stow --adopt zsh # then review with git diff
Create .stow-local-ignore in any package to exclude files: README.md, LICENSE, \.git.
brew install chezmoi
chezmoi init # new setup
chezmoi init --apply https://github.com/user/dotfiles.git # clone + apply
chezmoi add ~/.zshrc # track a file
chezmoi add --autotemplate ~/.gitconfig # auto-detect template variables
chezmoi add --encrypt ~/.ssh/id_ed25519 # add encrypted
chezmoi edit ~/.zshrc # edit source, not target
chezmoi diff # preview changes
chezmoi apply # apply to home directory
chezmoi update # pull from remote and apply
# ~/.local/share/chezmoi/dot_gitconfig.tmpl
[user]
name = {{ .name }}
email = {{ .email }}
{{ if eq .chezmoi.os "darwin" }}
[credential]
helper = osxkeychain
{{ end }}
{{ if eq .chezmoi.hostname "work-laptop" }}
[http]
proxy = http://proxy.corp:8080
{{ end }}
# ~/.config/chezmoi/chezmoi.toml
[data]
name = "Jane Doe"
email = "[email protected]"
# ~/.config/chezmoi/chezmoi.toml
encryption = "age"
[age]
identity = "~/.config/chezmoi/key.txt"
recipient = "age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p"
# ~/.local/share/chezmoi/run_onchange_install-packages.sh.tmpl
#!/bin/bash
{{ if eq .chezmoi.os "darwin" -}}
brew bundle --file=/dev/stdin <<EOF
brew "ripgrep"
brew "fd"
brew "fzf"
EOF
{{ else if eq .chezmoi.os "linux" -}}
sudo apt install -y ripgrep fd-find fzf
{{ end -}}
Login shell: /etc/profile -> ~/.bash_profile OR ~/.bash_login OR ~/.profile (first found)
Interactive shell: ~/.bashrc
Best practice — put everything in .bashrc, source from .bash_profile:
# ~/.bash_profile
[[ -f ~/.bashrc ]] && source ~/.bashrc
Order: .zshenv (always) -> .zprofile (login) -> .zshrc (interactive) -> .zlogin (login)
Logout: .zlogout
Keep .zshenv minimal. Put most config in .zshrc.
# -- History --
HISTFILE=~/.zsh_history
HISTSIZE=50000
SAVEHIST=50000
setopt SHARE_HISTORY HIST_IGNORE_DUPS HIST_IGNORE_SPACE
# -- PATH (deduplicated in zsh) --
typeset -U PATH path
path=("$HOME/.local/bin" "$HOME/go/bin" "$HOME/.cargo/bin" "/opt/homebrew/bin" $path)
export PATH
# -- Aliases --
alias ll='ls -lAh'
alias g='git'
alias dc='docker compose'
alias k='kubectl'
alias ..='cd ..'
alias ...='cd ../..'
# -- Functions --
mkcd() { mkdir -p "$1" && cd "$1"; }
# -- Environment --
export EDITOR='nvim'
export VISUAL='nvim'
eval "$(starship init zsh)"
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
# ~/.gitconfig
[user]
name = Your Name
email = [email protected]
signingkey = ~/.ssh/id_ed25519.pub
[alias]
co = checkout
br = branch
ci = commit
st = status
sw = switch
lg = log --oneline --graph --all --decorate
unstage = reset HEAD --
amend = commit --amend --no-edit
wip = !git add -A && git commit -m 'WIP'
[core]
editor = nvim
pager = delta
autocrlf = input
excludesFile = ~/.gitignore_global
[init]
defaultBranch = main
[pull]
rebase = true
[push]
autoSetupRemote = true
[merge]
conflictstyle = zdiff3
[diff]
algorithm = histogram
colorMoved = default
[delta]
navigate = true
side-by-side = true
line-numbers = true
[gpg]
format = ssh
[commit]
gpgsign = true
[rerere]
enabled = true
# ~/.gitignore_global
.DS_Store
Thumbs.db
*.swp
*~
.idea/
.vscode/
# ~/.tmux.conf
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",xterm-256color:RGB"
set -g mouse on
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on
set -g history-limit 50000
set -g escape-time 0
unbind C-b
set -g prefix C-a
bind C-a send-prefix
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
bind r source-file ~/.tmux.conf \; display "Reloaded"
-- ~/.config/wezterm/wezterm.lua
local wezterm = require("wezterm")
local config = wezterm.config_builder()
config.font = wezterm.font("JetBrains Mono")
config.font_size = 14.0
config.color_scheme = "Catppuccin Mocha"
config.hide_tab_bar_if_only_one_tab = true
return config
# ~/dotfiles/Brewfile
brew "git"
brew "neovim"
brew "ripgrep"
brew "fd"
brew "fzf"
brew "stow"
brew "starship"
brew "git-delta"
brew "jq"
brew "bat"
brew "eza"
brew "tmux"
cask "wezterm"
cask "raycast"
cask "1password"
cask "docker"
brew bundle --file=~/dotfiles/Brewfile # install
brew bundle dump --force --file=~/dotfiles/Brewfile # export current
#!/bin/bash
# ~/.macos — run once on fresh install, then reboot
defaults write com.apple.finder AppleShowAllFiles -bool true
defaults write com.apple.finder ShowPathbar -bool true
defaults write com.apple.dock autohide -bool true
defaults write com.apple.dock autohide-delay -float 0
defaults write NSGlobalDomain KeyRepeat -int 2
defaults write NSGlobalDomain InitialKeyRepeat -int 15
mkdir -p ~/Screenshots
defaults write com.apple.screencapture location ~/Screenshots
killall Finder Dock SystemUIServer 2>/dev/null
# ~/.Xresources — apply with: xrdb -merge ~/.Xresources
Xft.dpi: 144
*.foreground: #c0caf5
*.background: #1a1b26
# ~/.config/systemd/user/ssh-agent.service
[Unit]
Description=SSH Agent
[Service]
Type=simple
ExecStart=/usr/bin/ssh-agent -D -a %t/ssh-agent.socket
[Install]
WantedBy=default.target
systemctl --user enable --now ssh-agent
export XDG_CONFIG_HOME="$HOME/.config" # config files
export XDG_DATA_HOME="$HOME/.local/share" # persistent data
export XDG_CACHE_HOME="$HOME/.cache" # disposable cache
export XDG_STATE_HOME="$HOME/.local/state" # logs, history
Tools that respect XDG: nvim, tmux (3.1+), git, starship, wezterm, alacritty, kitty, bat, ripgrep.
Never commit secrets in plaintext.
# git-crypt — encrypt specific files in a git repo
brew install git-crypt
cd ~/dotfiles && git-crypt init
# .gitattributes: secrets/** filter=git-crypt diff=git-crypt
git-crypt export-key ~/dotfiles-key # back up this key
git-crypt unlock ~/dotfiles-key # on new machine
# 1Password CLI — in chezmoi templates or shell
# {{ onepasswordRead "op://Personal/SSH Key/private key" }}
export GITHUB_TOKEN=$(op read "op://Dev/GitHub/token")
# age encryption — used natively by chezmoi
age-keygen -o ~/.config/chezmoi/key.txt
# Then set encryption = "age" in chezmoi.toml (see chezmoi section)
#!/usr/bin/env bash
set -euo pipefail
DOTFILES_REPO="[email protected]:user/dotfiles.git"
DOTFILES_DIR="$HOME/dotfiles"
if [[ "$OSTYPE" == darwin* ]]; then
command -v brew >/dev/null || /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(/opt/homebrew/bin/brew shellenv)"
brew install git stow
elif [[ -f /etc/debian_version ]]; then
sudo apt update && sudo apt install -y git stow
elif [[ -f /etc/arch-release ]]; then
sudo pacman -Sy --noconfirm git stow
fi
[[ ! -d "$DOTFILES_DIR" ]] && git clone "$DOTFILES_REPO" "$DOTFILES_DIR"
cd "$DOTFILES_DIR"
for dir in */; do stow -v "$dir"; done
if [[ "$OSTYPE" == darwin* ]]; then
brew bundle --file="$DOTFILES_DIR/Brewfile" || true
[[ -f "$DOTFILES_DIR/.macos" ]] && bash "$DOTFILES_DIR/.macos"
fi
echo "Bootstrap complete. Restart your shell."
chezmoi diff or stow -n -v before committing~/.config/ over ~/ when tools support ittools
Parallel execution with xargs, GNU parallel, and batch processing patterns. Use when user mentions "xargs", "parallel", "batch processing", "run in parallel", "parallel execution", "process list of files", "bulk operations", "concurrent commands", "map over files", or running commands on multiple inputs.
development
WebSocket implementation for real-time bidirectional communication. Use when user mentions "websocket", "ws://", "wss://", "real-time", "live updates", "chat application", "socket.io", "Server-Sent Events", "SSE", "push notifications", "live data", "streaming data", "bidirectional communication", "websocket server", "reconnection", or building real-time features.
tools
Frontend bundler configuration for Webpack and Vite. Use when user mentions "webpack", "vite", "bundler", "vite config", "webpack config", "code splitting", "tree shaking", "hot module replacement", "HMR", "build optimization", "bundle size", "chunk splitting", "loader", "plugin", "esbuild", "rollup", "dev server", or configuring JavaScript build tools.
tools
VS Code configuration, extensions, keybindings, and workspace optimization. Use when user mentions "vscode", "vs code", "vscode settings", "vscode extensions", "keybindings", "code editor", "workspace settings", "settings.json", "launch.json", "tasks.json", "vscode snippets", "devcontainer", "remote development", or customizing their VS Code setup.