Zach Blume

Patterns in agentic coding

We're inside a clear liftoff scenario for coding velocity. In the last thirty days I shipped 535 pull requests and 490,000 lines of code to production on my side project, outside my full-time job at Stripe. With new speed has come a Cambrian explosion of new engineering patterns. Coding agents have potentially reopened a lot of settled ideas, and the patterns are showing up faster than anyone is writing them down, so I thought I'd take the time to start writing down the ones that have worked for me in daily use and aren't gimmicks.

The thing is, a lot of what we know as software engineers comes down not to pure computer science but to impure computer engineering patterns that got codified as best practices through decades of discovery, based on the tooling we had at the time. The tooling has changed, and we're in an exciting period.

Liftoff scenario

0200400600Mar 2023: 16 merged PRs2023Apr 2023: 23 merged PRsMay 2023: 14 merged PRsJun 2023: 42 merged PRsJul 2023: 13 merged PRsAug 2023: 1 merged PRsSep 2023: 14 merged PRsOct 2023: 25 merged PRsNov 2023: 19 merged PRsDec 2023: 18 merged PRsJan 2024: 14 merged PRs2024Feb 2024: 12 merged PRsMar 2024: 21 merged PRsApr 2024: 25 merged PRsMay 2024: 23 merged PRsJun 2024: 8 merged PRsJul 2024: 11 merged PRsAug 2024: 3 merged PRsSep 2024: 0 merged PRsOct 2024: 0 merged PRsNov 2024: 8 merged PRsDec 2024: 0 merged PRsJan 2025: 0 merged PRs2025Feb 2025: 6 merged PRsMar 2025: 8 merged PRsApr 2025: 20 merged PRsMay 2025: 5 merged PRsJun 2025: 5 merged PRsJul 2025: 25 merged PRsAug 2025: 16 merged PRsSep 2025: 33 merged PRsOct 2025: 39 merged PRsNov 2025: 123 merged PRsDec 2025: 85 merged PRsJan 2026: 171 merged PRs2026Feb 2026: 211 merged PRsMar 2026: 50 merged PRsApr 2026: 45 merged PRsMay 2026: 259 merged PRsJun 2026: 178 merged PRsJul 2026: 157 merged PRsAug 2026: 196 merged PRsSep 2026: 201 merged PRsOct 2026: 553 merged PRsAiderSWE-agent, sweep.devusetusk.aiClaude CodeDevinCodexCursor agentsCopilot agentClaude Code on the webConductorConductor cloud553 in Oct 2026
My merged pull requests per month on my side project, labeled with roughly when I started using each coding agent.

For two years I was merging about 14 PRs a month, and then at the end of 2025 it went kind of vertical. The codebase went the same way:

0500k1M1.5M20232024202520261,414,672Jan 1, 2023: 1,966 linesFeb 1, 2023: 1,966 linesMar 1, 2023: 3,890 linesApr 1, 2023: 5,630 linesMay 1, 2023: 6,956 linesJun 1, 2023: 7,726 linesJul 1, 2023: 10,471 linesAug 1, 2023: 17,467 linesSep 1, 2023: 18,143 linesOct 1, 2023: 19,733 linesNov 1, 2023: 22,542 linesDec 1, 2023: 26,739 linesJan 1, 2024: 30,629 linesFeb 1, 2024: 32,520 linesMar 1, 2024: 33,721 linesApr 1, 2024: 34,891 linesMay 1, 2024: 35,760 linesJun 1, 2024: 37,203 linesJul 1, 2024: 41,622 linesAug 1, 2024: 42,629 linesSep 1, 2024: 47,915 linesOct 1, 2024: 49,078 linesNov 1, 2024: 49,172 linesDec 1, 2024: 49,342 linesJan 1, 2025: 49,731 linesFeb 1, 2025: 49,775 linesMar 1, 2025: 50,155 linesApr 1, 2025: 60,791 linesMay 1, 2025: 94,079 linesJun 1, 2025: 96,351 linesJul 1, 2025: 98,384 linesAug 1, 2025: 100,618 linesSep 1, 2025: 104,237 linesOct 1, 2025: 115,087 linesNov 1, 2025: 136,653 linesDec 1, 2025: 154,107 linesJan 1, 2026: 171,784 linesJan 15, 2026: 190,227 linesFeb 1, 2026: 216,922 linesFeb 15, 2026: 233,307 linesMar 1, 2026: 256,209 linesMar 15, 2026: 268,002 linesApr 1, 2026: 274,119 linesApr 15, 2026: 281,973 linesMay 1, 2026: 291,491 linesMay 15, 2026: 321,811 linesJun 1, 2026: 402,626 linesJun 15, 2026: 453,332 linesJul 1, 2026: 504,612 linesJul 15, 2026: 534,474 linesAug 1, 2026: 577,225 linesAug 15, 2026: 643,727 linesSep 1, 2026: 681,583 linesSep 15, 2026: 725,952 linesOct 1, 2026: 864,909 linesOct 15, 2026: 1,006,444 linesNov 1, 2026: 1,198,285 linesNov 6, 2026: 1,414,672 lines
Lines of code on my side project's main branch (non-blank JavaScript, TypeScript and Python).

