chezmoi
Manage dotfiles via chezmoi — apply safely, destroy files, manage LaunchAgents and externals, config and template gotchas
What it does
chezmoi apply may trigger an opencode server restart if plist files change (via run_onchange_after_ensure-launchagents.sh). The current session loses its WebSocket connection and appears to hang indefinitely.
You are running inside that server. When chezmoi apply restarts it, this session will go silent.
Triggers that cause a restart
| Trigger | What causes it | Effect |
|---|---|---|
run_onchange_after_ensure-launchagents.sh | Library/LaunchAgents/*.plist.tmpl content changed | Reloads all managed LaunchAgents, including opencode-web |
Skills, capabilities, and AGENTS.md are read fresh per-session — editing those does not trigger a restart. opencode handles config reloads itself.
Safe Workflow
Option A — Apply in a PTY, then reconnect (recommended)
Run chezmoi apply in a background PTY so you can observe it complete, then reload the browser tab to reconnect to the new server:
# 1. Run apply in a PTY session — this avoids blocking the current session
# (Use the pty_spawn tool, command="chezmoi", args=["apply"])
# 2. Read PTY output — wait for completion
# 3. Reload the browser tab / reconnect the TUI — the new server is up on port 4096
Option B — Apply and accept the hang
If you don't need to observe the output:
- Note any in-progress work (the session transcript survives in the DB)
- Run
chezmoi applydirectly - The session will go silent — this is expected, not a bug
- Reload the browser tab to reconnect
Diagnosing a Stuck/Hung State
If apply completed but the session is unresponsive and browser reload doesn't help:
# Check if the new server is running
launchctl print gui/$(id -u)/com.athal.opencode-web
# Check the server log for startup errors
tail -50 ~/Library/Logs/opencode-web.log
tail -50 ~/Library/Logs/opencode-web.error.log
Notes
- Session transcript data is persisted in
~/.local/share/opencode/opencode.db— the session is not lost, just disconnected - The LaunchAgent
KeepAlive: truemeans the server will always restart; the only failure mode is a crash loop from bad config - 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 —
chezmoi applyonly bootstraps agents that aren't loaded. To pick up plist changes on a running agent:launchctl kickstart -k gui/$(id -u)/<label> - 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. - "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.
Capabilities
Install
Quality
deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 6 github stars · SKILL.md body (5,425 chars)