I came across a recent episode from Scott Hanselman and Mark Russinovich, “Sculpt, not Spec”, that crystallised something I have been feeling but struggling to articulate about AI-assisted development workflows. There is a lot of chatter in the community right now about spec-driven development, SPEC.md files, plan.md files, and all manner of elaborate upfront documentation as the “right” way to work with AI coding tools. I think that conversation is missing something important.
Scott frames AI-assisted development as sculpting rather than specifying. He references the old idea attributed to Michelangelo, that David was already inside the block of marble and the sculptor’s job was simply to find him.
When I start a piece of work I often know the rough shape of what I want. I know the direction. I have a vague idea of the outcome. But I don’t know exactly how I want things to look, how the interaction flows should work, or what edge cases are going to bite me until I am looking at something that actually runs. Writing a comprehensive spec before touching code assumes I have a level of clarity I simply don’t have yet.
Scott puts it well: he could have sat down and carefully steepled his fingers, thought deeply, and written out a precise specification for his video editor project, but that would have been, as he says, “exactly what waterfall is as opposed to agile.” We spent decades arguing against waterfall in software engineering, and now some of us are enthusiastically re-inventing it just because the build tool is an LLM.
There is a framing in the discussion that I think is worth highlighting. Scott describes encountering people who write these elaborate, perfect plan.md files, getting them exactly right before sending the single command “do it” to the model. The interaction with the LLM should be an interaction, not a compile step."
If you are putting all the intelligence, all the decision-making, and all the edge case handling into the spec document up front, you are essentially just writing code in a different syntax. You’ve replaced Python or TypeScript with prose. You are doing the hard thinking yourself and then delegating the mechanical execution to the model. At that point, you are not really getting all the benefits of using these models.
Mark makes the same point from a slightly different angle: it is genuinely impossible to write a comprehensive spec. Human language is too abstract. The developers of the spec-then-implement model, even in traditional software engineering, never fully escaped this problem. Product managers write specs and developers come back saying “that’s not what I meant” because the spec had gaps, ambiguity, or assumptions that turned out to be wrong. Adding an LLM to the process doesn’t fix that fundamental communication problem.
Here is the thing that I think gets lost in the push towards more elaborate specs. Mark calls it “the ambiguity loop,” and I think he is right that it is a feature of these models, not a problem to be engineered away.
When you leave things ambiguous, the model fills the gap with something reasonable, drawing on everything it has learned. Giving a rough spec (“panorama scroll, whatever”), the model immediately comes back with a specific approach, suggesting it uses luma (brightness of pixel regions) rather than pixel-by-pixel comparison because that is a known better approach for this kind of problem. Scott wasn’t aware of that technique. A perfectly detailed spec from Scott would have missed it entirely because he didn’t know to include it.
If you specify everything, you eliminate this benefit. You get exactly what you asked for, no more. The model’s ability to bring in relevant knowledge, propose reasonable approaches, and fill in gaps with sensible defaults is precisely what makes it useful. Over-specifying trades that away for a false sense of control.
Both Scott and Mark have good examples of the real challenge with AI-assisted development, and it’s not the initial spec problem. It’s edge cases and polish.
One of Scott’s mini project is a great illustration. He specced it out in about three paragraphs covering pre-processing of raw image files, tile creation at different zoom levels, and mobile support. The first pass came back and it worked perfectly. One shot. And then he started scrolling around and it ran out of memory. Put it on an iPhone, moved it two inches, immediate memory loss because of viewport management, tile decay, scroll speed.
The lesson here isn’t that the spec was bad. The lesson is that no spec, however detailed, was going to capture those edge cases in advance. You don’t know what you don’t know until you’re looking at something that runs on actual hardware with actual usage patterns.
So where does this leave us? Scott puts himself in the middle between no spec at all, and full spec driven development. A rough outline, a few paragraphs of context, a clear statement of what you are trying to achieve, that is useful. It orients the model, gives it the domain context it needs, and sets the direction without over-constraining the solution. A few paragraphs rather than a 50-page document.
Treat the spec as a conversation starter rather than a full contract. You write enough to point the model in the right direction, then you iterate. You respond to what it produces. You push back when it’s wrong. You add requirements you didn’t think of until you saw the first attempt. That is sculpting. The spec is just the rough block of marble. The actual work happens in the back and forth.
For more complex projects, there is value in keeping a living document that records decisions, approaches tried, things that failed, and current state. Not as a upfront plan but as an evolving record. That kind of artifact serves your future self when you come back to the project months later, and it serves as something you can share with colleagues without asking them to read your entire git history.