Chezmoi¶
Chezmoi manages dotfiles by maintaining a source directory (~/.local/share/chezmoi) and applying files to the home directory.
File Naming Conventions¶
Source files use special prefixes that chezmoi interprets:
| Prefix | Effect | Example |
|---|---|---|
dot_ |
Deployed with . prefix |
dot_zshrc → ~/.zshrc |
executable_ |
Sets file executable (755) | executable_tmux-sesh → tmux-sesh (executable) |
private_ |
Sets permissions to 0600 | private_dot_env → ~/.env (private) |
*.tmpl |
Processed as Go template | dot_gitconfig.tmpl → ~/.gitconfig (templated) |
create_ |
Only create, never update | Preserves user modifications |
Directories follow the same rules: dot_config/ maps to ~/.config/.
Templates¶
Files ending in .tmpl are Go templates processed with chezmoi data. The data is defined in .chezmoi.yaml.tmpl:
These values are prompted once on first chezmoi init and cached. Use them in templates:
External Dependencies¶
.chezmoiexternal.yaml pulls in git repos automatically:
".config/tmux/plugins/tpm":
type: git-repo
url: "https://github.com/tmux-plugins/tpm"
refreshPeriod: 168h # Re-pull weekly
clone:
args: ["--depth", "1"]
Private Layer¶
This repo is public, so two things stay out of it: secret env values, and any
string naming the employer or its GitHub orgs. Both live in a private repo
cloned to ~/.config/dotfiles-private by .chezmoiexternal.yaml. Everything
else — tool config, aliases, completions — stays here.
| Path | Consumed by |
|---|---|
mise.toml |
mise, via a ~/.config/mise/conf.d/work.toml symlink — all age-encrypted secrets |
work.zsh |
.zshrc and browser-open — work_orgs, GH_DEFAULT_ORG |
finicky-work.js |
inlined into ~/.finicky.js by the dot_finicky.js.tmpl template |
claude_work/CLAUDE.md |
~/.claude_work/CLAUDE.md symlink |
Brewfile |
the brew bundle run script — private tap and its formulae |
Everything public degrades gracefully when the private repo is absent: .zshrc
and browser-open source work.zsh only if it is readable, the finicky
template omits the work handler, and the symlinks simply dangle.
Add or rotate a secret with mise run secret:set NAME, which writes the
age-encrypted value into the private repo (commit it there).
Key Commands¶
| Command | Purpose |
|---|---|
chezmoi apply |
Apply all changes |
chezmoi diff |
Preview pending changes |
chezmoi edit ~/.zshrc |
Edit a managed file |
chezmoi add ~/.config/foo/bar |
Start managing a new file |
chezmoi update |
Pull from remote and apply |
chezmoi cd |
Navigate to the source directory |
chezmoi doctor |
Diagnose common issues |
chezmoi data |
Show template data |
Quick access
The shell function cm is a shortcut — cm alone runs chezmoi cd, and cm <args> forwards to chezmoi.
Ignored Files¶
.chezmoiignore lists files that chezmoi should not manage — things like README.md, CLAUDE.md, the docs site, and other repo-only files.
Run Scripts¶
Scripts in .chezmoiscripts/ execute during apply. The naming controls behavior:
| Prefix | Behavior |
|---|---|
run_once_before_ |
Runs once, before file apply |
run_once_after_ |
Runs once, after file apply |
run_onchange_before_ |
Re-runs when file content changes |
The numeric prefix (00, 01, 02...) controls execution order.
Brewfile Management¶
brew install / brew uninstall keep the Brewfiles up to date on their own —
see Brewfile. The files live at homebrew/ in the
source dir and are symlinked to ~/.config/homebrew/, so brew bundle writes
into the repo rather than into a copy an apply would overwrite.
To regenerate one from scratch:
Always use --no-vscode
The --no-vscode flag prevents VS Code extensions from being included in the Brewfile.