Available
← all posts

Agentic Harness: What Software Design Actually Is

A factory of agents can write the code faster than you can read it. It still cannot decide what to build, and that decision is the whole job. What software design is, where it came from, how every era has done it, and why the agent factory skips the one stage that decides quality.

A factory line on a dark grid with the first station left empty: a request feeds a gap where design should be, then build, test and release carry on regardless

Earlier this year I gave a factory of agents a week and one of my own products, and almost no design. I wanted to see what the machine would do if I stayed out of the way.

It merged twenty five changes in a day. That felt like progress until I sorted them. Ten added something a user would notice. The other fifteen were fixing or undoing work from earlier the same week. The one new screen it built was clean, carefully named, and matched almost nothing I actually had in my head.

The code was fine. That was the unsettling part. None of it was broken in a way a compiler catches. It was broken the way a building is broken when nobody decided where the doors go.

What I had skipped was design. Not diagrams. Decisions. This is the fifth post in a series on building an agentic harness, and it is about the one stage the new factories leave out.

What software design is

Software design is the set of decisions about what to build and how the parts fit, made before and around the code. It is not the drawing. The drawing is a record of a decision, and you can have the drawing with none of the thinking that is supposed to sit under it.

David Parnas wrote the clearest version of this in 1972. A module, he said, is "characterized by its knowledge of a design decision which it hides from all others". So you do not carve a system up by the steps it runs. You start, in his words, "with a list of difficult design decisions or design decisions which are likely to change", and each part is built to hide one of them. Design is naming those decisions and placing them on purpose, before they harden into code.

Here is the working definition I use now, learned the hard way. A design starts from the desired product, the finished thing as the user will meet it, and turns it into the artifacts a build can be checked against: the contract, which is the interfaces and what each one promises; the data model, written down to the last field; and, for anything a user sees, the design system. Then it becomes a path to build that product in vertical slices, each slice a thin cut through the whole stack that a user can actually use. A design is finished when that path is numbered and a stranger could build the first slice without asking you a question. Anything looser is an intention, and two builders will read one intention two ways.

Why it matters

Fred Brooks settled this in 1986, in an essay called "No Silver Bullet". He split the difficulty of software into two kinds, "essence", the difficulty built into the problem, and "accident", the difficulty that only comes from how we happen to build today. Then he named the hardest part:

The hardest single part of building a software system is deciding precisely what to build.

That sentence is the whole argument. The deciding is the essence. The typing is the accident. For forty years the accident is the part we kept making cheaper, with better languages, better tools, and now a model that writes a module in seconds. The essence did not move.

It matters because the cost of a wrong decision depends entirely on where you catch it. Caught in a design, a wrong decision costs a sentence. Caught in the code, it costs a rewrite. Caught in production, it costs your users. Malte Ubl put the reason teams at Google write a design document before coding in one line: "Early identification of design issues when making changes is still cheap."

There is a sharper reason now. A model is trained to produce plausible output, and plausible is not the same as right, and it is a long way from good. Hand it the deciding and it will decide, confidently, every time, with no stake in the answer and no taste to guide it.

Generation got cheap this year. Deciding what to generate did not.

Where it comes from

The field admitted this at the very start. In October 1968, at Garmisch in Germany, fifty odd people from eleven countries met at a conference sponsored by NATO. The phrase they coined for the meeting, as the report by Peter Naur and Brian Randell records, "was deliberately chosen as being provocative": software engineering. They were there because projects ran late, cost too much and shipped broken, what some of them called the software crisis. The complaint was never that the code was hard to type. It was that nobody was deciding well.

The names that followed all say the same thing from different angles.

  1. Winston Royce, 1970. His paper is the one usually blamed for rigid, up front design, the so called waterfall. Read it and he argues the opposite. His first rule is a heading in capitals, "PROGRAM DESIGN COMES FIRST", and his third is "DO IT TWICE", build a pilot and expect to throw it away. The pure one pass sequential version, he warns, "is risky and invites failure".
  2. David Parnas, 1972. Decompose a system by the decisions that are likely to change, and hide each one.
  3. Edsger Dijkstra, 1974. He named the habit that holds all of this together, "the separation of concerns".
  4. Fred Brooks, 1975. In "The Mythical Man-Month" he wrote the line that every design argument since has leaned on: "I will contend that conceptual integrity is the most important consideration in system design."

Fifty years, and the discipline kept arriving at the same place. The decisions outrank the typing.

How we have been doing it until now

The practice swung hard between two extremes before it settled.

