
Where Does Software Engineering Go From Here? (Part 2)
If agents write all the code, what does the new software development lifecycle look like? What does it mean for technologists?
Something strange happened when I came back from vacation earlier this summer. I’d been too busy surfing (or at least, attempting to surf) the coast around Agadir to touch a keyboard for two weeks, but the coding flow I came back to, the exact same one I had before, felt… off.
Slow.
Like there was resistance where there shouldn’t be. Like paddling out against the current. The kind of friction you only feel when you’ve had time to step away and reset your dopamine levels.
- Why do I lint and build in a pre-commit hook, then again in CI?
- Why am I hunting for the right skill or plugin instead of it just showing up?
- Why is the agent reading stale docs? Actually, why do we even have docs?
- Why can’t I get a briefing on what changed since I last looked?
- Why can’t my agents see each other’s branches before they build colliding abstractions?
- Why am I writing bug reports by hand when the system already has the telemetry?
- Do I really need the full review ceremony when nobody on the team has read every line, and nobody ever will again?
Don’t get me wrong, my setup today is sublime, but only relative to an IDE and a git forge that were designed for someone typing lines by hand. Moreover, it’s just for one person, and software engineering is rarely ever a single-player game.
There’s a gap.
In Part 1, I said we’d sped up one station in the development process (coding) and left the rest running at the old speed. Today, let’s take it a step further, let our imaginations go wild, and redesign the software development process from scratch.

0. Getting the right metaphor
This is a product design problem, and like any good product designer does, we start from first principles.
At its core, software development is about writing a set of instructions to execute a series of actions that will lead to some desired outcome, and code is the language used to convey those instructions. Software engineering is doing that in a way that makes optimal use of your resources, within your constraints, in a reliable manner, that produces the intended (or superior) outcomes, preserves optionality for evolving the system as needs change, and can be maintained by someone other than the person (or agent) who wrote it.
To make it easier, we’ll focus on development for now. The most natural way to get someone to do what I want (assuming they’ll comply) is simply to state the outcome I desire. The more competent the person, the fewer details and specific instructions I need to give. The more familiar they are with me, the more likely they are to infer my intention, fill in gaps in the instructions, and do the thing in a way that conforms to my taste. Despite the problems I talked about last time, LLMs are still a great translation layer from spoken language to code.

Let’s up the ante and imagine a group of people trying to give instructions to one person, the executor, all at the same time. You can have the group take turns, in which case the executor has to figure out the best way to complete the tasks, in what order, and how much they can realistically get done. If the instruction givers were feeling benevolent and wanted to help the poor chap out, they might take some time to get aligned first, so they’re not overwhelming them or asking for contradictory things. If they’re super nice, they might break the instructions down into more manageable chunks too, only giving the executor what they can realistically handle in one go.
To get the tasks done, the executor might need some tools, either to do them at all or to do them more efficiently. A manual on how to do them would be great too, especially if it encodes the preferences of the people giving the instructions, the kind of knowledge you can’t look up. If that’s not there and the task is particularly difficult, they’ll need to spend some time figuring things out, either by referencing other people’s work or by reasoning step by step from what they already know towards something new. That last part is a leap that, despite all their impressive accomplishments, LLMs still can’t make on their own.
Now let’s say the executor finishes. How do you know they’re done? Well, you can verify it for yourself if you’re watching them, or they can give you a progress update for you to check. If they like you, they’ll summarize it down to just the relevant parts, and you can go back and forth with them from there. If there are multiple people who need to keep an eye on what’s happening, the executor probably has to announce their progress somewhere everyone can keep track of. And since some messages only matter to specific people, those only go to the people they’re meant for. An executor who’s competent will be able to push/pull information to you at just the right cadence for you to absorb it.
Next, let’s assume it’s not just one, but a group of executors on the receiving end of your instructions. You might delegate specific instructions to the ones who specialize in them, or have a few of them collaborate on one goal. If there’s a lot of work and you need it done quickly, you’ll want the flexibility to bring in some outside muscle as needed. Perhaps you can have the executors check each other’s work too, incentivizing finding flaws and places to improve, which is usually a task that’s done better by a different set of executors than the ones who worked on the task.
Now if you’ve ever tried to organize a group of people to do something, you’d be forgiven if you started sympathizing with the dictators of the world and the amazing benefits of autocracy. It’s much easier to get things done when one person calls the shots, even if it isn’t you. Someone has to set priorities, resolve contradictory instructions, and make the final call when the group can’t agree on a design. Open source, of all places, figured this out early. Linux grew up with Linus Torvalds holding the final say, and Python with Guido van Rossum, the original benevolent dictator for life.

