On September 9 at 07:21 I typed four words to an agent: push, PR, merge. At 07:23 I interrupted it: stop, just push to master, I'm not going to open a pull request to myself. The agent pushed three commits, fast-forward, and wrote the rule down so the next session would know it. In between, it had done exactly what the tooling around it is built to do, and that's the part worth looking at.
The change
The work was small. An internal tool keeps a catalog of entries that we generate once, review, and sometimes touch up by hand in production. The agent had generated a new batch for the entries that had none, and I wanted it in production.
At 07:08 I asked the question that mattered: the import updates existing entries in place, some of them were edited by hand in production, so what exactly will this overwrite? The agent went and checked. Those edits are saved in place, under the same identifier, so a full import would have replayed our local versions over the production ones and reset their review status. Silently.
The next ten minutes went like this. An import option that only creates entries that don't exist yet. Sixteen tests, two of them pinning that exact danger. A run against a copy of production, rolled back. A second door found on the way: the import button in the review screen called the same function without the guard, so it got the same fix. And a read-only preflight script that tells you, against production, what the import would do before it does anything.
That was the review. It happened in the session, before the commit, and it started with one question from the person who knew the hand edits existed.
Then the tooling took over
At 07:15 I said I'd pull master on the server and run the two commands. The agent pointed out that the branch had never been pushed. At 07:21 I wrote "push + PR + merge into master", because that's the sentence twenty years of workflow put in your fingers.
The agent took the words literally, and the instruction file of that repository routes "push" and "create a PR" to a shipping skill. So it started a release: health checks, the test suite, the linter, a look for a version file to bump and a changelog to update, and the discovery that it could push to our Git host but had no credentials to open the pull request there. Two and a half minutes of ceremony for three commits I had already reviewed with the agent, line by line, ten minutes earlier.
That's when I stopped it.
What a pull request is for
A pull request is a conversation between two people about a change one of them made. The author explains, the reviewer asks, and the merge records that someone other than the author looked. It's also a lock: nothing lands while the conversation is open.
With one human and several agents, none of that holds. The author is an agent, the reviewer is me, and the review already happened, in the session, while the change was being made, because that's when I can ask "what will this overwrite?" and get an answer in minutes. A PR opened after that is me approving my own review. It adds a merge commit, a CI run, and a page nobody reads.
Mathieu Poli, who runs frontend engineering with us, wrote the team version of this: pull requests do work with agents, and that's exactly the trap. On a repository where I'm alone with my agents, the trap is just easier to see.
What replaced it
On that repository, the rule born that morning is short, and the agent wrote it down itself at 07:25: when I say push, it pushes to master, fast-forward, and nothing else. No pull request, no version bump, no changelog. I'm the only maintainer there, and by the time I say push, the review has already happened.
On the repository where most of my agents work every day, the same idea had already gone further. Nothing but main is ever pushed. Agents work in local worktrees and land their work on main under a shared lock, rebased or fast-forwarded, then push right away. Every session pulls before writing, because several of them run at the same time on different machines. Commits are small and frequent. A rejected push is normal: another session pushed first, you rebase and push again, never force.
There, the lock a PR gives you comes from pulling before writing and from the remote refusing anything that isn't a fast-forward. The review comes from the question asked in the session, before the commit, by the person who knows what's in production. The trace comes from commit messages that say why, not what.
What's still true
- The reflex was mine. The agent did what I asked, in the words I used.
- The stricter rule holds because a rejected push is cheap. On September 11, on the second repository, a session's push was rejected because another session had pushed while it was writing. Rebase, push, done. Without that, "everything on main" would be a race.
- Sixteen old agent branches are still sitting on the first repository's remote. The second one has none left.
If you run several agents on one repository: where does review happen for you, in the pull request or before the commit? I'll answer in the comments with how our sessions are set up.
Top comments (2)
The detail that matters is the last one: the agent wrote the rule down so the next session would know it. Most agent workflows survive the push and die at session N+1, where the human assumption from session N has evaporated and the tooling politely rebuilds the ritual from scratch. The silent-overwrite catch is the other half — asking 'what exactly will this overwrite?' is what separates an agent from a for-loop. Did the written rule hold in the next session, or did you end up re-stating it anyway?
The cost came from the instruction file routing the word "push" to the shipping skill, which cannot know that the review already happened in the session. The rule the agent wrote at 07:25 holds because it rests on a fact about that repository: you are the only maintainer. Does the written rule state that condition, or only that push means a fast-forward to master?