First it formalised. Structured design, from Larry Constantine and Ed Yourdon in the 1970s, gave us coupling and cohesion, the idea that the parts should lean on each other as little as possible and hold together inside as much as possible. Then object oriented design, and the Unified Modeling Language from Grady Booch, James Rumbaugh and Ivar Jacobson, adopted as a standard in November 1997. The field over corrected into heavy modelling, drawing the whole system in careful notation before a line of it ran.

Then it rebelled. Agile treated a thick up front design as waste. Martin Fowler asked the question directly in an essay titled "Is Design Dead?" and answered it: "Not by any means, but the nature of design has changed." The movement leaned on the rule they called "you aren't gonna need it", on doing the simplest thing that could possibly work, on design that emerges as the code grows. That only holds up because tests, continuous integration and refactoring made changing a decision later cheap enough to risk.

Strip away the method wars and the actual work has barely changed in fifty years. It is a conversation before it is an artifact, and it runs as a loop, not a checklist. A design session moves through the same steps whatever the decade.

  1. Identify the goals. What we are trying to achieve, stated as an outcome, not a feature. "A user can share a link short enough to read aloud" is a goal. "Build a URL shortener" is a label.
  2. Identify the requirements. What it must do, and the walls it has to live inside. Can a user choose their own slug, do links expire, who may delete one. And the constraints: "Alexa cuts off a skill after about eight seconds" is a whole design in one sentence. A requirement nobody states becomes a decision the builder makes for you, out of sight.
  3. Draft the simplest solution that meets them. The simplest, not the grandest. The pull is always to design for the system you imagine in a year. Design for the goals in front of you, and leave room rather than build it.
  4. List every way it blows up. This is the step that earns the session. Attack your own draft. The slug collides. One key runs hot. The real data does not match the document, which you only learn by exporting a sample and counting the shapes. The load is read heavy and all the thought went into the write path.
  5. Address each one. Fold the answers back in. Some kill the simple draft and you take the next simplest. Most just harden it.
  6. Explain it back. Say the design to the person who owns the product, in plain words, and watch where they frown.
  7. Address the misunderstandings. The frown is the finding. Fix the design where the explaining exposed a gap, then explain it again, until nothing frowns.

Steps four to seven are the loop, and most of the quality is made there, not in the first draft.

The session is not finished when the talking stops. It is finished when it has produced the things a build agrees to. Bertrand Meyer named the sharpest of them a contract: an interface that states what it expects, what it guarantees in return, and what it keeps true throughout. The data model is the second, every field pinned down. For anything a user sees, the design system is the third, so a surface is decided once and reused, not improvised per screen. Those three describe the desired product in full.

Then, and only then, the plan to build it. Not one big push, and not a database this week and a screen next month, which leaves a user nothing they can use until the last layer lands. Vertical slices instead: each one a thin cut through the whole stack that a real user can act on, so feedback arrives early and a wrong decision is caught while it is still one slice wide. The first slice is what Alistair Cockburn called a walking skeleton, a tiny build that runs end to end and links the main parts together, meant to grow rather than be thrown away.

None of this is exotic. It is a whiteboard, a handful of pointed questions, and a real sample of the data. Where we landed, across all the method wars, is a short written design that holds these decisions, done before the build and kept light.

  1. The design document. Google's version, which Ubl describes, records the approach and the key trade offs so the hard problems surface while they are still cheap to fix.
  2. Working backwards. Amazon writes a press release and a list of frequently asked questions for a product before the product exists, so the argument about what it is for happens before the building.
  3. The architecture decision record. Michael Nygard proposed these in 2011: one short file per significant decision, with its context and its consequences, kept next to the code.

Three different shapes, one habit. Write the decision down, keep it small, do it before you build.

Why a software factory is missing this process

In the last post I drew the factory line: a request becomes a fixed process, reusable parts, an automated build and test, a release, then a measurement that feeds back. The 2026 factories of AI agents keep that line and put an agent on each station. They are very good at four of them.

This week Coforge announced one, an Autonomous Software Factory, with agents working in parallel across coding, testing, validation, code review and quality assurance, under a layer of governance. The people, it says, move up to architecture, governance and the business decisions. Vercel's Foreman, from August, puts a classifier, an analyst, an implementer and a reviewer on the line and stops at a draft pull request.

Not every tool skips it. The spec-driven ones built the stage on purpose, and I will come back to where they put it. Amazon's Kiro runs requirements, then design, then tasks, and will not build until a person approves each one. GitHub's Spec Kit runs specify, plan, tasks, implement, with a gate between. Those are the exception. The systems announced as factories are the ones that compress the stage back out.

