Skip to content

Best practices

The habits that get the most out of Claude Code: verifiable goals, planning before coding, precise prompts, a lean setup, tight context management and safe ways to scale up.

Claude Code is not a chatbot that answers and waits. It reads files, runs commands, makes changes and works through problems while you watch, redirect it or walk away. That changes the job: you spend less time typing code and more time describing outcomes, setting up checks and reviewing results.

This page collects what has worked for me across client and personal projects. Most of it traces back to one constraint.

The constraint behind everything: context

The context window holds the whole conversation: every message, every file Claude has read, every command's output. A single debugging session can consume tens of thousands of tokens, and model performance drops as the window fills. Early instructions get forgotten and mistakes creep in.

Treat context as your scarcest resource. Context window shows what fills it, a custom status line can display usage permanently, and costs has more ways to cut token use.

Give Claude a way to check its own work

This is the single biggest lever. Claude stops when the work looks finished. Without something it can run, "looks finished" is the only signal, and you become the test suite. Give it a check that returns pass or fail and the loop closes: work, check, read the result, fix, repeat.

A check is anything with output Claude can read: tests, a build's exit code, a linter, a script diffing output against a fixture, or a browser screenshot compared with a design.

Instead ofTry
"write a function to parse UK postcodes""write parsePostcode. SW1A 1AA and sw1a1aa should both normalise to SW1A 1AA; ABC 123 should return null. add those as tests and run them"
"tidy up the pricing page""[screenshot] make the pricing page match this. screenshot your result, compare, list the differences and fix them"
"CI is red""CI fails with [paste]. fix the cause, not the symptom, and show me a passing run"

Decide how strictly the check gates completion:

  1. In the prompt. Ask Claude to run the check and iterate. Works today, on anything.
  2. Across the session. Set the check as a /goal condition. A separate evaluator re-checks after each turn and Claude continues until it is met; if Claude stalls, the run eventually stops with the goal still set.
  3. As a hard gate. A Stop hook runs your script and blocks the turn from ending until it passes (there is a cap on consecutive blocks).
  4. With a second opinion. A verification subagent or a self-checking workflow has a fresh model try to refute the result, so the worker is not marking its own homework.

Each step costs more setup and less attention. The last two are what let an unattended run finish correctly.

Ask for evidence rather than assurances: the test output, the command and what it returned, a screenshot. Reviewing evidence is faster than re-running checks yourself. After Claude's own checks pass, run /verify (see skills) to confirm the change in the running app.

Explore, plan, then build

Jumping straight to code risks a neat solution to the wrong problem. Plan mode separates looking from doing.

  1. Explore. Press Shift+Tab until the status bar shows ⏸ plan mode on, or start with claude --permission-mode plan. Claude reads and answers questions but changes nothing.

    read src/billing and explain how invoices and credit notes are generated.
    also check how we handle VAT for EU customers.
    
  2. Plan. Ask for a concrete plan.

    I need to support reverse-charge VAT for EU businesses. which files change, what's the data flow, and what are the risks? write a plan.
    

    Press Ctrl+G to open the plan in your own editor and change it before Claude starts.

  3. Build. Approve the plan (or press Shift+Tab to leave plan mode) and let Claude implement against it.

    implement the plan. add tests for reverse-charge invoices, run the billing suite and fix failures.
    
  4. Commit.

    commit with a clear message and open a pull request
    

Planning has overhead. If you could describe the diff in one sentence (a typo, a log line, a rename), skip it. Plan when you are unsure of the approach, the change spans several files, or you do not know the code well.

Be specific

Claude infers a lot, but it cannot read your mind. Name files, state constraints and point at examples.