Things are starting to look very economics-y.
Interestingly, the book that started modern economics opens on a factory floor. In the first chapter of The Wealth of Nations, Adam Smith describes a pin factory where making a pin had been divided into about eighteen distinct operations, and ten people could make upwards of 48,000 pins a day between them. Had they each worked alone, he figured none of them could have made twenty, “perhaps not one pin in a day.” He put the difference down to “a proper division and combination of their different operations,” which is pretty much the thought experiment above, written down in 1776.
Requests become work orders, priorities determine their place in the queue, manuals become skills, and peer checks become inspections. Hopefully you can see why the popular software factory metaphor took off - it fits almost too well.
Now that we have a general idea of the different parts, it becomes more of a design problem: which parts do we expose to the engineer using the factory, and which can we keep hidden or expose selectively? When the work outgrows what one pair of hands can produce, what’s the optimal way of organizing units of work?
Luckily, physical factories have had over a century to get this right, so there’s plenty to learn there. Roughly speaking, the people running a car plant watch what’s coming in, where the line’s backing up and what failed inspection. They leave the welding to the robots, and the line only pulls them in when something’s actually wrong. The metaphor is obviously not perfect, but it does give us a concrete shape to start iterating on.
1. Done means shipped
On a factory floor, a product is done when it rolls off the line. In software, it’s done when a user has it, and anything short of that is inventory sitting on a shelf, which lean manufacturing counts as waste (though even waste has its uses - more on that later).
So the loading dock gets built first: a pipeline that takes a change all the way to production, and rolls it back when it misbehaves. Ship It! made the case back in 2005: “You’ll reap benefits for the rest of the product’s life cycle if you’re willing to invest the time up front to get your infrastructure set up properly.”
In the past, a startup could get away with poor engineering practices because it wrote code slowly enough for humans to keep some rough picture of the system in their heads, so the mess accumulated gradually. When agents can generate a month of implementation in an afternoon, the same lack of discipline becomes catastrophic. You can create a codebase faster than anyone can understand it.
If you take only one thing away from this article, let it be this: you can only go as fast as you trust your processes, so the guardrails must go up first. The folks behind TigerBeetle, a database for financial transactions, built a whole engineering methodology around this go-slow-to-go-fast idea, and TigerStyle sums it up better than I can: “Do the hard thing today to make tomorrow easy.” With agents, the dock is an afternoon of work, so you don’t have any excuse not to be shipping.

