Claude Code Best Practices: A Practical Playbook for Everyday Developers

Here's a scene you might recognize. You open your terminal, type claude, describe a feature, and Claude writes some files. You skim them, push back on a couple of things, and eventually ship. You feel productive.

But if you're honest, you're using Claude Code like a faster Stack Overflow. You're still holding every thread, babysitting every decision, copy-pasting output between tabs. The tool is impressive. Your workflow with it is not.

The good news: the gap between "occasional user" and "power user" isn't talent or secret prompts. It's a handful of habits and a bit of setup. This post walks you through them — from the one idea that explains almost everything, to a concrete cheat sheet you can start using today.

It draws on Anthropic's official best-practices guide, their write-up on maximizing the value of your sessions, and lessons from experienced users. You don't need to memorize all of it. Pick two or three habits, make them automatic, and add more over time.

The One Idea That Explains Everything: Mind the Context Window#

Before any tactic, understand the single constraint everything else follows from.

Claude Code has a context window — a working memory that holds your entire conversation: every message, every file it reads, every command's output. It fills up faster than you'd think. A single debugging session or codebase exploration can consume tens of thousands of tokens.

Here's why that matters: model performance degrades as the context window fills. When it's getting full, Claude starts "forgetting" earlier instructions and making more mistakes. It's like a coworker three hours into a meeting with no notes — the important stuff from hour one has blurred.

So the master skill is context management. Almost every best practice below is really the same idea in a different outfit: spend your context on the actual task, not on noise. A short, relevant conversation beats a long, cluttered one every time.

Keep that frame in your head and the rest of this guide will feel obvious.

Part 1: Set Up Once, Benefit Forever#

A little upfront investment pays off on every future session. Do these once per project.

Write a CLAUDE.md — and Keep It Short#

CLAUDE.md is a special file Claude reads at the start of every conversation. It's your project's permanent memory: the commands, conventions, and gotchas Claude can't infer from the code alone.

The number one mistake beginners make is writing too much. It feels helpful to document everything — your stack, your style, every rule you can think of. But CLAUDE.md loads into context every single session, and a bloated file backfires. As the official guide puts it bluntly: if the file is too long, "Claude ignores half of it because important rules get lost in the noise." The docs give a concrete target: keep each CLAUDE.md under 200 lines. Longer files consume more context and reduce how reliably Claude follows them.

The fix isn't to delete rules you need — it's to only write the ones that actually change Claude's behavior. Before you add any line, apply this test:

The CLAUDE.md test: "Would Claude make a mistake on my codebase without this line?" If no, delete it.

Don't spend a line saying "use TypeScript" if Claude already always uses TypeScript. Do spend a line on the thing it keeps getting wrong — like reaching for CommonJS require in an ES-modules project. Document corrections, not confirmations.

The fastest way to start: run /init. Claude reads your project and generates a starter CLAUDE.md. Then delete most of it and keep only what's genuinely load-bearing.

