Personal dotfiles managed with chezmoi.
Source repo: github.com/mickmcq/dotfiles → applied to $HOME.
Note: this repo assumes I am using chezmoi, macOS, kitty, bash, brew, NeoVim, R, and a large assortment of mostly terminal-based utilities, some core utilities, some related to teaching, and some related to music. It is probably easier to install everything, then subtract the things you don't want, than to rebuild this piecemeal. The best place to subtract things is in the Brewfile. Also, I advise you to create your own .secrets file. I explain this further in a video on YouTube.
| Source file | Target | Notes |
|---|---|---|
private_dot_bashrc |
~/.bashrc |
private_ = mode 600 on apply |
dot_bash_profile |
~/.bash_profile |
sources ~/.profile and ~/.secrets |
private_dot_profile |
~/.profile |
sets LANG=en_US.UTF-8 when that locale exists |
encrypted_private_dot_secrets.age |
~/.secrets |
age-encrypted secrets and personal identifiers — the single source of truth (renamed from .api_keys 2026-08-02; not everything in it is an API key) |
private_dot_dircolors/private_LS_COLORS |
~/.dircolors/LS_COLORS |
trapd00r/LS_COLORS palette, dir mode 700; loaded by ~/.bashrc via GNU dircolors (needs coreutils) |
dot_config/nvim-private/encrypted_private_personal.lua.age |
~/.config/nvim-private/personal.lua |
age-encrypted, machine-local nvim settings |
dot_config/private_kitty/ |
~/.config/kitty/ |
kitty terminal config, dir mode 700; runtime state/backups excluded via .chezmoiignore |
dot_homebrew/Brewfile |
~/.homebrew/Brewfile |
Homebrew manifest (taps/brews/casks); install with brew bundle --global |
private_dot_gitconfig |
~/.gitconfig |
git config (user, filters, gh credential helper) |
dot_config/git/ignore |
~/.config/git/ignore |
global git ignore (.claude/settings.local.json) |
private_dot_gitignore_global |
~/.gitignore_global |
legacy global ignore (.DS_Store, *~) referenced by core.excludesfile |
private_dot_inputrc |
~/.inputrc |
readline vi mode and vi-command binds |
private_dot_blerc |
~/.blerc |
ble.sh binds; ble.sh itself is installed separately (see step 3) |
private_dot_editrc |
~/.editrc |
libedit vi mode |
private_dot_Rprofile |
~/.Rprofile |
R startup: loads ~/.secrets (see below), quit-without-saving, history hook |
private_dot_Renviron |
~/.Renviron |
non-secret R startup vars only; R_LIBS_USER must live here because R reads it before .Rprofile runs |
encrypted_private_dot_gcalclirc.age |
~/.gcalclirc |
age-encrypted; Google OAuth client id + secret |
dot_config/todoist/encrypted_private_config.json.age |
~/.config/todoist/config.json |
age-encrypted; Todoist API token |
private_dot_dictdrc |
~/.dictdrc |
dictd client; hardcodes /Users/mm223266 paths |
dot_hammerspoon/private_init.lua |
~/.hammerspoon/init.lua |
Hammerspoon config |
private_dot_ssh/private_config |
~/.ssh/config |
agent/keychain settings only — key material is excluded via .chezmoiignore |
dot_config/mpv/ |
~/.config/mpv/ |
mpv.conf + input.conf (rubberband pitch binds) |
dot_config/private_cmus/private_rc |
~/.config/cmus/rc |
cmus settings; cache/history/playlists excluded via .chezmoiignore |
dot_config/yazi/ |
~/.config/yazi/ |
yazi.toml + package.toml; plugins are git clones, restored with ya pkg install |
.chezmoiexternal.toml |
— | recipe: clone mickmcq/kickstart.nvim into ~/.config/nvim |
Not managed:
~/.git-credentialsholds plaintext tokens (credential.helper = store) and is excluded via.chezmoiignore— never commit it. Same for~/.ssh/id_*.~/.config/gh/hosts.ymlis also left alone:gh auth loginregenerates it (step 0).
~/.secrets is the single source of truth for every credential and personal
identifier. It is age-encrypted in this repo and reaches programs two ways:
- Shells —
~/.bash_profilesources it, so exports land in every login shell. - R —
~/.Rprofileparses it and callsSys.setenv(). This is deliberate and not redundant: RStudio.app and R.app are GUI apps, so they launch without the login shell's environment. Anything already set in the environment wins, so a shell export still overrides the file.
Two files are encrypted separately rather than folded into ~/.secrets, because
each program insists on reading its own config file: ~/.gcalclirc and
~/.config/todoist/config.json.
History: until 2026-08-02 the R keys were a second, hand-maintained copy inside
~/.Renviron. The copies had drifted — a differentANTHROPIC_API_KEYand two extra HuggingFace tokens under the spellingsHF_TokenandHF_NEW_TOKEN. If some R script still references those two names, update it toHF_TOKEN; the old tokens were live at the time of the merge and are worth revoking at huggingface.co/settings/tokens.
Neovim config is not stored here; it's pulled in as an external (its own
repo, mickmcq/kickstart.nvim). See that repo's README for its editing workflow.
Encryption uses age. The private key lives at ~/.config/chezmoi/key.txt
(never committed). Config is in ~/.config/chezmoi/chezmoi.toml.
⚠️ Order matters: restore the age key beforechezmoi apply. Without it, chezmoi cannot decrypt.secrets/personal.luaand apply fails.
The following process assumes that bash is your shell. If you use this on a new macOS machine, you may find that zsh is your shell. I installed bash from brew in a later step, detailed below. The changes to your configuration won't take effect until after that step.
The first command below comes from https://brew.sh, and may change over time. It may be better to view that URL to copy the latest command. Then run the second and third commands.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install chezmoi age gh
gh auth login # enables HTTPS git pulls (no SSH key needed)The key is backed up two ways (see Key backup below). Preferred — the passphrase-encrypted blob synced via iCloud Drive:
age -d "$HOME/Library/Mobile Documents/com~apple~CloudDocs/chezmoi-age-key.age" \
> ~/.config/chezmoi/key.txt # prompts for your passphrase
chmod 600 ~/.config/chezmoi/key.txt(Same-Mac alternative — restore from the local Keychain copy:)
security find-generic-password -s chezmoi-age-key -w | xxd -r -p \
> ~/.config/chezmoi/key.txt
chmod 600 ~/.config/chezmoi/key.txtchezmoi init --apply mickmcqThis clones this repo, applies the bash files, decrypts .secrets and
personal.lua using key.txt, and clones the nvim external into
~/.config/nvim. It also lays down ~/.homebrew/Brewfile.
Before you move on to step 3, you may want to examine ~/.homebrew/Brewfile and delete unwanted packages. There are over 130 packages, though, so it can be a tedious process! It may be easier to install everything, then subtract the things you don't want gradually over time.
chezmoi apply (step 2) put the Brewfile in place; now install everything from it:
brew bundle --global # installs all taps, brews, casks (incl. powerline-go)The most important package is bash. After installing it, you need to say
chsh -s /opt/homebrew/bin/bashEven this may not be enough. I have sometimes had to also manually add /opt/homebrew/bin/bash to /etc/shells. On the other hand, in one case it was automatically added without my knowing intervention.
One package that is not added in the above process is ble.sh. That package must be installed separately, using the instructions at https://github.com/akinomyoga/ble.sh.
Yazi's plugins are also not covered by brew bundle — they're git clones listed
in the managed ~/.config/yazi/package.toml. Restore them with:
ya pkg installchezmoi verify && echo "state matches"
test -f ~/.secrets && test -d ~/.config/nvim && echo "files in place"Edit a normal managed file (bash configs, etc.):
chezmoi edit ~/.bashrc # edits the source
chezmoi apply # writes changes to $HOME
chezmoi cd && git add -A && git commit -m "..." && git push && exitEdit an encrypted file (decrypts, re-encrypts on save):
chezmoi edit ~/.secrets
chezmoi edit ~/.config/nvim-private/personal.lua
chezmoi cd && git add -A && git commit -m "..." && git push && exitEdit the neovim config itself (init.lua, plugins, colors …): that's the
external repo — edit those files directly and commit to mickmcq/kickstart.nvim,
not via chezmoi. (chezmoi edit ~/.config/nvim/init.lua → "not managed".)
~/.config/chezmoi/key.txt is the only thing that can decrypt anything here.
Two backups exist:
- Local macOS Keychain — service
chezmoi-age-key(this Mac only). - Passphrase-encrypted blob in iCloud Drive — the off-machine backup;
restore with
age -d(see Step 1). The passphrase is memorized, stored nowhere.
If key.txt and both backups are lost, the encrypted files are
unrecoverable. Keep the passphrase safe.