Back to Insights
21 Jun 20265 min readAI & LLMs

Your Agent Did the Work, Then It Vanished. Here's How to Get It Back.

There is a specific kind of dread that only exists in 2026. You set an agent loose in a worktree, go make coffee, come back — and the work is gone. Not "needs review" gone. Gone gone. The branch isn't there. git log doesn't show it. The worktree directory has been swept up. Hours of an agent's output, evaporated.

We've run head-first into this enough times to have learned the one fact that decides whether you get the work back or not. It is not the fact the panic-Googling will tell you first. So here it is up front, because it's the whole post:

If the agent committed, your work is almost certainly still there. If it didn't, it's almost certainly not. Everything else is detail.

This is a real, named failure mode

We're not extrapolating from one bad afternoon. The Anthropic claude-code tracker has it documented in several forms:

  • #34327: Claude Code ran git reset --hard origin/main autonomously within the first second of session startup — twice — "destroying 12 unpushed commits + all uncommitted work." Crucially, the reporter recovered the committed half: "partially recovered via reflog." The uncommitted half was gone.
  • #46444: worktree auto-cleanup "silently cleaned up the previous session's worktrees without committing… ~10 days of development… permanently deleted." ~300 files. Never committed — never recovered.
  • #55724: with 13 parallel agents, "5 committed successfully, 8 failed due to lock contention" — and the worktrees of the 8 that failed were auto-removed before they could commit.

It isn't an Anthropic thing, either. Cursor's forum has the same shape: an agent runs git restore or git stash mid-session and uncommitted edits disappear. Different vendor, identical boundary.

Notice the pattern across every one: the committed work that got recovered came back through git's own safety nets. The work that was never committed is the work that stayed lost.

Why committed work survives — and where it actually lives

When an agent runs git commit, git writes a commit object into the shared object store under .git/objects. That object does not get deleted when the branch is deleted, when the worktree is removed, when HEAD is reset, or when the agent crashes. It just becomes unreachable — an object no ref points to anymore. Unreachable is not the same as deleted.

There are two safety nets that find unreachable commits, and the difference between them is the part most people get wrong:

The reflog is the everyday net. git reset --hard, a botched rebase, a branch that moved — the old tip is still in git reflog, and you just git reset --hard HEAD@{1} your way back. We verified the textbook case on Git 2.50.1:

$ git reset --hard HEAD~2      # two commits "gone"
$ git reflog
d7f4c1d HEAD@{0}: reset: moving to HEAD~2
c5c5632 HEAD@{1}: commit: feat: agent work part 2
6c211c4 HEAD@{2}: commit: feat: agent work part 1
$ git branch rescued c5c5632   # back

But the reflog will not save you from a removed worktree — and this is the trap. A worktree's HEAD reflog lives inside that worktree's metadata (.git/worktrees/<name>/logs/HEAD). When the worktree is removed, that reflog is deleted with it. We confirmed it: after git worktree remove --force, the per-worktree reflog is gone, and the commit survives only as an unreachable loose object in the shared store. git reflog shows you nothing.

For that case you need the deeper net: git fsck.

$ git worktree remove --force ../wt-feature
$ git branch -D feature                     # nothing points at the commit now
$ git log --oneline --all
583774d initial commit on main              # the agent's commit is gone from history
$ git fsck --no-reflogs --dangling
dangling commit 3514f038bc7d5b0157ca9cf65a8ee4223c29586f
$ git show 3514f03                          # there's your work, intact
$ git branch recovered 3514f03              # back

--no-reflogs is the trick that makes the output usable: it lists only commits unreachable from refs and reflogs — the true orphans — instead of drowning you in everything.

The honest boundary, and the clock

Two caveats, both verified for real, both load-bearing.

Uncommitted, never-staged work is genuinely gone. Files an agent edited but never git add-ed are ordinary files; if the worktree directory was deleted, nothing was ever written to the object store, and fsck has nothing to find. We tested it — recover list correctly reports nothing. (One subtlety: git add alone does write a blob, so staged-but-uncommitted content resurfaces as a dangling blob — raw content, no filename. Only the never-staged stuff is truly unrecoverable.)

Recovery is time-bounded. Unreachable objects don't live forever. On a fresh repo the defaults are gc.pruneExpire = 2 weeks (loose unreachable objects) and gc.reflogExpireUnreachable = 30 days. Worse, gc.auto (~6700 loose objects) means a routine git command can trigger a gc that prunes early — and a machine churning many short-lived agent worktrees fills that threshold fast. We proved the cliff:

$ git gc --prune=now
$ git show 15f10196
fatal: bad object 15f10196...              # permanently gone

So the operational rule when you've just lost something: stop. Don't run more git commands than you need to, and do not run git gc or git worktree prune first. Recover, then clean up.

The 70-line rescue tool

We wrapped the whole playbook into one script, recover, test-first (7/7 green: worktree-remove → recoverable, reset → recoverable, after gc --prune=now → correctly gone, never-staged → correctly nothing). The demo above walks through losing a commit to a removed worktree and getting it back:

recover list                 # dangling commits, newest first: sha · author · date · subject
recover show <sha>           # the full diff, to confirm it's the one
recover to <branch> <sha>    # restore it onto a fresh branch

recover list runs git fsck --no-reflogs --dangling, sorts newest-first, and prints a subject + diffstat for each — because fsck is noisy (every --amend, rebase, and dropped stash leaves dangling commits too), and the subject line is how you spot your commit in the pile. One bash gotcha we hit and fixed, worth passing on: piping a set -e print-loop into grep -q truncates the pipe and trips a SIGPIPE failure — so the tool builds its whole report in a buffer and emits it with a single printf.

The real lesson

The tool is the small part. The lesson is the boundary: the single most valuable thing you can do for an agent's work is make it commit, early and often — even throwaway WIP commits. A commit is the line between "recoverable for two weeks" and "gone forever." Everything recover, reflog, and fsck do only works on the right side of that line.

We build and run autonomous agent fleets in production. If you're hardening a multi-agent setup, talk to us.


Get the tool → recover in agent-ops — open source (MIT), a single dependency-free script, part of our toolkit for running coding agents in production.

AI agentsgitrecoveryreflogwar story

Found this useful?