Prompt engineering for Claude Code
Prompt engineering for Claude Code means writing each request as a short brief: what to change, where, why, and a done-when check that Claude runs itself. The done-when clause matters most, because it turns a request into work Claude can prove with a test or command. Plan mode, context priming, and effort settings then control how Claude gets there.
This page is for developers who run Claude Code every day, and for tech leads who want a team to write briefs the same way. You type “fix the reconnect bug”, Claude edits three files, reports success, and you are left reading a 200-line diff to find out whether it is true. The fix is not a longer prompt. It is a prompt that says what “done” looks like, so that the evidence arrives with the diff.
What a good Claude Code brief gives you
Section titled “What a good Claude Code brief gives you”- A four-part brief (what, where, why, done-when) that works for bug fixes, features, and refactors.
- Done-when clauses that make Claude run a failing test, a type check, or a command before it reports success.
- Three context-priming patterns that stop Claude from guessing at code it has not read.
- A rule for when to use plan mode and when to raise effort, and when neither helps.
- Copy-paste prompts for a bug fix, a feature, a test suite, and a review of Claude’s own diff.
- A
/briefproject skill that gives the whole team the same template.
How do you structure a Claude Code prompt?
Section titled “How do you structure a Claude Code prompt?”Compare two requests for the same bug. The first is “Fix the WebSocket bug.” The second:
What: The WebSocket client stops reconnecting after the third failed attempt.Where: src/realtime/socket.ts (reconnect logic) and src/realtime/__tests__/socket.test.ts.Why: The backoff timer resets on partial connections, so mobile users on weak networksnever recover and have to reload the app.Done when: a new test that simulates three failed reconnects fails on the current code,passes after your fix, and `npm test -- socket` plus `npm run typecheck` both pass.Show me the failing run and the passing run.The second prompt answers the four questions every Claude Code brief needs:
- What changes, stated as behaviour rather than as an edit (“stops reconnecting”, not “change line 80”).
- Where Claude should look first. Naming files saves exploration and keeps the edit inside the area you expect.
- Why the change matters. The reason lets Claude choose between fixes: “mobile users on weak networks” rules out a fix that only works on stable connections.
- Done when: the check that proves the work. Claude Code can run commands, so a check you can express as a command is one Claude runs before it reports back.
The fourth part is what separates prompting an agent from prompting a chat model. Without it, Claude decides for itself when it is finished, and “finished” often means “the code compiles”. With it, you get a claim plus the output that backs the claim.
Replace npm test and npm run typecheck with your project’s commands. If you put them in CLAUDE.md once, the brief can say “the checks in CLAUDE.md pass” and stay short. See the memory system for what belongs there.
Write done-when clauses Claude can prove
Section titled “Write done-when clauses Claude can prove”A done-when clause earns its place when Claude can run it and you can read the result in seconds. Four forms cover most work:
| Clause | Example | What it proves |
|---|---|---|
| Red, then green | “Write the test first, run it, show it failing, then fix.” | The test exercises the bug, not just the happy path. |
| Named command | “npm run typecheck and npm run lint exit 0.” | No type or lint regressions anywhere in the project. |
| Observable behaviour | “curl -i localhost:3000/api/users/abc%20def returns 400, not 500.” | The fix works end to end, not only in a unit test. |
| Boundary | “No file under src/generated/ changes. Show git diff --stat.” | The change stayed where you expected. |
Ask for the evidence explicitly (“paste the last lines of each output”). Claude then reports what it ran, not only what it believes. A clause such as “make sure it works” or “keep the code clean” proves nothing, because Claude cannot run it and you cannot check it.
When the acceptance criteria come from a product story rather than from a bug report, write them as tests before the agent starts. Executable acceptance criteria covers that step across tools.
Prime Claude’s context before you ask
Section titled “Prime Claude’s context before you ask”Claude Code reads files on demand, but it reads what it thinks is relevant. When the answer depends on specific code, tell it what to read first.
Read, then answer
Section titled “Read, then answer”Read src/auth/middleware.ts, src/auth/jwt.ts, src/auth/session.ts and their tests.Then tell me what would break if the access-token expiry changed from 1 hour to 15 minutes.List each affected call site with its file and line. Do not edit anything yet.This grounds the answer in the code on disk instead of in Claude’s assumptions about how auth code usually looks. “Do not edit anything yet” keeps it a question.
Show an example to copy
Section titled “Show an example to copy”Look at how src/api/routes/orders.ts handles errors: the try/catch shape, theRFC 7807 error body, and the logger calls. Apply the same pattern to every handlerin src/api/routes/products.ts. Done when the products route tests pass and a`grep -n "console.log" src/api/routes/products.ts` returns nothing.Pointing at an existing file is more precise than describing a convention in words, and it keeps new code consistent with the code a reviewer already knows.
State constraints first
Section titled “State constraints first”Constraints:- Do not add dependencies to package.json.- All database access goes through the Prisma client in src/lib/db.ts.- Validate input with Zod, following src/api/routes/orders.ts.- Do not touch src/generated/ (it is regenerated on build).
Task: add GET /api/v2/analytics that returns daily active users for a date range.Done when: route tests cover an empty range, a range over 90 days (400), and a normalrange; `npm test` and `npm run typecheck` pass.Constraints at the top are read before Claude starts planning. Constraints that apply to every task belong in CLAUDE.md, not in each prompt.
When should you use plan mode?
Section titled “When should you use plan mode?”Plan mode is a permission mode in which Claude reads code and proposes a plan, and edits stay blocked until you approve it. Enter it in one of three ways:
- Type
/plan, optionally followed by a description of the task (/plan migrate sessions to JWT). - Press
Shift+Tabuntil the mode indicator shows plan mode. - Start the session in it:
claude --permission-mode plan.
Use plan mode when the order of changes matters or when you would reject the work if the approach were wrong: changes across more than a handful of files, data migrations, or anything touching auth or payments. Skip it for a one-file fix with a clear test, where the plan would only restate the prompt.
The plan is where your review effort pays off most. Reading a 20-line plan is faster than reading the diff it produces, and a wrong approach costs nothing to correct at that point. Check that the plan names its verification steps; if it does not, ask for them before you approve.
For a larger planning workflow, including when to plan in a separate session, see feature planning with Claude Code.
How much reasoning should a prompt ask for?
Section titled “How much reasoning should a prompt ask for?”Effort sets how much Claude reasons before it acts. Claude Code accepts low, medium, high, xhigh, and max (checked against claude --help, v2.1.283). Set it for the session with /effort, at launch with claude --effort high, or through the CLAUDE_CODE_EFFORT_LEVEL environment variable in scripts. The default model, Claude Opus 5.5, starts at medium effort on the latest release channel; the models hub lists the defaults for other models and channels.
For a single hard turn, add the word ultrathink to the prompt. In v2.1.283 it adds a one-turn instruction to reason more thoroughly and leaves the session’s effort setting unchanged. “Think hard” and “think more” are ordinary prompt text with no special effect.
Raise effort when the problem needs multi-step reasoning: concurrency, security analysis, or an architecture decision. Keep the default for routine edits. Better context helps more often than more effort does. If Claude’s answer is shallow because it never read the relevant code, a higher effort level only produces a longer wrong answer. Deep reasoning in Claude Code covers effort levels, ultracode, and team caps in full.
Prompts for bug fixes, tests, and self-review
Section titled “Prompts for bug fixes, tests, and self-review”Each prompt below carries its own done-when clause, so the result arrives with evidence.
The last step of that prompt is a cheap mutation test. A test that still passes after you break the code it covers proves nothing, so ask Claude to show you the red run.
How do you make the whole team write briefs the same way?
Section titled “How do you make the whole team write briefs the same way?”A template in a wiki gets copied once and then drifts. A project skill travels with the repository, so every developer who clones it gets the same /brief command. Commit this file as .claude/skills/brief/SKILL.md:
---name: briefdescription: Turn a one-line request into a four-part brief with a provable done-when clause.argument-hint: <what should change>disable-model-invocation: true---
Treat this request as the "What" of a brief: $ARGUMENTS
Before editing anything:1. Name the files you will start from (Where) and the user-facing reason (Why). If either is unclear from the code, ask me instead of guessing.2. Write a done-when list: a test that fails before the change and passes after it, plus the test, type-check and lint commands listed in CLAUDE.md.3. Show me the brief and wait for "go".
When you finish: list every command you ran with the last lines of its output,show `git status --short` and `git diff --stat` (so new, untracked files count too),and mark any changed behaviour that no test covers as UNTESTED.A developer then types /brief the WebSocket client stops reconnecting after three failures, and Claude fills in the Where, Why, and Done when before it touches code. disable-model-invocation: true keeps the skill manual, so Claude does not start briefing every small question on its own. Custom commands covers skill frontmatter and arguments in full.
For a tech lead, the skill is also a review standard. A pull request whose description has no failing-then-passing run and no UNTESTED list did not follow the brief, and the reviewer can send it back without reading the diff.
How do you verify Claude’s output without reading every line?
Section titled “How do you verify Claude’s output without reading every line?”Prompting well moves your review effort from the diff to the evidence. Use this order:
- Approve the intent. For risky work, read and correct the plan in plan mode. This is your main review point.
- Require evidence in the report. The done-when clause makes Claude return commands and their output. Check that the failing run came before the passing one.
- Run the gate yourself or in CI. Re-run the project’s test, type, and lint commands, or let CI do it. Claude’s transcript is a claim; your gate is the proof.
- Get a second opinion on the diff. Run the self-review prompt above, or
/code-reviewfor a structured review. See review automation for running reviews on every pull request. - Read the UNTESTED list, not the whole diff. Spend your reading time on behaviour that no test covers, and on files outside the Where list.
You still sign off, but on the plan, the evidence, and the untested gaps, not on every line. Evidence, not diffs explains that way of working and when it is safe to adopt.
What breaks when you prompt Claude Code, and how do you recover?
Section titled “What breaks when you prompt Claude Code, and how do you recover?”Claude reports success, but the tests were never run. The prompt had no done-when clause, or it said “make sure it works”. Recovery: reply with “Run npm test now and paste the output”, and add the evidence line to your brief template.
Claude ignores a constraint in a long session. Early instructions compete with everything read since. Recovery: restate the constraint at the start of the next prompt. For a constraint that applies to every task, move it into CLAUDE.md. For a session that has drifted far, /clear and start again with the brief.
Claude “fixes” the test instead of the code. A done-when that only says “tests pass” lets Claude weaken the assertion. Recovery: add “do not change existing assertions; if a test looks wrong, stop and tell me why”. Undo the bad edit with /rewind (or Esc twice) to go back to the last checkpoint.
Claude invents code that is not there. It answered from assumptions. Recovery: correct it with the fact (“the token is stored in Redis, see src/auth/session.ts line 45”) and ask it to read the file before continuing. Next time, use the read-then-answer pattern.
Plan mode still produced edits. The session was not in plan mode, or you approved the plan. Recovery: check the mode indicator before you send the prompt, or start with claude --permission-mode plan. Asking Claude to “plan first” in a normal mode is a request, not a block.
Higher effort did not improve the answer. The missing ingredient was context or a checkable goal, not reasoning. Recovery: go back to the default effort, add the files to read and a done-when clause, and try again.
Where to go next with Claude Code prompting
Section titled “Where to go next with Claude Code prompting”- The memory system: put your test commands and standing constraints in
CLAUDE.mdso every brief can stay short. - Deep reasoning in Claude Code: effort levels,
ultracode, and team effort caps. - Feature planning: plan mode for multi-step features.
- Batch operations: apply one well-formed brief across many files.
- Debugging workflows: prompts for finding root causes.
- Effective prompting techniques: the tool-independent principles behind this page.
- Prompt engineering for Codex: the same brief adapted to Codex.
- Prompt templates in Cursor: the same idea as reusable Cursor templates.
- Grill Me and Grill With Docs: let the agent interview you before you write the brief.