Personal dotfiles managed with chezmoi, supporting both macOS and Linux (Fedora/RHEL). Features encrypted secrets management using age, cross-platform templating, and automated setup via Ansible.
Two options: automated (recommended) or manual.
This is the easiest way to get everything configured on a new machine.
Prerequisites:
- macOS:
brew install chezmoi age ansible-core - Linux (Fedora):
sudo dnf install chezmoi age ansible-core - 1Password CLI authenticated (
op whoamishould work)
Run the setup:
ansible-playbook shanemcd.toolbox.dotfiles
exec zsh # Reload shellThe shanemcd.toolbox Ansible collection automatically:
- Creates
~/.config/chezmoiwith secure permissions - Fetches the age key from 1Password (from the "Chezmoi Key" item)
- Clones the dotfiles repo and initializes the secrets submodule
- Decrypts secrets via
.chezmoi.toml.tmpl - Applies all configuration
If you prefer manual control or don't have Ansible set up yet.
Prerequisites:
- macOS:
brew install chezmoi age - Linux (Fedora):
sudo dnf install chezmoi age
Setup steps:
-
Initialize and apply:
chezmoi init --apply [email protected]:shanemcd/dotfiles.git
This automatically:
- Clones the dotfiles repository
- Initializes the
external_secretssubmodule (private repo with encrypted secrets) - Prompts for the age private key if not already present (paste from 1Password)
- Writes the key to
~/.config/chezmoi/key.txtwith secure permissions - Generates
~/.config/chezmoi/chezmoi.tomlfrom.chezmoi.toml.tmpl(which decrypts secrets on-the-fly) - Applies all dotfiles to your home directory
-
Reload the shell:
exec zsh
Done! Environment configured.
This setup uses chezmoi with several key features:
- Cross-platform templates: Files ending in
.tmpluse Go templates to handle macOS vs Linux differences - Encrypted secrets: Sensitive data is encrypted with age and stored in a private git submodule
- Template-based decryption:
.chezmoi.toml.tmplautomatically decrypts secrets when chezmoi processes it - Symlinked encrypted files: Individual encrypted files (like gcloud config) are symlinked from the private submodule
Three-layer approach:
-
Private encrypted repository (dotfiles-secrets):
- Git submodule at
external_secrets/ - Contains
chezmoi-secrets.toml.age(encrypted template variables) - Contains encrypted dotfiles like
~/.config/gcloud/credentials.db - Requires both GitHub access AND the age encryption key
- Git submodule at
-
Template-based decryption (
.chezmoi.toml.tmpl):- Automatically decrypts secrets when chezmoi generates config
- Uses
output "age" ...to decrypt on-the-fly - Falls back to placeholder values if key is missing
-
Age encryption key (
~/.config/chezmoi/key.txt):- Required to decrypt all secrets
- Automatically prompted during
chezmoi initif not present - Public key:
age1wuc38w6748e7l0za4v5paccs9muasjuuqrdqq8npqyxl0dfseclsfh386e - Backed up in 1Password (item: "Chezmoi Key")
Security model:
- Encrypted with age (secure even if GitHub is compromised)
- Private repository (not publicly visible)
- Requires both GitHub access AND encryption key
# Edit a managed file
chezmoi edit ~/.zshrc
# Or edit directly in the source directory
vim ~/.local/share/chezmoi/dot_zshrc.tmpl
# Preview what will change
chezmoi diff
# Apply changes
chezmoi apply -v
# Add a new file to chezmoi
chezmoi add ~/.gitconfigOn machine A (where you made changes):
chezmoi cd
git add .
git commit -m "Update zsh config"
git push
exitOn machine B (pulling changes):
chezmoi update --init # Pulls, regenerates config, appliesThe --init flag is important—it recreates ~/.config/chezmoi/chezmoi.toml from the template, ensuring secrets are re-decrypted.
When you need to add or change secrets (API keys, project IDs, etc.):
# 1. Navigate to secrets submodule
cd ~/.local/share/chezmoi/external_secrets
# 2. Decrypt secrets
age -d -i ~/.config/chezmoi/key.txt -o chezmoi-secrets.toml chezmoi-secrets.toml.age
# 3. Edit your secrets
vim chezmoi-secrets.toml
# 4. Re-encrypt
age -r age1wuc38w6748e7l0za4v5paccs9muasjuuqrdqq8npqyxl0dfseclsfh386e \
-o chezmoi-secrets.toml.age chezmoi-secrets.toml
# 5. Clean up and commit to secrets repo
rm chezmoi-secrets.toml
git add chezmoi-secrets.toml.age
git commit -m "Update secrets"
git push
# 6. Update main dotfiles repo to track new submodule commit
cd ~/.local/share/chezmoi
git add external_secrets
git commit -m "Update secrets submodule"
git push
# 7. Update on other machines
chezmoi update --init- Homebrew path management (
/opt/homebrew/bin) - iTerm2 shell integration
- Bun JavaScript runtime
- Tinty theme auto-switching based on system dark mode
- fzf via Homebrew
- Krew (kubectl plugin manager) in PATH
- Podman aliases and socket configuration for toolbox environments
- fzf from system packages
Check what chezmoi will do:
chezmoi diffSee what files are managed:
chezmoi managedVerify template rendering:
chezmoi execute-template < ~/.local/share/chezmoi/dot_zshrc.tmplView current configuration data:
chezmoi dataForce re-apply everything:
chezmoi apply --forceFor detailed technical documentation, architecture decisions, and development guidelines, see CLAUDE.md.
For the Ansible automation code, see shanemcd/toolbox.