Skip to content

A symlinked `~/.codex` or `~/.claude` turned back into a real directory

Source: Troubleshooting reference

Symptom: you hand-symlinked ~/.codex (or ~/.claude) to scratch, and some time later it is a plain directory again holding only the managed config — while the scratch copy sits frozen at the date the link died. Nothing logged an error.

Root cause: chezmoi manages files inside both directories (config.toml, AGENTS.md, hooks.json, profiles, rules/, themes/, agents/ for Codex; settings.json, skills/, hook scripts for Claude). A source directory means chezmoi’s target state for that path is “directory” — so on the next chezmoi apply it removes whatever is there, symlink included, and recreates a real directory with just the managed files. Everything else is orphaned wherever the link pointed.

Confirm — a stale target next to a fresh $HOME copy is the tell:

Terminal window
chezmoi managed | grep -x '.codex' # non-empty ⇒ chezmoi owns this path
stat -c '%n %y' ~/.codex ~/scratch/.codex # scratch frozen, home current

Fix: don’t symlink the managed directory. For Codex on a shared home, configure a host-local runtime and run bash install/codex.sh sync-runtime. The scratch installer no longer moves Codex children or SQLite files. For Claude, it still supports selected unmanaged children. See Scratch space.

Then reconcile the orphaned copy by hand — the script won’t touch it, because it cannot tell your stale data from a deliberate second install:

Terminal window
du -sh ~/scratch/.codex # what was orphaned

The supported CODEX_HOME boundary now includes managed-configuration sync; see Codex host-local state.