✨ feat: migrate dotfiles management from rsync bootstrap to chezmoi - #12
Merged
Conversation
First step of the chezmoi migration: the dotfiles manager itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pure git mv, no content changes: leading dots become dot_ prefixes, .extra.tmpl becomes private_dot_extra.tmpl (0600 target), and bin scripts gain executable_ prefixes. Repo-level files (.gitignore, .gitattributes, .github, .macos, tests/, Brewfile, bootstrap.sh) keep their names — chezmoi ignores dot-prefixed source files natively, and the rest gets a .chezmoiignore next. .claude/settings.local.json stays machine-local and undeployed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
.chezmoi.toml.tmpl prompts once for a machine class (mac / linux / wsl / ephemeral) that drives all per-machine gating, and points macs at the development clone as the source dir. .chezmoiignore keeps repo-level files out of $HOME, drops macOS GUI config from Linux targets, and strips identity/secrets from ephemeral boxes. The deployed global gitignore/gitattributes (referenced by .gitconfig's excludesfile / attributesfile) split into dot_-prefixed copies so the repo's own housekeeping files stay repo-only. bin/subl becomes a symlink_ source file (chezmoi doesn't support raw symlinks in source state). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- dot_gitconfig.local.tmpl brings ~/.gitconfig.local under management: the mac branch renders byte-identical to the live file (verified with execute-template | diff); linux gets identity only with a documented agent-forwarding signing recipe; wsl adds 1Password's official core.sshCommand=ssh.exe pattern. Work identity (~/.gitconfig-ica) stays untracked. - private_dot_extra.tmpl switches from op inject to chezmoi's native 1Password templating (private_ = mode 0600). - dot_claude/create_CLAUDE.local.md.tmpl replaces bootstrap's printf; create_ preserves the only-write-when-missing semantics. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
README and CLAUDE.md now lead with the chezmoi one-liners (fresh machine, --one-shot disposable box, development clone) and document the machine-class system. bootstrap.sh becomes a thin deprecated wrapper around `chezmoi init --source . --apply`; the dotfiles alias becomes `chezmoi apply`. Secrets docs switch from op inject to chezmoi's onepasswordRead. Also fixes the stray ßß in the README title. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
chezmoi.bats does a full init + apply into an isolated $HOME for each machine class: ephemeral gets shell config and nothing sensitive, linux gets identity without signing plus a 0600 .extra, wsl gets the ssh.exe wiring, and create_ semantics are proven non-destructive on re-apply. shell.bats follows the dot_* renames; extra-tmpl.bats now enforces Go-template invariants and renders the template for real. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The per-class apply tests need the chezmoi binary. Hosted runners get the official installer into ~/.local/bin (PATH via GITHUB_PATH); the Rocky container and WSL distro install to /usr/local/bin as root, with curl added to their package sets. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GitHub's ubuntu runners export XDG_CONFIG_HOME, which chezmoi prefers over $HOME/.config — so the first test's machineClass=ephemeral config persisted outside the per-test $TMPHOME and promptStringOnce silently reused it, making the linux/wsl tests apply the ephemeral class (no .gitconfig.local) on CI while passing locally and in WSL's clean env. All chezmoi invocations now go through a helper that pins HOME and every XDG dir into the test's temp home. Verified locally by running the suite with a poisoned XDG_CONFIG_HOME. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rocky 9 images ship curl-minimal, which conflicts with the curl package while already providing the curl binary the chezmoi installer needs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 1 of the cross-platform plan: the repo becomes a chezmoi source directory. Seven atomic commits — Brewfile addition, pure renames, scaffolding, machine-class templates, docs + bootstrap deprecation, test rework, CI wiring.
What changes
dot_zshrc,private_dot_extra.tmpl,bin/executable_has-glyphs, …); repo-level files keep their names and stay undeployed (dot-prefixed = invisible to chezmoi, the rest via.chezmoiignore).mac/linux/wsl/ephemeral) drives all gating. Deviation from the approved plan:personal-mac/work-maccollapsed into onemacclass — both GitHub identities live on one Mac via includeIf, so the split bought nothing; a class can be added later if a work-only Mac appears.~/.gitconfig.localcomes under management as a template: the mac branch renders byte-identical to the live file (verified); linux gets identity-only with a documented agent-forwarding signing recipe; wsl gets 1Password's officialcore.sshCommand=ssh.exepattern. Note this puts name/email/github-user in a public repo — they're already in public commit metadata, but flagging it.~/.gitconfig-ica(work) stays untracked.~/.extraswitches from op inject to chezmoi's nativeonepasswordReadtemplating (mode 0600 viaprivate_); the ephemeral class never deploys it..gitconfig'sexcludesfile/attributesfile) split from the repo's own copies; the global one no longer carries repo-specific entries.bootstrap.shis a deprecated wrapper;dotfilesalias becomeschezmoi apply.Acceptance gate (from the plan):
chezmoi apply --dry-run -vagainst the live $HOME shows exactly two diffs, both intended (new.extratemplate header; global gitignore losing repo-only entries). 52 managed targets, mapping audited.Test plan
bats tests— 18/18 locally (full init+apply per machine class in isolated $HOMEs; create_ non-destruction; template render; dot_* parse/source checks)chezmoi execute-template < dot_gitconfig.local.tmpl | diff - ~/.gitconfig.local— identicalchezmoi apply --dry-run -v— only the two intended diffschezmoi applyon this Mac, open new shell, signed commit🤖 Generated with Claude Code