How Configuration Works
The repo manages application configs through two mechanisms: symlinks for files you edit directly, and templates for files generated from environment variables.
Symlinked Configs
These config files are symlinked from their system location to the repo. Editing either side changes the same file.
| Application | System Path | Repo Path |
|---|---|---|
| Zsh | ~/.zshrc |
configs/shell/.zshrc |
| Starship | ~/.config/starship.toml |
configs/shell/starship.toml |
| Mise | ~/.config/mise/config.toml |
configs/mise/config.toml |
| Ghostty | ~/.config/ghostty/config |
configs/ghostty/config |
| Zed | ~/.config/zed/settings.json |
configs/zed/settings.json |
| Claude | ~/.claude/settings.json |
configs/claude/settings.json |
| GitHub CLI | ~/.config/gh/config.yml |
configs/gh/config.yml |
| btop | ~/.config/btop/btop.conf |
configs/btop/btop.conf |
| AWS | ~/.aws/config |
configs/aws/config |
| Colima | ~/.colima/default.yaml |
configs/colima/default.yaml |
| VS Code | ~/Library/Application Support/Code/User/settings.json |
configs/vscode/settings.json |
~/.zshenvis not symlinked. The shell role copiesconfigs/shell/.zshenv.exampleto~/.zshenvonly on first run (when it does not exist) so each machine keeps its own secrets. The.zprofilethat bootstraps Homebrew is generated by the shell role on first run as well.
How Symlinks Work
When the playbook runs, it creates symbolic links so the system path points to the file inside the repo. Because both paths reference the same underlying file:
- Editing the file in its system location (e.g.,
~/.config/ghostty/config) changes the repo copy. - Editing the file in the repo (e.g.,
configs/ghostty/config) changes what the application sees.
To propagate changes to another machine:
# On the machine where you made changesgit add . && git commit -m "update ghostty config" && git push
# On the other machinegit pull && make updateTemplated Configs
These files are generated from Jinja2 templates using values from your ~/.zshenv. They are re-rendered on every playbook run, so direct edits will be overwritten.
| File | Template Source |
|---|---|
~/.gitconfig |
roles/git/templates/gitconfig.j2 |
~/.config/git-configs/personal.gitconfig |
roles/git/templates/gitconfig-personal.j2 |
~/.config/git-configs/work.gitconfig |
roles/git/templates/gitconfig-work.j2 |
~/.ssh/config |
roles/ssh/templates/config.j2 |
To change these configs, either:
- Edit the Jinja2 template in the repo, or
- Change the variable values in
~/.zshenvand re-runmake setup
Environment Variables (~/.zshenv)
The ~/.zshenv file is never committed to the repo. It holds personal data that varies per machine and per user. On first run, setup.sh copies .zshenv.example to ~/.zshenv as a starting point.
Required Variables (fill before running setup)
| Variable | Purpose |
|---|---|
GIT_USER_NAME |
Full name used in git commits |
GIT_ORGS |
CSV of <github-org>:<folder>:<email> triples (first entry = default identity) |
SSH_KEY |
Filename of the single SSH key used everywhere (default: id_ed25519) |
The example file also prepends ~/.local/share/mise/shims to PATH so mise-managed runtimes (Node, Python, Java, Bun, etc.) are visible to GUI apps and login shells.
Recommended Variables (for multi-org separation)
| Variable | Purpose |
|---|---|
GIT_ORGS |
CSV of <github-org>:<folder>:<email> triples. First entry is the default identity. |
Example:
export GIT_ORGS="sujeet-pro:~/personal:sujeet@personal.com,Quince-Engineering:~/work:sujeet@quince.com"Optional Variables (configure later)
Secret env vars all carry the _CRED suffix and live in per-service files under $CREDS_HOME/<svc>/creds.sh — never in ~/.zshenv. Non-secret per-service config lives next to them in $CREDS_HOME/<svc>/config.sh. Both are auto-sourced by $CREDS_HOME/loader.sh (which ~/.zshenv sources at the end). The currently-configured services are: anthropic, atlassian, datadog, github, google, looker, mixpanel, npm, okta, slack, snowflake, statsig.
See configs/creds/README.md for the layout and the per-service env-var matrix.
Multi-org Separation
Git is configured with conditional includes based on directory path and remote URL — driven entirely by GIT_ORGS:
Directory-based matching
Each GIT_ORGS entry maps one folder to one identity. Any repo under that folder uses the org’s email automatically.
Remote URL-based matching
The same identity also applies to repos cloned outside the mapped folder, as long as the remote URL matches github.com:<org>/... (SSH or HTTPS). This means you never have to remember to switch git identities.
How it works
The first GIT_ORGS entry is the default identity used for repos that don’t match any folder or remote. The per-org overrides are emitted as ~/.config/git-configs/<org>.gitconfig and loaded via includeIf in ~/.gitconfig.