A six-part engineering guide: from individual prompts to specification-driven probabilistic software.
Read: Prompt engineering is becoming programming →Contracts: declarative style, types and capabilities
Declare the result instead of every step: typed structures between stages, contracts per module, and explicit permission boundaries.
Declare the result, not every step
The instruction attempts to prescribe the execution path.
The system declares what must be true. The runtime selects the execution strategy.
A prompt that scripts every step encodes assumptions about one specific model and becomes obsolete the moment that model changes. A specification that declares the required outcome, the constraints and the acceptance criteria survives the change, because switching models turns into a re-verification exercise rather than a rebuild. Given how often models are replaced now, this difference decides whether each upgrade costs your team days or a quarter.
Natural language in, typed structures between stages
Prose should not pass unchanged between internal modules. Extract it once into a validated object, then route on facts, not phrasing.
“Our site feels dated. Can you make it more premium, and maybe rethink the start page?”
extraction
routing
When prose is passed unchanged from one internal stage to the next, small differences in wording cascade into different behaviour further down, and nobody can point at where the result went wrong. Extracting the request once into a validated structure converts that fuzzy handoff into an inspectable one: you can log it, diff it, replay it, and route on facts instead of phrasing. It also lets stages be tested independently, which is what makes incremental improvement possible.
Every prompt module should have a contract
What must already be true
What the module must produce
Never violated, at any point
Preconditions, postconditions and invariants turn a vague quality discussion into an automatic decision. Without them, whether a module is finished is settled in review meetings, which is slow, inconsistent and easy to relitigate. With them, the system itself refuses to hand on a result that violates the contract. This also draws clean lines of responsibility between your teams and any external partner, because the contract states what each side owes the other.
Declare what each component is allowed to change
Permission is part of the program, never something the model infers for itself.
Serious AI incidents are rarely a badly worded answer. They are a plausible-looking result combined with an action the component was never meant to take: publishing, spending, deleting, changing permissions, or writing to customers. Permission must therefore be part of the program, never something the model infers about itself. An explicit capability matrix per component makes the blast radius of any component visible before it ships, and reviewable when it changes.
More articles
Design reliable UX for connected devices across hardware, apps, BLE, Wi-Fi, cloud, onboarding, errors, and recovery.
Read: UX for Connected Devices: Designing Experiences Across Hardware, Apps, Connectivity, and Cloud →Hardware companion apps: hard parts, partner skills, and questions that separate specialists from agencies.
Read: How to Choose the Right Companion App Partner for Your Hardware Product →