Operations
RFC: v0.2.503 Repository Reorganisation
Status: Accepted. This RFC was opened in this PR and immediately accepted by the maintainer with explicit decision to ship the reorganisation incrementally within v0.2.503 rather than the originally-proposed two-version deprecation window. Phases land as separate commits on
feat/v0.2.503; each is independently atomic and verified bydot lint+ the existing test matrix.
Summary
Split the current chezmoi-managed monorepo into a framework layer (distributable CLI + library) and a defaults layer (user-facing configuration), with the framework layer publishable as a standalone tarball to Homebrew, Scoop, and AUR. Maintain backwards-compatible behaviour for existing users via a one-shot migration script that runs on first apply after upgrade.
Motivation
R4 hard-audit identified the framework/user-config intermingling as the highest-leverage structural gap blocking de-facto- framework status (HARD_AUDIT_2026.md §8.5 Top-5 adoption gaps). Concrete symptoms:
-
Distribution stuck at "curl-pipe-bash". The Homebrew / Scoop / AUR manifests scaffolded in v0.2.503 (
install/{homebrew,scoop,aur}/) cannot publish until there's a singlebin/dottarball — chezmoi'sdot_*/executable_*/private_*prefixes force the current layout. Until that's fixed, downstream distros have nothing to package. -
New contributor onboarding cost. Even with the v0.2.503
STRUCTURE.md, ~20 chezmoi-prefixed root paths require a concept (the chezmoi naming contract) to navigate. Abin/+lib/+defaults/layout is self-documenting. -
Framework forks are blocked. Anyone wanting to fork the CLI without the maintainer's personal configs has to manually delete 80+ tool-specific directories under
dot_config/. A clean separation makes "fork the framework, apply my own defaults" a one-command flow. -
Test surface bleed. CI runs
chezmoi apply --dry-runon every PR, exercising both framework templates AND the maintainer's personal defaults. A real consumer running the framework will not exercise the maintainer'sdot_config/aider/etc. — and yet a regression there blocks CI.
The reorganisation is breaking for existing user installs: chezmoi tracks deployed files by source path, so moving bin/dot to bin/dot means the old ~/.local/bin/dot would be removed before the new path is installed. Mitigation: ship a migrate-v0.2-to-v0.3.sh script that runs before the first post-upgrade chezmoi apply.
Detailed design
Target layout
Following the Debian/aws-cli discipline (every top-level path has a clear purpose; contributor orients in <30 seconds):
.
├── bin/ # CLI entrypoints
│ ├── dot # was bin/dot
│ ├── dot-load-benchmark-pty # was bin/dot-load-benchmark-pty
│ ├── dot-theme-sync # was bin/dot-theme-sync
│ ├── dot-bootstrap # was bin/dot-bootstrap
│ └── dot-update # was dot_local/bin/executable_update (renamed)
├── lib/ # Framework library (no chezmoi)
│ ├── commands/ # was scripts/dot/commands/
│ ├── ui.sh # was scripts/dot/lib/ui.sh
│ ├── utils.sh # was scripts/dot/lib/utils.sh
│ ├── platform.sh # was scripts/dot/lib/platform.sh
│ ├── log.sh # was scripts/dot/lib/log.sh
│ ├── bento.sh # was scripts/dot/lib/bento.sh
│ └── secrets_provider.sh # was scripts/lib/secrets_provider.sh
├── share/ # OS-conventional resources
│ ├── man/man1/dot.1 # was dot_local/share/man/man1/dot.1
│ ├── completions/ # was dot_local/share/zsh/completions/
│ └── docs/ # was docs/
├── defaults/ # User-facing default config (was dot_config/, etc.)
│ ├── home/ # dotfiles deployed to $HOME (dot_X → .X)
│ ├── config/ # dotfiles deployed to $XDG_CONFIG_HOME
│ └── tools/ # per-tool configs (mise/, npmrc/, ...)
├── install/ # Distribution + bootstrap
│ ├── install.sh # was install.sh (moved one level down)
│ ├── homebrew/dot.rb # already at install/homebrew/ in v0.2.503
│ ├── scoop/dot.json # already at install/scoop/ in v0.2.503
│ ├── aur/PKGBUILD # already at install/aur/ in v0.2.503
│ ├── provision/ # was install/provision/ (chezmoi run_onchange_ hooks)
│ └── migrate/ # NEW: migrate-v0_2-to-v0_3.sh + rollback
├── tests/ # unchanged
├── examples/ # unchanged
├── tools/ # NEW: ops scripts not shipped to users
│ ├── ci/ # was tools/ci/
│ ├── release/ # was tools/release/
│ ├── maintenance/ # was tools/maintenance/
│ ├── docs/ # was tools/docs/
│ └── version-sync.sh # was scripts/version-sync.sh
├── .chezmoiroot # NEW: points at defaults/
├── README.md
├── LICENSE
├── CHANGELOG.md
├── CLAUDE.md / AGENTS.md / per-harness renders
└── (no more dot_X at root)
chezmoi adaptation
.chezmoiroot lets chezmoi treat a subdirectory as the source root. With .chezmoiroot = "defaults", chezmoi will look for defaults/home/dot_zshrc, defaults/config/dot_starship.toml, etc. — and deploy to the normal ~/.zshrc / ~/.config/starship.toml paths.
This means:
- Repo top-level is no longer required to follow chezmoi naming.
bin/dotis a plain shell script, notdot_local/bin/executable_dot.share/man/man1/dot.1is a plain file, not chezmoi-deployed.- A Homebrew formula can
bin.install 'bin/dot'directly.
Migration tool
install/migrate/migrate-v0.2-to-v0.3.sh:
- Detect existing chezmoi state at
~/.local/share/chezmoi/~/.config/chezmoi/chezmoi.toml. - Read the user's pinned source repo from chezmoi.toml; if it's
sebastienrousseau/dotfiles@<v0.2.x>, warn and confirm. - Run
chezmoi diffand persist the per-file output to~/.local/state/dotfiles/v0_2_to_v0_3_pre_diff.logso the user has a record of pre-migration state. - Run
chezmoi forgetfor paths that are moving (no destructive delete — chezmoi forget only un-tracks). - Update
~/.config/chezmoi/chezmoi.tomlto point at the new sourceDir with.chezmoiroothonoured. - Run
chezmoi apply— picks up the new layout and re-creates the user's files at their canonical paths. - Run
dot doctoranddot lintto verify.
The migration is idempotent and safe to abort: at step 4 the chezmoi state is removed but no user data is deleted. At step 6 chezmoi notices "these files already exist on disk with content matching the source" and is a no-op.
Library bash-source paths
Today scripts/dot/commands/<cmd>.sh does:
SCRIPT_DIR=""
After reorganisation:
SCRIPT_DIR=""
Or, more robustly, drive lookup from a single env var set by bin/dot:
The Homebrew formula sets $DOT_LIB to ${libexec}/lib so bin/dot finds its library wherever the package manager installed it.
Distribution surface
Once bin/dot is standalone:
| Channel | Artefact | Verify command |
|---|---|---|
| Homebrew tap | dot-${VERSION}-${OS}-${ARCH}.tar.gz | brew install sebastienrousseau/tap/dot && dot version |
| Scoop bucket | dot.json → dot-${VERSION}-windows-${ARCH}.zip | scoop install dot && dot version |
| AUR | dotfiles-git PKGBUILD building from source | paru -S dotfiles-git && dot version |
install.sh | Same SHA256-verified path as today | bash install.sh |
| Direct tarball | Cosign-signed + SLSA-attested release asset | per docs/security/VERIFY_RELEASE.md |
The chezmoi-managed defaults/ subtree is only consumed when a user wants the maintainer's opinionated config layer. It's a strict superset: install dot standalone for the CLI; layer defaults/ on top if you want the wallpaper-theming + multi-shell setup.
Backwards compatibility
| Surface | v0.2.x behaviour | v0.2.503 behaviour | Breaking? |
|---|---|---|---|
~/.local/bin/dot | Deployed by chezmoi | Replaced by Homebrew/Scoop install, OR symlinked by chezmoi from the new source | Yes — path may move; migration script handles it |
~/.zshrc etc | Source-pinned at dot_zshrc | Source-pinned at defaults/home/dot_zshrc, chezmoi reads via .chezmoiroot | No — destination path unchanged |
dot <cmd> API | All subcommands work as documented | Same | No |
scripts/dot/commands/*.sh consumers | Direct source paths used in user customisations | Path moves to lib/commands/*.sh | Yes — affects any user who source'd these directly |
.chezmoidata.toml | Repo root | Repo root (unchanged for compatibility with old user chezmoi init flows) | No |
Two-version deprecation window
v0.2.503 ships with the migration script and a deprecation warning in dot doctor. v0.4.0 removes any v0.2.x shim code. Users who skip v0.2.503 entirely (v0.2.x → v0.4.0) hit a hard error and must run the migration tool from a v0.3.x release manually.
Alternatives considered
A) Keep the chezmoi monorepo as-is
Pros: zero migration cost; works today. Rejected: blocks Homebrew/Scoop/AUR publication permanently. The Top-5 adoption gap remains. R4 audit's "9.0/10 internal · 7.5/10 adoption" plateau persists.
B) Two-repo split (framework + defaults)
Publish dot framework at sebastienrousseau/dot and the maintainer's personal defaults at sebastienrousseau/dotfiles.
Pros: cleanest possible separation. Framework forks trivial. Rejected (for v0.3): requires a second repo, doubles the CI matrix, and forces users to install from two sources. Defer to v0.4 if v0.3 single-repo with .chezmoiroot proves insufficient.
C) Rename current root files only (cosmetic)
Just rename bin/dot → bin/executable_dot without .chezmoiroot.
Rejected: chezmoi only resolves the executable_ / dot_ prefixes for files inside its source root, so moving the prefixed file outside breaks chezmoi-driven install entirely without giving us a standalone tarball.
Unresolved questions
- How does the
defaults/subtree behave when a user wants to override one default? Today they editdot_config/X.tmpldirectly. Post-reorg, do they: (a) editdefaults/config/X.tmpland live with merge conflicts on framework updates, or (b) use a chezmoidataoverride + template conditional, or (c) maintain a second repo layered atopdefaults/? - Should
install/migrate/ship in the regular framework install, or only via a one-shothttps://...migrate.shURL? Bundling it forever increases install size; URL-only requires the user to find and trust the right URL during a stressful upgrade moment. - Does
.chezmoirootsurvive existing user customisations in~/.config/chezmoi/chezmoi.toml? Needs verification on a real upgrade test. - Windows-native
bin/dot: standalone PowerShell rewrite, or wrapper that shells to bash via WSL/git-bash?POWERSHELL_PARITY.mddocuments the current stub state.
Implementation plan
| Phase | Scope | Effort |
|---|---|---|
| 1 | Draft + ratify this RFC. Get user OK. | Done (this PR's draft) |
| 2 | Create defaults/, bin/, lib/, share/, tools/ and copy files. Update bash source paths. Add .chezmoiroot. | 1 week |
| 3 | Write install/migrate/migrate-v0_2-to-v0_3.sh. Test against a synthetic v0.2.503-installed environment. | 3 days |
| 4 | Update CI: every workflow that references scripts/, dot_local/, dot_config/ needs path updates. | 3 days |
| 5 | Update every doc that references the old paths. Most are in docs/manual/. | 1 day |
| 6 | Cut v0.2.999 RC as a deprecation-warning-only release; let real users dry-run the migration. | 1 day + 2-week soak |
| 7 | Cut v0.2.503 with the actual reorg + migration tool. | 1 day |
| 8 | Publish to Homebrew/Scoop/AUR using install/{homebrew,scoop,aur}/ scaffolds. | 1 week |
| Total | ~5 weeks calendar time |
See also
HARD_AUDIT_2026.md§8.3 — cross-platform gap analysis.HARD_AUDIT_2026.md§8.5 — Top-5 de-facto adoption gaps.STRUCTURE.md— today's layout (honest about the chezmoi-prefix forcing function).GOVERNANCE.md— RFC process this document follows.install/README.md— distribution-channel publication checklist.- Reference: Debian/aws-cli — clean top-level discipline.