Chezmoi
npx -y skills add athal7/dotfiles --skill chezmoiAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Manage dotfiles via chezmoi — apply safely, destroy files, manage LaunchAgents and externals, config and template gotchas
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
7.4 KB, as published. Nobody here has run it
chezmoi apply deploys source files to ~ and runs run_onchange scripts (brew bundle, skill sync, etc.).
Deploy workflow
Changes land via chezmoi-deploy, not pull requests. The source dir is pinned to the primary checkout, so a bare chezmoi apply always reads main — work is verified render-only until deployed.
- Verify render-only — never a bare
chezmoi applyfrom a worktree. Pass-S "$(pwd)"with no-mutation verbs:chezmoi diff -S "$(pwd)",chezmoi apply -n -v -S "$(pwd)"(dry-run; also shows which scripts would fire),chezmoi cat -S "$(pwd)" <target>. - Deploy with
chezmoi-deploy <branch>. It locks, fast-forward-merges the branch into the primary checkout'smain, runschezmoi apply --force, and pushesmainto origin. Safe from a hosted aoe session: the session runs in a tmux pane independent of any LaunchAgent, and the generator only reloads agents whose plist content actually changed — it never touches the tmux pane a deploy is running from. Gated by anaskpermission. - Escape hatch — to exercise one deployed file's runtime behavior without a full deploy:
chezmoi apply -S "$(pwd)" --exclude=scripts --persistent-state "${TMPDIR:-/tmp}/branch-state.boltdb" <target>— mutates only that path, runs no scripts, leaves global state untouched.
chezmoi apply reloads changed LaunchAgents automatically — the run_onchange_after_aa-launch-agents.sh generator renders plists from dot_config/launchd-yaml/agents.yaml and reloads only what changed. To force-reload an agent manually during testing:
# Restart a running agent (picks up plist changes):
launchctl kickstart -k "gui/$(id -u)/<label>"
# Full reload (for structural changes like new binary paths):
launchctl bootout "gui/$(id -u)/<label>"
launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/<plist-file>
# Load a new agent for the first time:
launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/<plist-file>
Notes
- Session transcript data is persisted in
~/.local/share/opencode/opencode.db— sessions survive restarts - Adding a new
[data]key to.chezmoi.toml.tmplrequireschezmoi initbeforechezmoi apply—applyalone does not regenerate~/.config/chezmoi/chezmoi.toml chezmoi initis destructive to the live config — it re-renders the template from scratch. The "config file template has changed" warning fromchezmoi applyis cosmetic when scripts are already deployed; do not runchezmoi initto silence it.- Machine-specific config lives in
.chezmoidata/local.yamlin the source directory — secrets manifest, calendar config, reminders, per-org config. This file is gitignored. Copylocal.yaml.examplefrom the repo root to~/.local/share/chezmoi/.chezmoidata/local.yamlto get started. The example must NOT live under.chezmoidata/itself — files there get merged intochezmoi dataand would leak placeholder values into runtime.
Gotchas
.chezmoidatavalues are plain data — template expressions like{{ .chezmoi.arch }}inside YAML string values are not evaluated. Arch/OS logic must live in the.tmplfile itself..appbundles viachezmoiexternal— usetype = "archive"with target"Applications/<AppName>.app"(unique TOML key per app) andstripComponents = 1to strip the archive's root directory. WithoutstripComponents = 1the app ends up double-nested inside the archive's root directory. TOML does not allow duplicate keys, so each app needs its own unique target path.- LaunchAgent binary path changes — after moving a binary (e.g., brew →
~/.local/bin),launchctl bootout+bootstrapis required to pick up the new plist;kickstartalone is not sufficient if the service is crash-looping. - Updating a plist — apply first to deploy the new file, then
launchctl kickstart -k gui/$(id -u)/<label>to reload. - Inline shell in plist templates — avoid
/bin/sh -cwith inline scripts inProgramArguments. Three escaping layers (XML entities, shell quoting, content characters) make this fragile — an apostrophe in text content will silently break single-quoted strings,&needs&in XML, etc. UseProgramArgumentswith a standalone script instead: each argument is a separate<string>element, no shell involved. - Deleting a managed file —
chezmoi applydoes not remove files whose source entry was deleted. Usechezmoi destroy <target>before removing the source entry — it removes both in one step. Order matters: if yougit rmthe source first,chezmoi destroyreturnsnot managedand you mustrmthe deployed file manually. Note: files managed via.chezmoiexternal.toml.tmplcannot be destroyed this way — chezmoi owns them; remove the external entry instead. - Deleting a skill — skills in
skills/are synced to~/.agents/skills/by therun_onchange_after_sync-and-validate-skillsscript, which replaces local skills wholesale. Removing a skill fromskills/is sufficient — nochezmoi destroyneeded. External skills (inpackages.skills) must be removed from the list; they will be gone on the next apply. - Empty files are skipped — chezmoi does not deploy 0-byte files. Python
__init__.pyfiles need at least a comment (e.g.,# package name) or they won't appear at the target. - "X has changed since chezmoi last wrote it" prompt — chezmoi's persistent state SHA for that target drifted from the live file (often after an external tool rewrote it, after a template edit between sessions, or after picking
skip in a previous prompt). Ifchezmoi diffis empty after the prompt, the live and rendered content actually match — pickoverwrite (or rerun with--force) to resync state. Pickingskip leaves state stale and the prompt will reappear next apply. Recurring offender:~/.zshrc, occasionally rewritten by tool installers (bun, mise) at session startup. __pycache__under managed lib dirs — Python bytecache in~/.local/lib/{kb,cal}/__pycache__/is generated at runtime and triggers "has changed since chezmoi last wrote it" prompts on every apply. Fix: add**/__pycache__to.chezmoiignore.- Non-TTY "has changed" prompt fails — when
chezmoi applyruns from an agent session (no TTY attached), the interactive prompt errors with "could not open a new TTY: open /dev/tty: device not configured". Usechezmoi apply --forceto skip prompts in non-interactive contexts. chezmoi-templatespre-commit hook renders against the current worktree, not the primary checkout — it passes-S "$(git rev-parse --show-toplevel)", so it now correctly catches templates referencing a.chezmoidata/*.yamlkey that only exists on the current branch (previously it silently validated against the primary checkout'smaindata and always passed). The tradeoff:.chezmoidata/local.yamlis gitignored, so worktrees never receive it — templates depending on it will fail this hook when committed from any worktree. Known affected templates:dot_envrc.tmpl(needs.secrets) anddot_config/opencode/opencode.json.tmpl(needs.runlayer). Workaround: symlink.chezmoidata/local.yamlfrom the primary checkout into the worktree before committing, or bypass the hook for that one commit.