Iman Suherman — Building solutions. Delivering impact.

Articles

Spec-Driven Development: write the contract before the agent writes the code

Prompt-driven coding dies with the chat. Specs survive: SHALL requirements, acceptance tests, and regeneration prompts so another agent can rebuild the same product. Here is how we run SDD on Analytica Copilot.

Updated 13 Sept 202610 min read
Spec-Driven DevelopmentAI deliveryAnalytics
Spec-Driven Development — Spec, Implement, Verify, Deliver: write the contract before the agent writes the code

Coding agents are fast. They are also forgetful. A Saturday chat that produced a dashboard is gone by Monday — and the next agent has no idea what “done” meant, which SQL was forbidden, or why APAC decline is the demo story. Spec-Driven Development (SDD) exists so the contract outlives the session.

Loading diagram…

The SDD loop: humans own the contract; agents implement; tests and traces prove delivery.

Prompt vs spec

Vibe coding feels productive because the agent is always moving. The cost shows up later: silent architecture drift, untestable “almost” behaviour, and a product that only the original chat could recreate. A spec is slower to start and cheaper to continue.

Loading diagram…

Prompts die with the tab. Specs are versioned, reviewable, and rebuildable.
  • Prompt: “Make an analytics copilot that answers questions.”
  • Spec: the agent SHALL generate a QueryPlan; SHALL NOT execute arbitrary SQL; SHALL return answer, evidence, visualisation, and the plan itself.
  • Prompt dies with the tab. Spec is git-versioned, reviewable, and reusable by the next agent.
  • Prompt hopes the model remembers constraints. Spec makes constraints executable via tests and runtime traces.

The loop we actually run

On Analytica Copilot (the SDD Analytics Copilot demo behind https://analytica-demo.suherman.net) every major capability is numbered SDD-001 … SDD-013. The tree is the authority — not a README written after the UI looked nice.

  1. 01Product vision, personas, and the Bahasa demo journey.
  2. 02SHALL requirements SDD-001 … SDD-013 (workspace, dataset, copilot, governance, dashboards, tenancy, locale, ops).
  3. 03Domain, OpenAPI, and agent-tool contracts — QueryPlan, semantic model, dashboard DSL.
  4. 04Implementation in src/ against those contracts.
  5. 05Acceptance tests + Gherkin. Then runtime traces in the product UI (Jejak).

Traceability is the point. If a behaviour exists in the UI, you should be able to point at a requirement ID, a contract, a test, and a runtime trace. If you cannot, it is not specified — it is a prototype accident.

A concrete spec: SDD-004

Conversational analytics is the hero flow: “Why did revenue drop last month?” The spec does not say “use an LLM to query the database.” It freezes the safety rails first.

markdown
# SDD-004 Conversational Analytics

The system SHALL allow a user to ask an analytical
question using natural language.

The agent SHALL resolve metrics against the semantic model.
The agent SHALL generate a QueryPlan.
The agent SHALL NOT directly execute arbitrary SQL.
The engine SHALL validate the QueryPlan before execution.

The system SHALL return:
  answer, result data, evidence,
  visualisation recommendation, QueryPlan.

Acceptance is Gherkin, not a vibe check. One scenario from the same file:

gherkin
Scenario: Ask for monthly revenue
  Given the commerce semantic model is loaded
  And the SQLite demo database contains order data
  When the user asks "What was revenue last month?"
  Then the agent resolves the "revenue" metric
  And creates a governed QueryPlan
  And the analytics engine executes the query
  And the answer contains the resulting revenue
  And the evidence shows the metric definition
  And the execution trace is persisted

Loading diagram…

SDD-004 in motion: natural language in, governed QueryPlan, then answer + evidence — never arbitrary SQL from the LLM.

Governance is the product

Without SDD, an analytics agent will eventually emit SQL. That is convenient in a demo and unacceptable in a tenant. QueryPlan is the contract: the model proposes a plan, the engine validates it against the semantic model, then compiles SQL. The LLM never talks to SQLite directly. That rule lives in SDD-004, SDD-005, and the ADRs — so a regeneration agent cannot “helpfully” skip it.

Specs as a regeneration kit

The strongest SDD test is uncomfortable: delete src/, keep specs/, and ask a coding agent to rebuild. Analytica Copilot is written so that is possible. specs/regeneration/ holds the blueprint and copy-paste prompts. Non-negotiable invariants sit at the top: no arbitrary SQL, dashboards are JSON specs (not generated React trees), Next.js monolith + SQLite, demo clock 2026-09-05, soft multi-tenancy, Bahasa Indonesia UI.

Loading diagram…

Regeneration kit: specs stay; implementation can be rebuilt by another agent.

How to start in your own repo

You do not need thirteen requirements on day one. You need numbered contracts that a later agent cannot shrug off.

  1. Give every behaviour an ID (PROJ-001 …). One file per ID under specs/requirements/.
  2. Write SHALL and SHALL NOT in the same file. Constraints belong next to the feature, not in a Slack thread.
  3. Add one Gherkin scenario that would fail if the agent “just shipped UI”.
  4. Freeze contracts the model must obey: OpenAPI, tool schemas, semantic metrics, ADRs.
  5. Point the coding agent at the spec ID — not at a paragraph in chat. Implementation is a diff against the contract.
  6. Keep a regeneration prompt beside the specs. If src/ vanished tomorrow, that prompt is the bootstrap.

What SDD is not

  • Not waterfall. Specs stay small, numbered, and revisable. We approve them; we do not freeze a 40-page novel.
  • Not “write docs after the demo.” If the spec is updated to match the code, the code won. Flip that.
  • Not a substitute for human merge. Agents prepare; people still decide FINAL_REVIEW. That is the same rail as Agent On Rails.

Where this lives on suherman.net

We already used this loop live in the sharing session with SDD Analitik Kopilot: natural-language question → governed QueryPlan → evidence → dashboard. The same specs are what a coding agent reads when regenerating the app.

Bottom line: Spec-Driven Development is how you keep coding agents on rails without babysitting every prompt. Write the contract first. Let the agent implement. Keep tests and traces as proof. When the chat is gone, the spec is still there — and that is the only artefact another agent, or another Saturday, can trust.

← All articles

Spec-Driven Development: write the contract before the agent writes the code · suherman.net