Skip to content
Pere Villega
Go back

Specifications Are the Interface

8 min read

A specification can be extremely detailed and still be useless. It can describe the wrong outcome with impressive precision, freeze an implementation before we understand the problem, or repeat information which the code already expresses better.

It can also be the difference between delegating work and delegating guesswork.

When an agent performs the implementation, the specification becomes the main interface through which we exercise engineering judgement. I use “specification” broadly here. It may be a paragraph, a set of examples, an API description, a test, a diagram or a collection of invariants. The format matters less than the decisions it makes explicit and the feedback it enables.

That does not make specification-driven development a universal methodology. If anything, cheaper implementation makes it more important to choose the smallest useful specification, because prose can now be overproduced as easily as code.

What the Interface Must Carry

A useful interface separates intent from implementation.

Suppose the request is “add retries to payment submission”. That sentence names a mechanism, but leaves the important questions open. Which failures are retryable? Can two attempts create two charges? How long may the caller wait? What should an operator observe? Is the existing provider contract allowed to change?

The specification should carry what the implementation cannot decide responsibly:

It should usually leave local class names, helper functions and control flow open. If every implementation decision is prescribed, we have written code badly in prose. If no externally visible outcome is prescribed, we have written a wish.

This extends the argument from declarative development. The valuable part of a specification is not that it appears before the code. It is that it provides a source of intent which the generated implementation cannot quietly redefine.

Different Uncertainty Needs Different Specifications

There is no single best specification format. Each one reduces a different kind of uncertainty and introduces its own blind spots.

FormUseful whenWhat it does not prove
Short task briefScope is small and local conventions are strongThat ambiguous words mean the same thing to everyone
Worked examplesBehaviour depends on awkward inputs or state transitionsThat the examples cover the important space
Acceptance criteriaProduct behaviour needs review before implementationThat the implementation satisfies the criteria
Types and schemasData shape and valid states are centralThat the data has the right business meaning
Executable testsBehaviour can be observed cheaply and repeatedlyThat the assertions are complete or independent
Architectural decisionA consequential option and its trade-offs need preservingThat the decision will remain correct as constraints change
PrototypeWe need to discover feasibility, usability or an unknown dependencyThat the exploratory implementation is ready to operate

These forms can reinforce one another. A natural-language outcome gives meaning to an executable test. An OpenAPI description constrains the messages at an HTTP boundary. The OpenAPI Specification defines this as a language-agnostic interface description which humans and computers can use without reading the service’s source, but even a precise schema cannot tell us whether issuing a refund is permitted in a particular business situation.

More forms also mean more things which can disagree. If the prose says a retry is safe, the acceptance test expects one charge, and the API contract allows clients to omit the idempotency key, which one wins? The specification needs ownership and precedence, not just volume.

A Spec Is Not the Same as Repository Context

Persistent project instructions and task specifications solve related but different problems.

The repository may say that database migrations require a rollback, public functions need documentation, and a particular module owns payment state. Those rules apply across many changes. The retry specification should describe this change: the outcome, constraints, exceptions and evidence.

Mixing them creates two familiar problems. Repeating all project knowledge in every task produces long, stale briefs. Hiding task-critical behaviour in a large instruction file makes it easy for both people and agents to miss.

Birgitta Böckeler’s analysis of specification-driven development tools makes a similar distinction between a task-oriented specification and the persistent “memory bank” around it. She also offers a useful spectrum:

  1. Spec-first: write a specification for the task before implementation.
  2. Spec-anchored: retain and maintain the specification as the feature evolves.
  3. Spec-as-source: humans edit the specification rather than the generated code.

Those are materially different commitments. A design note can be valuable during one migration and disposable afterwards. An HTTP contract used by several teams must evolve with the service. A spec-as-source system needs generation which is repeatable enough, and an escape route for behaviour the specification language cannot express comfortably.

Calling all three “SDD” does not resolve those differences.

Tooling Can Add Discipline and Paperwork

GitHub’s Spec Kit is a concrete example of a structured workflow. Its current documented path establishes project principles, specifies what to build, plans the technical approach, breaks it into tasks, implements them and converges the result against the artefacts. That separation can prevent an agent from jumping from a vague idea straight into code. It also gives reviewers explicit places to challenge intent and design.

The files are not enforcement by themselves.

An agent may misunderstand a requirement while producing every requested document. Two generated artefacts may agree because they repeat the same mistaken assumption. A checklist can record that security was considered without detecting a vulnerability. The output looks controlled because it is orderly, which is not the same as being correct.

Böckeler reached a related conclusion in her 2025 evaluation of Kiro, Spec Kit and Tessl. She found value in spec-first work but also encountered disproportionate ceremony, repetitive Markdown and instructions which agents still ignored. Her objection is not that specifications are pointless. It is that one workflow does not fit every problem, and more specification artefacts create another review burden.

That burden matters. Reviewer attention is finite. Asking somebody to read a task brief, research note, design, data model, API contract and task list before inspecting a small change may reduce scrutiny rather than improve it. The specification has then become a lossy copy of the code and the organisation has two maintenance problems.

I would judge a specification practice by three questions:

  1. Which uncertainty does this artefact remove?
  2. Who checks that it expresses the intended outcome?
  3. What mechanism detects divergence between it and the implementation?

If the answers are vague, adopting a more elaborate framework will not make them precise.

Discovery Still Needs Room to Move

Specifications are hardest to write when the problem contains an unknown we cannot settle by thinking harder. We may not know whether an external API has the required behaviour, whether a query meets the latency target, or whether users understand the interaction.

In those cases, the right specification may be an experiment:

Question
Can the provider safely deduplicate retries after a client timeout?

Probe
Build the smallest integration which submits the same operation twice
with a controlled timeout between attempts.

Evidence
Record provider responses and resulting transaction identifiers.

Boundary
Use the test account. Do not change production configuration.

Stop
Report the result; do not turn the probe into the production implementation.

This is still specification. It specifies learning rather than pretending the final design is already known.

The result should feed the next version of the brief. Perhaps the provider supports idempotency and the production design becomes simple. Perhaps it does not, and we need a local state machine. The cheap prototype has earned its keep by replacing an assumption with evidence.

The danger is allowing exploratory code to become authoritative merely because it works once. A prototype optimises for learning. Production code must also account for operation, maintenance, security and failure recovery. Crossing that boundary deserves a new decision.

Keep the Human on the Intent Side

An agent can help expose gaps in a specification. Ask it to identify undefined terms, construct counterexamples, trace affected interfaces and propose tests. A fresh review can find assumptions which the implementation conversation has normalised.

It should not silently own both the requirement and the proof. If the same agent turns a vague sentence into acceptance criteria, writes the code and writes the tests, all three can share one coherent misunderstanding.

Human ownership does not mean typing every word. It means deciding which outcomes matter, resolving product and architectural trade-offs, and approving movement of the boundary. For higher-risk work, the acceptance criteria or verifier may need a separate owner. For a reversible local refactor, a brief and focused diff review may be entirely adequate.

The previous chapter argued that greater autonomy needs explicit authority, evidence and stop conditions. A specification carries those decisions into the agent’s working loop. Its strength should rise with the cost of a wrong interpretation, not with our enthusiasm for a methodology.

The best specification is therefore not the longest or the most formal. It is the smallest interface which preserves the important human decisions and produces useful objections while there is still time to act on them.

That last requirement leads to the next part of the control system: Tests Are Backpressure.


Share this post on:

Previous Post
Tests Are Backpressure
Next Post
Letting Go Without Losing Control