Key takeaways
- Writing code is not the slow part any more. In 31 days our main repo merged 473 pull requests. 130 of them needed someone to come back and merge main into the branch, 239 merge commits in all, and 238 of those were made by a person.
- The PRs that needed that took a median of 44 hours from open to merge. The ones that did not took 2. Of the 60 PRs that stayed open longer than three days, 51 needed at least one merge of main.
- babysit-pr splits the job at one label:
LGTM, “looks good to me”, which the author adds when the work is done. Before it, a skill keeps the agent on the PR until CI is green and every review bot is answered. After it, a GitHub Actions workflow keeps the PR mergeable until a person merges it, and addsRTM, “ready to merge”, once someone other than the author approves. - The workflow never merges, never closes, and never changes a line the author wrote. A conflict it cannot resolve around the author’s code goes back to the author as
REWORK. - The skill is public, MIT licensed: babysit-pr-skill on GitHub , with the watcher script and the design of the workflow. The workflow itself is still in dry run on our repo, and I say below why.
Why do finished pull requests go stale?
Writing the code stopped being the slow part. With the architect pattern and agents doing most of the typing, our repo takes about 13 commits a day into main. That is good for shipping and bad for every open pull request, because each of those commits can put a PR into conflict or turn its CI red.
I pulled the last 31 days of merged PRs to see where the time went.
The 44 against 2 is a correlation, not a cause. A PR that stays open longer gives main more time to move under it, so it is more likely to need a merge. But the merges themselves are real work that somebody did 239 times in a month. Five people made 238 of them by hand. One PR needed eight merges of main over the seven days it was open.
The approval itself was fast. Once a PR got its first approval, the median time to merge was zero hours. The waiting happened before that: the author finished, then the PR sat until a reviewer got to it, and while it sat, main moved. We started labelling finished PRs LGTM on 20 October. The 20 that merged since then waited a median of 38 hours between LGTM and merge, and one in four waited more than 78.
That is the gap this is for. Nobody is careless here. The author thinks they are done, the reviewer has not opened it yet, and the branch rots in between.
Why not close stale pull requests with actions/stale?
The usual answer to stale pull requests is actions/stale : a GitHub Action that adds a stale label to issues and pull requests after a set number of days of inactivity, and closes them automatically some days later unless someone comments or pushes.
That fits a pull request nobody is working on. It does nothing for the ones we had. Ours were finished work that went stale while they waited for a reviewer, because main moved under them. Closing them throws the work away, and a stale label tells the author what they already know. What the PR needs is someone to merge main in, re-run the red CI job and keep it green until a person approves it. So instead of closing stale pull requests, we keep them mergeable.
How babysit-pr keeps pull requests mergeable
The split follows who is waiting. Before LGTM the author is still on the PR, usually an agent session, and the skill keeps that session doing useful work instead of declaring victory when the code compiles. After LGTM the author has moved on, so the work goes to something that does not need them: a workflow that runs whether or not anyone is looking.
LGTM stands for “looks good to me”. On most teams a reviewer says it about someone else’s code. Here the author puts it on their own PR as a label that means “I am done, nothing left for me to do”. It is a person’s word: the agent adds it only when it was told to hand the PR over. That label is the opt-in for everything after it, and it is the thing that makes a developer comfortable letting a bot push to their branch.
Before LGTM: a Claude Code skill carries the PR to ready
The skill started as the babysit-pr skill in Theo Browne’s tstack
. I kept its watcher and its core rules and changed where it stops.
One watcher per pull request
pr-wait polls one pull request and prints one line per real event: a check failed, all checks finished, someone commented or reviewed, main moved under files this PR touches, the branch went behind or into conflict, the PR merged. In Claude Code it runs under the Monitor tool, so each line wakes the agent once. An event that needs no action ends the turn without a message. “Still waiting” is not news, and an agent that says it fifty times fills its own context with nothing.
Sort the red CI job before touching code
There are four kinds of red, and only one is a code fix:
- The PR broke it. Fix it with the smallest change.
- The runner flaked. Re-run the failed jobs once. A second failure on the same head is not a flake.
- Main is red. Do not fix main on someone’s feature branch. Report it and wait.
- A process check is red, for example the PR does not link an approved issue. That is a step for a person.
Agents left alone treat all four as the first, and the PR grows a workaround for a test that is broken on main.
Prove a review finding before fixing it
A review finding the agent accepts gets a failing test first, then the fix. A finding it dismisses gets a written reason. This is the same rule as our proven review skill, and it is what stops review bots from steering a PR by volume.
Keep the PR the size of its goal
Review loops grow a PR one cheap-looking fix at a time: a guard for an edge case nobody hits, a test for behaviour that did not change, a compatibility shim. The skill fixes real bugs in the intended case and declines the rest in writing. The worthwhile ones become issues.
Ready is a checklist
Every gating CI job green on the current head, every review bot finished on this head, nothing waiting on a human, no unresolved thread, no conflict. When that holds the agent reports it and stops watching.
After LGTM: a GitHub Actions workflow resolves merge conflicts
The workflow has two jobs.
The gate decides what each PR needs
The gate is cheap: no agent, no checkout of PR code. It runs on every push to main, every CI completion, every label and review, and every 30 minutes, and one GraphQL query gives it every open LGTM PR. For each one a pure function decides what to do. Add RTM if it is approved by someone other than the author, green, and conflict-free. Leave it alone if a review is running. Re-run red CI once. Send a conflict, or CI that is still red after its re-run, to the fixer.
The fixer agent merges main in
The fixer is an agent job for one PR at one head. It merges main into the branch without committing, gives the agent the conflicted files and the failing logs, and lets it edit only the conflicted files and the files the PR already changes. Then it asks one question.
Can this PR land without changing a line its author wrote?
If yes, the verdict is MODERNIZE. The agent resolves the conflict around the author’s lines, a validator checks the result, and the workflow pushes a normal merge commit. If no, because main deleted the function the PR edits or the PR’s own code fails CI, the verdict is REWORK. Nothing is pushed, LGTM comes off, and the author gets a comment with the smallest rewrite. If main already does what the PR does, the verdict is CLOSE, and a person closes it.
The validator keeps every line the author wrote
The validator is what makes the rule hold. It rejects any merge that drops a line the PR added, or a line main added to a conflicted file. It rejects edits outside the allowed files, leftover conflict markers, and changes to CI or security files. An agent that tries to “fix” the author’s code ends with a label asking for a human, never with a push. The workflow pushes without force, and only if the branch has not moved since the attempt started. One attempt per head and base, two per head, three comments per PR per day.
It never merges
RTM, “ready to merge”, is the gate’s statement that a PR has everything it needs: the author’s LGTM, an approval from someone else, green CI and no conflict. A person does the merging. That kept the design small, and it kept the argument about whether a bot should merge out of the review.
What changes for the author, the reviewer and whoever merges
The author says done once. They do not come back three days later to merge main and wait for CI again, and an agent’s PR does not rot because the session that opened it ended.
The reviewer opens a PR that is green and mergeable on today’s main, so their approval is the last step and not the start of another round.
Whoever merges works from one list. RTM stays on once the gate adds it, and if main breaks the PR after that, the workflow fixes it and the label stays.
And the author keeps control of their code. The worst the bot can do to a branch is add a merge commit that a validator has checked line by line.
Why our old merge conflict resolver never ran
We had a conflict resolver before this one. A detector found conflicted PRs and commented on them, and the resolver ran when someone added a label asking it to. In the same period the detector ran about 2,500 times. The resolver ran zero times.
I do not think anyone was lazy. A developer who considers a PR finished does not come back to it to press a button. Automation that waits to be asked will not be asked. That is why this one starts from LGTM, the moment the author says they are done, and does the rest without them.
What is not working yet?
Two things, and I would rather say them here than have you find them.
The workflow is in dry run
Its gate only logs what it would do until a repository variable says otherwise. Before it went that far, a review that only keeps findings it can prove with a failing test found eleven bugs in it. A few are worth knowing if you build your own. GitHub’s label search lags, so a PR it returns may have lost the label seconds ago, and the decision has to check live labels. A “this head already had its re-run” marker written before the re-run call succeeds lets one failed API call use up the head’s only retry. And a “lose no line” check that does not follow renames sees every line of a renamed file as lost.
The agent runners were down
Since 19 October every job aimed at our agent runners has failed to get a machine: 406 cancelled, 24 still queued when I checked. The gate runs elsewhere and is fine, but the fixer needs an agent runner, and a dead one looks exactly like a quiet day. Nothing failed loudly. Jobs queued and then got cancelled. If you build this, alert on fixer runs that sit queued.
So the numbers above are the before picture. Right now we have 27 open LGTM PRs, 7 of them with red CI and none with RTM. Those are the numbers this should change, and I will report what it did.
How to install the babysit-pr skill
github.com/LivinTribunal/babysit-pr-skill has:
SKILL.md, the skill, with a short “configure once” section for your CI workflows, review bots and process checks.scripts/pr-wait, the watcher. It needs Python and an authenticatedgh.docs/after-lgtm.md, the design of the after-LGTMworkflow: the labels, the gate, the fixer, the rule that it never changes the author’s lines, and the eleven bugs.
The workflow is a design rather than a file to copy, because ours runs against one company’s labels, runners and CI. Build yours from the doc, ship it in log-only mode, read a day of its decisions, then turn it on.
It pairs with the architect pattern , which decides who writes the code, and grain , which decides what the code looks like. babysit-pr is what happens after either of them opens the pull request. If you are tuning the agent itself, the CLAUDE.md A/B test and the context limit that cut token use by 17% cover the instructions and the cost.

