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 (11)
Before the commit for us too, but on a running preview rather than the diff. Each ticket gets its own stack and a private preview URL, and the developer who asked tests it and answers in the ticket thread. After that a script commits, opens the PRs and merges them, so the PR is a record of a review that already happened. Your 07:08 question is the part I can't script. On that first repository, do you read the diff at all, or only ask questions in the session?
Both. The 07:08 question is the part a preview URL wouldn't have caught. The import looked fine; some production entries had been edited by hand under the same identifier, and a full import would have written our local versions over them. The agent went and checked. That's the review. The PR afterwards would only have recorded it.
Fair hit on previews. A preview only knows the data it was built with, so a hand edit sitting in production under the same identifier never shows up there. The agent asking what the import would overwrite was the review. How did it find those entries: comparing against the last import, or reading timestamps on the production side?
Neither. I already knew those entries were there, because I had edited them by hand. The agent didn't discover them. I asked what a full import would do to them, and it checked the write path: same identifier, in place, review status reset. The read-only preflight against production came after that, once we knew the danger.
That's the clearer version: the review was your memory of the hand edits, and the agent's part was tracing the write path once you named the risk. It matches where we ended up. The person who asked knows what matters in production, so that check stays with them. The agent is good at confirming what a write would actually touch.
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?
Yes, it held, and it's stored where the next session can't miss it: in the agent's memory for that repository, which the next session reads at startup. The overwrite question is the part that doesn't fit in a rule like that. It came from knowing that some entries had been edited by hand in production, and no file in the repo said so.
The reflex breaks the moment the committer is a machine. I run a site where an agent pushes straight to main — the PR's job (a second pair of eyes) got replaced by gates: typecheck, e2e, complexity audits, all blocking the push itself. Review moved from a UI ritual to the hook chain, and the honest trade-off is that nobody rubber-stamps a diff at 5pm anymore; either the gate catches it or nobody looks. The part I still do by hand is reading the diff of anything that touches auth or money — that review genuinely needs a human. Where do you draw the line between ceremony and safety net?
The line, on that repo, is whether a second human exists. There isn't one, so a PR is ceremony. The safety net is the session: three commits we'd already looked at, then a question about what the import would overwrite. A typecheck would have let the pull request through, because the code was fine. The ask was the bug.
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?
Only the second. The note the agent wrote at 07:25 says push goes straight to master, fast-forward, no pull request, and says nothing about why. You're right that the why is what makes it safe: the day a second person commits to that repository, the rule keeps firing and nobody gets a review. It lives in the agent's memory for that repo, so adding the condition takes one line.