@sebastienrousseau/dotfiles
Version:
The Trusted Shell Platform — Universal dotfiles managed by Chezmoi. Features Bash & Zsh for macOS, Linux & WSL. Rust modern tooling & enterprise-grade security.
242 lines (185 loc) • 18.1 kB
Markdown
---
render_with_liquid: false
---
<!-- Copyright (c) 2015-2026 Dotfiles. All rights reserved. -->
# Repository Layout
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`](../NAMING_CONVENTIONS.md). For the broader
architectural rationale (philosophy, startup model, flake strategy), see
[`ARCHITECTURE.md`](ARCHITECTURE.md). For the configuration-management
strategy at a higher level, see [`../CONFIG_STRATEGY.md`](../CONFIG_STRATEGY.md).
---
## 1. Chezmoi source tree — the actual dotfiles
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_foo` deploys as `.foo` (not `dot_foo`). Chezmoi
> consumes the `dot_` prefix even when stacked with `executable_`.
### Chezmoi data and templates
| 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. |
### Shell rc files (root level)
| 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`](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 |
### Large chezmoi directories
| 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 root
Scripts triggered when their content changes. Numbering follows the
convention in [`../NAMING_CONVENTIONS.md`](../NAMING_CONVENTIONS.md):
- `run_onchange_20-ghostty-config.sh.tmpl` — re-renders Ghostty config
- `run_onchange_21-topgrade-config.sh.tmpl` — refreshes topgrade config
- `run_onchange_after_fonts.sh` — post-deploy font cache refresh
---
## 2. AI-assistant files — **three** files, three distinct roles
This 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 |
| `docs/OPENCODE.md` | 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.
---
## 3. Agent-protocol surface
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 |
---
## 4. CI/CD and repo metadata
| 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 |
---
## 5. Build, bootstrap, and dev tooling
| 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 |
---
## 6. Scripts (`scripts/`) — repo-local, never deployed
Nothing under `scripts/` ends up in `$HOME`. It's all tooling for running
the repo itself.
| Subdir | Purpose |
|-------------------------------------------|-----------------------------------------------------------------|
| `tools/ci/` | CI helpers (`check-copyright-headers.sh`, `install-chezmoi-verified.sh`, `validate-ci-config.sh`) |
| `scripts/dot/commands/` | Subcommand implementations for the `dot` CLI |
| `tools/docs/` | Manual build pipeline (`build-manual.sh`, `check-manual.sh`) |
| `scripts/theme/` | K-Means CIELAB theme engine + HEIC merge/convert |
| `scripts/ops/`, `tools/maintenance/`, `tools/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 |
---
## 7. Documentation (`docs/`)
| Path | Purpose |
|---------------------------------------|----------------------------------------------------------------------------|
| `docs/manual/` | 26-page GNU-Stow-style reference manual (the v0.2.501 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 |
---
## 8. Tests (`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.
---
## 9. Other top-level
| 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 |
| `docs/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 |
---
## 10. Local-only artefacts (gitignored — if you see them, don't commit them)
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 `tools/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 |
---
## How to decide where a new file belongs
A quick decision tree for common cases:
- **New app config that lives under `~/.config/<app>/`** → `dot_config/<app>/` (see `docs/NAMING_CONVENTIONS.md` → "Adding New Modules").
- **New user-facing CLI script** → `dot_local/bin/executable_<name>`.
- **New `dot` subcommand** → implementation in `scripts/dot/commands/<name>.sh`, routing in `bin/dot`.
- **New repo-only automation** (CI helper, maintenance task, release step) → `scripts/<domain>/<name>.sh`.
- **New test** → `tests/unit/<domain>/test_<feature>.sh` (follow `test_{domain}_{feature}.sh` naming).
- **New doc** → pick the narrowest of `docs/architecture/`, `docs/reference/`, `docs/guides/`, `docs/operations/`, `docs/security/`.
- **New alias file** → `.chezmoitemplates/aliases/<category>/<tool>.aliases.sh` (see conventions doc).
- **New run-once hook** → `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.