It took about a year and a half to get to 40,000 lines, and then it barely moved for about six months.that's when I thought it would never make real money and was losing interest, to be honest Today it's about 1.4 million.

Lines of code and PR counts are famously bad metrics, and anywhere they get tracked, Goodhart's law kicks in fast. On my side project there's nobody to impress and nothing to game, so I'm only using them to show the shape of the curve. The better measure is the business: users are using these features, and error rates and incidents haven't gone up along with the volume.

And it isn't slop. It's higher quality code than I used to write by hand, with way more tests and way stricter rules about how things are supposed to be built than I ever had the patience for.the sections on linters and testing below get into how The amount of code I write by hand has durably gone to about zero since last November, and my hours spent on my side project are now closer to being a manager of a bunch of agents. The patterns below are what's let me do that.

The Gang of Four and the command pattern

I started thinking about this article while reading Martin Fowler's Refactoring. He referenced the Gang of Four's Design Patterns from 1994, which I'd never read. I was surprised to find the command pattern in it, because I use it all the time at Stripe without knowing where it came from.

With the command pattern, you package an operation and its inputs into an object with an execute method. In the version I use, the class keeps the steps together and exposes one method to the caller. Something like this, in Ruby:

ruby
class ApproveLoanApplication
  def initialize(application)
    @application = application
  end

  def execute
    validate!
    offer = build_offer
    notify_merchant(offer)
    offer
  end

  private

  # def validate!, def build_offer, def notify_merchant ...
end

ApproveLoanApplication.new(application).execute

Whoever calls it just sees the one method, and when you open the file the execute method reads kind of like a table of contents for everything below it.

The class gives the operation private helper methods and a place to hold its inputs. A base class can also give every command the same logging or other shared behavior.

I'd been using the pattern for years without knowing its history. It made me wonder what else I'd been doing without knowing its name.

Some of these older patterns have become more useful to me with agents, including this one.more on that in #9 Others have become cheap enough to use where I wouldn't have bothered before.

1. PR walkthrough videos

I have a prompt in AGENTS.md that tells the agent to test the flow it built, record a video, and add voice narration explaining the walkthrough. Now if I go into Conductor and say "make this simple change and put up a PR," it comes back with a narrated demo.

Here's a real one, from a pretty small PR on my side project that hides the lists a contact is already on when you go to add them to a list. Everything in it is fake seed data. Turn your sound on:

The videos have become one of the quickest ways for me to review a PR. I can often spot the wrong behavior without reading any code, then tell the agent what to change. Watching the flow and hearing the explanation makes it easier to catch things I wouldn't think to ask about in a code review.

Most of the PRs on my side project have a video now. In a way it almost feels like scrolling TikTok. You're sending ideas at a bunch of parallel coding agents and getting back full demo videos every few minutes, over and over.

2. Project chats

For anything bigger than one PR, I've started keeping one long-running agent chat per project, and I treat it like the eng lead. It holds the plan, splits the work into PRs, starts other agents on them, keeps track of which ones merged and which ones are stuck, and deals with rebases and review comments as they come in.

And then I mostly just chat with it, the same way I'd talk to a tech lead. Where are we at? What's blocking the email stuff? Let's cut the mobile part for now and come back to it. It goes and does that across however many PRs it needs to, and I don't have to be the one keeping the state of all the open PRs in my head. Honestly, that used to be most of the work of running a project.

3. Project chats left to run on their own /goal for weeks with guardrails

The next step past that is a project chat that you just let go. I give it a constrained domain,this one part of the app, these folders, nothing else verification rules for what counts as done,tests pass, a walkthrough video, the metric actually moved and a /goal. Then it runs for days or weeks, shipping PRs on its own, and when it actually needs a decision it slows down to ask.

The narrow domain limits what it can change, and the verification rules give it concrete conditions to meet before calling the work done. I tell it where it's free to ship and where it needs to stop and ask.

4. Build guardrails and metrics first, then let the agent rip against them