Another nice property of defining done as shipped is that it gives the agents a definition of done you can check against production: the change is live, users can use it, and the health checks still pass. This is especially important when you leave agents unattended for long stretches of work, or hill-climbing towards a goal, because an agent will happily climb whatever hill you point it at leaving carnage in its wake if it means climbing faster. TigerStyle’s rule to put a limit on everything applies here too; an agent you’ve left running overnight needs a budget, and a point where it stops and asks for help.
2. One floor, one live copy of the code
Right now every engineer and every agent works on their own copy of the code, and a surprising amount of the job is reconciling them - just think back to the last time you had to reconcile a large merge conflict. It’s also why I’m forced to lint before every commit and then again in CI, and then again upon merging, and once again before deploying. There’s a lot of wasted work.
Trunk-based development already cuts some of that reconciliation. DORA’s research has said for years that teams with few, short-lived branches ship faster and break less.
Google has worked on a common trunk for years. The vast majority of its engineers work at head in their own workspaces, and branches are mostly for cutting releases. Back in 2016, its 25,000-plus developers committed 16,000 changes on a typical workday, and automated systems committed another 24,000, long before anyone was calling them agents.
Anthropic has started rebuilding source control around the same idea. When its daily merges grew from about 2,500 in May to over 30,000 in September 2026, Git became a bottleneck. Its replacement, Scion, assumes clients are always online: commits, merges and rebases happen on the server, and changes are available everywhere immediately. Clients fetch the files they need, and many jobs don’t need a working copy at all. That’s much closer to a shared factory floor than thousands of self-contained replicas.
The factory I’d like to work in takes that a step further: one floor, one live workspace shared by humans and agents, with your laptop just a window onto it. Branches mostly disappear, pull requests with them, and everything lands on trunk behind a flag until it’s ready. Checks aren’t repeated against an unchanged revision.
Google didn’t drop code review, though; it still expects all code to be reviewed before it’s committed. The review just works differently. It happens change by change, right before each one lands on trunk, instead of on a branch waiting to be merged. The factory keeps review too, it just changes shape again: inspectors look at every change, and people read the ones that matter (more on both in sections 4 and 5).
Anthropic has had to rethink the merge queue too. When hundreds or thousands of changes can land while tests are running, a global lock becomes impractical. So it invested in testing after merge and before deployment, accepting that concurrent changes can conflict and relying on Claude to fix them quickly.
Commits stick around, but you stop writing them. Hand-crafting commits made sense when one person typed every change; nobody should be curating the edit stream of a dozen agents. Atomicity still matters, though. Every change on trunk should build, pass and revert cleanly on its own (the old not rocket science rule), and keeping it that way is a job for another agent, one that batches the stream into units like that, puts them in order, links each back to the conversation that asked for it, and only ships a unit when prod would stay green.
One floor won’t stop two agents from making contradictory assumptions in different files; git only sees text. Sure they’ll see each other’s work as soon as it lands, but they’ll coordinate better if they can also see who is working on what.
3. Decisions happen in public
So if nobody opens a pull request, where does the work start? With an issue, written in plain English.
One of the unpleasant (or pleasant, depending on your personality) side effects of using LLMs is that they multiply the decisions we make, and a lot of them shouldn’t happen alone in a chat window.
Let’s drag those conversations out into the open. Every issue becomes a thread anyone at the company can read (or anyone on the internet, for open source). People pop in when they know something you don’t, and when the road forks, they vote. Open source has worked like this for decades. Python’s big changes went through public proposals anyone could argue about, and for most of that time, Guido still made the final call, just with everyone’s arguments on the table.
Block’s Builderbot is an early agent-era version of this. You can tag it in a Slack thread, a few people can steer it at once, and in Block’s words, “the conversation is the development environment.” It still opens a pull request at the end, but I doubt it’ll need to for long.
4. Read the code that matters
Deciding well means understanding the system, and the only way I know to keep that understanding is to read the code. Which is a problem when agents write more of it than anyone can read.
Skip the reading and you rack up what people have started calling comprehension debt: code that works and that nobody understands. It’s nastier than technical debt because nothing feels wrong. The code’s clean, the tests are green, and then something breaks and nobody can tell you why it was written that way. In one trial, mostly junior engineers who learned a new library with AI help scored 17% lower on a quiz about it afterwards, with the biggest gap on debugging, and the ones who handed the work off entirely did worst of all.

