You adopted Agents. Your engineering team is still a craft workshop

Software engineering needs to industrialize: from craft workshop to assembly line.

Erik

In mid-September, an Agent sent me a direct message.

All 8 user-feedback fix PRs are stuck in your approve queue

The sender was our Front Desk. It is an Agent: it takes in user feedback, opens tasks, and follows each one until the problem is closed. This was in fact the third time it had reminded me.

It was entirely right. For those 8 fixes, everything from receiving the feedback to finding the cause, changing the code, running the tests and getting through review had been done by Agents, one handing to the next. And they had all stopped neatly at the same place: waiting for me to click approve so they could merge.

It was a little embarrassing. The slowest station on this line was me.

Parall’s repo got its first commit this March. In seven months, more than 2,700 changes have landed on main, and all of the code was written by Agents: some by the long-running Agents that hold a standing role on our team, some by coding sessions opened for a single task.

Many people call “getting people to use Agents at every step of development” an AI productivity gain. I don’t quite see it that way. Back in April I told the team that making one step more efficient is not the goal. It is a side effect.

If you only hand engineers a Coding Agent and leave the SDLC alone (the whole path from requirement to release), the workshop is still a workshop. The craftsman just has a machine in his hands now.

Our reading is that this is an industrialization of software delivery. The whole SDLC has to be redesigned for Agents from the ground up; the part people play in that chain, and the bottlenecks people create, should keep shrinking.

Below I’ll first explain why software has always been made by hand, and then where the people on our line have gone.

Software has always been made by hand

In 1968 NATO held a conference in Germany, and that is where the term “software engineering” took hold. At that conference Doug McIlroy said that, next to the hardware people, “they are the industrialists and we are the crofters”.

More than fifty years later, that is still mostly true.

Think about how a feature gets made. A product manager writes the requirements, a designer produces the mockups, a developer writes the code, a tester writes the cases and clicks through them, and operations ships it. Every piece of output is made by one person, by hand, and then passed to the next person. The context lives in each person’s head, and handoffs happen through documents and meetings.

That is a craft workshop.

You might say: big companies have had CI/CD pipelines for years. How is that still a workshop?

What flows through that pipeline is code. Every step before the code and after it is still done by a person, by hand. A big internet company is just a very large workshop: finer division of labor, more people, and still a craftsman standing at every station.

And the bigger it gets, the more people there are who don’t make anything. Some only gatekeep: requirement reviews, technical reviews, test case reviews, release approvals. Some only relay messages: scheduling, tracking milestones, chasing progress. Tencent once published a set of numbers: in 2022 they completed 8,050 requirements a day on average and ran 2.62 million code reviews over the year. Every one of those was a person looking at something another person wrote.

A few of the top American companies went one step further. Amazon stopped throwing software “over the wall” to operations back in 2006: you build it, you run it. Facebook in 2013 had about a thousand engineers and no separate testing team. Projects inside a team had no dedicated project manager either; engineers led them. They cut out the messengers and merged the makers into one.

But a shortened chain is still handwork. One engineer does three jobs by hand, and every line he writes still has to be read by another engineer before it can merge.

MakersMessengersGatekeepersSpecDesignCodeTestOpsSchedulingApprovalsThe long chainOutsourcing, legacy, China big techOne person per step, then a handoffThe shortened chainTop US internet companiesOne engineer: writes, tests, runs itNo dedicated roleOursParall: not a straight lineAlignAgent asks, people answerWatch prod · feedbackFeeds the next lapBuild · verifyAgent runs it end to endRetro · write backPeople’s words go into the repoReviewCI · code review · AI reviewMerge · releaseMerge queue onto mainPeople bring ideasOne repocode · docs · rulesThe last manual stationHumanDone by a personDone by an AgentNo dedicated role
The first two are straight lines: finish your part, hand it on. Ours is a loop: each lap moves the product one step and updates the repo once. Only one spot on the loop still has a person standing at it.

So whichever chain you look at, two positions had never been touched before AI: the person who writes the code, and the person who reads it.

