AI

Choosing the Right Pull Request Size for Agentic Coding

How to size pull requests in the age of AI and agentic coding: stop splitting by lines or layers and scope each PR around a single, testable unit of behavior.

/9 min read
Choosing the Right Pull Request Size for Agentic Coding

Here are two great ways to make yourself miserable in the age of agentic coding.

  1. Slice your work so thin that every change is its own pull request. The migration here, the API endpoint there, the form component in a third. Each one is tidy. Each one is also a tiny ceremony. Open the PR, wait for pickup, nudge a reviewer, switch your brain to something else, switch it back, re-prime the agent, merge, repeat. You spend your day babysitting. The actual coding took four minutes and the orchestration took four hours.
  2. Let the agent run wild and dump the whole feature in one heroic 10,000-line diff. Backend, frontend, tests, a config change it decided to throw in for fun. Nobody can review it, but someone will approve it anyway. A cheerful "LGTM" on ten thousand lines no one read end to end is not reviewing, it's praying. QA can't tell you what the edge cases are because they can't even find the edges. Something is wrong, but good luck spotting it in there. So it sits. Then it needs rework. Then it sits again.

Too small and you drown in process. Too big and you drown in rework. I've done both, often in the same week, sometimes in the same afternoon. It's a Goldilocks problem, except the answer everyone reaches for, a line count, is the wrong bowl of porridge entirely. Getting pull request size right isn't about finding the magic number. It's about changing what you measure.

TL;DR

Stop sizing pull requests by the diff and stop splitting them by layer. Size by behavior: the smallest slice a user can observe, that you can pin down with one set of acceptance tests, and that a reviewer can hold in their head in one sitting. One observable behavior, front to back, one PR. Line count was always just a proxy for "can a human verify this safely," and agents only raised the stakes.

Lines of code were always a proxy

We've had decades of data saying small PRs are better, and it's good data. The old SmartBear study at Cisco found defect-finding drops off a cliff past 500 lines, reviewers run out of gas after about an hour, and in top open source projects nearly half of all PRs come in under 100 lines. But lines of code were never the thing we actually cared about. They were a stand-in for the real question: can a human hold this change in their head and tell whether it's correct? Line count is just a blurry proxy, easy to measure, which is exactly why we reach for it and exactly why it steers us wrong.

Here's the trap. If "small" is the goal, the obvious move is to split by layer. One PR for the migration, one for the backend, one for the frontend. Look how small each one is. Except none of them is verifiable on its own. The migration PR does nothing a user can see. The backend PR has no UI to exercise it. You've made three small, technically correct, individually useless diffs, and the only place the actual behavior exists is in your head, smeared across three review threads. That's not small. That's fragmented.

Agents make this worse

The annoying part is that agents shove us in exactly the wrong direction right when we can least afford it. They make code nearly free to produce, so PRs are getting bigger, not smaller: AI-assisted PRs run about 18% larger, with more issues per PR. And it isn't just the published numbers. On my own team, the big PRs are the ones that come back: QA issues and rework on them run 50 to 100% higher than on the right-sized ones.

Code generation got cheap, and that's the whole story. When the cost of producing a change drops to near zero, the bottleneck moves somewhere else, and where it moved is review, verification, and your attention. Those didn't get cheaper. If anything they got more expensive, because now you're reviewing code you didn't write, with reasoning that isn't visible in the diff, that may have quietly drifted from what you actually asked for three iterations ago.

Studies of failed agentic PRs say the same thing: the rejected ones are reliably bigger, and maintainers keep asking for a "single coherent change". The machines are great at generating volume. We're still the ones who have to vouch for it.

None of this is the agents' fault. They're doing exactly what we asked. The fix isn't a better agent, it's a better unit of work.

Size by behavior

So stop sizing by the diff, and stop sizing by the layer. Size by behavior.

A behavior is the smallest slice of work that a user can actually observe, that you can pin down with one coherent set of acceptance tests, and that a reviewer can hold in their head in one sitting. It's vertical, not horizontal, and it runs front to back. The migration, the API, and the UI that together deliver one coherent thing all belong in the same PR, because they're one behavior, and that behavior is the unit you can actually verify.