TechniqueVagueSpecific
Scope it"add tests for cart.py""test cart.py for the case where a discount code expires mid-checkout. no mocks; use the test database"
Point at the source"why is the Scheduler API so odd?""read the git history of Scheduler and explain how its API ended up like this"
Reference a pattern"add a date picker""look at how the existing form fields in components/forms are built, especially SelectField, and build a DatePicker the same way using only libraries we already have"
Describe the symptom"fix the upload bug""uploads over 10 MB fail silently since Tuesday. start in api/uploads, check the size limit and proxy config, write a failing test, then fix it"

Vague prompts have their place when exploring. "What would you change in this file?" can surface things you would not have thought to ask.

Feed it rich input

  • Reference files with @ instead of describing where code lives.
  • Paste or drag images straight in.
  • Give URLs for documentation; allowlist domains you use often with /permissions.
  • Pipe data in: cat crash.log | claude -p "what caused this?".
  • Tell Claude to fetch what it needs itself, using shell commands, MCP tools or file reads.

Set up your environment once

A little setup pays off in every session. Features overview explains when each piece fits.

A lean CLAUDE.md

Run /init for a starting point, then refine. Include what Claude cannot work out for itself:

IncludeLeave out
Commands Claude would not guessThings obvious from reading the code
Style rules that differ from the defaultsStandard language conventions
How to run tests, and which runnerFull API docs (link instead)
Branch naming and pull request etiquetteThings that change weekly
Architecture decisions specific to this projectTutorials and long explanations
Environment quirks and required variablesFile-by-file descriptions
Non-obvious gotchasPlatitudes like "write clean code"

For every line, ask whether removing it would cause a mistake. If not, cut it. A bloated file buries the rules that matter. If Claude keeps ignoring a rule, the file is probably too long; if it asks questions the file answers, the wording is ambiguous. Treat it like code: review it when things go wrong and check that edits actually change behaviour. /doctor will suggest cuts for a checked-in file.

If one instruction keeps getting missed, mark that line alone as IMPORTANT. Emphasise everything and nothing stands out. Commit the file so the team improves it over time. See memory for imports, rules and locations.

Permissions that do not nag

From v2.1.283, auto mode is the built-in starting mode for interactive terminal and VS Code sessions (earlier versions only on Pro, Max and Team plans). A classifier reviews most actions and blocks only risky ones: scope escalation, unknown infrastructure, actions driven by hostile content.

In Manual mode Claude asks before file writes, shell commands and MCP tools. Safe, but after the tenth prompt you are clicking rather than reviewing. Two tools help in either mode:

  • Allowlists via /permissions for commands you trust, such as pnpm lint or git commit.
  • Sandboxing via /sandbox, which isolates filesystem and network access at OS level so Claude can work more freely inside the boundary.

See permission modes, permissions and sandboxing.

Prefer CLI tools

Command-line tools are the most context-efficient way to reach external services. Install gh and Claude will use it for issues, pull requests and comments; without it, unauthenticated API calls hit rate limits quickly. The same goes for aws, gcloud, sentry-cli and friends. Claude also learns unfamiliar tools well: "run flyctl --help, then use it to scale the worker app to two machines."

MCP servers

Connect external systems with claude mcp add, for example:

claude mcp add --transport http linear https://mcp.linear.app/mcp

Then Claude can implement tickets, query databases, read monitoring data or pull designs. See MCP.

Hooks for the non-negotiables

CLAUDE.md is advisory; hooks always run. Ask Claude to write them ("write a hook that runs Black after every Python edit", "write a hook that blocks any write under db/migrations/applied"), edit .claude/settings.json by hand, and browse what is configured with /hooks.

Skills for knowledge and workflows

A skill is a folder in .claude/skills/ with a SKILL.md. It can be reference material:

---
name: event-schema
description: Conventions for analytics events in this app
---
# Analytics events
- Event names are snake_case verbs in the past tense: report_exported
- Every event carries workspace_id and actor_id
- Never send email addresses or free text

or a workflow you trigger:

---
name: hotfix
description: Prepare a hotfix branch for a production bug
disable-model-invocation: true
---
Prepare a hotfix for: $ARGUMENTS