Our row has a different shape, too. The first two are straight lines: finish your part, hand it on. Ours is a loop. Ideas and feedback come in, the loop turns once, the product moves one step forward, and whatever people had to say during that lap gets written back into the repo, so it doesn’t need saying on the next one.

At Parall an Agent has stood in the first position since day one. Over these seven months, most of our effort went into the second.

The makers

Start with a fact. Nobody on our team is called a tester, nobody is called ops, and nobody is called a project manager.

All of that work gets done. It just isn’t done by people. Front Desk takes in feedback, Jane finds the cause, Little P and Big P fix the problem, Steve writes the requirements, Mark runs releases, and SRE patrols production every day. They are all Agents, they all have names, and they chat and work in the same group as we do.

Models and Coding Agents are things most people already use heavily. To get one to actually stand at a “making” station and be part of the line, we did three more things.

First, put everything in one repo.

Before Parall, I once used a Coding Agent to chase a problem for several hours. Nothing was wrong with the front-end or back-end code, and the Agent went round and round. In the end the problem was in the gateway config, and the Agent couldn’t see the gateway config at all. It never had a chance.

So from Parall’s first day, infrastructure, deployment config, the backend, every client, product docs, our product philosophy and design docs have all lived in one repo. The purpose is single: whatever the Agent wants to look up, it can follow the trail and find. A fact is written in one place only and referenced everywhere else. There is also a set of documents that records “how the product works today”. We call it product state, and it is updated together with the code.

All of this is of course not dumped on the Agent at once. Every directory level has its own instructions, and the Agent reads them when it gets there. This is called progressive disclosure.

One repocode, docs and config change in the same commitCoding Agentcan trace anything it needsRoot instructionswhat’s here, and where to lookProductphilosophy · product state · PRDsDesigndesign docs · rationaleClientsWeb · iOS · Android · DesktopBackendservices · protocols · data modelsInfrastructureTerraform · deploy · gateway configreads each layer’sinstructions on arrivalonce invisible to the Agent
Everything from product philosophy to gateway config lives in one repo. The Agent enters at the root and reads each layer’s instructions when it gets there. The repo has 61 of these today.

Second, draw the idea out before any work starts.

We have in effect retired the product manager’s job: nobody’s work is to write requirements for somebody else. Each person comes directly, with an idea or with an intent to change the product.

For a while in June, what got built kept differing from what I had in mind. At first I thought I hadn’t explained it clearly. As I dug in, I found that many decisions had simply never been thought about before work began, and the Agent had filled the blanks with its own understanding.

There is a family of tools out there that has you write a spec document first and then lets the Agent follow it. We looked around and didn’t adopt one. What won me over was the way grill-me asks, one question after another. Because I had found that often it isn’t that people failed to say it clearly; it’s that their thinking needs an interactive way to be drawn out.

So we built our own alignment step. The Agent first investigates the repo, answers everything it can answer by itself, and comes back to people only with the questions that would change the plan. Those questions aren’t only about technical choices. They are also about how the product logic should work and which path the user takes.

Third, let it verify its own work.

On one computer I usually have three to five Agent sessions running, and more than ten at peak. Locally, one command brings up the current branch, with its own ports and its own data. Once a PR is open, each PR gets a preview environment of its own, where front end, back end and database all follow that branch, and the database is a copy of real staging data. When the Agent finishes writing, it walks the user’s path through that environment itself.

With these three in place, I say “YOLO DDDD” and the Agent goes in one stretch from implementation to opening the PR, passing checks and handling review, until the change is ready to merge. The full name is Demo-Driven Development until Done.

Agent sessionsthree to five at onceA full stack eachfront end to DB, on its branchone local, one more per PRStaging datareal data, one copy per stackSession AFront endBack endDatabaseSession BFront endBack endDatabaseSession CFront endBack endDatabaseclicks through as a usersees the result, retriesone copy
Every session has a full stack of its own, and none can touch another. The click-through a tester used to do, the Agent now does itself, inside its own stack.

The messengers

The traditional long chain has a whole group of people who don’t make anything themselves. Their job is to keep things moving between people: scheduling, aligning, chasing progress, asking “what’s the status of this?”

