← Back to articles

June 3, 2026

9 min read

Spec-Driven Development with AI: From Prompt to Verifiable Endpoint

How to use technical specifications as a contract between the developer and the model to generate code that can be verified, not just code that compiles.

Leer en espanol

The problem with vague prompts and AI

A prompt like "implement the checkout endpoint" produces code that compiles. It might even work on the happy path. But without a spec defining which inputs it accepts, which errors it returns, what prior state it requires, and what side effects it triggers, the model fills the gaps with assumptions. Some are correct; others are not.

The result is an endpoint that appears to work but fails on edge cases the developer did not anticipate because they were not specified. The model does not fail — it does what it can with the information it received. The responsibility for the spec belongs to the developer, not the model.

What a spec needs for AI to generate verifiable code

A useful spec for AI has four parts: the API contract (method, path, body, possible responses), preconditions (what state must exist before the endpoint works), expected effects (what changes in the database, what events fire, what emails are sent), and explicit error cases (what happens if the resource does not exist, if the user lacks permission, if the payload is malformed).

It does not need to be long. Two pages of well-written spec produce better output than ten pages of narrative description. Precision matters more than volume. One concrete example of expected input and output is worth more than three paragraphs describing behavior in the abstract.

Complete spec that serves as direct model input.

POST /orders/:id/fulfill

preconditions:
  - order.status must be 'paid'
  - order.items must all have available inventory

request:
  params:
    id: string (order UUID)
  body:
    shippingProviderId: string
    notes?: string

responses:
  200:
    order:
      id: string
      status: 'fulfilling'
      fulfillment:
        trackingNumber: string
        labelUrl: string
        carrier: string
  409:
    error: 'order_not_fulfillable'
    reason: 'invalid_status' | 'insufficient_inventory'
  404:
    error: 'order_not_found'
  403:
    error: 'not_authorized'

side_effects:
  - Reserves inventory for each line item
  - Creates shipment record linked to order
  - Emits OrderFulfilled domain event
  - Sends fulfillment confirmation email to customer

From generated endpoint to verification

Once the model generates the endpoint from the spec, verification is direct: each field in the spec is a test case. Preconditions are test setup. Responses are assertions. Side effects are additional verifications — that the event fired, the email was queued, the inventory was reserved.

That cycle — spec, generation, spec-derived test — is faster than the traditional approach because the test is not written from scratch by the developer. It is derived from the same spec that guided the implementation. The effort of writing the spec is amortized in verification speed.

When spec-driven development with AI does not work

Spec-driven with AI does not work well when the problem space is not yet clear. If it is unknown what an endpoint should do, writing a premature spec closes options before exploring them. In that case, explore with the model first — rapid prototype, alternative discussion, hypothesis validation — then write the spec once the approach is clear.

It also fails when the spec describes the solution instead of the behavior. "The endpoint must call the Stripe service and then update the database" is an implementation spec. "The endpoint must mark the payment as confirmed and notify the customer" is a behavior spec. The second allows the model to choose the implementation; the first imposes it without justification.

More articles

Back to articles