Spec-driven agentic development in practice
A long long time ago, software development was done a bit differently. First the actual business needs were collected, collated and then documented. Out of such business requirements then we created the technical counter part, the technical requirements. Often this job was called requirements engineering and sometimes people who never touched the code did that job. Those said technical requirements, oftentimes called specifications or specs for short, then were handed off to programmers. Not developers, no, these were programmers, they turned specs into code. And then a bunch more stuff happened before it ever saw the light of day in reality, but that is maybe something for another time.
What I wish to focus on today is the first bit. See, with LLMs getting real good at what they do, they also get real bad at everything. There are waves of “this is genius” to “this is dumb” back to genius again. The insight if you look closely at each of these waves and each of these prompt engineering, loop engineering etc hypes, is that people just figured out how to properly use the tools at our disposal to get a consistent output from them of greater than average quality.
To properly develop things, there are a million and one items to consider. For this, we focus on the spec. Why do you need a spec, how to get a spec, how to refine the spec, how to use the spec to get the application and then how to continue on from there. Upfront, if you just want a quick script that mushes some data together, you don’t need a spec. You do exploratory work to figure out what to actually build? Happy vibing.
If you have a slightly more complex thing going on, yeah the spec will be useful.
Why do you need a spec
LLMs are dumb. They are better autocomplete. They can’t “think”. That’s still something you and I need to do unfortunately. Even if we apply labels like “thinking model”, yeah it’s not real thinking.
Because they are dumb you need to tell it, restrict it, to what you need. Think of it this way, What if you had the following back and forth with an LLM:
Name a city.
Geneva, Switzerland.
No, I meant a city in the United States.
How about Geneva?
That’s in Switzerland.
No, there is a City called Geneva in Ohio, United States.
But I want it to be in the state of Washington!
Ok, there is a Geneva in the state of Washington.
You’d be right to call this a silly example, which is the point. If you’d ask about a city like you ask about a problem or a code feature, the LLM would react the same way. So the more restrictions and specifications we are preparing, the more precise the output can be what we actually want. Except when you want a place called Geneva, which exists apparently 23 times in the United States, for some reason.
The better you are at telling the LLM what you want, and also super important, what it is you don’t want, the better the output is going to be.
There is this great game you might have seen online where someone teaches their kid how to give good instructions and be precise about it. The kid tells the parent how to make a sandwich. And it forgets steps, skips steps and the parent just blindly follows, being even obtuse to follow exactly the instructions given. To you and me it’s clear how to make a sandwich. The LLM is the most obtuse entity you will ever meet. It can infer some things based on what it already knows, or worse just makes things up.
However, if you go in and be precise, define the things you want and don’t want, you give the LLM less room to miss something or make up something random.
How to get a spec
Now you can just throw a braindump at an LLM and tell it to make a spec for you. I do that all the time. I also have some actual guidelines on what a spec means.
So first make that guideline. Or directly a skill if you prefer. Mine are skills these days and they see pretty much daily use.
Give it a vision. A high level concept of what you are trying to do.
- A timer for workouts.
- An app to connect elderly people.
- A library that takes care of this very annoying thing I need to do every day.
Two to four sentences. Dense. Concise. No bla. It can sound a bit stilted due to cramping a few words in there which are important to you, but do it. The vision is the northstar of your spec. If it doesn’t follow that then it is probably not what you want. You are giving the LLM a compass with this and now while the exact path isn’t clear yet, we are approaching the right direction at least.
Do some high level comparisons.
- Like X but with Y.
- In the direction of X with added Y.
- Imagine X but in space!
These ground your endeavour in reality. Try not to use too obscure references or use urls to the info you are referencing, at least the LLM can look them up then. Having none is fine, try to keep it at 5 or less though if you write any. This already gives us some guardrails on the journey and makes certain invalid comparisons or avenues less likely for the LLM to take.
Define principles.
- Never share the users data (duh).
- An API key is only shown once.
- The app always feels fast even if it has to do huge data actions behind the scenes.
- It never feels super serious.
Whatever your principles for your development project are, defining them in what is to be true at all times, or what cannot be true ever, is extremely important. This gives the LLM now a much narrower path to travel.
Now is a good time to refine this part. Just what you have so far. I’ll talk more about that below on what I use, but at least read it and edit whatever feels wrong. It doesn’t have to be perfect, you can always add and edit later, but it should not read wrong to you at this stage.
Then, and only then, do the features you want. You can roughly say what the features are above, or what the main feature is, but here is where your features live, not anywhere above. Define each one with an outline of what it does, for whom and why they want that.
As a user I can register so I can access the features requiring an account.
Sounds like a user story? That’s because it is. You can add some details if you want, but I would keep it simple here. Make sure you get a list of all features that you want in the first version (MVP) in, and if you already have more ideas, mark them as a separate ideas section for future enhancements. Not a fully specced out feature, more a collection of all.
And lastly, if you can, specify the technology. Want python and Postgresql? Or how about Rust and SvelteKit? How about HTMX? Multiple microservices or one monolith? Try to get some base specifications in here, this can already answer some questions that may come up.
Yeah there are questions. Lots of them. This is where we go into refinement.
How to refine a spec
Your spec is now a rough outline. You could hand it to a decent developer and they could probably build it. However your LLM is too dumb to do a good job. You need some more of that brainpower. Time for questions.
This is probably the number one thing that I see people not doing and just wasting time. Are you ready?
Ask the LLM, to ask you questions, clarifications about the specs.
That’s the magic.
Not my invention either. There are a lot of people who have come across it, but I had the pleasure to interview a couple dozen people and I asked each one about this. Not one of them has told me to date that they tell the LLM to ask questions from the developer about the spec, about the application or anything else for that matter. They ask the LLM plenty, but not the other way around.
You can try it on your specs in a limited way even. Here is the prompt I used (with Claude Opus 4 something) before I used skills, to refine the non feature parts of the spec:
Look at the SPECS.md and in there at the Vision, the Comparisons and the
Principles. Check if they are coherent to each other. Then critique them for
this specific project and ask me questions about them to improve the quality
and clarity of each item. Don't assume, ask me questions about these items
instead.
That started a back and forth which refined the beginning already to a fine point. I ran the prompt multiple times to really hone in on what was important. The better your compass and your guardrails are here, the more precise the next steps.
Which is doing the almost same thing with features. Almost, but not entirely unlike the first part.
With features, you want to drill deeper. Much deeper. While the same “ask me questions, clarifications” holds true here, features need one more trick up their sleeves to take your spec from meh to great.
Verification is the game here. For each feature, have at least one part that describes how the LLM can verify that this feature functions as intended. If you hear “acceptance test” in your brain right now, you are on the right track. If you don’t know what that is, well I just explained it above in a compressed way. What you exactly want to do with that is always up to you. For me, I have the LLM write actual tests, unit and smoke tests that try to check for that behaviour. Sounds also a lot like Test Driven Development? Yes. That is true as well. That way if something else screws up what already works the tests will tell. Even if that something is my butter fingers.
When all of the features are in, the tech stack is polished up a bit, I run a cross check. Does all of this make sense together, top to bottom? Is there something I missed?
This is also where I have a list of vantage points to look at.
- How’s the security of this looking?
- What about compliance, or is that not relevant?
- Performance shouldn’t be ignored either, how well should this perform to be viable, what can be done to improve there?
- Is this an internal only project or something for public consumption?
- What about monetization?
- What does internationalization look like?
- Is accessibility considered?
- Can this be longterm maintained, do we even need to?
You can probably come up with a dozen more questions, all good ones to ask, but also ones that are very different depending on what you do or where your main area of work is. You can ask the LLM to come up with some or quiz you what you do and then come up with more based on that.
If you take nothing else away, then hopefully that asking the LLM to ask you is a fantastic tool you didn’t know you had.
Now you have a spec, now what?
How to use a spec to get the application
Depending on the size of the project (the larger the more likely) I have the LLM make a TODO.md file with specific tasks in the order it should do them, and to check them off as it does them. If you use multiple agents, this is a fantastic point to also split it for individual agents.
Now point your software of choice at the todo file or the specs for smaller things and have it implement what is outlined in there. On Claude I like to use the /goal skill currently.
Depending on how you want the agent to do its work, once it’s done, send it to verify. Let it check if everything according to spec and todo is done, really done and functional as outlined. Depending on if you had interrupts or outages, or out of tokens, that may be in various stages of broken. Or it just skipped something. But here you can just send it over and over again to what you have created in the specs and eventually you get something that works.
How to deal with a spec past the first iteration
Now to close the circle, what to do after? You still have those ideas in the specs and that’s a good place for them to live. Add more, pull one into features, enhance them, then run the refinements again. Make the cross checks. Maybe your principles need to change. All ok.
The main take away is to treat the specs as the source of truth, not the code. The specs describe how the code currently, or how it should be once you run your agents over it. That way you keep having up to date documentation and it’s easy for an agent to see what’s going on in your code. Familiar? Spec driven development also worked that way in the olden days.
My closing advice, use it at least once in a decent sized project. Even once you are done with it, you can still decide to throw away the specs or make a note that this is only kept for documentation of the base features. It’s most certainly not for everyone, but most can get a great deal out of it, to get consistent and useful outputs by going down the path of spec-driven agentic development.