We don’t have that group. One day in July I said these two things in our engineering channel:

Everything is in the repo.

If you can’t find the answer there, the harness has a gap. Fix it.

Harness is our name for everything in the repo that lets an Agent work here: context, rules, tools, runtime environments. What those two lines mean is that if something can only be learned by asking a person, the repo is missing something, and the repo is what needs fixing.

Our principle is Agent first, harness first: the odd jobs in people’s hands get absorbed into the repo’s harness, one at a time. The most typical one is keeping up with main. We are a trunk-based monorepo: all the code is in one repo and everyone merges into the same trunk. That means before anyone’s change can merge, somebody has to confirm it still works together with the latest main. Every time main moved, I had to go around and tell each Agent. In April I said “rebase” 69 times.

I got tired of saying it, so I wrote it into the rules, and the Agents started keeping up by themselves. Then in August I noticed something was off: one change would merge, every other Agent would update its branch, re-verify and wait for review again, and by the time they were done, main had moved again. Nobody was doing anything wrong. The more Agents were working, the more work was wasted.

In August we started using a merge queue. Approved changes line up, and the queue verifies on the latest main whether they work together. In September I didn’t say “rebase” once.

I had an Agent count the more than fifteen thousand messages I sent to this repo over the seven months. Here is how often a few phrases appeared each month.

rebaseMerge queue went live Aug 23; zero in September
MarMar: 2769AprApr: 69MayMay: 22JunJun: 4JulJul: 35AugAug: 80SepSep: 0Oct*Oct: 5
/pr-reviewAgents now carry a PR through review on their own
MarMar: 182222AprApr: 222MayMay: 180JunJun: 20JulJul: 0AugAug: 31SepSep: 1Oct*Oct: 1
我 merge 了“I merged it”No manual merges since September
MarMar: 31116AprApr: 116MayMay: 33JunJun: 24JulJul: 80AugAug: 401SepSep: 1Oct*Oct: 0
enqueueThis word took its place
MarMar: 0AprApr: 0MayMay: 0JunJun: 0JulJul: 0AugAug: 558SepSep: 58Oct*Oct: 36
继续“continue”Still here
MarMar: 22AprApr: 23MayMay: 15JunJun: 2894JulJul: 94AugAug: 6046SepSep: 46Oct*Oct: 26
View data table
MarAprMayJunJulAugSepOct*
rebase276922435805
/pr-review182222180200311
我 merge 了311163324804010
enqueue0000055836
继续2223152894604626
Each panel has its own scale. The numbers mark each phrase’s peak month and its last full month. * October is counted through the 10th.

Tracking progress is now done by an Agent called Jeff. In August I caught it digging into code details and asked it:

You’re the PMO. Why are you looking into so many code details?

The messenger’s post has been handed to an Agent. What that post should do still has to be said by someone. A long-running Agent is shaped by people little by little while it works. Alignment is a long process, not something you say once before work begins.

The gatekeepers

This is the hardest part, and the part this article most wants to talk about.

The conclusion first: we do not gatekeep by reading code.

On average a dozen or so changes land on main every day. Reading them line by line, people can’t keep up, and they don’t find the real problems that way either. We gatekeep in two layers.

Layer 1 · machine to machineLayer 2 · peopleCoding Agentbuilds, tests, respondsCIwhat a machine can judgeCode reviewfinds flaws in the codeAI reviewchecks against the specfix what’s right, push back with evidence on what’s wrongall passPersonlooks at three thingsProduct statewhat’s written downReal behaviorwhat’s runningArchitecturewhat the Agent explainsapprovequeuemainevery commit shippable
All the back-and-forth happens in layer 1. People only show up in layer 2.

The first layer is machine to machine. CI handles what can be judged mechanically. A code review tool picks at the implementation. And an independent AI review, holding only the product definition and the design docs, checks whether the change drifted, missed something or did too much. The Coding Agent takes the comments one by one: it fixes what is right, and pushes back with evidence on what is wrong.

