A map of every top-level folder and file in this repo, grouped by purpose. Use this when you’re not sure where something belongs or why a particular directory exists.
For naming conventions (file prefixes, run-script numbering tiers), see
../NAMING_CONVENTIONS.md. For the broader
architectural rationale (philosophy, startup model, flake strategy), see
ARCHITECTURE.md. For the configuration-management
strategy at a higher level, see ../../CONFIG_STRATEGY.md.
Chezmoi reads this directory and deploys to $HOME. Filename prefixes
carry semantics:
| Prefix | Effect | Example |
|---|---|---|
dot_ |
Deployed with a leading . |
dot_gitconfig.tmpl → ~/.gitconfig |
private_ |
Sets 0600 perms on deploy |
private_dot_ssh/ → ~/.ssh/ |
executable_ |
Sets +x on deploy |
executable_dot → ~/.local/bin/dot |
run_onchange_ |
Runs once when its content hash changes | run_onchange_20-ghostty-config.sh.tmpl |
.tmpl |
Rendered as a Go template at apply time | dot_npmrc.tmpl |
Gotcha:
executable_dot_foodeploys as.foo(notdot_foo). Chezmoi consumes thedot_prefix even when stacked withexecutable_.
| Path | Role |
|---|---|
.chezmoi.toml.tmpl |
Init-time prompts (name, email, signing key). |
.chezmoidata.toml |
Source of truth for version, profile, default theme, shell, feature flags. |
.chezmoidata/ |
Split data files: themes.toml, keybinds.toml, hardware.toml. |
.chezmoiignore.tmpl |
Feature-flag-gated “don’t deploy these to $HOME” list. |
.chezmoitemplates/ |
Reusable template partials (aliases/, functions/, paths/, desktop/). Not deployed. |
| Path | Target | Purpose |
|---|---|---|
dot_bashrc, dot_profile |
~/.bashrc, ~/.profile |
Bash startup |
dot_zshenv, dot_zprofile, dot_zshrc |
~/.zshenv etc. |
Zsh startup chain (see ARCHITECTURE.md for order) |
dot_vimrc, dot_inputrc, dot_psqlrc, dot_sqliterc, dot_Xresources |
~/.* |
Classic per-tool dotfiles |
dot_gitconfig.tmpl, dot_npmrc.tmpl |
~/.gitconfig, ~/.npmrc |
Templated — identity/tokens injected at apply |
dot_cargo/config.toml.tmpl |
~/.cargo/config.toml |
Rust build dirs redirected to /tmp |
dot_fdignore, dot_noderc, dot_rustfmt.toml |
~/.* |
Per-tool config |
private_dot_netrc.tmpl, private_dot_ssh/ |
~/.netrc, ~/.ssh/ |
0600 files |
| Path | Target | Notes |
|---|---|---|
dot_config/ |
~/.config/ |
Largest — fish, zsh, nvim, ghostty, tmux, niri, mise, and ~90 other app configs. |
dot_local/bin/ |
~/.local/bin/ |
Every dot-* subcommand and helper script (the dot CLI lives here). |
dot_local/share/ |
~/.local/share/ |
Fonts and shared data. |
dot_etc/opt/chrome/policies/ |
~/etc/opt/chrome/policies/ |
Managed Chrome enterprise policies. |
run_onchange_* hooks at the rootScripts triggered when their content changes. Numbering follows the
convention in ../NAMING_CONVENTIONS.md:
run_onchange_20-ghostty-config.sh.tmpl — re-renders Ghostty configrun_onchange_21-topgrade-config.sh.tmpl — refreshes topgrade configrun_onchange_after_fonts.sh — post-deploy font cache refreshThis is the most common source of confusion in the repo. All three files exist on purpose and don’t overlap:
| File | Deployed to | Audience | Scope |
|---|---|---|---|
dot_claude/CLAUDE.md |
~/.claude/CLAUDE.md |
Claude Code, in any cwd on this machine | Personal, cross-project |
CLAUDE.md (repo root) |
Not deployed | Claude Code, when cwd is this repo | Repo-scoped guidance |
OPENCODE.md (repo root) |
Not deployed | OpenCode CLI, when cwd is this repo | Repo-scoped guidance (mirror) |
.claude/settings.local.json |
Not deployed, not tracked | Claude Code | Per-machine permission allowlist |
Each of the three tracked files carries a header comment explaining its role to prevent drift. Keep that header in place when editing.
Standards-compliant discovery endpoints that let external agents and tools find this workstation’s agent capabilities:
| Path | Purpose |
|---|---|
.well-known/agent-card.json |
A2A v0.3 agent card — skills, capabilities, URL |
.well-known/agent.json |
Legacy pointer card, kept for back-compat |
.well-known/mcp/server-card.json |
MCP server discovery manifest |
| Path | Purpose |
|---|---|
.github/workflows/ |
20+ workflows: ci.yml, ci-enforced.yml, reusable lints, release pipelines |
.github/workflows/reusable-*.yml |
Shared workflow fragments (shell-lint, lua-lint, nix-lint, copyright-lint, test-suite, secrets-scan, security-baseline) |
.github/ISSUE_TEMPLATE/, PULL_REQUEST_TEMPLATE.md, CODEOWNERS, SECURITY.md, CONTRIBUTING.md, CODE-OF-CONDUCT.md, FUNDING.yml |
Standard GitHub metadata |
.github/security-policies/ |
Org-level security policy files |
.github/branch-protection-config.json, BRANCH_PROTECTION.md |
Codified branch-protection settings |
.github/dependabot.yml |
Dependency bump schedule |
.devcontainer/ |
GitHub Codespaces + VS Code dev container |
Dockerfile.test, tests/Dockerfile.sandbox |
Ubuntu sandboxes for integration / e2e tests |
| Path | Purpose |
|---|---|
install.sh |
Top-level one-liner installer |
install/provision/, install/lib/ |
Platform-specific install helpers invoked by install.sh |
Makefile, Justfile.tmpl, treefmt.toml |
Convenience runners |
mise.toml, mise-versions.lock.json |
Mise toolchain versions (locked) |
flake.nix, flake.lock (root) |
Root Nix flake for direnv + repo dev shell |
nix/flake.nix, nix/home.nix |
Separate flake for Home Manager activation (used by dot upgrade and ci-enforced.yml → lint-nix) |
lib/wasm-tools/ |
Vendored WebAssembly tooling (build output gitignored) |
.envrc |
direnv hook into the root flake |
scripts/) — repo-local, never deployedNothing under scripts/ ends up in $HOME. It’s all tooling for running
the repo itself.
| Subdir | Purpose |
|---|---|
scripts/ci/ |
CI helpers (check-copyright-headers.sh, install-chezmoi-verified.sh, validate-ci-config.sh) |
scripts/dot/commands/ |
Subcommand implementations for the dot CLI |
scripts/docs/ |
Manual build pipeline (build-manual.sh, check-manual.sh) |
scripts/theme/ |
K-Means CIELAB theme engine + HEIC merge/convert |
scripts/ops/, scripts/maintenance/, scripts/release/ |
Operator tooling |
scripts/diagnostics/, scripts/qa/, scripts/security/, scripts/secrets/ |
Domain-scoped scripts |
scripts/fonts/, scripts/demo/, scripts/git-hooks/, scripts/tools/, scripts/tuning/, scripts/lib/ |
Supporting scripts |
scripts/uninstall.sh, scripts/version-sync.sh |
Top-level ops entrypoints |
docs/)| Path | Purpose |
|---|---|
docs/manual/ |
26-page GNU-Stow-style reference manual (the v0.2.500 feature) |
docs/architecture/ |
This file + core architecture docs (ARCHITECTURE, INTEROP, fleet, walkthrough) |
docs/operations/ |
Runbooks, traceability matrix, migration notes |
docs/reference/ |
Command/config reference material |
docs/guides/ |
Long-form how-tos |
docs/security/ |
Threat model, disclosure policy, audit records |
docs/adr/ |
Architecture Decision Records |
docs/themes/ |
Theme catalogue / screenshots |
docs/interop/ |
Agent/MCP interop notes |
docs/archive/ |
Superseded docs kept for history |
docs/NAMING_CONVENTIONS.md |
Naming bible (file prefixes, run-script numbering tiers) |
docs/index.md, docs/README.md, docs/AI.md, docs/COPYRIGHT |
Entry points |
tests/)| Path | Purpose |
|---|---|
tests/framework/ |
test_runner.sh, assertions.sh, mocks.sh — the custom shell-test framework |
tests/unit/ |
Unit tests organised by domain: aliases/, ci/, docs/, dot-cli/, fish/, functions/, install/, nvim/, ops/, secrets/, security/, shell/, theme/, tools/, diagnostics/, misc/, nushell/ |
tests/integration/ |
End-to-end install and apply flows |
tests/regression/ |
Guardrail tests for previously-broken behaviours |
tests/performance/ |
benchmark_runner.sh and friends |
tests/benchmark.sh, tests/test-aliases.sh, tests/test-docker.sh |
Top-level entrypoints |
tests/Dockerfile.sandbox |
Fresh-Ubuntu sandbox image for integration tests |
Tests execute shell source files directly — do not use Go template
syntax in non-.tmpl files, or the test framework will choke on the curly
braces.
| Path | Purpose |
|---|---|
config/ |
Repo-local tool configs: cliff.toml (changelog), gitleaks.toml, pre-commit-config.yaml, stylua.toml, trivyignore |
templates/chezmoi-data/, templates/projects/ |
Starter scaffolding for new machines / new projects |
examples/ |
14 standalone demo scripts used by the manual and tutorials |
CHANGELOG.md, LICENSE, README.md |
Standard |
CONFIG_STRATEGY.md |
High-level “how configuration management works here” overview |
.gitattributes, .gitignore, .gitleaksignore, .editorconfig, .secrets.baseline, .sops.yaml, .luacheckrc |
Repo-level tool configs |
.pre-commit-config.yaml → config/pre-commit-config.yaml |
Symlink so pre-commit finds the canonical config |
The following paths can appear during local work but are excluded from
version control. If one of them ever shows up in git status, check the
.gitignore entry rather than adding the file:
| Path | Source |
|---|---|
_build/ |
Output of scripts/docs/build-manual.sh |
.pnpm-store/ |
pnpm’s content-addressable store (should never appear here) |
.claude/ |
Claude Code per-machine state (settings.local.json permission allowlists) |
node_modules/ |
Node dependency trees from repo-local scripts |
.version-sync-backup/ |
Timestamped backups from version-sync.sh |
lib/wasm-tools/target/ |
Rust build artefacts for the vendored wasm tooling |
dot_etc/machines/ |
Host-specific installer overrides |
A quick decision tree for common cases:
~/.config/<app>/ → dot_config/<app>/ (see docs/NAMING_CONVENTIONS.md → “Adding New Modules”).dot_local/bin/executable_<name>.dot subcommand → implementation in scripts/dot/commands/<name>.sh, routing in dot_local/bin/executable_dot.scripts/<domain>/<name>.sh.tests/unit/<domain>/test_<feature>.sh (follow test_{domain}_{feature}.sh naming).docs/architecture/, docs/reference/, docs/guides/, docs/operations/, docs/security/..chezmoitemplates/aliases/<category>/<tool>.aliases.sh (see conventions doc).run_onchange_<NN>-<verb>-<noun>.sh.tmpl at the root, using the numbering tier appropriate to its category.If none of the above fits, stop and ask in an issue or PR before introducing a new top-level directory. The current layout is deliberate and one-off additions cost everyone later.