What belongs in CLAUDE.md (and what doesn't)

✅ Include❌ Leave out
Commands Claude can't guess (build, single-test, typecheck)Anything Claude can figure out by reading the code
Code style rules that differ from the language defaultStandard conventions Claude already follows
Testing instructions and your preferred test runnerDetailed API docs — link to them instead
Repo etiquette (branch naming, PR conventions)Information that changes frequently
Non-obvious gotchas and required env vars"Write clean code" and other self-evident advice

Here's a compact, effective example:

# Code style
- Use ES modules (import/export), not CommonJS (require)
- Destructure imports when possible

# Workflow
- Typecheck when you finish a series of changes
- Prefer running a single test, not the whole suite, for speed

# Gotchas
- Auth middleware must run BEFORE rate limiting in route registration

One more tip: treat CLAUDE.md like code. Check it into git so your team benefits, review it when Claude misbehaves, and prune it regularly. If Claude keeps breaking a rule you did write, the file is probably too long and the rule is getting lost in the noise.

For workflows or domain knowledge that only matter sometimes, don't put them in CLAUDE.md at all — use a Skill (a SKILL.md in .claude/skills/). Skills load on demand when they're relevant, so they don't tax every conversation.

Cut the Permission Prompts#

Claude asks for approval before actions that could change your system — file writes, shell commands, and so on. That's safe, but after the tenth approval you're rubber-stamping instead of reviewing. Two settings cut the interruptions without giving up control:

  • Permission allowlists — pre-approve tools you trust so Claude stops asking about them. The easy way: pick "Yes, and don't ask again" at a prompt, and the rule is saved for that repo. Or run /permissions to edit rules directly. They use a Tool(specifier) format with * as a wildcard — Bash(npm run test:*) allows any npm run test... command, Bash(git commit *) allows commits. And it's safe: allowing Bash(npm test *) won't also permit npm test && rm -rf ., since each part of a chained command must match on its own.
  • Sandboxing — run /sandbox to turn on OS-level isolation for shell commands. Inside the sandbox, Claude can run most commands without stopping to ask, because the operating system enforces which files and network domains they can touch. Commands that can't run sandboxed fall back to the normal approval flow.

Let Claude Use Your CLI Tools#

Command-line tools are the most context-efficient way for Claude to reach the outside world. If you use GitHub, install the gh CLI — Claude already knows how to use it to open PRs, read issues, and check comments (and it avoids the rate limits that hit unauthenticated API calls). The same goes for aws, gcloud, and friends. Claude can even learn a tool it doesn't know: "Use foo-cli --help to learn this tool, then use it to do X."

Part 2: The Workflow That Produces Good Code#

Setup done. Now the day-to-day loop. Get this rhythm right and the quality of what Claude produces jumps.

Explore → Plan → Code → Commit#

The most common way to get bad code is to let Claude start coding immediately. It'll happily solve the wrong problem, fast. The fix is to separate thinking from doing.

EXPLORE  →  PLAN  →  CODE  →  COMMIT
(read)      (agree)   (build)   (ship)
  1. Explore. Enter plan mode by pressing Shift+Tab until the status bar shows ⏸ plan mode on. In plan mode Claude reads files and answers questions but makes no changes. Ask it to understand the relevant area first: "Read /src/auth and explain how we handle sessions and login."
  2. Plan. Ask for a concrete plan: "I want to add Google OAuth. What files change? What's the session flow? Write a plan." Review it. This is your cheapest chance to catch a wrong approach — before a single line is written.
  3. Code. Approve the plan (or press Shift+Tab to leave plan mode) and let Claude implement, checking its work against the plan.
  4. Commit. "Commit with a descriptive message and open a PR."

One caveat: planning has overhead, so skip it for small, clear changes. Fixing a typo, adding a log line, renaming a variable — just ask Claude to do it. A good rule of thumb: if you could describe the diff in one sentence, skip the plan. Reach for planning when you're unsure of the approach, the change spans multiple files, or you don't know the code well.

Be Specific — the Prompt Is Your Steering Wheel#

Claude can infer a lot, but it can't read your mind. The more precise your instructions, the fewer corrections you'll make. Notice how much better the "after" prompts are:

Instead of...Try...
"add tests for foo.py""write a test for foo.py covering the case where the user is logged out. avoid mocks."
"fix the login bug""users report login fails after session timeout. check token refresh in src/auth/. write a failing test that reproduces it, then fix it."
"add a calendar widget""look at how existing widgets work — HotDogWidget.php is a good example — and follow that pattern for a new calendar widget."
"why is this API so weird?""look through this file's git history and summarize how its API came to be."

The pattern in every "after": name the file, describe the scenario, point to an example, and say what "done" looks like. And you can hand Claude rich input directly — reference files with @ (Claude reads them before responding), paste or drag in a screenshot, give a URL to docs, or pipe data in with cat error.log | claude.

(Vague prompts still have a place — when you're exploring, "what would you improve in this file?" can surface things you'd never have thought to ask.)

Give Claude a Way to Verify Its Work#

This is the single highest-leverage habit in the entire guide, so slow down here.

Claude stops when the work looks done. Without a way to check, "looks done" is the only signal it has — which means you become the verification loop, catching every mistake by hand. Give Claude something that returns a clear pass or fail, and the loop closes on its own: Claude does the work, runs the check, reads the result, and keeps iterating until it passes.

A "check" is anything that returns a signal Claude can read:

  • a test suite ("run the tests after implementing"),
  • a build or linter (a non-zero exit code is a signal),
  • a screenshot compared against a design ("take a screenshot of the result and list the differences from this mockup, then fix them").

Two habits make this pay off. First, put the check in the prompt: "write the function, then run the tests and fix any failures" in one message. Second, ask Claude to show the evidence — the test output, the command it ran, the screenshot — rather than just asserting "done." Reviewing evidence is faster than re-running the check yourself, and it works even for sessions you weren't watching.

If you take one thing from this post, take this: if you can't verify it, don't ship it.

For Bigger Features, Let Claude Interview You#

When a feature is fuzzy in your own head, don't write a long prompt and hope. Turn the tables and have Claude ask you the questions:

I want to build [brief description]. Interview me in detail using the
AskUserQuestion tool. Ask about implementation, UI/UX, edge cases, and
tradeoffs. Don't ask obvious questions — dig into the hard parts I might
not have considered. When we've covered everything, write a complete
spec to SPEC.md.

Claude will surface decisions you hadn't thought about. When the spec is done, start a fresh session to build it — the new session has clean context focused entirely on implementation, plus a written spec to work from. Time spent making the spec precise pays back far more than time spent watching the implementation.

Part 3: Manage the Session Like a Pro#

Remember the master constraint. These are the habits that keep your context clean so Claude stays sharp.

/clear Between Unrelated Tasks#

The most useful command you're probably underusing. When you finish one task and move to something unrelated, run /clear. It wipes the conversation but keeps your setup (tools, permissions, CLAUDE.md). Carrying task A's context into task B just pollutes the window and slows Claude down.

/compact When One Task Runs Long#

If a single task genuinely needs a long conversation, /compact summarizes the history — preserving key code, decisions, and file states while freeing space. You can even guide it: /compact Focus on the API changes. A nice detail from Anthropic's session guide: compacting is much cheaper before you step away than after, because it works off the still-warm cache. So compact before lunch, not after.

Course-Correct Early — and Rewind When Needed#

Tight feedback loops beat long ones. The moment Claude drifts off track, redirect it:

  • Esc stops Claude mid-action while preserving context, so you can steer.
  • "Undo that" has Claude revert its last changes.
  • Esc Esc or /rewind opens the rewind menu. Every prompt is a checkpoint — you can restore the conversation, the code, or both, to any earlier point.

Because you can always rewind, you can be bold: tell Claude to try a risky approach, and if it doesn't pan out, rewind and try another. (One caveat: checkpoints only track changes made through Claude's file-editing tools, not shell commands — so it's not a replacement for git.)

Here's the meta-rule: if you've corrected Claude more than twice on the same issue, stop. Your context is now cluttered with failed attempts. Run /clear and start fresh with a sharper prompt that bakes in what you just learned. A clean session with a better prompt almost always beats a long session full of corrections.

Use Subagents to Keep Investigation Out of Your Main Context#

When Claude researches your codebase, it reads lots of files — and every one lands in your context window. Subagents solve this. A subagent runs in its own separate context, does the messy reading, and reports back only a concise summary. Your main conversation stays clean and focused on building.

Use subagents to investigate how our auth system handles token refresh,
and whether we have existing OAuth utilities I should reuse.

They're perfect for any job that generates a lot of throwaway output — trawling a log file, mapping an unfamiliar module, or (as we'll see) reviewing a diff.