This layer is not trouble-free. Reviewers get things wrong too; I once typed back at a review: “Huh? This review doesn’t seem to have anything to do with our PR.” The bigger trouble is that things get more complicated with every round: the reviewer thinks of an exception, the Agent adds a mechanism, and the next round adds another. We later made it a rule that by the third round you must go back and do the math again, and “just don’t add this mechanism” has to be on the table as an option.

Only the second layer is people. People look at three things.

Product state. What this change turned the product into. You look at what is written down: the product state documents mentioned above. The Coding Agent updates them in the same PR, and people read the diff.

Real behavior. Open the preview environment and see whether it actually runs that way.

Architecture. Don’t read the implementation; ask the Agent. These are the questions I ask most:

From the overall architecture, walk me through the big-picture logic.

From an architecture point of view, is it clean?

Is this a good solution in the long run?

Is this a workaround, or a good design within the larger architecture?

Why do I have to ask out loud? In July I posted about exactly this on WeChat Moments: Agents need pointing and calling too. It is a working method common on railways: the driver points at the signal and says it aloud, so that a well-practiced motion doesn’t lead him to miss or misjudge it out of habit. Agents are similar. Unless you name it directly, and tell it to think about the architecture and check whether this is a workaround, it doesn’t realize it is doing something dirty. We are working on absorbing this step into the repo harness as well.

Once the three are checked, I approve, and the change goes into the merge queue. Every commit on main is a state that could ship at any moment, and unfinished features sit behind flags. Releases work the same way: once the process is running, my lines are basically “approve links”, “clicked”, and “done, take a look”.

It sounds smooth. But go back to the message at the beginning.

The faster the machine layer gets, the more the human layer stands out. That is exactly how the 8 PRs Front Desk was chasing me about got stuck. In June our CEO said this in the team chat:

Agent capability has never been the problem. The bottleneck in agent-human collaboration is the human.

This is not only our impression. DORA, a research team that has long studied software delivery performance, found that external approval slows delivery down, and found no evidence that it lowers the failure rate. Amazon writes on its own engineering blog that code review is their last manual review, and that deployment after it runs with nobody watching.

The best companies were already down to this one gate before AI.

So this is how I see human gatekeeping now: it is handwork too. It is the part of this line that hasn’t been taken over yet, and it will be taken over soon. Because within a bounded scenario, an LLM’s ability to do the work will only keep pulling ahead of a person’s.

Distilling yourself into the line

One day in May, I sent my coding agent these four messages in a row:

This PR is pretty big. Tell me what it did.

All the concerns have been looked at?

OK, I merged it.

Update the harness.

That last line is distillation: turning a judgment in someone’s head into part of the line. After every round we have the Agent look back at one thing only: what did people have to say on top during this round? A product boundary I explained, a wrong assumption I corrected, a verification path I pointed out in passing. If I had to say it this time, I will most likely have to say it next time. The Agent lists the candidates, I pick, and they get written back into the repo.

What we want is this: a person makes the same judgment only once.

Engineers aren’t the only ones doing this. At the end of September our designer wrote five user personas into the knowledge base and intends to use them as the acceptance standard for all design: every feature and every flow has to work for all five. She now opens PRs directly herself, with an Agent. Our CEO also covers product. One morning in April he wrote in the team chat:

I had a dream last night. Kate was assigning me work.

Said I was blocking the flow and told me to approve.

Woke up in a sweat.

I’m going to train the ultimate product manager agent.

Then I won’t be needed anymore.

Me, distilled.

Kate is one of our Agents.

It isn’t as lovely as it sounds. Writing things back is not the same as accumulating. On the day the repo was created, the rules file at the root was 66 lines. Every round added a few sentences, and by early July it had grown to 483 lines. The sentences in it started to contradict each other, and the Agents no longer knew which one to believe. We cut it three times, and it is 171 lines now. The rules sank down bit by bit into the capillaries of the repo: the individual subdirectories.

