A01: Prompt Engineering for Claude Code
Related chapters: Ch1 Installation & First Session, Ch2 CLAUDE.md & Memory, Ch6 Custom Skills
Prompt engineering for Claude Code is fundamentally different from prompting a chatbot. When you're talking to Claude in a browser, you're crafting text for text generation. When you're working with Claude Code, you're giving instructions to an agent that has tools, makes multi-step decisions, and operates on your real filesystem. This appendix covers the specific patterns that make Claude Code effective.
Why Claude Code Prompting Is Different
In a chat interface, your prompt is the only input Claude receives. In Claude Code, your prompt is one of many inputs:
Claude Code's full context:
┌──────────────────────────────────────┐
│ System prompt (Claude Code's core) │ ← You don't control this
│ CLAUDE.md (your project rules) │ ← You control this (Ch2)
│ Memory files (saved preferences) │ ← Claude manages this
│ Tool definitions (Read, Write, etc.) │ ← You don't control this
│ Conversation history │ ← Both of you build this
│ Your current prompt │ ← You control this
│ Tool results (file contents, etc.) │ ← Generated by tools
└──────────────────────────────────────┘This means your prompt doesn't need to carry all the context. CLAUDE.md handles project standards. Memory handles your preferences. Tool results handle the actual code. Your prompt just needs to say what to do and why.
The Specificity Spectrum
Every prompt falls on a spectrum from vague to over-constrained. The optimal zone depends on your task:
Too Vague (Ineffective)
Fix the bug.Problem: Claude doesn't know which bug, where to look, or what "fixed" looks like. It will waste tool calls exploring the codebase randomly.
Too Constrained (Inefficient)
Open src/auth/middleware.ts at line 42. Change the if statement from
`if (token.expired)` to `if (token.expired || !token.valid)`. Then open
src/auth/types.ts and add a `valid: boolean` field to the Token interface
on line 15. Then run npm test.Problem: You've done all the thinking. If you already know exactly what to change, just change it yourself. You're using Claude as a typing assistant, not a reasoning partner.
Just Right (Effective)
Users are reporting 401 errors when their JWT token has been rotated but the
old token hasn't expired yet. The issue is likely in the auth middleware
(src/auth/). Find where we validate tokens and add a check for token
validity beyond just expiration. Run the auth tests to verify.Why this works:
- What: Fix 401 errors during token rotation
- Where:
src/auth/directory (narrows the search) - Why: Token validity check is missing (explains the root cause)
- How to verify: Run the auth tests (defines success)
- What's NOT specified: Exact files, line numbers, implementation details — Claude figures these out
The Five Prompt Patterns for Claude Code
Pattern 1: The Investigation Prompt
Use when you need Claude to understand something before acting.
I'm seeing intermittent 500 errors in production. The error logs mention
a "connection pool exhausted" message from the database layer.
Investigate:
1. Find where we configure the database connection pool
2. Check if there's connection leak potential (connections opened but not closed)
3. Look at the middleware chain for anything that might hold connections open
4. Report your findings before making any changesKey elements:
- Describe symptoms, not solutions
- Ask Claude to report before changing
- Give starting points but don't prescribe the investigation path
Pattern 2: The Implementation Prompt
Use when you want Claude to build something specific.
Add rate limiting to the /api/upload endpoint:
- Max 10 uploads per user per minute
- Return 429 with retry-after header when exceeded
- Use the existing Redis instance for tracking (REDIS_URL is in .env)
- Follow the pattern in src/middleware/auth.ts for middleware structure
- Add tests
Don't modify any existing endpoints.Key elements:
- Clear requirements with numbers
- Point to existing patterns ("follow the pattern in...")
- Explicit boundaries ("don't modify any existing endpoints")
- Include tests
Pattern 3: The Review Prompt
Use when you want Claude to analyze without changing.
Review the changes on this branch (feature/payments) for:
1. Security issues (especially around payment data handling)
2. Error handling gaps (what happens when Stripe API is down?)
3. Missing tests for edge cases
Don't fix anything — just list the findings with severity ratings.Key elements:
- Specific review dimensions (not just "review this")
- Explicit "don't fix" instruction (Claude will try to fix otherwise)
- Ask for severity to help prioritize
Pattern 4: The Refactoring Prompt
Use when you want Claude to restructure existing code.
The user authentication logic is split across 4 files with duplicated
validation. Consolidate into a single auth service:
- Keep the public API unchanged (same function signatures)
- Extract shared validation into private methods
- Don't change the database schema
- Run existing tests to verify nothing breaksKey elements:
- Describe the current problem (duplication)
- Describe the target (single service)
- Constraints ("keep the public API unchanged")
- Verification step ("run existing tests")
Pattern 5: The Exploration Prompt
Use when you're learning a codebase or technology.
I just joined this project. Walk me through the architecture:
1. What's the tech stack? (read package.json, go.mod, or equivalent)
2. How is the code organized? (describe the directory structure)
3. Where's the main entry point?
4. How does a request flow from the API layer to the database?
5. What testing patterns are used?Key elements:
- Open-ended but structured
- Numbered questions (Claude answers each one)
- Starts broad, goes specific
Anti-Patterns: What NOT to Do
Anti-Pattern 1: "Be Careful"
Be very careful when making changes. Double-check everything. Make sure
you don't break anything. Be extra cautious.Why this fails: These are emotional instructions, not actionable ones. Claude doesn't have a "careful mode." Instead, tell Claude specifically what to watch for:
Before committing: run the test suite, check for TypeScript errors with
tsc --noEmit, and verify the API responses haven't changed shape.Anti-Pattern 2: Premature Abstraction Requests
Create a flexible, extensible framework for handling all possible
authentication scenarios. It should support OAuth, SAML, JWT, API keys,
and any future auth methods.Why this fails: Claude will over-engineer a massive abstraction that nobody needs. Instead, build for your current needs:
Add JWT authentication to the /api/users endpoint. Use the jsonwebtoken
package. Store the secret in process.env.JWT_SECRET.Anti-Pattern 3: Chaining Unrelated Tasks
Fix the login bug, then add a dark mode toggle, then update the README,
then review the PR from last week.Why this fails: Context rot. By the time Claude reaches task 4, it has forgotten the details of task 1. See A02 Context Engineering. Instead, do one task per session or use /clear between unrelated tasks.
Anti-Pattern 4: Referencing External Knowledge Claude Doesn't Have
Implement the solution from that Stack Overflow answer we discussed yesterday.Why this fails: Claude doesn't have memory of conversations in other tools (browser, Slack, etc.). Give it the actual content:
Implement this approach for handling race conditions:
[paste the specific approach, not just a link]Prompt Templates for Common Tasks
Bug Fix Template
Bug: [describe the symptom]
Expected: [what should happen]
Actual: [what happens instead]
Reproduce: [steps or test case]
Suspected area: [file or module, if known]
Find the root cause, fix it, and add a regression test.Feature Implementation Template
Feature: [one-sentence description]
Requirements:
- [requirement 1]
- [requirement 2]
- [requirement 3]
Constraints:
- [what NOT to change]
- [performance/security requirements]
Pattern to follow: [reference existing code]
Verify: [how to test]Code Review Template (Pipe Mode)
git diff main..HEAD | claude -p "Review these changes:
1. Correctness: any logic bugs?
2. Security: any vulnerabilities (OWASP top 10)?
3. Performance: any N+1 queries, unnecessary re-renders, or memory leaks?
4. Style: anything inconsistent with the existing codebase?
Rate each category: PASS / CONCERN / FAIL. Explain any non-PASS ratings."Chain-of-Thought in Tool-Calling Contexts
In a chatbot, chain-of-thought means "think step by step before answering." In Claude Code, chain-of-thought happens naturally through the tool-calling loop:
- Claude reads the prompt and decides what information it needs
- It calls Read/Glob/Grep to gather context
- With each tool result, it refines its understanding
- It eventually acts (Write/Edit/Bash)
You can enhance this natural chain-of-thought by structuring your prompt to encourage investigation before action:
Before implementing anything:
1. Read the existing tests to understand what's expected
2. Check if there's a similar feature elsewhere in the codebase
3. Plan the approach and tell me before you start coding
Then implement.This "investigate, plan, implement" structure is formalized as the R-P-E-R-S workflow in Ch15 Production Workflows.
Token Efficiency in Prompts
Your prompt is a small fraction of Claude Code's context, but it sets the direction for everything that follows. A well-structured prompt leads to fewer tool calls, less context consumption, and better results.
Efficient: Point Claude to the right place
The rate limiter config is in src/config/rate-limits.ts. Increase the
/api/upload limit from 10 to 25 per minute.Claude reads one file, makes one edit. ~500 tokens total.
Inefficient: Make Claude search
Somewhere in the config files there's a rate limit setting. Find it and change it.Claude searches multiple files, reads several configs. ~3,000 tokens total.
Both produce the same result, but the efficient prompt uses 6x fewer tokens. When you know where something is, say so. When you don't, that's fine, but acknowledge it:
I'm not sure where the rate limit config lives. Check src/config/ first,
then the middleware directory.Key Takeaways
- Your prompt is one input among many — CLAUDE.md, memory, and tool results carry most of the context. Keep prompts focused on WHAT and WHY.
- Describe symptoms, not solutions for investigation tasks. Let Claude use its tools to find the answer.
- Point to existing patterns when asking for implementations. "Follow the pattern in src/auth/middleware.ts" is more effective than specifying every detail.
- One task per session (or use
/clearbetween unrelated tasks) to avoid context rot. - Ask Claude to investigate before acting for complex tasks. The natural chain-of-thought through tool calls produces better results than jumping straight to implementation.
- "Be careful" is not actionable. Replace emotional instructions with specific verification steps.
See also: A02 Context Engineering for how to manage the full context budget, and A05 Tool Calling Internals for how Claude decides which tool to use.