Learn to Spot the Failure Patterns#

Most bad sessions are one of a few recognizable shapes. Catch them early:

The trapWhat it looks likeThe fix
Kitchen-sink sessionOne task, then an unrelated question, then back — context full of junk/clear between unrelated tasks
Correcting on repeatYou correct, it's still wrong, you correct againAfter two failed tries, /clear and write a better prompt
Over-stuffed CLAUDE.mdClaude ignores half your rulesRuthlessly prune; move must-happen rules into hooks
Trust-then-verify gapPlausible code that misses edge casesAlways give a check — tests, script, screenshot
Infinite exploration"Investigate X" → 200 files read, context goneScope it narrowly, or use a subagent

Part 4: Level Up — Intermediate Moves#

Comfortable with the basics? These are the patterns that separate steady users from the people whose output looks almost unfair. Add them one at a time.

A Cheat Sheet of Commands Worth Knowing#

You don't need all of these on day one, but knowing they exist means you'll reach for the right one when the moment comes.

Commands to keep in your back pocket

CommandWhat it does
/initGenerate a starter CLAUDE.md from your project (then prune it)
/clearWipe the conversation, keep your setup — use between tasks
/compactSummarize a long conversation to free up context
/rewindRestore conversation and/or code to an earlier checkpoint
/contextSee what's loaded (system prompt, CLAUDE.md, MCP tools) before you type
/modelSwitch models for the task at hand
/code-reviewReview your current diff for bugs in a fresh subagent
/doctorDiagnose your install (API key, Node version, config, permissions)
/helpList every available command — your safety net

A small money-saving note from Anthropic's session guide: /model and effort settings are baked into the prompt cache, so switching them mid-conversation forces an expensive re-read. Set them at the start of a session (or right after /clear) when it's cheap.

Hooks: Make Some Things Non-Negotiable#