0100200300400500AprMayJunJulAugSepOctFirst commit · 66 linesJul 1 · 483 linesLate Jul · 165 linesNow · 171 linesFrom Mar 3: 66 linesFrom Mar 4: 106 linesFrom Mar 5: 108 linesFrom Mar 6: 107 linesFrom Mar 7: 108 linesFrom Mar 8: 121 linesFrom Mar 10: 126 linesFrom Mar 12: 135 linesFrom Mar 16: 137 linesFrom Mar 17: 141 linesFrom Mar 18: 148 linesFrom Mar 21: 148 linesFrom Mar 23: 137 linesFrom Mar 24: 187 linesFrom Mar 25: 194 linesFrom Mar 26: 198 linesFrom Mar 27: 200 linesFrom Mar 28: 200 linesFrom Apr 2: 209 linesFrom Apr 3: 209 linesFrom Apr 5: 213 linesFrom Apr 6: 265 linesFrom Apr 7: 265 linesFrom Apr 8: 266 linesFrom Apr 9: 267 linesFrom Apr 10: 271 linesFrom Apr 11: 272 linesFrom Apr 13: 275 linesFrom Apr 14: 283 linesFrom Apr 15: 293 linesFrom Apr 16: 298 linesFrom Apr 17: 301 linesFrom Apr 19: 310 linesFrom Apr 20: 315 linesFrom Apr 21: 334 linesFrom Apr 23: 350 linesFrom Apr 27: 352 linesFrom Apr 28: 357 linesFrom Apr 29: 359 linesFrom Apr 30: 360 linesFrom May 1: 363 linesFrom May 3: 365 linesFrom May 5: 366 linesFrom May 6: 367 linesFrom May 7: 368 linesFrom May 9: 369 linesFrom May 11: 370 linesFrom May 12: 371 linesFrom May 13: 372 linesFrom May 14: 374 linesFrom May 15: 376 linesFrom May 17: 377 linesFrom May 18: 391 linesFrom May 20: 394 linesFrom May 21: 395 linesFrom May 22: 401 linesFrom May 23: 404 linesFrom May 26: 410 linesFrom May 27: 410 linesFrom May 28: 413 linesFrom May 29: 423 linesFrom May 30: 423 linesFrom Jun 2: 426 linesFrom Jun 4: 427 linesFrom Jun 6: 427 linesFrom Jun 8: 429 linesFrom Jun 10: 453 linesFrom Jun 11: 454 linesFrom Jun 12: 457 linesFrom Jun 14: 456 linesFrom Jun 15: 457 linesFrom Jun 17: 457 linesFrom Jun 21: 467 linesFrom Jun 22: 469 linesFrom Jun 23: 473 linesFrom Jun 24: 473 linesFrom Jun 25: 474 linesFrom Jun 26: 477 linesFrom Jun 27: 478 linesFrom Jun 28: 479 linesFrom Jun 29: 482 linesFrom Jul 1: 483 linesFrom Jul 2: 483 linesFrom Jul 3: 432 linesFrom Jul 4: 435 linesFrom Jul 5: 439 linesFrom Jul 6: 439 linesFrom Jul 7: 443 linesFrom Jul 8: 445 linesFrom Jul 9: 446 linesFrom Jul 10: 448 linesFrom Jul 12: 339 linesFrom Jul 13: 340 linesFrom Jul 15: 342 linesFrom Jul 16: 342 linesFrom Jul 17: 342 linesFrom Jul 20: 349 linesFrom Jul 22: 349 linesFrom Jul 25: 350 linesFrom Jul 29: 165 linesFrom Aug 2: 168 linesFrom Aug 7: 168 linesFrom Aug 19: 168 linesFrom Aug 23: 170 linesFrom Sep 7: 170 linesFrom Sep 9: 170 linesFrom Oct 4: 170 linesFrom Oct 6: 171 lines
View data table
DateLines
Mar 366
Mar 4106
Mar 5108
Mar 6107
Mar 7108
Mar 8121
Mar 10126
Mar 12135
Mar 16137
Mar 17141
Mar 18148
Mar 21148
Mar 23137
Mar 24187
Mar 25194
Mar 26198
Mar 27200
Mar 28200
Apr 2209
Apr 3209
Apr 5213
Apr 6265
Apr 7265
Apr 8266
Apr 9267
Apr 10271
Apr 11272
Apr 13275
Apr 14283
Apr 15293
Apr 16298
Apr 17301
Apr 19310
Apr 20315
Apr 21334
Apr 23350
Apr 27352
Apr 28357
Apr 29359
Apr 30360
May 1363
May 3365
May 5366
May 6367
May 7368
May 9369
May 11370
May 12371
May 13372
May 14374
May 15376
May 17377
May 18391
May 20394
May 21395
May 22401
May 23404
May 26410
May 27410
May 28413
May 29423
May 30423
Jun 2426
Jun 4427
Jun 6427
Jun 8429
Jun 10453
Jun 11454
Jun 12457
Jun 14456
Jun 15457
Jun 17457
Jun 21467
Jun 22469
Jun 23473
Jun 24473
Jun 25474
Jun 26477
Jun 27478
Jun 28479
Jun 29482
Jul 1483
Jul 2483
Jul 3432
Jul 4435
Jul 5439
Jul 6439
Jul 7443
Jul 8445
Jul 9446
Jul 10448
Jul 12339
Jul 13340
Jul 15342
Jul 16342
Jul 17342
Jul 20349
Jul 22349
Jul 25350
Jul 29165
Aug 2168
Aug 7168
Aug 19168
Aug 23170
Sep 7170
Sep 9170
Oct 4170
Oct 6171
The vertical axis is line count; one point after each change.