Now find the design stage in Coforge's or Vercel's. It is one box, called the analyst, or it is off the diagram entirely, folded into the things humans supposedly still do. The factory industrialised every station except the one that decides whether the thing is worth building at all.

Whatever that one box does, it does not hold a session. Nobody asks the clarifying questions. Nobody writes down the constraints. Nobody pulls a real sample of the data to see what is actually there. Nobody attacks the draft to find where it blows up, and nobody explains the design back to check it even landed. The agent reads the ticket and starts typing, and every requirement the ticket left unstated becomes a decision the agent makes quietly, at speed, on its way past.

The reason is the one from the top of this post. Generation got cheap, so the diagrams optimise the cheap part and compress the expensive part into a single box. A thin box gets filled by whoever is standing there, and the one standing there is an agent with no taste. That is why the output is appalling in the specific way mine was: not bad typing, bad decisions, made fast and merged before anyone decided they were wrong.

Sean Grove made the related point about specifications at a talk last year. We keep the generated code and throw away the prompt that produced it, which he compared to shredding the source and then carefully version controlling the binary. The agent factory does the same thing to design. It keeps the binary and shreds the source.

What it could look like

A real design stage, before any agent writes code. Its output is not a drawing. It is the desired product written down as the artifacts a build is checked against, and a path of vertical slices to reach it.

What it produces. The desired product, defined as the user will meet it, and under that the three artifacts from the last section: the contract, the data model, and the design system. Then the path to build it, a numbered run of vertical slices, one intention each, each usable and revertable on its own, the first a walking skeleton that runs end to end.

Why it runs in that order. Each stage feeds the next, and skipping one hands its decisions to the machine. The desired product bounds everything after it, so you fix the target before you argue about the parts. The research, reading the real code and a real sample of the real data, keeps the artifacts honest to what is there instead of to what a document claims should be there. The data model is pinned before any slice, so the schema and the code that fills it cannot later disagree. The slices come last because you cannot cut a product into usable pieces until you know what the whole product is.

How a person stays in it. The agent does the legwork. It asks the clarifying questions, writes down the constraints, gathers the data, drafts each artifact, and attacks its own draft for where it blows up. A person answers the questions and makes the calls with teeth. Then the agent explains the design back, the person fixes what the explaining got wrong, and that exchange, not a signature, is the approval. Nothing is built before it.

The design stage: the desired product, its artifacts, then slices

None of this is new. It is the design document, the working backwards press release, and the decision record, reborn as the factory's first station and made into a gate the agents cannot walk past.

Where in the loop it should go

The tools answer this, and they mostly answer it the same way. Design goes first, as a gate. Kiro will not build until a person approves the requirements, then the design, then the tasks. Spec Kit runs specify, plan, tasks, implement, in that order, with a gate between each. Jules shows you a plan and waits for a yes before it touches code. All three put design at the front of the line, and all three are right to. The decisions do belong before the typing.

But "at the front, once" is only half the answer, and it is the half that quietly turns into a waterfall. Design once, approve once, build the rest of the way, and the feedback from building and from real users has nowhere to go except a change request against code that already exists. There are three places design can sit, and the version that works uses all three.

  1. Up front, for the whole product. Before any slice, fix the target: the goals, the contract, the data model, the design system. This is the Kiro and Spec Kit gate, and it is where the desired product gets decided. Skip it and every slice pulls its own way.
  2. Again, for each slice. Each vertical slice gets its own short design pass before it is built, because the slice is where the target meets the real code and the real data, and that is where the target turns out to be a little wrong. A small design each time keeps the whole thing from freezing around the first guess.
  3. As the yardstick, all the way down the line. Design does not drop out once the build starts. The reviewer checks the change against the design, not against taste in the moment. The measuring station, the one I argued last time is the hardest to get right, scores against the design's success criteria instead of a mood. And what the measuring learns feeds the next design pass. That is the arrow that closes the loop.

Where design sits: the gate up front, the yardstick to the end

So design is not one station you pass through. It is the gate at the front and the thing the last two stations measure against, and it runs again, smaller, for every slice. Put it anywhere later than the front and it stops being design. It becomes an argument about code that already exists, which is the most expensive argument there is.

How it should be implemented

