Managed with chezmoi.
Tracked configuration lives under home/, and chezmoi apply normally deploys regular-file copies into $HOME.
The repository therefore remains clean when an application or a user edits a deployed file.
The detailed rationale and the boundary between shared and machine-specific settings are documented in DESIGN.md.
sh -c "$(curl -fsLS https://get.chezmoi.io)" -- \
init --apply --purge-binary \
git@github.com:ambi/dotfiles.git \
--source "$HOME/src/dotfiles"The bootstrap installer runs a temporary chezmoi binary and removes it after the apply. The initial run prompts for the Git name, email address, optional HTTP proxy, and whether to install personal Homebrew packages. Homebrew is installed when necessary, then the common Brewfile installs the managed chezmoi package. The personal Brewfile is applied only when the machine opted into it.
| Task | Command |
|---|---|
| Pull and deploy repository updates | git pull && chezmoi apply |
| Preview deployed-file changes | chezmoi diff |
| Audit all managed local state | dotfiles-diff |
| Edit the source and deploy it | chezmoi edit --apply ~/.zshrc |
| Import a regular deployed file | chezmoi re-add ~/.config/foo |
| Update external skills | skills update -g -y |
| Upgrade Homebrew packages | brew update && brew upgrade |
| Upgrade mise tools | mise upgrade |
| Check source and destination consistency | chezmoi verify / chezmoi doctor |
| Run repository checks | mise run check |
| Format repository shell scripts | mise run format |
dotfiles-diff compares chezmoi-managed targets, the active Homebrew package
profiles, mise tool installations, and external Agent Skills with the repository.
It only reads local state and exits with 0 when everything matches, 1 when it
finds drift, and 2 when a check cannot complete.
Homebrew cache cleanup candidates and available package or tool upgrades are not
configuration drift, so the command does not report them.
Editing a deployed file changes only the copy under $HOME.
Chezmoi reports that difference, and chezmoi apply asks before replacing a locally modified target.
For a regular managed file, import an existing deployed change into the repository explicitly:
chezmoi diff ~/.vimrc
chezmoi re-add ~/.vimrc
git diff.zprofile, .zshrc, and .gitconfig are regular managed files, so the same re-add workflow applies to them:
chezmoi diff ~/.zprofile
chezmoi re-add ~/.zprofile
git diffUse these import operations only when the change should become shared configuration. Generated files remain templates and should not be edited or re-added directly.
The generated chezmoi configuration stores the values needed to render two machine-specific fragments:
~/.config/dotfiles/shellenv.zshcontains the Homebrew environment and optional proxy.~/.config/git/machine.inccontains Git identity, the ghq root, and optional proxy.
.zprofile and .gitconfig load these fragments, while the frequently edited shared files remain regular files.
| Variable | Purpose |
|---|---|
name |
Git user.name |
email |
Git user.email |
proxy |
Proxy settings in .zprofile and .gitconfig; an empty value omits them |
brewPrefix |
Homebrew prefix derived from the OS and architecture |
installPersonalPackages |
Whether Brewfile.personal is applied |
Run chezmoi init --prompt to answer the prompts again.
Existing installations made before installPersonalPackages was added treat it as false until the configuration is regenerated or edited.
Arbitrary per-machine configuration belongs in files that chezmoi intentionally does not manage:
~/.zprofile.localfor login-shell environment variables and commands~/.zshrc.localfor interactive-shell aliases, functions, and commands~/.gitconfig.localfor any Git sections or overrides
The shared shell and Git configuration loads these files when present.
Create and edit them directly; chezmoi apply will not overwrite them.
These local extension files cannot be imported as-is because they are intentionally outside the managed set.
Move a setting into the corresponding shared file when it should become portable.
Do not store secrets in tracked files.
.zprofile initializes the generated Homebrew and proxy environment, places ~/.local/bin on PATH, and exposes mise shims to login-shell commands.
.zshrc performs full mise activation and contains only interactive behavior such as completion, history, key bindings, and the prompt.
fzf stays installed for the commands and tools that invoke it, but its shell integration is not loaded, so it leaves the key bindings alone.
History search is zsh's own prefix search on ^P and ^N.
Run y instead of yazi when the shell should change to Yazi's final directory on exit.
The prompt reports the current Git branch, an in-progress operation such as a merge or rebase, a yellow ! for staged changes, and a red + for unstaged ones.
It collects all of this from a single git status --porcelain=v2 call rather than from vcs_info, which spawned a Git process per question and cost more for the branch name alone.
Untracked files are excluded so the check never scans beyond the index and tracked worktree entries.
Only portable, intentional settings are tracked. Application history, sessions, credentials, caches, and generated state stay local.
- Karabiner and VS Code settings are regular chezmoi-managed copies.
~/.claude/settings.jsonis not tracked because its local UI state and plugin enablement do not make plugin installation reproducible.
~/.claude contains history, sessions, and other application state, so only selected files are managed.
home/dot_agents/skills/contains locally authored skills, deployed as regular files.home/.chezmoiscripts/run_onchange_after_30-install-agent-skills.sh.tmpllists external skills synchronized by the skills CLI.home/dot_config/mise/config.tomlinstalls Bun andnpm:skills.home/dot_claude/symlink_skills.tmplpoints~/.claude/skillsat the shared runtime directory~/.agents/skills; it does not link$HOMEback into this repository.
The CLI records external sources and update state in ~/.agents/.skill-lock.json.
To add a skill, edit the synchronization script and run chezmoi apply.
To remove one, delete it from the list and run skills remove -g <name> -y.
Brewfile contains OS-level packages and applications shared by all macOS machines.
Brewfile.personal contains opt-in software such as Steam that should not be installed on work machines.
Changing either file reruns brew bundle install --no-upgrade on the next chezmoi apply.
Package upgrades remain an explicit maintenance operation described in Updating installed packages, and Brew Bundle does not uninstall packages removed from a file.
Tools useful in every development directory remain in the global mise configuration.
ShellCheck and Betterleaks are dependencies of this repository's checks, so they live in the repository-local mise.toml instead.
Changing either mise configuration runs mise install from the repository on the next chezmoi apply.
ShellCheck validates the POSIX shell scripts, while Zsh startup files are syntax-checked with Zsh itself using zsh -n.
Betterleaks performs a redacted scan of the working tree without live credential validation.
From the repository root, install and record a shared formula in one operation:
brew bundle add --file Brewfile --install FORMULA_NAMEUse the appropriate type flag for entries other than formulae:
brew bundle add --file Brewfile --install --cask CASK_NAME
brew bundle add --file Brewfile --install --tap OWNER/REPOSITORY
brew bundle add --file Brewfile --install --vscode EXTENSION_IDTarget Brewfile.personal instead when the package should be installed only on personal machines:
brew bundle add --file Brewfile.personal --install --cask CASK_NAMEIf the package was already installed with brew install or brew install --cask, run the same brew bundle add command without --install to record it afterward.
Do not replace either managed file with brew bundle dump during routine updates.
dump captures the whole installed state and cannot infer which profile owns each package.
Use a dump written to a temporary file only as an audit snapshot.
Installation and upgrade are deliberately separate operations.
chezmoi apply only installs what is missing, because the package script runs brew bundle install --no-upgrade and mise install leaves an already installed version alone.
Absorbing new versions is therefore a manual maintenance step.
brew update
brew outdated
brew upgradebrew upgrade upgrades outdated formulae and casks.
Casks that update themselves are reported as current; brew upgrade --greedy replaces those too and is rarely what you want for applications with their own updater.
Restrict the upgrade to the packages this repository declares:
brew bundle install --file Brewfile
brew bundle install --file Brewfile.personalWithout --no-upgrade, brew bundle install upgrades the listed entries and leaves anything installed outside the two files untouched.
Reclaim disk space afterwards with brew cleanup.
Do not run brew bundle cleanup: it uninstalls everything absent from the single file it reads, and this repository splits the declaration across Brewfile and Brewfile.personal.
mise outdated
mise upgradeThe tracked tools are pinned to moving targets such as latest and lts, so mise upgrade installs the newest matching version without any configuration edit.
Run it from the repository root to cover the global tools and the repository-local mise.toml in one pass; elsewhere it covers only the global set.
Use mise upgrade --bump only for tools pinned to a fixed version, because it rewrites the version in the configuration file.
mise prune removes installed versions that no configuration references any more.
mise itself is a Homebrew formula here, so brew upgrade updates it; do not use mise self-update.
skills update -g -yNeither upgrade path modifies this repository, so nothing needs to be committed or re-applied unless a version pin in mise.toml or home/dot_config/mise/config.toml changes.