1. Branch from the latest release tag as hotfix/<short-name>
2. Reproduce the bug with a failing test
3. Make the smallest fix that passes it
4. Run the full test suite and the type checker
5. Update CHANGELOG.md under "Unreleased - Fixes"
6. Open a pull request against the release branch

Run it as /hotfix duplicate emails on checkout. Use disable-model-invocation: true for anything with side effects.

Custom subagents

Define specialists in .claude/agents/ with their own tools and instructions:

---
name: perf-reviewer
description: Reviews changes for performance regressions in hot paths
tools: Read, Grep, Glob, Bash
model: opus
---
You review code for performance problems: N+1 queries, unbounded loops over
user data, missing indexes, large synchronous work on request threads.
Cite file and line for each finding and suggest a concrete fix.

Then ask explicitly: "use a subagent to check this diff for performance problems." See subagents.

Plugins

/plugin browses marketplaces of ready-made skills, hooks, subagents and MCP servers. For typed languages, a code intelligence plugin gives Claude precise symbol navigation and error detection after edits.

Talk to it like a senior colleague

Ask questions

When joining a codebase, ask what you would ask the person who wrote it: how logging works, how to add an endpoint, what a particular line does, which edge cases a class handles, why one function is called instead of another. No special prompting needed, and it saves your teammates a lot of interruptions.

Let it interview you

For larger features, start small and ask Claude to interview you with the AskUserQuestion tool:

I want to add <short description>. interview me with the AskUserQuestion tool about implementation, UX, edge cases, risks and trade-offs. skip the obvious and dig into the hard parts. keep going until we've covered everything, then write a full spec to docs/specs/<name>.md

Then start a fresh session to implement it, with clean context and a written spec. The best specs are self-contained: they name the files and interfaces, say what is out of scope, and finish with an end-to-end check that proves the feature works. Time spent sharpening the spec pays back more than time spent watching implementation.

Manage the session

Correct early

Tight feedback loops beat hoping for a perfect first attempt.

  • Esc stops Claude mid-action with context intact.
  • Esc twice, or /rewind, restores earlier conversation and code, or summarises from a chosen message.
  • "Undo that" asks Claude to revert.
  • /clear resets between unrelated tasks.

If you have corrected the same thing twice, the context is full of failed attempts. /clear and start again with a better prompt that includes what you learned. A clean session with a sharper prompt almost always wins.

Keep context clean

  • /clear between unrelated tasks.
  • Auto-compaction preserves key code and decisions when the window fills, but you can steer it with /compact <focus>.
  • To summarise only part of the conversation, open /rewind, choose a message and pick Summarize from here (condense from that point on, keep earlier context) or Summarize up to here (condense earlier messages, keep recent ones in full). See checkpointing.
  • Add compaction guidance to CLAUDE.md, such as "when compacting, keep the full list of modified files and the test commands".
  • Use /btw for side questions: the answer never enters history. See interactive mode.

Investigate with subagents

Research fills context with file reads. Delegate it:

use subagents to find out how feature flags are evaluated on the server and whether there's an existing helper for percentage rollouts

Each subagent explores in its own window and reports a summary.

Rewind instead of tiptoeing

Every prompt that starts a turn creates a checkpoint. Esc twice or /rewind lets you restore the conversation, the code or both. That makes it cheap to say "try the risky approach": if it fails, rewind. Checkpoints are saved with the session, so they survive closing the terminal.

Warning: Checkpoints only track edits made through Claude's file tools. Changes from shell commands or other processes are not captured, so checkpoints are not a substitute for git.

Name and resume sessions

Use /rename and treat sessions like branches: one per workstream. claude --continue picks up the latest; claude --resume lets you choose. See sessions.

Scale up

Non-interactive runs

claude -p "prompt" runs without the interactive interface, for CI, git hooks and scripts. It still creates a resumable session unless you add --no-session-persistence.