Here is the shape that works, drawn from running one of these for real on my own products.

  1. Start with the questions, in writing. The agent asks what it must do and what it must not, and lists the constraints the build has to live inside. A person answers. An unasked question is a decision handed to the machine. Then research is its own step: the agent reads the real code and a real sample of the data and returns findings, not a plan. The data is the source of truth, not the document that describes it.
  2. The design is a written artifact in the repository, versioned next to the code, and it is the source of truth for the build. Specifications are the thing you keep, not the thing you throw away.
  3. Cut the work into vertical slices, not layers. Each step is a thin path through the whole stack that a user can act on, one intention, the files it touches named, what proves it stated, what it depends on stated. The first is a walking skeleton that runs end to end. A step whose title needs the word "and" is two steps, and a step that builds a layer with nothing on top of it is not a slice.
  4. Pin the contract and the data model to the field before any slice, so the two cannot disagree. The interfaces and what each one promises, and every table, column, type and key. Half an hour of writing the field list beats a day of reconciling a schema against the code that fills it. For anything a user sees, the design system is decided here too, once, not per screen.
  5. Put a diagram in. The reader takes the shape in two seconds, then reads the prose to confirm it.
  6. The agent explains the design back, and approval is the person fixing what it got wrong. Once that exchange settles, the agents build to it. Reopening the decision through the back door costs the person the work of deciding twice.
  7. The gates read the design, not vibes. An implementer agent may not start a change that is not in the approved path. The reviewer checks the change against the design. The test suite encodes the design's success criteria, so the measuring station is scoring against something written down rather than against whatever looks right today.
  8. Keep it light. The design carries decisions and a path, not an inventory of files. Files change every day and decisions do not, so a design that lists files is stale the day it is written.

I will be honest about the one thing that makes this hard to hold to. The design stage is still the station I am most tempted to skip, because the machine makes starting feel free. The weeks I gave in to that are the weeks I described at the top.

This is the fifth post in a short series on building an agentic harness. A harness runs one agent safely. A spec tells it what you meant. A factory runs many of them on one line. The factories shipping this year are very good at the four stations that write and check the code, and almost silent on the one that decides what the code is for. If you run one, I would like to know where your design stage lives, or whether it lives at all. My guess is that it is a box called requirements that nobody owns. Tell me I am wrong.

References

  1. Peter Naur and Brian Randell (eds.), Software Engineering: Report on a conference sponsored by the NATO Science Committee, Garmisch, October 1968.
  2. Winston W. Royce, Managing the Development of Large Software Systems, Proceedings IEEE WESCON, August 1970.
  3. David L. Parnas, On the Criteria To Be Used in Decomposing Systems into Modules, Communications of the ACM, December 1972.
  4. Edsger W. Dijkstra, On the role of scientific thought (EWD447), 30 August 1974.
  5. Frederick P. Brooks, Jr., The Mythical Man-Month, Addison-Wesley, 1975.
  6. Frederick P. Brooks, Jr., No Silver Bullet: Essence and Accident in Software Engineering, IFIP 1986, reprinted IEEE Computer, April 1987.
  7. Edward Yourdon and Larry L. Constantine, Structured Design, Prentice-Hall, 1979.
  8. Unified Modeling Language, adopted by the Object Management Group, November 1997.
  9. Martin Fowler, Is Design Dead?, 2000, revised 2004.
  10. Malte Ubl, Design Docs at Google, 6 July 2020.
  11. Colin Bryar, Working Backwards: how to write an Amazon PR/FAQ.
  12. Michael Nygard, Documenting Architecture Decisions, 15 November 2011.
  13. Sean Grove, The New Code, AI Engineer World's Fair, 2025.
  14. Coforge, Coforge Introduces Autonomous Software Factory for the Era of Agentic Software Development, 29 October 2026.
  15. Vercel, Building a software factory, 25 August 2026.
  16. METR, Uplift update, 24 February 2026.
  17. Bertrand Meyer, Applying Design by Contract, IEEE Computer, vol. 25, no. 10, October 1992.
  18. Alistair Cockburn, Crystal Clear: A Human-Powered Methodology for Small Teams, Addison-Wesley, 2004. The walking skeleton is Strategy 3.
  19. Amazon Web Services, Kiro: from a prompt to requirements, design and tasks, the spec-driven agentic development environment.
  20. GitHub, Spec Kit: open source toolkit for spec-driven development, September 2025.
ShareXLinkedIn

Questions about the build, or building something similar? Say hello. I read every message.

Comments

Sign in with GitHub to join the conversation.

Built from Scratch

A newsletter on video streaming infrastructure. No spam, unsubscribe anytime.