You could argue we stopped reading compiler output decades ago and we’re fine, so why is this any different? Mostly because a compiler is boring. Give it the same code and you get the same output every time, and it’s had a few decades of stress tests (and, for some, formal verification) under its belt. Ask an agent for the same fix twice and you might get two different fixes, and you won’t know which one went out unless somebody reads it.
If I could give the factory one thing to optimize, it’d be how well the people running it understand what it’s building, which directly feeds into the trust I talked about in section 1.
A big part of that is avoiding cognitive surrender: taking the AI’s answer without checking it. Fluent, confident answers make that easy, and pretty much every agent I’ve used sounds like that. In reasoning experiments, people pushed back more when they had something at stake and found out right away whether they’d gotten it right. A ticking clock made it worse.
So every change should trace back to whoever made the call or signed off on it. Your name’s on it, and when something you waved through comes back broken, you hear about it. Pilots in flight simulators made fewer automation errors when they felt accountable for how they used it. And the 3am scramble stays with the agents (section 9), so only real emergencies get decided against a clock.
Agents should surface uncertainty where it could change the decision. When researchers made an LLM’s explanations reflect its actual certainty, people got better at telling its right answers from its wrong ones. Longer explanations just made them more confident. Even a plain “I’m not sure, but…” helped. Any confidence score needs checking against actual results, though; models tend to be overconfident when they grade themselves.
The good news is that some code really is more critical than others; it’s one of the first distinctions you learn to make in this job. Aviation made it formal decades ago, grading flight software by how bad a failure would be, and the higher the grade, the more of the checking has to be done by someone other than the author. The factory should grade every change by blast radius the same way, and send your reading time where a mistake would actually hurt.
Everything that’s not critical gets cheaper to read. You get a briefing on what changed in your corner since you last looked, and answers about how something works can be checked against the current code. The docs explaining what the code does are unnecessary, and why it exists lives in the thread where somebody decided.
Some expectations can live in the code itself. TigerStyle wants assertions on all logic and state, so a bug crashes the program on the spot instead of quietly corrupting your data. Hardly anyone keeps that up by hand, because it’s tedious. Agents don’t get bored, though.
Optimizing for understanding also means teaching it. A new hire used to spend their first few weeks scrolling through old Slack threads and closed PRs to work out how things got this way. The factory has all of it, every thread, decision and dead end, and can walk you through it. It can replay an old incident against copies of the real services, let you make the call, then show you what actually happened, the way pilots train in a simulator. That matters most for juniors, who are getting hired less and risk skipping the struggle that taught the rest of us the job.
5. Inspections should be done by others
The code nobody reads still has to be checked, and the earlier the better. Half of Toyota’s production system rests on that idea: the line stops the moment something looks off, and any worker can pull the cord, so a defect never reaches the next station.
I’ve never been a unit test guy; give me end-to-end tests that use the product the way a user would. Until now, most teams ration them because they’re slow, they flake, they break every time the UI moves, and the good ones need the services you depend on, like the payment processor or the email that has to actually arrive. The whole test pyramid is basically a budget built around how expensive they are, and Google’s testing blog once told everyone to just say no to more of them.
Agents once again invert the equation. They can write and maintain the suite, fix flaky tests instead of rerunning them, and run everything on every change. For the services you can’t hammer, they build stand-ins. StrongDM’s agents test against their own clones of Okta, Jira, Slack and Google Docs, thousands of scenarios an hour, and break them in ways the real services would never allow. The pyramid flips, and I can finally say I was right all along and get my way.
Just don’t let whatever built the thing inspect it. Let an agent edit a failing test and it’ll find the shortest path to green; StrongDM learned that “return true is a great way to pass narrowly written tests,” so they keep the real scenarios outside the codebase, where the agents can’t touch them. And since models trained on the same internet tend to fail together, the inspectors should be different models with different jobs. Security gets its own agents and pentesters, attacking the running system around the clock and feeding whatever they find straight back into the line. Another cleans up after everyone, and another pokes at production all day looking for bugs before users find them.
Software quality jumps once the line looks like this; more checks run, earlier, and none of the inspectors get tired on a Friday afternoon.
6. Production feeds the line
The last inspector is the user, and right now we barely listen. Every error, rage click, support ticket and quiet cancellation is telling you what to fix or build next, and most of it dies in a dashboard nobody opens, or reaches the code as a bug report somebody typed up by hand.
In the factory, the loop closes on its own. The system files the issue itself, with what broke, who it hit, the logs, a repro and the change that most likely caused it, then drops it into a thread like everything else. A human decides whether it matters, and the agents take it from there.
Fixing the bug is only half of it. Whatever let it through gets fixed too, with a new scenario, a check or a sharper skill, so each failure gives the factory a way to catch the same mistake next time. Every calls this compound engineering, the idea that each piece of work should make the next one easier, and it’s why I’d build this station second, right after the loading dock, even though it sits at the far end of the line.
None of it replaces talking to users, though. The telemetry will tell you what broke, but not what they wish existed or why the quiet ones left, and that makes talking to them one of the few ways of collecting feedback that’s as important as it ever was.
7. Cheap tokens turn one design into ten
All that feedback gets a lot more useful when you have more than one thing to compare. Models are getting ridiculously fast; OpenAI already serves a coding model at over 1,000 tokens a second, and Taalas, a startup that etched the small Llama 3.1 8B model straight into a chip, claims 17,000. Those are speed figures, not prices. My bet is that useful inference gets cheap enough to make trying several designs routine.
If that happens, you get to try ten designs instead of picking one. Why argue over two onboarding flows in a meeting when you could have both built and clickable by lunch, then let real users pick?
You can try it on old decisions, too. Since every decision is on record, you can essentially time-travel and fork the code from a decision (as opposed to a commit), then have the agents rebuild an alternate-reality version of the codebase where that decision went the other way. Tokens permitting, the next time someone insists their way of doing things would have been better, you can actually go check.