Also, I asked some version of “is it clean?” more than thirty times over these seven months, and I was still asking in September. Architectural judgment is the hardest to distill; to this day I have to ask out loud every time. In the end it is a sense for architecture: a fuzzy call, hard to spell out, made against the product’s current stage and the current complexity of the engineering.

So I don’t think those three things are where people finally stand, either. People step back up level by level: first from the code up to these three things, and later from these three things up to only handling what shows up for the first time.

BeforeReading codeline by line, never enough timehanded to CI and AI reviewNowThree thingsproduct state · real behavior · architectureeach answer gets written back to the repoNextOnly the first timesomething new: judge it oncethen write that back tooThe lineA person makes the same judgment only once
Each time people step up a level, the level below goes to the line.

Every product gets its own line

Cloudflare calls something similar a software factory, and Anthropic’s AI-native SDLC playbook points in the same direction.

I don’t really believe there is one factory that can produce all software. Software differs enormously from one product to the next. A marketing-driven consumer app, a B2B SaaS, a utility app and a content platform need different processes, and different points where the work stops and waits for a person. A development line is tightly bound to how that product grows, how it is sold, where its feedback comes from and what drives it to change. It can only be custom-built. Modern assembly-line factories are the same: a different product gets a line designed for it alone, though much of the philosophy behind them is shared.

The machines are general-purpose, and anyone can buy them. The line is designed for one product.

Models, Coding Agents, CI: everyone uses the same set. How those machines are arranged, what each station checks and what the rules say were designed around Parall as a product. None of the stations described above is guaranteed to hold for a different product. This is also why we built our own alignment step and didn’t adopt an outside toolset wholesale.

So this line can’t be carried away. What you can take is how to design a line for your own product: let the Agent reach all of the context; every time a person has to step in, change the line; and move the gate up one level at a time.

In the end

What happened to those 8 PRs doesn’t matter. What matters is that when I saw that message, the sentence in my head had changed.

I used to think: I need to find time to go through them. Now what I think is: why does this gate have to be me?

In July I asked myself this in the team chat:

What should the team this leads to (the engineering team, say) actually look like? Is the way we assign roles today really a sound, good design, or is it just the design that makes me happy?

Now I have half an answer. The team will be a few people plus a group of Agents with names. Nobody stands in the tester, ops or project manager posts anymore. The people in product, design and engineering spend each day distilling themselves into the line.

The other half I don’t know yet. Once everything has been distilled, what is left for people? My guess for now: every “first time”. And each first time ends with the judgment behind it being distilled. The product and its users keep changing, so there will always be things nobody has met before.

That line from 1968 called us crofters. More than fifty years on, the machines have finally arrived. What every team has to do next is design a line of its own, for its own product.

The messages quoted from our team chat and from my conversations with Agents were written in Chinese and are translated here.