What Is Intent-Driven Development, and Why Prompts Alone Cannot Replace a Spec
Prompting your AI coding agent is rarely the right first move. Writing a spec is.
That inversion feels wrong until you watch an agent confidently refactor a module in a way that technically satisfies your prompt and completely violates the system's behavioral contract. The prompt said "clean up the retry logic." The agent removed the idempotency guard because nothing in the prompt said to keep it. The tests passed. The incident happened three days later.
This is not an AI reliability problem. It is an intent problem.
Why Prompts Decay the Moment You Hit Enter
Intent-driven development is the practice of encoding system requirements in a durable, versioned, machine-checkable form before any AI agent touches the code. A prompt is not that. A prompt is a one-shot instruction issued against a snapshot of the codebase that will never exist again. The second a dependency is bumped, a schema is migrated, or a collaborating service changes its contract, the prompt's implicit assumptions dissolve. The prompt itself sits inert in a chat window, unaware.
Consider what a prompt actually encodes: your intent at a moment in time, expressed in natural language, against a context window that is already a lossy compression of the actual system. A prompt for a payment service might say "add exponential backoff to the Stripe webhook handler." What it does not say: do not break idempotency, preserve the existing dead-letter queue behavior, keep the retry ceiling under Stripe's 72-hour event expiry window. A senior engineer knows all of that. The prompt does not.
A spec encodes that knowledge durably. It survives the next sprint. It survives the next engineer. It can be diffed, reviewed, and enforced the same way a test suite is enforced, because it lives in the repository alongside the code it governs.
The asymmetry matters at scale. One prompt driving one task is manageable. Fifty AI-generated changes per week across a mid-size codebase, each backed only by ephemeral chat context, is a compounding liability. You cannot audit what you cannot read, and you cannot read a Slack thread from six weeks ago as a reliable source of truth about why a module behaves the way it does.
How to Write a Spec That an AI Agent Can Actually Use
A machine-checkable spec is not a Word document or a Confluence page. It is a structured declaration of what a change must satisfy, expressed close enough to the code that tooling can verify it.
Start with behavioral invariants, not implementation notes. An invariant is a property that must remain true across every version of the code. For the webhook handler above, the invariant is not "use exponential backoff." The invariant is "exactly-once processing of each webhook event ID, with retry attempts bounded to less than 72 hours from event receipt." The implementation detail flows from the invariant. Reverse that order and you get a spec that an agent satisfies by the letter and breaks by the spirit.
Version the spec with the code. The spec file belongs in the same pull request as the implementation. When a reviewer merges a change to the retry ceiling, the spec for that ceiling changes in the same commit. A spec stored separately from the code it describes is a spec that drifts, and a drifted spec is worse than no spec because it creates false confidence.
Make the spec machine-checkable at diff time. The verify step should run on every pull request, not once at the end of a project. Tools like ThunderLang are built specifically for this: you declare what a change must satisfy, and the verify-diff step gates AI-written code against that intent before it merges. Without this gate, the spec is documentation. With it, the spec is a contract.
Keep the invariants at the right altitude. Not every behavior belongs in a machine-checkable spec. Whether a variable is named retryCount or attemptCount is not a behavioral invariant. Whether a failure mode surfaces to the caller as a 503 or silently drops the request absolutely is. Overly granular specs create friction without safety. Under-specified ones create safety theater. Senior engineers know the difference: spec the observable contract, leave the implementation to the agent.
Attach proof artifacts. Every time the verify step runs and passes, it should emit a signed artifact that records the spec version, the code commit, the agent model and version, and the timestamp. This is your audit trail. When a regression appears six months from now, you can reconstruct exactly which spec version was active and whether the change that introduced the regression passed or bypassed the gate. Without proof artifacts, you have logs. With them, you have evidence.
To make this concrete: a team shipping a billing service might write three top-level invariants into their spec file. First, all charge attempts must be idempotent on order ID. Second, partial refunds must never exceed the captured amount. Third, all tax calculation must delegate to the rate service and never inline a rate constant. These three invariants, machine-checked on every PR, do more to prevent AI-introduced regressions than any amount of post-hoc code review, because they run before the code lands, not after.
The practical workflow looks like this: an engineer writes or updates the spec before writing the prompt. The AI agent generates an implementation. The verify-diff step runs the spec against the diff. If the spec passes, the artifact is stored and the PR can merge. If it fails, the agent gets the failure output as context and iterates. The human reviews the spec and the artifact, not every line of generated code. That is the leverage intent-driven development actually provides: review what the system must do, not what the agent happened to write.
The objection I hear most often is that writing specs takes time that slows the team down. Compared to what? Compared to triaging a production incident caused by an AI change that satisfied a prompt while violating an implicit assumption nobody wrote down? The spec is the time savings, deferred and compounded.
ThunderLang's approach encodes this discipline directly into the development workflow, making the spec a first-class artifact rather than an afterthought bolted onto an existing process.
Gate your first AI change
ThunderLang lets you declare what a change must satisfy, then gates AI-written code against that intent with a verify-diff and durable proof artifacts. Start with one module, write three invariants, and run the gate before your next AI-assisted PR. Try it here.
A prompt tells an agent what you wanted once; a spec keeps telling every agent what the system must always do.