claude -p "summarise the open TODO comments by owner"
claude -p "list every environment variable the app reads" --output-format json
claude -p "watch this log and describe each error class" --output-format stream-json --verbose

Plain text by default; json gives one object with a result field; stream-json emits one object per line starting with an init event. See headless mode.

Parallel sessions

Choose based on how much coordinating you want to do:

  • Worktrees for isolated CLI sessions that cannot collide.
  • Cross-session messaging so your sessions can pass findings to each other.
  • The desktop app for managing several local sessions visually.
  • Claude Code on the web for sessions on Anthropic's infrastructure.
  • Agent view (research preview): claude agents to dispatch background sessions and watch them from one screen.
  • Agent teams (experimental, off by default) for automated coordination with shared tasks and a lead.

Fresh context also improves quality. A writer and reviewer split works well:

Session A: writerSession B: reviewer
"Add idempotency keys to the payments API"
"Review @src/payments/idempotency.ts for race conditions, key collisions and consistency with our other middleware"
"Here's the review: [paste]. Address it."

The same trick works for tests: one session writes them, another writes code to pass them.

Fan out across many files

For big migrations, /batch <instruction> splits the change across 5 to 30 subagents, each in its own worktree. To drive it from your own script:

  1. Ask Claude to write the work list to a file: "list every Java class still using the old logging facade and save the paths to todo.txt".

  2. Loop over it:

    while read -r f; do
      claude -p "Switch $f from LegacyLog to SLF4J. Reply DONE or SKIPPED with a reason." \
        --allowedTools "Edit,Bash(./gradlew compileJava)" \
        --permission-mode dontAsk
    done < todo.txt
    
  3. Run on two or three files first, refine the prompt, then run the lot.

--allowedTools pre-approves exactly what the job needs and --permission-mode dontAsk denies anything else instead of waiting for an answer that will never come. You can also slot Claude into existing pipelines with claude -p "..." --output-format json | your_tool.

Auto mode for unattended work

claude --permission-mode auto -p "fix every lint error in packages/web"

The classifier blocks risky actions while routine work proceeds. If it keeps blocking in a -p run, Claude Code does not simply stop; permission modes explains the fallback and thresholds.

Add an adversarial review

The longer Claude works alone, the more an independent review matters. A reviewer subagent sees only the diff and your criteria, not the reasoning behind the change. For bugs, run the bundled /code-review skill. To check against a plan, write the prompt yourself:

use a subagent to review the idempotency diff against docs/specs/idempotency.md. confirm every requirement is implemented, each listed edge case has a test, and nothing outside scope changed. report gaps, not style opinions.

The findings come straight back to the implementing session, which can fix and re-review.

Note: A reviewer told to find gaps will nearly always find some. Chasing all of them leads to over-engineering. Ask it to report only problems affecting correctness or the stated requirements, and treat the rest as optional.

Failure patterns to recognise

PatternWhat it looks likeFix
The kitchen sinkOne task, then an unrelated question, then back again/clear between unrelated tasks
Correction spiralWrong, corrected, still wrong, corrected againAfter two failed corrections, /clear and write a better first prompt
The novel-length CLAUDE.mdRules ignored because they are lost in noisePrune hard; turn must-haves into hooks
Plausible but untestedLooks right, misses edge casesAlways give a check; if you cannot verify it, do not ship it
Endless exploration"Investigate X" reads hundreds of filesScope it tightly or hand it to a subagent

Build your own instincts

None of this is a rulebook. Sometimes a long, accumulated context is exactly right because you are deep in one hard problem. Sometimes skipping the plan is right because the task is exploratory. Sometimes a vague prompt is right because you want to see Claude's interpretation first.

Notice what works. When the output is great, note the prompt, the context and the mode. When it struggles, ask whether the context was noisy, the prompt vague, or the task too big for one pass. That intuition is worth more than any checklist.