The consistency problem
You've experienced this. You write a prompt that gets you brilliant code on Monday. You reuse it on Wednesday for a similar task and get something barely functional. Same model, same task, wildly different quality.
This isn't random. AI models aren't inconsistent — they're precisely consistent with whatever context they receive. The variance you're seeing is variance in your prompts, not the model. Every ambiguity in the prompt becomes a decision point the model resolves on its own, and those resolutions accumulate into outputs that can look completely different from each other.
The consistency problem is a specification problem. A vague prompt is a spec with holes. The model fills those holes with its best guess based on training data — which might be excellent or might be completely wrong for your stack, your constraints, and your definition of "done."
The fix isn't to become a "prompt whisperer" with magical phrasing. It's to understand what information the model actually needs to generate consistently good code — and to provide that information every time.
Context is everything
A model generating code is doing something deceptively complex: it's inferring your entire technical environment from a few sentences, then writing code optimized for that inferred environment. When the inference is wrong, the code is wrong — even if it looks right.
The four context dimensions that determine output quality are:
- Stack context: Language, framework, version, existing patterns in your codebase
- Constraint context: Performance requirements, security requirements, what must not change
- Failure context: What "broken" looks like — error conditions, edge cases, acceptance criteria
- Phase context: Where you are in the development lifecycle — designing, implementing, debugging, or hardening
Most developers provide one of these four. The developers shipping consistently good AI code provide all four, every time. Not because they're being pedantic — because each dimension eliminates a category of bad output.
Mental model: Think of your prompt as a contract. A contract with gaps is a liability — the other party fills the gaps however benefits them. A complete contract is enforceable. Your prompt works the same way: every gap the model fills is a risk you don't control.
The 5 prompt patterns that ship code
These aren't templates to copy-paste. They're structures that encode the context dimensions above into natural-language prompts. Each pattern targets a specific failure mode in AI code generation.
Role + Task
Assign a precise role before stating the task. The role primes the model's "voice" — it shifts the frame from "generate something that looks like this" to "reason like this expert would reason."
You are a senior TypeScript engineer working on a Next.js 14 App
Router codebase with strict TypeScript and ESLint enforced.
Your task: implement a rate-limited API route for /api/export
that handles burst traffic from a single user without blocking
other users.
Constraints-First
State what the code must NOT do before saying what it should do. Constraints eliminate a large swath of technically-correct-but-wrong solutions. They're especially powerful for security and performance work.
Constraints:
- No external dependencies beyond what's already in package.json
- Must not block the event loop for inputs larger than 10MB
- Must not expose internal file paths in error messages
- Must pass: npm run build && npm test
With those constraints: implement a CSV parser for the /api/import
route that handles malformed input gracefully.
Test-First
Ask for the tests before the implementation. This forces the model to reason about acceptance criteria explicitly — and often reveals ambiguities in your own requirements before a single line of production code is written. Pairs perfectly with the Golden Code methodology's BUILD cycle.
Write the test suite for a JWT refresh token rotation function.
Tests should cover:
- Valid token returns new access + refresh pair
- Expired refresh token throws AuthError
- Reused refresh token invalidates the entire token family
- Concurrent refresh requests are idempotent
After I approve the tests, you'll implement the function.
Error Context
When debugging, give the model the full context stack, not just the error message. The error message is a symptom. What the model needs is the environment, the call stack, the recent changes, and your reproduction steps. This is the pattern that turns 10-minute debug loops into 10-second fixes.
Environment: Node 20, Express 4.18, PostgreSQL 15 via Prisma 5.
Error occurs: only in production, not locally. Started after
deploy on 2026-03-09.
Error: "Cannot read properties of undefined (reading 'userId')"
Stack trace: [paste full trace]
Recent changes: [paste git diff or describe changes]
Reproduction: POST /api/orders with valid JWT but no active session
What's the likely root cause, and what's the minimal fix?
Iterative Refinement
Treat the first response as a draft. Refine with targeted feedback instead of re-prompting from scratch. Iterative refinement preserves the context the model has already built up — re-prompting throws it away. One well-directed follow-up is worth three fresh prompts.
# After receiving initial implementation:
"The implementation is correct but has two issues:
1. The error handling swallows the original error — I need
the cause preserved in the thrown error for logging.
2. The retry logic uses exponential backoff but doesn't
cap at max delay. Cap at 30 seconds.
Keep everything else the same."
What breaks prompts
The flip side of the five patterns is understanding the three failure modes that consistently produce bad AI code. These aren't subtle — they're the same mistakes in different forms.
Vague scope
"Build me an auth system" is not a task. It's a category. The model doesn't know if you want JWT or sessions, if you need OAuth, what your user table looks like, what "auth" means in your domain. It will make assumptions — and it will be wrong about at least two of them.
Fix: define the smallest complete unit of work. "Implement POST /api/auth/refresh — it takes a refresh token in an httpOnly cookie and returns a new access token in the response body. The access token expires in 15 minutes." That's a task with a clear boundary.
Missing stack context
The model has seen millions of ways to implement any given pattern. Without stack context, it picks the most statistically common approach — which might be in a different framework, an older version, or a pattern that conflicts with your existing code architecture.
Fix: include your versions and existing patterns. If you already have a pattern for error handling in your codebase, show it. "Match the error handling pattern used in src/api/users.ts" is more effective than describing the pattern in prose.
No failure criteria
If you don't tell the model what "broken" looks like, it will produce code that looks complete — and may be functionally correct under happy-path conditions while silently failing on anything unusual. The model optimizes for "looks good," not "handles everything."
Fix: state edge cases explicitly. "Handle the case where the upstream API returns 429. Handle the case where the response body is malformed JSON. Handle the case where the user's timezone is null." Each explicit failure criterion is code that gets written and tested, instead of silently missing.
Phase-aware prompting
The right prompt depends heavily on where you are in the development lifecycle. The mistake most developers make is using implementation-phase prompts for design-phase questions — and vice versa.
| Phase | What you want from AI | Prompt posture |
|---|---|---|
| Design | Surface edge cases, question assumptions, model data structures | "What will break at scale? What am I missing? What are the tradeoffs?" |
| Implementation | Write focused, tested, idiomatic code for one module at a time | "Implement X with constraints Y. Write tests first." |
| Debugging | Diagnose the root cause with full context, propose minimal fix | "Here's everything. What's the likely cause? What's the minimal fix?" |
| Hardening | Think adversarially — find what breaks, what leaks, what fails under load | "How would you attack this? What inputs would break it? What's missing?" |
This is the insight behind midas_prompt in the MCP server workflow: it generates phase-aware prompts automatically based on where you are in the Golden Code lifecycle. Instead of manually calibrating your prompt posture for each phase, the tool does it for you — with the right constraints, the right context, and the right definition of "done" for that phase.
Before and after: the delta that ships code
The difference between a weak prompt and a strong one isn't length — it's information density. Here's the same task with and without the patterns applied.
Example 1: Implementing a webhook handler
"Add a webhook handler for Stripe events to my Express API."
"You are a senior Node.js engineer. Stack: Express 4.18, TypeScript 5, Node 20. Implement POST /api/webhooks/stripe. Constraints: verify Stripe-Signature header using stripe.webhooks.constructEvent, return 200 immediately before processing, enqueue events to a Redis list for async handling. Handle: invalid signature → 400, missing header → 400, unknown event type → 200 (silently ignore). Write the test suite first."
Example 2: Debugging a production error
"I'm getting 'Cannot read properties of undefined' errors in production. How do I fix it?"
"Production-only error, started 2026-03-09 after deploying session middleware refactor. Error: 'Cannot read properties of undefined (reading: userId)'. Only occurs on authenticated routes when the request has a valid JWT but no corresponding session in Redis (TTL expired). Stack trace: [trace]. What's the root cause? Minimal fix that doesn't change the session schema."
The weak prompts will get you something. The strong prompts get you something you can ship. The delta isn't cleverness — it's the four context dimensions applied consistently.
Prompt engineering for code isn't a dark art. It's applied specification. The model will give you exactly what you ask for — so the real work is learning to ask with precision. Role + task, constraints-first, test-first, full error context, iterative refinement. Apply those patterns with phase awareness and your AI tools stop being lottery tickets and start being force multipliers.
The developers shipping consistently good AI code aren't more creative with their prompts. They're more disciplined. Treat the prompt as the spec, and you'll stop being surprised by what you get.
Automate phase-aware prompting
Install midas-mcp and let midas_prompt generate context-rich, phase-aware prompts for your current task — with the right constraints, stack context, and failure criteria built in automatically.
Also read: Ship AI Code 10x Faster Without Skipping the Important Parts →