My side project had a bunch of integrations that each worked a little differently, which made it a great job for a big fan-out of agents. But before I pointed agents at it I spent a while on something pretty boring, which was an accuracy page I could actually trust. That meant fixing the ground-truth samplessome of the hand-gathered ones were just wrong and adding more reference samples.

Once I trusted that page, I opened one agent per integration, and they all reported their results against the same numbers. A lot of them fixed their integration. Some came back with a PR that only documented why the issue couldn't be fixed yet, which honestly was the result I wanted in those cases, way more than a fake fix that looked good.

If I'd skipped the accuracy page, I'd have gotten a pile of confident PRs and no way to tell which of them made things worse.

5. Giant refactors with backfilled coverage against main shipped first

You do a giant refactor and then you stop. You take the existing main branch and your refactor branch, give them both to a coding agent, and say something like:

Write regression tests for the behavior I've refactored, but write them against main first. Think through how the refactor could break that behavior and cover those cases.

Then you check that those tests pass on main, and see whether or not they fail on your new branch. If something passes on main and fails on your branch, you changed behavior somewhere, and now you know where.

You might think this is kind of useless, because the agent has access to everything. It can read the refactor it's supposed to be catching, so there's no test holdout. But in practice I've found it extremely helpful. I think it works because the tests have to pass on main first, so they end up pinned to what the old code actually did. This has let me merge refactors that I wouldn't have had the nerve to merge otherwise.

6. Agents launching agents

A lot of my agent sessions aren't started by me anymore. When a ticket gets created in Linear, it automatically turns into a Conductor workspace with an agent working it end to end. There's also a Slack bot that can read the codebase and the support tickets, and if a conversation turns into "can we fix this," it can start a coding session, check in on it, and send it follow-ups.

Most of the work went into the handoff. The bot's instructions say "Write a self-contained brief. The coding agent cannot read this thread," because the new agent starts with none of the conversation that led to it. They also say "Do not infer authorization from a request to start coding," since an agent that's allowed to start other agents will happily read a lot of permission into a pretty casual message.

7. Custom linters for architectural rules

I now use custom linters for coding standards and architectural rules that I used to leave to code review. I want the guidance agents get to be deterministic. A failing check tells them they did something wrong, so I don't have to tell them in review.

For example, you can ban data access outside of a data access layer. In JavaScript that's a single ESLint rule:

js
// eslint.config.mjs
export default [
    {
        files: ["**/*.ts"],
        ignores: ["src/data/**"],
        rules: {
            "no-restricted-imports": [
                "error",
                {
                    paths: [
                        {
                            name: "src/db",
                            message: "Go through src/data instead.",
                        },
                    ],
                },
            ],
        },
    },
];

My side project has custom rules with names like no-supabase-or-postgres-mocking, no-vague-variable-names, and require-useeffect-explanation.

Before agents, we humans often skipped writing these kinds of "purity" rules and left ourselves in a more mixed state. Somebody would query the database from a controller once because there was a deadline, and then there were two ways to do it, and eventually five, and everyone sort of lived with it because writing and maintaining the rule felt like more work than it was worth. And for people it kind of was. You could just tell the new person how things were supposed to work.

Agents move much faster when these rules are strict and clear. If the questions are already settled and there's one correct pattern, the agent doesn't have to guess which of the five ways is the real one by reading the codebase.and it'll often pick the wrong one, because the wrong one is usually the most common With those rules enforced by linting, the agent keeps going until everything passes, and I spend less time pointing out the same mistakes in review.

Writing the rules got cheap too. A custom lint rule used to take me most of an afternoon, which was hard to justify for something that saved a few review comments a year. An agent writes one in a few minutes.

8. A useful explosion of integration and end-to-end tests

I've also started writing a lot more integration and end-to-end tests.

The testing pyramid (another old pattern) says to write lots of unit tests, a smaller number of integration tests, and only a handful of end-to-end tests at the top, because end-to-end tests are slow and flaky and a pain to keep working. That made sense when a person had to write and maintain every one of them. Most teams I've been on had a pretty thin layer of end-to-end tests because of it, and we leaned on people clicking around before a release to cover the rest.

Writing and fixing an end-to-end test is cheap now, and the tests are worth more, because an agent can't look at the app the way I can unless something makes it look. A unit test that an agent wrote for code it just wrote tends to check that the code does what the agent thinks it does, which isn't very much information. An end-to-end test that logs in, clicks through the flow, and checks what's on the screen is going to fail when the feature is actually broken, no matter who wrote it.

So I've ended up with a lot more tests at the top of the pyramid than I ever would have written by hand, and agents run them on every change. They're still slow, though, and at some point the suite gets slow enough to be the bottleneck. Recently I had an agent combine overlapping tests into longer scenarios that walk through a whole flow, to bring the runtime back down.

