
TL;DR: Big up-front specs came back. We used to write them for humans, now we write them for AI agents. I think the spec shouldn't be a document at all. It should be the types, functions, tests and decisions an agent produces from a conversation about your business. Nobody writes a spec. Everybody checks one.
Prompts in, types out
Technical/Functional Spec to Agile to Spec-Driven Development. It feels a bit cyclical!
Someone writes a long document explaining what they want, hands it to an agent, and gets software back in minutes. Everyone calls this progress. I think it's the old mistake wearing a new coat.
Here's an old story that explains why.
Two builders offer to build your extension. The first says: "I've done this for twenty years, I know exactly what I'm doing, just tell me precisely what you want, down to the fittings, before I start." So you spend six weeks writing it all down. He reads it, nods, and disappears to build.
The second says: "Give me the gist. I'll put something up today and you tell me what's wrong with it."
By the time the first one's read your document, the second one has already knocked a wall down, been told it's the wrong wall, and started on the right one.
We keep hiring the first builder. We just changed who reads the document. It used to be a business analyst, now it's an agent.
What actually carries the information
Strip away the document. Ask what, in the whole pipeline, actually says what the software should be.
Not the discovery notes. Not the requirements doc. Not the tickets. Two things survive:
- The code, as a statement of what the system means. Types for what exists, functions for what happens.
- The tests, as a statement of what we expect.
Everything else is commentary.
The idea
Don't write a spec. Have a conversation. Let the types and functions the agent produces be the spec.
Prompts in, types and functions out, tests out, everything else follows.
This isn't new. Scott Wlaschin wrote a whole book, Domain Modelling Made Functional, arguing that well-designed types already say what a spec used to say. The problem was always that not every team had someone who could do it well. Agents fix that problem, not the idea.
A car park, four artefacts, no document
The council wants to sort out its car parks. The rules are the ones everyone argues about at the ticket machine. She talks. The agent writes.
She says: you pay for a bay by the hour, up to four hours. There's a ten-minute grace period after your ticket runs out, because the law says so. Blue badge holders park free, all day. If you overstay past the grace period, you get a Penalty Charge Notice, £50, or £25 if you pay it in fourteen days. And you can appeal a PCN if the machine was broken, because the council has lost more than one fight over that.
The agent turns that into scenarios she approves:
Given a car has overstayed by 9 minutes
Then no penalty is issued
Given a car has overstayed by 20 minutes and pays the penalty within 14 days
Then the penalty is 25.00And a model:
const chargeable = (s: Stay): boolean =>
minutesOver(s) > GRACE_PERIOD_MINUTES;
const penaltyDue = (s: Stay): number =>
paidWithinDays(s, 14) ? 25 : 50;She reads it and stops. "Blue badge holders. They don't pay anything, any duration." The model missed it. One line gets added, and the reason gets a name and a date next to it:
D-001: Blue badge holders are exempt from charges and penalties.
Decided by the council, 22 Sep 2026, per the disabled parking provisions.Then tests, built from her scenarios, not from the model:
it("gives a blue badge holder free parking", () => {
expect(chargeable(blueBadgeStay)).toBe(false);
});
it("reduces the penalty if paid within 14 days", () => {
expect(penaltyDue(paidOnDay(10))).toBe(25);
});Nobody in that whole process wrote a specification. There is one anyway. It's the types, the tests, and the log of who decided what and why.
"I can't read TypeScript"
You don't have to. Ask the agent.
"Are blue badge holders really exempt?"
"Yes. Rule D-001, decided 22 September, and there's a test proving it."
The old spec couldn't answer a single question about itself. This one can, and it shows its working every time.
But someone still has to talk to the agent
Fair point. Engineers don't decide what a council's parking team needs. Someone still carries the business's wishes across.
Here's the difference: that person never translates anything into anything. They react. "What happens if the machine was broken?" is a question anyone can answer, and the agent can generate a hundred more like it for you to wave through or stop. That's how agile always worked. Product owners never read code, they reacted to what the software did. This just moves the reaction earlier, to a sentence instead of a screen.
Where the engineers go
Nowhere. The hard part of this loop was never typing code. It's telling the difference between "the agent got me wrong" and "I hadn't thought this through". The first is a retry, the second is a proper conversation, and mixing them up is how you ship confident rubbish.
Someone who's been paged at 3am reads a model differently to someone who's written the conversation down for the first time. That instinct doesn't get replaced. It gets busier.
The bit that's still prose, on purpose
The decisions log is the one part of this that's still English, and that's deliberate. Uncle Bob's rule about comments applies here too: say why, never what, because the code already says what. D-001 doesn't restate the rule. It says who decided it and why. That's the only part of this whole idea that should ever be a sentence.
Legacy systems
"Fine for a new car park system. I've got twenty years of an existing one." Point the agent at the database and the code instead of a person, and it drafts a first model of what the system already does. It'll be wrong in places. Treat it like the second archer's first shot and correct it. You're not rewriting anything. You're describing, for the first time, what's already there.
The stuff that isn't rules
More goes in the model than people expect. Most NFRs are just rules wearing suits. A rate limit is a constraint. "No customer data leaves the UK" is a constraint. Audit trails, retention, accessibility contrast, a performance budget. All of them can be types and tests, checked the same way as everything else. A lot of what makes prose specs long is requirements that were always constraints, written as paragraphs.
Look and feel is different, and it's different because it was never a specification in the first place. You can't approve a colour palette by reading about it. You could formalise some of it, type checks against the CSS, constraints on the components, but why would you, when a screenshot and someone looking at it answers the question for free? An agent can take that screenshot and judge it too. The model owns what the system does. A working slice owns what it looks like, and you judge that by looking at it, the same way you always did. Show, react, adjust, and what you learn flows back into the scenarios.
The trap is the prose design spec. "The dashboard should feel welcoming and modern." Uncheckable, unseeable, and gone by the second sprint. Screens beat sentences. That was true before agents and it's still true.
The bits I haven't solved
Changing the spec means changing the running system, which is a real coupling and a real slowdown anywhere regulated. And when the agent gets it wrong, the liability sits exactly where it always did, with whoever signed off the model, not the agent that drafted it.
The chain-checking itself I've started on. It's called runspec, and it's at the bottom of this post.
Try it
I built a small tool off the back of this, runspec. Four files: scenarios someone approves, a model an engineer checks, tests generated from the scenarios, and a numbered decision for every rule. runspec check runs before every commit and proves the chain holds: every test traces to a scenario, every rule to a decision, and nothing generated has been hand-edited.
It's a dumb gate on purpose. All the thinking stays with the people and the agent. A dumb gate is one you can actually trust.
Prompts in, types out.