The nine designs you don’t ship are the factory’s shavings, and some of them will be worth keeping. Save the agent traces and the reasons things failed or were rejected, so the next agent can see what you’ve already tried. A failure can become a test; a discarded design might fit another product. And a good set of traces, with failures and rejections clearly marked, could be useful enough to sell as training or evaluation data. You’ve already paid for those tokens. You might as well get more than one use out of them.
8. The factory outlives the product
The factory should carry over from one product to the next. Say you’ve got a good SEO skill. You can use it on every site you run, and update it once when search changes. Same with the deployment pipeline and the agents checking the work. Each product will need some setup of its own, but you shouldn’t be starting over or digging through a plugin directory to remind the agents how to do their jobs.
That’s a good reason to spend time writing skills. When someone works out how to run a migration safely, write down what they did and how they checked it. Anthropic’s skill format is just a folder of instructions, scripts and resources, so most of this is documenting things you’ve already figured out. Next time, the agent has your team’s own procedure to follow instead of piecing one together from whatever it finds.
Keeping that factory useful becomes part of the job. You work out why the inspector missed a bug, or whether a cheaper model could do the same job. When a skill goes stale, you fix it before it causes trouble across every project using it. In a way we all end up doing CI/CD and DevOps, which is funny, given how many of us spent years treating the pipeline as somebody else’s problem.
I think this makes software studios a lot more viable too: one small team running several products through the same factory. With inference eating into SaaS margins, there’s more reason to share the engineering costs across those products. The token bill still grows with usage, and each product still needs customers and support. But you don’t have to rebuild the machinery to make and maintain software every time you have another idea.
9. Lights out
Manufacturing calls a plant that runs with nobody in it a dark factory, and FANUC’s robots have been building robots in one since 2001, unsupervised for up to a month at a time. The AI crowd borrowed the term for the top of its five levels of coding automation, where nobody reads the code at all.
In reality, lights out is pretty rare, because somebody still has to move the pallets and keep the robots running. Software makes it easier to track changes and roll back the code, which helps, but that won’t unsend an email or restore deleted data. We’re already leaving our agents with tasks to complete overnight; how far they can go on their own depends on what can be undone.
When something breaks at 3am, the agents roll back the change, flip the flag, fail over, whatever it takes, then dig into the cause and leave a write-up and a fix in the thread for the morning. Microsoft’s own SRE agent has already mitigated over 35,000 incidents across its services.
Once again, Google was ahead of the game here, and stated this in their SRE book a decade ago: “If a page merely merits a robotic response, it shouldn’t be a page.” Now the robots can give that response themselves, and a human only gets woken up when it’s actually a big deal: customer data at risk, money moving, something that can’t be undone, or the agents being unable to fix what’s broken.
And again, complete removal of human oversight is still a long way off, because automation is also how small problems become big ones; AWS’s huge 2021 outage started with an automated job to scale capacity. Agents can fix things non-stop, which counter-intuitively means that you need to be stricter than ever about not living with bugs for too long. Your job as an engineer is to address the root cause of failures earlier in development so they don’t happen in the first place.
10. Touch grass
A factory makes what you already know how to make. You, dear developer, remain its most important part, so investing in yourself is part of keeping it useful. If the foundation was correctly laid out, once it gets going the factory can ship software at frightening speed. But deciding what is worth building, how to improve the factory itself, the hard trade-offs that allow you to differentiate from the competition, all that still falls to you. Getting better at that takes time to learn and think, even when there’s nothing to immediately show for it at the end of the day.
Which raises the question of what to do with all the time these tools supposedly give us back. There’s a saying in Arabic “العمر بيخلص والشغل ما بيخلص” - life comes to an end, but work never does. The inspiring and frightening thing about humans is that we’ll always find ways to fill our time. If nobody decides otherwise, the time agents free up will go the same way, into more agents and more prompting. If there is a limit to demand for automation, we’re still nowhere near it.
Part 1 made the case for spending it on learning, but there’s also something to be said against using your time “optimally”. Case in point, I wouldn’t have noticed any of this without two weeks away from a keyboard. The best thing a factory can do for its people is buy them that time to learn, think, write, and live.



