You spend an hour with an agent fixing a real bug. The edits look right on disk. Then they're just... gone. The file is back to its last-committed state, no error, no diff, no trace. Nothing crashed. Something quietly reset the working tree out from under you.
This is one of the most demoralizing failure modes in agent-driven and multi-process development, because the work never existed anywhere durable. We've eaten this exact loss more than once, and it always comes from the same two sources.
We ran more than one thing against the same repo at the same time:
Both felt safe in the moment. Worktrees are supposed to isolate work. And an auto-loop resetting to clean before it starts seems hygienic. The assumption in both cases was: "my uncommitted edits are mine; another process can't touch them."
The killer detail: uncommitted edits are not stored in git's object database. Tracked-but-uncommitted changes live only in your working tree and index. When any process runs `git checkout .` or `git restore .`, git overwrites those files with their last-committed content and writes nothing to the object store. There is no dangling commit, no blob to fish out — so reflog and fsck cannot bring it back 0. That's the whole horror of it: it's not "hard to recover," it's unrecoverable by git.
The two paths to that reset:
The unifying root cause: work that isn't committed has no owner git will defend. Worktree isolation protects committed branch state, not your dirty working tree against a sibling process that runs a reset.
Commit fast, and disarm anything that resets the tree. Two moves:
A WIP commit takes about 10 seconds and converts "ephemeral edits a reset can erase" into "an object in the database that survives any later checkout/reset and is recoverable via reflog."
```bash
git add -A && git commit -m "wip: <what you just did>"
```
Don't wait for "done." Commit the moment the work would hurt to lose. You can always `git commit --amend` or squash later. A commit is the only thing a sibling process can't silently revert — and even if a branch gets rewound, the commit stays reachable through `git reflog` (git-reflog docs).
If you're not ready to commit, at least stash — `git stash` saves dirty state as real commit objects (git-stash docs), so a later `git checkout .` in the tree can't touch it.
Find the self-coder / auto-improve / watcher process and either stop it or remove its reset step before you start hand-editing in that repo.
```bash
launchctl list | grep -i improve
launchctl unload ~/Library/LaunchAgents/com.<yourorg>.improve.plist
grep -rn "checkout \.\|reset --hard\|restore \." path/to/loop/
```
The non-negotiable rule for any automated loop: it must never run `git checkout .` / `git reset --hard` / `git restore .` on a tree a human or another agent might be editing. If a loop needs a clean state, it should do its work in its own dedicated worktree or a throwaway clone, never the shared one.
If you genuinely want two agents in parallel, give each its own worktree on its own branch and let them integrate by merging commits — not by sharing a dirty working tree:
```bash
git worktree add ../repo-agent-b -b agent-b/feature
```
Then neither one's reset can reach the other's files, and integration happens through committed history.