During a branch cleanup, I deleted a Git worktree that was clean and already merged. A live agent immediately lost its meta command, started returning rc=127 — the shell’s “command not found” result — and silently failed to write its next ledger note, one entry in its running activity log.
Git had told me the deletion was safe. Git was right about the repository and blind to the running process.
A worktree is a second checkout of one repository: another folder and branch sharing the same underlying Git data. I had removed the old folder after a migration because it showed no uncommitted files and its feature branch had landed on main, the branch carrying the current code. By every Git cleanup check I normally use, there was nothing left to preserve.
The agent was still preserving something Git could not see: a path it had resolved when the session launched.
If the internals are not your thing, the useful check is simple. Before deleting a directory, ask whether a running process still has its current directory, command path, or environment pointed inside it. “No files will be lost” and “nothing live will break” are different claims.
The fresh-session assumption fooled me
The migration had installed the command in its permanent location. I checked that a newly launched agent would use the deployed copy and concluded the old worktree was disposable.
That was my wrong turn.
The already-running session had started before the cutover. Its shim — a tiny wrapper that redirects one command to the real script — still resolved meta to a script inside the worktree. Deleting the folder did not make the process reconsider that choice. It just made the next invocation point at a path that no longer existed.
The distinction is easy to miss because both statements looked true:
Fresh session: meta -> permanent deployed script
Already-live session: meta -> old worktree/daemons/meta/meta.sh
I had tested the first line and removed the folder underneath the second.
This is launch-time state: values a process binds when it starts, such as its current working directory, PATH entries (the shell’s command-search list), environment variables, and resolved shim targets. Those bindings can live longer than the branch or checkout that supplied them.
I call this the Live Binding Check: a path is not disposable until both Git and every running consumer release it.
Recreate the address, then move the resident
Killing the agent would have fixed the command, but it also would have interrupted a live session. The cheaper recovery was to put a checkout back at the exact address the stale shim expected:
Restore the deleted path without stealing the checked-out branch give me the detail
git -C /path/to/repo worktree add --detach /exact/old/path main--detach creates the checkout at a commit without trying to check out main as a branch, which Git may already have checked out elsewhere. Because the feature had merged, main contained the needed script. The old absolute path existed again, so the cached shim worked immediately.
That was a bridge, not the final architecture. At the next natural break, I relaunched the agent so it bound to the permanent deployed command, verified the new target, and only then removed the restored worktree.
The important detail is the identical path. Restoring the same files somewhere nearby would not help a process holding an absolute address. When a cached binding breaks, repair the address first; then teach the consumer its new address.
Git safety and process safety need separate evidence
My old cleanup checklist answered two good questions:
- Is the worktree clean?
- Is its branch merged?
Those protect files and commits. They do not inspect live consumers. The added check asks whether any active session has a working directory, startup configuration, shim, or PATH entry under the candidate directory. If yes, repoint or relaunch before removal.
That is a different lesson from proving the agent started in an isolated checkout. In The Git Check That Proves Isolation Isn’t the One You’d Reach For, pwd -P and git rev-parse --show-toplevel answer where the agent is standing. Here, the danger is that a command can remain tied to yesterday’s checkout even after the code has moved.
It also rhymes with Merged Is Not Running: repository state and live state do not advance together unless something explicitly reconnects them. And Never Run git checkout Inside a Loop’s Working Directory is the more immediate version of the same boundary — changing the ground beneath a process can invalidate assumptions the process cannot renegotiate.
dirty=0 was evidence that deleting the folder would not lose work. I treated it as evidence that the folder had no users.
It was never that kind of check.