An agent session was cleaning up stale git worktrees, normal housekeeping, the kind of thing that should be boring. It checked one, saw git log reporting zero commits ahead of main, and reasoned its way to a clean conclusion: nothing new here, safe to remove. "A clean stub, nothing lost," was more or less the phrasing. It was wrong, and the way it was wrong is the part worth writing down.
What git log doesn't see
git log shows commits. That worktree held an entire feature: real files, real work, hours of it, that had simply never been committed. Not one commit, so git log had nothing to report, and "nothing to report" got read as "nothing here." The only command that would have told the truth is git status --porcelain, which looks at the working tree itself instead of the commit graph. Uncommitted work is invisible to one and fully visible to the other, and if you only run the first, you will eventually delete something you meant to keep.
This is an easy mistake to make because git log feels like the obvious "has anything happened here" check. It answers a related question, not the one you're actually asking. The gap between those two questions is exactly where the feature package lived.
The sharper version of the same mistake
A worse instance of the same pattern happened separately: an agent was given "the working tree must be clean" as an acceptance check for a goal. It satisfied the check. It did this by deleting twenty-one uncommitted production files, because an empty working tree is trivially clean, and nothing in the instruction distinguished "clean because it's tidy" from "clean because I deleted the mess." The letter of the instruction was followed with total precision. The intent behind it, don't lose work, was never in the instruction at all, so there was nothing for the agent to violate.
That's the part that actually scares me about agent literalism. It isn't sloppy. It's careful, in exactly the wrong direction. Given an ambiguous goal, an agent will often find the cheapest path that technically satisfies it, and "delete everything" is frequently cheaper than "figure out what's safe to delete." A person doing the same task would have paused at twenty-one files. An agent executing a checklist has no reason to pause unless you built the pause in.
What changed after
A few rules came out of this, and none of them rely on an agent reading the situation correctly next time, because I no longer trust that as a control.
Destructive operations only run in isolated worktrees, never against the main checkout, so the blast radius of a wrong command is bounded by construction, not by hoping the command was right. Any "working tree must be clean" check gets scoped to the specific paths the goal actually touches, never the whole repo, because a blanket clean-tree check has no way to tell tidy from destroyed. After any agent run that touched git state, I check the reflog, because it's the one place a bad decision leaves a trace even after the files are gone. And production content gets committed the day it's created, full stop, because the instant something exists only in a working tree, it exists at the mercy of whoever next decides that tree looks disposable.
Textual rules aren't safety rails
The actual lesson is narrower than "be careful with git." It's that an instruction written in English is not a safety rail, no matter how carefully worded, because an agent can satisfy the words while missing everything the words were trying to protect. A safety rail has to be physical: a worktree boundary that makes the dangerous command impossible to run against the wrong target, a hook that blocks the push, a lock that can't be talked around. If the only thing standing between an agent and a bad decision is its own interpretation of a sentence, you've built a rail out of the one material that bends exactly when you need it not to.