Here's the example I keep coming back to. Say you're building a feature that has a CRUD interface and a report.

The full create-update-delete interface is one PR. Not three, and definitely not split into a backend PR and a frontend PR. Creating, updating, and deleting a thing is one coherent behavior. It's got one acceptance story: a user can manage these records and the right things happen. Front to back, one slice, one review.

The report is a separate PR, because it's a genuinely different behavior. Different acceptance tests, different edge cases, different definition of done. It doesn't belong glued onto the CRUD work just because they share a feature, and it shouldn't have to wait for the CRUD work to be perfect.

A few more, just to calibrate. Each of these is one behavior, one PR, front to back:

  • A user can reset their password (the request form, the email, the token, the reset screen).
  • An inspector can duplicate an existing inspection template.
  • A user can filter the inspections list by status.
  • An admin can export a report to CSV.

And a couple that aren't:

  • Too small: "Add the inspection_templates table." A step inside a behavior, not a behavior of its own.
  • Too big: "Build the account settings page." Four behaviors wearing a trenchcoat (change your password, update your email, manage notifications, close your account). Four PRs, not one.

None of this is a formula. Sizing by behavior is more art than science.

It runs on gut feel, and two good engineers will sometimes draw the line differently. Even a plain CRUD interface breaks into several PRs once it does more than plain CRUD: bolt on bulk import or an approval step and each becomes its own behavior. A strong rule of thumb, not a law.

One quick test for all this: try writing the acceptance criteria first. If they hang together as one story, it's one behavior. The moment you're adding "and, separately, the user can also...," it's two, and that's a second PR. Porridge that's just right.

And notice you're not really sizing the diff at all. You're scoping the spec, and the agent writes the code from it. So this is really spec by behavior: one behavior per spec, and the right-sized PR drops out the other end. You choose the unit before a line of code exists.

Small isn't free

Slicing too fine has two costs, and agents make both worse.

The first cost is ceremony, and it's bigger than it looks, because every PR runs the whole agentic pipeline gauntlet. A change doesn't just get written. It gets planned, implemented by the agent, passed through an automated reviewer, read by a human, checked by QA, and validated by a user. Most of that is fixed cost: it takes about the same effort whether the PR delivers a complete behavior or one trivial step. Split one behavior into five atomic PRs and you pay all of it five times, and so does everyone downstream. The reviewer context-switches five times, QA gets pinged five times, the agent reloads the picture five times.

Back when a human typed the code by hand, you couldn't crank out fifty of these a day, so the tax stayed small. An agent can. Now a cost that used to be mildly annoying becomes the whole job, and you stop engineering and start tending a conveyor belt of trivial diffs.

The second cost: the slices can't be checked on their own. An "add the table" PR has nothing a reviewer can reason about, nothing QA can test, nothing a user can click. So it either sits blocked until its siblings land, or everyone waves it through on faith, which is the exact opposite of why you split it up. The pieces only mean something once they're reassembled into a behavior, which is the very thing you took apart.

The exceptions, because there are always exceptions

Sometimes a change really does deserve its own PR even though it isn't a user-visible behavior. A risky data migration you want to deploy and watch on its own. A shared infrastructure change a dozen things depend on. Fine. Those are deliberate calls about deployment risk, not the default. The default is behavior. Reach for the exception when you can say out loud why this one earns its own slice.

Stop counting lines

We spent years arguing about whether a PR should be 200 lines or 400. Wrong argument. Line count was always a proxy for "can a human verify this safely," and agents just raised the stakes by making it trivial to generate way more code than any of us can hold in our heads.

So size your work by behavior. Let the acceptance tests show you where the seams are. One observable behavior, front to back, one PR. Not the smallest atomic change you can make, and not the whole feature in one go. The smallest thing that's actually worth shipping and reviewing as a unit.

Get this right and something bigger opens up, worth its own post: a pipeline that quietly gets better every time the models do. More on that soon.

The agents didn't change the rule. They just made it matter a lot more.

Get More Tactical Insights

Join readers getting weekly tactics on agentic coding and AI leadership. Unsubscribe anytime.

← All Articles