Your Agent Committed Files It Didn't Write
An autonomous content loop committed four posts under a title that said four, and the commit contained five. The fifth was written by hand hours earlier and was sitting uncommitted. Nothing errored, and the loop's own scoring was about to be wrong because of it.
Running agents unattended on a real repo?
Book a rescue session — staging, attribution, and guardrails set up so the loop can't eat your work.
Bottom Line
git add -Astages everything dirty, not everything the agent wrote. Your in-progress work goes in too.- Nothing errors. The commit looks correct. By git, the stolen file is indistinguishable from agent output.
- If you grade the agent on its commits, you are now grading it on your files.
- Fix 1: stage explicit paths. The agent lists what it created. Anything else, it leaves and logs.
- Fix 2: put authorship in the file (
origin: loop/origin: session). It survives rebases, reverts, and bad staging. Commit messages do not.
What Happened
A nightly content loop generated four blog posts and committed them with a message saying four posts. The commit contained five.
The fifth had been written by hand earlier that day and left uncommitted in the working tree. The loop’s ship step ran git add -A, which swept it in.
The consequence was not a lost file — it was a corrupted measurement. The loop was graded partly on how many of its posts carried affiliate links. The hand-written post had none, because it was never meant to be loop output. So the engine’s affiliate rate was about to be scored roughly 25% worse than it deserved. The agent was on track to be punished for work it never did.
The part worth sitting with: the loop’s own verifier could not catch this. It reasoned correctly from git, and git said the file was in the agent’s commit. It reached a wrong conclusion from accurate data. The only reason anyone noticed is that the human who wrote the stray file happened to be in the room.
Why git add -A Is Wrong Here
git add -A is fine in a human workflow. You know what you changed. You glance at git status. You have context the command lacks.
An autonomous process has none of that. It cannot distinguish:
- Files it created this run.
- Files a human left dirty from an hour ago.
- Files a different agent is midway through writing.
- Build artifacts, editor scratch files, half-finished experiments.
All of it is just “dirty” to -A. And the operation succeeds, so there is no failure signal anywhere in the pipeline.
This gets sharper with more than one agent. Two loops running against one repo with git add -A will each commit the other’s partial work, in whatever interleaving the scheduler produces. The commits stay green. The attribution becomes noise.
Fix One: Stage Explicit Paths
The agent must name what it wrote.
# wrong
git add -A
git commit -m "[loop-content] 4 posts"
# right
git add \
"src/content/blog/post-a.md" \
"src/content/blog/post-b.md" \
"src/content/blog/post-c.md" \
"src/content/blog/post-d.md"
git commit -m "[loop-content] 4 posts"
Add the corresponding instruction, because it is the half people skip:
Stage only files you created in this run, by explicit path. Never use
git add -Aorgit add .. Ifgit statusshows files you did not generate, leave them unstaged and log their paths in your run report.
That last clause turns a silent hazard into a visible one. A run report that says “3 files were dirty that I did not write: …” is useful information about your repo. Silence is not.
A cheap belt-and-braces version, if you want the guarantee enforced rather than requested:
git stash push --keep-index --include-untracked -m "pre-agent-run"
Run it before the agent starts, and unrelated dirty state is physically out of reach.
Fix Two: Put Authorship in the File
Explicit staging fixes the immediate bug. It does not fix the deeper one: commit messages are a fragile place to store authorship.
Markers like [loop-content] or [session] in a commit subject are attribution by convention. They break under rebase, squash, revert, cherry-pick, and any hand-edited commit. And when the same repo is written by both a human and an automated loop, staging decides which marker a file ends up under — which is exactly the thing that just went wrong.
Put the signal in the artifact instead:
---
title: "Some Post"
date: "2026-08-19"
origin: loop # or: session
---
Now authorship travels with the content. Rebase it, revert it, move it between branches, sweep it into the wrong commit — the field is still correct, because it is part of the file rather than part of the history.
Build your cohorts by filtering that field:
grep -l "^origin: loop" src/content/blog/*.md | wc -l
Never by parsing git log.
The General Rule
When commit attribution is a measurement input for grading an agent,
git add -Ais a correctness bug, not a convenience.
And the broader version, which applies to any autonomous system you intend to evaluate:
Any process that both produces work and is graded on that work needs an authorship signal it cannot accidentally forge.
The forgery here was accidental — no agent was trying to take credit. That is what makes it easy to miss. There was no adversary and no error, just a staging command that was slightly too broad, quietly making a measurement lie.
If you are running autonomous loops that you plan to tune based on their output quality, check how they stage before you trust a single one of their numbers.
Related
Want your loop audited before it runs unattended again?
Staging, attribution, guardrails, and a measurement path you can trust. Book a rescue session.
Need OpenClaw fixed live?
Remote rescue sessions for gateway, auth, tunnel, VPS, and model access problems.
See Rescue Session