CLAUDE.md is advisory — Claude usually follows it, but it's a suggestion. Hooks are deterministic. They're scripts that run automatically at specific points in Claude's workflow, whether Claude "wants" them to or not, and they run outside Claude's reasoning loop (so they cost no tokens and don't interrupt its thinking).

Use hooks for things that must happen every time, with zero exceptions. A few high-value examples:

  • Auto-format on save. A PostToolUse hook that runs your formatter (prettier, gofmt, …) after every file write — so formatting is never something you have to ask for.
  • Block dangerous commands. A PreToolUse hook that intercepts things like rm -rf or a force-push and requires explicit confirmation.
  • Make "done" mean done. This is the best one. A Stop hook fires when Claude signals a task is complete, and runs a verification script as a gate — your test suite, a check that expected files exist, an API call. Until the check passes, the hook blocks the turn from ending, so Claude keeps working. This is what catches the classic "Claude said done, but two of three handlers have empty error handling" bug — automatically, especially in longer unattended runs.

You don't have to hand-write these. Ask Claude: "Write a hook that runs eslint after every file edit." Then browse what's configured with /hooks.

The Two-Claude Review Pattern#

This is one of the highest-leverage tricks there is, and it's simple. The Claude that wrote the code is biased toward it — it made the tradeoffs and took the shortcuts. So have a fresh Claude review it.

The cleanest version uses a subagent so the feedback comes straight back into your session:

Use a subagent to review the changes in the last commit against PLAN.md.
Check every requirement is implemented, the edge cases have tests, and
nothing outside the task's scope changed. Report gaps, not style nits.

Because the reviewer sees only the diff and your criteria — not the reasoning that produced it — it evaluates the result honestly. (Claude Code even ships a /code-review skill that does exactly this for correctness.) One caution: a reviewer told to find gaps will always find some. Tell it to flag only things that affect correctness or your stated requirements, or you'll drown in over-engineering.

MCP: Connect Claude to Your Real Tools#

MCP (Model Context Protocol) servers let Claude reach beyond your files — into GitHub, your database, Figma, monitoring dashboards, and more, as native tools instead of copy-paste. Add one with a single command:

claude mcp add --transport http notion https://mcp.notion.com/mcp

Once connected, you can say things like "query the users table to understand the schema before writing the migration." One rule matters above all: least privilege — read-only by default. For most tasks Claude needs to read your database, not write to it. Give write access sparingly, and never point it at production without a very good reason.

Skill vs. MCP, quickly: use a Skill to give Claude a workflow or knowledge ("here's how we deploy"); use MCP for live data or actions ("what's the current state of the database"). When in doubt, prefer a skill — you can read and audit it; an MCP server is more of a black box.

A Few More Power Moves#

  • Turn up the reasoning for hard problems. Set a higher reasoning effort with /effort at the start of a session for genuinely hard, ambiguous design work — it can surface constraints you'd have missed — and keep it low for routine edits. (Many users also swear by dropping the word ultrathink into a prompt as a natural-language nudge for deeper thinking.)
  • Pick the right model for the job. Use a stronger model for ambiguous, multi-file architecture work and a lighter, faster one for routine edits and quick lookups. You don't need the biggest model for everything.
  • Run more than one Claude. For unrelated workstreams, run parallel sessions — ideally in separate git worktrees so their edits never collide. Experienced users describe having "dozens of Claudes running at all times," each on its own branch and task.

The Real Shift: From Prompting to Designing a System#

Step back and notice the pattern in Part 4. The recurring move isn't "write a cleverer prompt." It's put the constraint in configuration, not in conversation.

Beginners re-type the rules every session: "only read, don't modify," "focus on the internal package," "use our error conventions." Power users encode those constraints once — a tight CLAUDE.md, a subagent whose tools are scoped so it physically cannot write files, a hook that guarantees a check runs — and then they never think about them again. The prompt-crafting approach depends on how carefully you worded things today. The configured approach is consistent in a way prompting never is.

That's the whole mindset in one sentence: stop treating Claude Code like a chat window, and start treating it like a system you configure. The investment compounds — every hook, every scoped subagent, every pruned CLAUDE.md line keeps paying off on every future session.

You don't have to do it all at once. Here's a gentle first week:

DayOne small habit
1Run /init, then delete most of it — keep CLAUDE.md under ~50 lines
2Practice /clear between unrelated tasks
3Add a verification step to your prompts ("run the tests and fix failures")
4Try Explore → Plan → Code on your next multi-file change
5Add one PostToolUse hook that runs your linter
6Do a two-Claude review: have a fresh session review your last commit
7Connect one MCP server (GitHub is a great first one)

Conclusion#

None of this requires being a better prompter. It requires a few good habits and a little setup:

  • Mind the context window — it's the resource everything else protects. Spend it on the task.
  • Give Claude a way to verify its work, and make it show the evidence.
  • Put constraints in configCLAUDE.md, hooks, scoped subagents — not in every prompt.
  • Start small. A tight CLAUDE.md, a habit of /clear, and one verification step will do more for you than twenty clever prompts.

The tools to run a genuinely disciplined AI-assisted workflow already ship with Claude Code. Most people just never find them. Now you have. Pick two habits from this post, make them automatic this week, and add more as you go — that compounding is exactly what separates the occasional user from the person everyone asks for advice.