Personal configuration files, managed with chezmoi. Uses Go templates for hostname-based multi-environment support across work and home machines.
Prerequisite: Homebrew — everything else is installed from it (see Provisioning a new machine).
One thing in this repo is encrypted with age, decrypting against the identity at ~/.config/chezmoi/age-identity.txt:
.chezmoisecrets.age— YAML of static secrets (URLs, server addresses), decrypted on demand by thechezmoi-secretshelper.
The single inviolable rule: the identity file must exist at that path before chezmoi apply runs. If it doesn't, chezmoi-secrets cannot decrypt the static secrets. Recovery is just "place the identity, re-run apply" — no corrupted state, only missing files.
dot-secret's runtime backends are not encrypted — they are generic, convention-based scripts that carry no store-specific details (see Runtime secret access).
The age identity must exist at ~/.config/chezmoi/age-identity.txt before apply. It is generated per-machine (it cannot be copied) and registered as a recipient elsewhere.
-
Install Homebrew, then bootstrap:
brew install chezmoi age -
Create
~/.config/chezmoi/age-identity.txt— pick one:- Secure Enclave —
age-plugin-se keygen -o ~/.config/chezmoi/age-identity.txt - YubiKey — write the stub printed by
age-plugin-yubikey - Password-backed —
age-keygen | age -p -o ~/.config/chezmoi/age-identity.txt(passphrase-encrypted key; age prompts for it on apply)
- Secure Enclave —
-
Register it as a recipient on an existing machine: append the recipient line to
.chezmoisecrets-recipients.txt, runchezmoi-secrets edit(save to re-encrypt), commit, push. First machine? Add the line in your local clone instead, then seed secrets withchezmoi-secrets editafter step 4. -
Clone and apply:
chezmoi init --apply git@github.com:USER/dotfiles.git -
Install packages:
brew bundle --file ~/.local/share/chezmoi/Brewfile -
Set fish as login shell:
command -v fish | sudo tee -a /etc/shells && chsh -s "$(command -v fish)" -
Select the
dot-secretbackend:echo onepassword > ~/.config/dot-secret/backend(see Runtime secret access).
Static secrets live in .chezmoisecrets.age. The [secret] block in .chezmoi.toml.tmpl calls a chezmoi-secrets wrapper that decrypts on demand. Templates read values with:
{{ (secret | fromYaml).some_key | quote }}
To update:
chezmoi-secrets edit # modify values, save
chezmoi diff # verify rendered templatesCommit .chezmoisecrets.age and push. Other machines pick up changes on the next chezmoi update.
Short-lived automation secrets (API keys for tooling, agent skills, etc.) go through dot-secret instead of being stored in shell startup files or ~/.claude/settings.json.
dot-secret list
dot-secret get linkup_api_key
dot-secret set firecrawl_api_keyThe public command is a stable dispatcher: it reads a backend name from a local selector at ~/.config/dot-secret/backend and execs the matching implementation under ~/.config/dot-secret/impls/<backend>. The impls are generic, convention-based scripts managed by chezmoi from dot_config/dot-secret/impls/ — they contain no vault names, item names, or other store-specific details, so they are safe to keep in this public repo. Each backend stores secrets at a derivable location:
| Backend | Selector | Convention |
|---|---|---|
| 1Password | onepassword |
op://dot-secret/<name>/credential (dedicated dot-secret vault) |
| macOS Keychain | keychain |
generic-password, service dot-secret.<name>, account $USER |
The selector is kept local (not committed) so the repo never reveals which machine uses which password manager. Set it once per machine, e.g. echo onepassword > ~/.config/dot-secret/backend. New backends (e.g. pass for non-hardware systems like WSL) drop in as additional impls/<backend> scripts.