TLDR: Ten prompting patterns that changed how I ship code — from full-context dumps and XML structure to TDD prompting and multi-turn sessions as a PR loop. The steelman prompt and the "explain to a junior" trick are the two I use every single week.
10 power moves — and 5 bonus hacks — that changed how I ship code. Concrete examples, real prompts, no fluff.
Let me be honest with you. For the first three months of using Claude, I was basically treating it like a fancier, chattier Stack Overflow. Paste error → get answer → close tab. Rinse and repeat. I thought I was being productive. I was not.
The shift happened when I was debugging a particularly gnarly async race condition in a Node.js service. I'd been going back and forth with Claude for 20 minutes, copy-pasting error messages, getting surface-level fixes that didn't stick. Out of frustration, I just dumped the entire file, explained our architecture, described what I'd already tried, and told it exactly what behavior I expected. The response that came back was so different. It caught a subtle issue I'd been blind to for two days.
That's when I realised: the model hadn't changed. My prompting had.
What follows are the 10 techniques I've actually shipped code with — not theoretical advice, but things that have a direct, measurable effect on output quality. I've added real prompt templates you can steal immediately.
01 — Give Full Context, Not Just the Broken Piece
Context is everything
This is the single highest-leverage change you can make. When you paste a 10-line snippet and say "this is broken," Claude has to guess at your stack, your intent, your constraints, and what you've already tried. It's like calling a doctor and saying "my arm hurts" without mentioning you fell off a bike.
The fix is almost embarrassingly simple: before asking, paste the full relevant file (or function), describe your architecture in one sentence, and state what you've already tried. That last part is critical — it prevents Claude from walking you back through dead ends.
# Instead of this:
"Why is my useEffect running twice?"
# Do this:
I'm building a Next.js 14 app (App Router) with a Postgres
DB via Prisma. Here's my component:
[paste full component]
The issue: useEffect fires twice on mount, causing a double
API call. I've already tried: React.StrictMode removal,
adding an abort controller. Expected: single fetch on mount.
The difference in output quality is night and day. Claude will now correctly identify that Next.js's dev mode double-invokes effects intentionally, and guide you to the right solution rather than a band-aid fix.
02 — Use XML Tags Like You Mean It
Structure your prompts
Claude was trained on a lot of structured content. XML tags aren't just cosmetic — they help the model parse complex, multi-part requests without ambiguity. Think of it like writing typed function signatures versus passing a bag of dynamic props. One is explicit; the other requires guessing.
I started using XML tags when I needed Claude to simultaneously understand context, act on a task, and follow constraints. Without tags, long prompts often get the priorities jumbled.
<context>
Node.js 20, Express 5, Postgres 16, Prisma ORM.
Monorepo structure. Each service is a separate package.
</context>
<code>
[paste your route handler here]
</code>
<task>
Refactor this route to use async/await throughout.
Add proper error handling with typed errors.
Do NOT change the function signature or return shape.
</task>
<constraints>
- Keep it under 50 lines
- Use our existing AppError class
- No new dependencies
</constraints>
Pro tip: The
<constraints>tag is underrated. Listing what NOT to do prevents Claude from "improving" things you didn't ask it to touch — a common source of frustration when it refactors 5 things you wanted left alone.
03 — Iterate in the Same Thread — Treat It Like a PR Loop
Don't blow up the thread
I used to start a new Claude conversation for every sub-task. Write the function → new chat. Add tests → new chat. Refactor → new chat. This is one of the biggest efficiency killers. You lose accumulated context every single time.
Instead, treat one Claude thread like a pull request review cycle. Generate, then review, then refactor, then test — all in sequence, in the same conversation. Claude holds context across the whole thread and gets progressively better at understanding your codebase's idioms.
The PR Loop workflow:
- Step 1: "Write the getUserById function using our Prisma client."
- Step 2: "Now add error handling — use our AppError class for not found cases."
- Step 3: "Write Jest tests covering: happy path, user not found, DB connection failure."
- Step 4: "Review the function for N+1 query risks and suggest optimizations."
Each step builds on the last. By step 4, Claude has a model of your function, your error patterns, your test style, and your DB setup — all from the same conversation.
04 — Role Prompting — Make Claude Think Like Your Tech Lead
Personality changes output
This one felt gimmicky to me at first. Telling an AI to "act as" something seemed silly. Then I tried it on a security review task and the response went from "here are some general security tips" to a methodical, prioritised threat model with specific CVEs. The persona shifts everything — vocabulary, depth, priorities, and assumptions.
Here are roles I actually use:
# Code review
"You are a staff engineer at a fintech company.
Review this code as if it's going to handle
$10M transactions per day. Flag anything that
could cause data inconsistency, silent failures,
or performance cliffs at scale."
# Architecture
"You are a principal engineer who has built
three distributed systems at >1M DAU. Given
this design doc, identify the top 3 assumptions
that are most likely to be wrong."
# TypeScript
"You are a TypeScript expert who prefers
functional patterns and hates any types.
Refactor this to be fully type-safe with no
type assertions."
Assigning a role is like pairing with a specialist instead of asking a generalist.
05 — Claude Projects — Stop Re-explaining Your Stack Every Time
Persistent memory for your codebase
One of the most painful things about AI-assisted development before Claude Projects was the cold-start problem. Every new conversation, you'd spend the first 5 messages catching Claude up: "We use ESM, not CommonJS. We have a monorepo. Our DB schema looks like this. Don't use fetch, we have an internal HTTP client." Every. Single. Time.
Claude Projects solves this. Create one project per repository, upload your key docs, and Claude walks into every conversation already knowing your codebase.
What to upload to your Project:
README.mdARCHITECTURE.mdtsconfig.jsonand.eslintrc- DB schema (as SQL or Prisma schema)
- Style guide or
CONTRIBUTING.md - A short hand-written "project conventions" note
That last one is the secret weapon. Something like: "We never use default exports. We use Zod for all validation. Errors are always AppError instances. Queries always go through the repository layer." Five minutes to write, saves five minutes of correction on every single response.
06 — Ask for Tests First, Before the Implementation
TDD your prompts
I didn't expect this one to work as well as it does. The idea is simple: before asking Claude to write a function, ask it to write the tests first. What happens is remarkable — it forces the model to reason about the contract, edge cases, and invariants before touching the implementation. You get better code AND better tests.
"Before writing the implementation, write Jest tests
for a function called parseInvoiceDate(input: unknown).
Cover these cases:
- Valid ISO 8601 string → returns Date object
- Valid Unix timestamp (number) → returns Date object
- Null/undefined → throws InvalidDateError
- Invalid string like 'yesterday' → throws InvalidDateError
- Date in the past (>2 years ago) → throws StaleInvoiceError
Once I approve the tests, then write the implementation
to make them pass."
This workflow has caught so many edge cases I'd have missed if I'd gone implementation-first. And when the implementation comes, it's already shaped to pass the tests — no rework needed.
07 — Debug with Reasoning — Diagnose Before You Fix
Root cause over patches
The instinct when something is broken is to ask "how do I fix this?" That's the wrong question. The right question is "why does this exist?" Asking Claude for a fix without a diagnosis is how you end up with code that works today and silently breaks tomorrow.
Rule: Never say "Fix this bug." Always say: "Don't fix it yet — explain what this code does step by step, then tell me where the logic breaks and why."
"Don't fix this yet.
First: trace through what this code does step by step,
including what happens to the data at each stage.
Then: identify where the logic breaks given this input:
{ userId: null, role: 'admin', permissions: [] }
Finally: explain WHY the current approach fails
conceptually — not just what line is wrong."
When I follow this pattern, I almost always learn something about my own code I didn't know. The bug is usually a symptom; the diagnosis reveals the disease.
08 — Use the Claude API — Automate the Boring Engineering Work
Build with it, not just talk to it
At some point you stop talking to Claude and start building with it. The API is where things get genuinely exciting. Any workflow in your engineering process that involves repetitive reasoning — PR descriptions, changelog generation, code review, test generation from specs — is a candidate for automation.
import Anthropic from '@anthropic-ai/sdk';
import { execSync } from 'child_process';
const client = new Anthropic();
async function generatePRDescription() {
const diff = execSync('git diff main --stat').toString();
const commits = execSync('git log main..HEAD --oneline').toString();
const msg = await client.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [
{
role: 'user',
content: `Write a PR description for these changes.
Commits: ${commits}
Diff summary: ${diff}
Format: ## Summary, ## Changes, ## Testing`,
},
],
});
console.log(msg.content[0].text);
}
generatePRDescription();
I have this wired to a git alias. git pr outputs a ready-to-paste PR description. Saved me probably 20 minutes a day.
09 — Prompt Caching — 90% Cost Reduction on Repeated Context
Speed and cost optimization
If you're using the Claude API with long system prompts — say, a full codebase context, a detailed style guide, or a large set of instructions — you're probably paying for that context on every single request. Prompt caching lets you store it and reuse it. The first call with a cacheable prompt is slightly slower; every subsequent call is dramatically cheaper and faster.
When caching makes sense:
- System prompts over 1,000 tokens
- Shared codebase context injected on every call
- Fixed instruction sets across a session
- Multi-turn agents with large shared context
- Batch processing pipelines
For production agents that run 50+ times per day against the same large context, this isn't a nice-to-have — it's the difference between a tool that's economically viable and one that isn't.
10 — Multi-turn Agents — Let Claude Chain Tasks Without You
Autonomous task execution
This is where it gets genuinely futuristic, and also where most devs haven't ventured yet. Claude can operate as an agent — give it a high-level goal and a set of tools (read file, run command, write file, search codebase), and it will plan and execute multi-step workflows autonomously.
# High-level goal
"Scaffold a new REST endpoint for GET /users/:id.
The endpoint should:
1. Validate the userId param with Zod
2. Query the users table via our Prisma client
3. Return 404 with AppError if not found
4. Write the route handler, service, and repository files
5. Write Jest integration tests
6. Run the tests and fix any failures"
# Tools you provide
tools: [read_file, write_file, run_command, search_codebase]
# Claude's autonomous loop:
→ reads existing route structure for patterns
→ writes handler, service, repository files
→ runs `npx jest users.test.ts`
→ reads test output, fixes failures
→ reports done with summary
I've used this pattern to scaffold entire feature slices in under 5 minutes. The key is providing well-defined tools and a clear, bounded goal. Unbounded goals ("make this codebase better") are where agents go sideways.
⚡ Bonus Hacks
Five things I wish someone had told me on day one.
Bonus #1 — The "Steelman My Approach" Prompt
Before committing to an architectural decision, ask Claude to both steelman your approach (make the best possible case for it) and then argue against it. You get a balanced view without confirmation bias from either direction. Better than asking "is this a good idea?" which usually gets a "yes, and here are some caveats."
"I'm planning to use a Redis-backed job queue for our
notification system instead of a Postgres-based approach.
First: make the strongest possible case FOR this decision.
Then: make the strongest possible case AGAINST it.
Finally: what's the one question I should answer before
deciding?"
Bonus #2 — Chain Prompts for Architecture Docs
Writing an ADR (Architecture Decision Record) is painful. Most devs skip it. Here's a chain that writes a complete ADR from a 2-sentence description: prompt 1 expands your idea into options, prompt 2 evaluates tradeoffs, prompt 3 formats it as a proper ADR. Three prompts in one thread, and you have documentation you'd have never written otherwise.
Prompt 1: "I want to add caching to our product API. List
3 possible approaches with one-line pros/cons each."
Prompt 2: "Given our stack (Node, Postgres, 50k DAU,
no Redis yet), score each approach 1-5 on: effort,
performance gain, operational complexity."
Prompt 3: "Write an ADR for the winning approach.
Use the MADR format."
Bonus #3 — Ask Claude to Compress Its Own Output
When Claude gives you a long, explanatory response and you just need the code — follow up with: "Give me only the final code, no explanation, as a single file."
Conversely, when you get code without context and something breaks, ask: "Walk me through the decision behind each non-obvious line."
You control the verbosity; don't just accept the default.
Bonus #4 — Use Claude to Write Your Own Prompts
This is very meta but genuinely useful. If you have a recurring task — say, reviewing migrations for safety — describe it to Claude and ask it to write the optimal prompt for that task. It'll ask clarifying questions about what you actually care about. The resulting prompt is usually better than what you'd have written yourself, and you can save it to your Claude Project for reuse.
"I need to review every DB migration before it goes
to production. Write me the optimal prompt I should
use, as a Claude system prompt. Ask me any clarifying
questions about our stack and what I care about first."
Bonus #5 — The "Explain to a Junior" Reverse Trick
When you're unsure whether you actually understand a piece of generated code, ask Claude: "Explain this implementation as if I'm a junior dev who has never used this pattern."
If the explanation reveals something you didn't know, you now know it. If it's all obvious, you've validated your understanding. Either way, you're not shipping code you only sort-of understand. This one has saved me from some genuinely embarrassing production incidents.
Found this useful? Share it with one developer who's still pasting error messages without context. They'll thank you later.
Tags: #ClaudeAI #PromptEngineering #AIForDevs #DevProductivity #BuildWithClaude #SoftwareEngineering