9. Repositories and DDD are cheaper to maintain now

I've changed my mind about a lot of architecture stuff in the last year. I used to like frameworks that let you write less code, and I'd mostly push back on heavy structure like domain-driven design. There were good reasons for that. The same object could pass through several layers, with slightly different names and representations in each. You had to type all that boilerplate, then keep it in sync.

Now that agents write the boilerplate, I care more about having one clear way to implement something. I also care more about boundaries that keep a change in one part of the code from breaking another. As I ship faster, I need those boundaries more.

If there's a model layer, a command layer, a single place for data access, and folders that say which domain owns what, I've found agents are better at finding the right place and following the existing pattern.

Naming helps too. I now prefer db.peer_fundraisers over db.peerFundraisers because it matches the table name, so an agent can grep for one string and find everything.

The migration itself got cheap, too. A big restructuring like this used to be the kind of suggestion that got shot down right away. Now I write a spec for the pattern and the folder structure, and an agent can do most of the migration in one go. It's much less of an ordeal.

10. Spiking slowly/by hand, then expanding rapidly by agent

Once the PRD and the eng design are agreed on, it's really tempting to hand the whole design doc to an agent and get the entire project back in one PR. I do this a lot now. I can often get most of a project built in a day, merge it behind a feature flag, and work through the remaining pieces in follow-ups.

But I think it mostly works when there's already a really good example in the codebase of the thing you're asking for. The first feature of a new kind should get built slowly and painstakingly and reviewed line by line, because that's the one the agent is going to copy. After that the next few similar features can go fast, because the agent has a working example to follow.

I do still draw a line on dangerous stuff. If a change touches something like the filter compiler or anything with money, I want it in smaller pieces, even when the agent could do it all at once.

11. Automated PR approval with backtested judges

I can't review every PR carefully at this pace, so I built an AI reviewer that scores each one and is allowed to approve the safe ones on its own. The final rating is the lowest of a few things: the model's rubric score, a set of hard caps from plain rules,migrations, auth, anything with money, big diffs a cap whenever a serious finding is still open, and a second judge that only sees the title, description and diff. The caps are there because a model's rating is easy to talk up.

I tuned it by backtesting it against past PRs, including ones that had caused real problems. It now approves a minority of PRs. The backtest still missed a known-bad change, so I don't treat the score as a guarantee. When an approved PR causes a problem, it goes on the known-bad list and the next backtest has to catch it.

I'm still adjusting the threshold. Line count alone isn't a useful way to decide what needs review, but I've found the model useful at weighing the diff alongside the other signals.

12. Build instead of buy (maintenance became cheaper)

I keep replacing vendors with code I own: a CSV import tool, a data grid library, a hosted job queue, an email editor, even my monitoring setup. A few years ago a lot of these would've been obviously wrong calls, the kind of thing where you'd spend a year maintaining something a company does better.

I've found agents particularly useful for replacing software I already use. I can check their work against the existing product. You can run the vendor's version and yours side by side, write tests against the behavior you actually depend on, and keep going until they match. It's the same loop as the refactor pattern above, just pointed at somebody else's software.

Meta, Stanford and Harvard put out ProgramBench (opens in a new tab) this year, which asks agents to rebuild real programs like SQLite and FFmpeg from only the binary and its docs, and Epoch AI and METR's MirrorCode (opens in a new tab) tests something similar. ProgramBench shows how hard full reimplementation still is. Its setup is much more restrictive than mine: no internet, no source code, no decompiler, and the whole program rebuilt from scratch. Real life is a lot friendlier. You don't need all of a vendor's product, just the parts you use, and you get to read the docs, look at the source when it's open, and write your own tests as you go.

Something similar is happening in game decompilation. Fans used to spend years reverse engineering a game's original code, matching it function by function, and this year AI sped that up so much that decomp.dev (opens in a new tab), one of the community's hubs, stopped tracking projects because the human-driven model stopped making sense.

In practice, I think a lot of the SaaS vendors that sell to developers can now be ripped out and replaced in a few days of work. Proprietary data, network effects, compliance work, and operating a difficult service still give me reasons to pay a vendor. If I mostly need the code, I'm more likely to consider building it now.

I'm still finding out which of these replacements were worth taking on.

13. Notice when you've followed Claude too far

Every so often I'll be a few days into an agent-driven refactor and realize I don't really understand where it's going anymore. Each step made sense, the agent kept proposing reasonable next steps, and I kept saying yes, and now the code is in a state nobody actually chose.

When that happens I need to stop and admit that I followed Claude too far. Then I step back and decide what I actually want the code to look like before asking it to write anything else.

Past Writing