The 5-Part AI Prompt Formula That Actually Fixes Bugs
A concrete framework for structuring prompts that get Claude, Copilot, and other AI coding assistants to diagnose root causes rather than guess at patches.
Paste a stack trace into Claude or Copilot and ask “what’s wrong?” and you will get an answer. Whether that answer is useful depends almost entirely on what else you included. Most developers treat AI debugging as a search engine query — toss in the symptom and expect a cure. The result is a confident-sounding patch that addresses the surface error while the actual cause survives untouched.
The problem is not the model. It is information debt. AI assistants can only reason about what you give them. When you hand them a vague symptom and nothing else, they fill the gaps with plausible assumptions that may have nothing to do with your actual code path. This guide builds a five-part prompt structure that eliminates those gaps — not by adding length for its own sake, but by feeding the model the exact categories of information it needs to reason rather than guess.
Why weak prompts produce plausible-but-wrong fixes
Consider two prompts targeting the same bug:
Weak prompt:
My React component re-renders too many times. Can you fix it?Structured prompt (we’ll build this below):
Environment: React 18, TypeScript 5, no Redux — local useState/useContext only.
Bug: ProductList re-renders on every keystroke in the parent SearchBar, evenwhen the product list data hasn't changed.
Expected: ProductList should only re-render when the `products` prop array changes.Actual: React DevTools Profiler shows ProductList rendering 12x per second whilethe user types. `products` comes from a useMemo that depends on `filterText`.
Relevant code: [minimal snippet with useMemo + prop drilling]
Steps already tried: Wrapped ProductList in React.memo — no effect.
Request: Before suggesting a fix, identify the root cause. Is the reference to`products` changing on every render despite useMemo? If so, why?The second prompt produces a different class of answer. The model can now check whether useMemo dependencies are actually stable, whether the array reference is being reconstructed unnecessarily, and whether React.memo fails here because a new function reference is being passed as a prop alongside products. The first prompt gets you boilerplate about useCallback and React.memo — technically reasonable advice, but aimed at a problem the model invented.
The core failure of weak prompts is that they force the AI to invent a mental model of your code from scratch. That invented model is frequently wrong in ways that are hard to detect because the suggestions still sound like real React advice.
The five-part structure
Part 1: Environment and constraints
State your runtime, framework, version, and anything that rules out certain solutions. This does not need to be long — one to three lines is usually enough.
Environment: Node 22, Express 5, PostgreSQL 16 via pg 8.x.Constraint: Cannot add new npm dependencies. Async/await only, no callbacks.This matters because AI models carry broad knowledge across many library versions. Without explicit pinning, they default to whatever patterns are most common in their training data, which may not match your stack. If you are on Python 3.9 and the model suggests match statements, that is a training-data assumption overriding your actual environment.
Part 2: Reproduction — what triggers the bug
Describe the precise sequence of inputs or conditions that surfaces the bug. If you can reduce it to a minimal reproducible case, do that before writing the prompt. The act of reduction often locates the bug on its own; when it does not, the minimal case gives the model exactly the surface it needs to reason about.
Reproduction: POST /api/orders with a valid body triggers the bug only whenthe authenticated user's account has `role: 'guest'`. Admin accounts work.The error does not appear in local dev because seed data only includes admin users.Without this, the model has to speculate about what conditions trigger the failure. It may fix the wrong branch entirely.
Part 3: Expected versus actual behavior
State these as separate, concrete observations — not a combined narrative. Include the exact error message or the exact observed output when you have it.
Expected: A 201 response with the created order ID.Actual: 500 — "Cannot read properties of undefined (reading 'permissions')"Stack trace: [paste the relevant frames, not the entire wall of text]Addy Osmani’s writing on AI coding workflows makes the same point: feed the AI actual system behavior, not your interpretation of it. “The request fails” is an interpretation. The stack trace is data.
Part 4: Relevant code and what you have already tried
Paste the smallest slice of code that contains the bug. Do not paste entire files. A focused 300-400 token snippet — the function, its immediate callers, and the relevant data types — consistently outperforms a 4,000-token dump of the full module. The model’s attention is finite and a smaller surface area means less chance of it latching onto unrelated patterns.
Also document what you have already tried. This is underused. If you have already added a null check, restarted the server, verified environment variables, and the bug persists, saying so prevents the model from suggesting those same steps as its first response.
Relevant code:[orderController.ts — createOrder function, ~30 lines][authMiddleware.ts — where req.user.permissions is set, ~15 lines]
Already tried:- Added optional chaining: req.user?.permissions — still fails- Confirmed req.user is defined (console.log shows the full user object)- The permissions property is present for admin users, missing for guestsPart 5: An explicit request to diagnose before patching
This part is the one most developers skip, and it is the most important. Explicitly ask the model to identify the root cause before writing a fix. Without this instruction, the default behavior of most AI assistants is to head straight for a code change — because a code change looks like the useful output.
Request: Before suggesting any code changes, explain what you believe is theroot cause of this error. Why would req.user.permissions be undefined only forguest accounts? Then, once you have identified the cause, propose a fix.This single sentence changes the model’s output significantly. It shifts the task from “produce a patch” to “reason about the failure, then produce a patch.” The reasoning step surfaces assumptions that would otherwise be hidden inside the code change, and it gives you a checkpoint to disagree before any code is written.
GitHub’s Copilot documentation for debugging specifically recommends this approach — asking “Why is the output of this code higher than expected? Please explain in depth” rather than jumping straight to “fix this.” The explanation-first mode catches cases where the model’s patch would be technically valid but addressing the wrong problem.
Putting the formula together
Here is a complete example of the full structure as a single prompt, targeting a real class of bug:
Environment: Python 3.11, FastAPI 0.111, SQLAlchemy 2.x async sessions.Constraint: ORM only — no raw SQL queries allowed by team policy.
Reproduction: PATCH /users/{id} succeeds and returns 200, but changes are notpersisted to the database. The issue occurs in staging (PostgreSQL) but not inlocal dev (SQLite). Happens for all users, not a permissions issue.
Expected: The updated fields should be visible in a subsequent GET /users/{id}.Actual: GET returns the original values. No errors or warnings in logs.
Relevant code:[async def update_user — the route handler, ~25 lines][db.py — session dependency, ~15 lines]
Already tried:- Added db.refresh(user) after commit — no change- Verified the PATCH body is reaching the handler correctly (logged it)- Confirmed the session is not being rolled back explicitly
Request: Before suggesting a fix, diagnose why changes committed in an asyncSQLAlchemy session would not persist in PostgreSQL but would appear to work inSQLite. Is this likely a transaction isolation issue, a session lifecycleproblem, or something about how async sessions handle commit?A prompt like this consistently gets a substantive diagnosis — in this case, the common async SQLAlchemy issue where session.commit() is not being awaited properly, or where the session context manager exits before the commit is reached. The model can reason to that conclusion because every relevant piece of evidence is present.
What this does not solve
The formula does not compensate for incorrect assumptions in parts 2 and 3. If your description of “expected behavior” is wrong — if the bug is actually that your mental model of the API is incorrect — the model will faithfully chase the wrong target. The structure helps the model reason; it does not verify that you have framed the problem correctly.
It also does not replace running the fix and checking the result. A well-reasoned diagnosis can still produce a patch that introduces a new edge-case failure. Treat the AI’s output as a hypothesis and verify it against your test suite and your own review before merging. The Prompt Engineering Playbook from Addy Osmani’s substack puts it plainly: the AI is a drafting tool, not a senior engineer — human review before deployment remains non-negotiable.
The five parts — environment, reproduction, expected vs. actual, relevant code plus what you tried, and an explicit diagnose-first request — are not a magic incantation. They are a checklist for the information that a thoughtful human debugger would want before sitting down with your code. The AI benefits from exactly the same information.
FAQ
Does this formula work with Copilot Chat, or just Claude? +
How long should the prompt be? Is longer always better? +
What if I don't know how to reproduce the bug reliably? +
Related reading
2026-05-21
Agetor Review: An Open-Source Kanban Board for Orchestrating Claude Code
Agetor is a 0.0.1 open-source orchestrator that pairs a Kanban board with Claude Code so you can run parallel agent tasks without juggling terminal tabs. A first look at what it does and what's planned.
2026-05-21
Veles: Hybrid BM25 + Semantic Code Search in a Local Rust MCP Server
Veles is an open-source MCP server in Rust that runs BM25 keyword search and semantic vector search together over a local index, giving Claude, Cursor, and other MCP assistants more precise code retrieval.
2026-05-21
Git for AI Agents: Version Control Built for LLM Coding Workflows
When an AI agent commits 40 times in an afternoon, git records every diff but none of the reasoning. Agent-native version control stores why each change was made, so you can bisect through agent sessions, not just diffs.
2026-05-21
Amp's Neo CLI: Why AI Coding Agents Still Live in the Terminal
Sourcegraph's Amp is reworking the command line around autonomous AI coding agents. Here's why the terminal remains core infrastructure for agentic development — and what changes when software, not a person, is the operator.
2026-05-21
Arcjet for AI Agents: Securing the Attack Surface Inside LLM Apps
Arcjet is moving its in-app security guards into AI agents, adding runtime checks against prompt injection, unsafe file reads, and risky web fetches. Here's why agentic apps need guardrails at the point of action, not just the network edge.
Get the best tools, weekly
One email every Friday. No spam, unsubscribe anytime.