I used to think Claude Code best practices were a matter of taste. Plan mode or not. Long CLAUDE.md or short. Pick what suits you, move on.
Then Anthropic scored roughly 400k sessions from over 235k users against hard evidence of success. Tests passing, commits landing, users confirming they got what they asked for. Taste turned out to be measurable. In this article, I’ll walk through what separated the sessions that worked from the ones that didn’t.
The gap had nothing to do with the model. It was behaviour.
And the study didn’t define expertise by job title or years of experience. It read three things off the transcript:
One thing to note before we get into them: expertise here is task-specific. A senior engineer asking their first Rust question is a beginner at Rust. An accountant who’s never written Python, but who tells Claude exactly which reconciliation rules to enforce and catches the edge case it fumbles at month end, is an expert at that task. All ten of the largest occupation groups landed within seven points of software engineers.
The study found that in novice sessions, each prompt set off about five Claude actions and roughly 600 words of output. In expert sessions, each prompt set off about twelve actions and 3,200 words. More than twice the work and five times the output, from the same tool.
The difference is not prompt length. It is whether the prompt contains the things Claude cannot infer: which file, which scenario, what counts as done, and what pattern to follow.
| Instead of | Say this |
|---|---|
| add tests for foo.py | write a test for foo.py covering the case where the user is logged out. avoid mocks. |
| why does ExecutionFactory have such a weird api? | look through ExecutionFactory’s git history and summarise how its api came to be |
| add a calendar widget | look at how existing widgets work on the home page. HotDogWidget.php is a good example. follow that pattern for a calendar widget with month select and year pagination. no new libraries. |
| fix the login bug | users report login fails after session timeout. check src/auth/, especially token refresh. write a failing test that reproduces it, then fix it. |
Notice what the right-hand column has in common. Each one names a location, a scenario, and a definition of done. None of them is longer than two sentences of real information.
This is the habit I picked up latest and regret most. Rather than telling Claude where something lives, give it the thing directly:
# Reference a file inline, Claude reads it before answering
> explain the token refresh logic in @src/auth/session.ts
# Pipe data straight in, works on files outside the project
cat error.log | claude -p "group these errors by root cause"
# Paste or drag an image directly into the prompt
> [screenshot] implement this design
You can also give Claude URLs for API docs and let it fetch what it needs itself. Use /permissions to allowlist domains you hit often so you are not approving the same fetch repeatedly.
A precision habit that is easy to miss: the tools available to Claude shape how precisely it can act. CLI tools are the most context-efficient way to reach an external service, because the output comes back compact and Claude already knows the syntax.
If you use GitHub, install the gh CLI. Claude will use it to open issues, create pull requests, and read comments. Without it, Claude falls back to the GitHub API, where unauthenticated requests hit rate limits. The same applies to aws, gcloud, and sentry-cli.
It also learns tools it has never seen. This prompt shape works surprisingly well:
Use 'foo-cli-tool --help' to learn about foo tool, then use it to
solve A, B, C.
For services with no good CLI, MCP servers are the answer. Our guide to connecting MCP servers with Claude covers the setup for both Claude Desktop and Claude Code.
This one felt strange the first time and is now how I start every feature bigger than a day of work. Instead of writing a long spec yourself, make Claude extract it from you:
I want to build [brief description]. Interview me in detail using
the AskUserQuestion tool.
Ask about technical implementation, UI/UX, edge cases, concerns, and
tradeoffs. Don't ask obvious questions, dig into the hard parts I
might not have considered.
Keep interviewing until we've covered everything, then write a
complete spec to SPEC.md.
It surfaces the decisions you’d otherwise hit halfway through implementation. Once the spec is done, start a fresh session to build it, so the implementation has clean context and a written document to work against.
The best specs name the files and interfaces involved, state what’s out of scope, and end with an end-to-end check that proves the feature works. Time spent sharpening the spec pays back more than time spent watching the build.
Try this now: Take the next feature on your list. Paste the interview prompt above with a one-line description. Answer honestly, including the questions you don’t have answers to yet. That gap is the actual work.
This is the habit that pays back most, and the one I see skipped most.
Claude stops when the work looks done. If there is no check it can run, then “looks done” is the only signal available, and you become the verification loop. Every mistake waits for you to notice it.
Give Claude something that returns pass or fail and the loop closes on its own. Claude does the work, runs the check, reads the result, and iterates until it passes. A test suite, a build exit code, a linter, a script that diffs output against a fixture, a browser screenshot compared to a design. Anything that produces a signal it can read.
# Weak: no way to know when it is done
> implement a function that validates email addresses
# Strong: the check is in the prompt
> write a validateEmail function. test cases: [email protected] is true,
'invalid' is false, '[email protected]' is false. run the tests after
implementing.
Once a check exists, you choose how strictly it stops Claude from declaring victory. Each level trades a bit of setup for a bit less of your attention:
| Level | How it works | Setup cost |
|---|---|---|
| In one prompt | Ask Claude to run the check and iterate in the same message | None, works today |
| Across a session | Set the check as a /goal condition. An evaluator re-checks after every turn and Claude keeps going until it holds | Low |
| As a hard gate | A Stop hook runs your check as a script and blocks the turn from ending until it passes | Medium, one script |
| Second opinion | A verification subagent or dynamic workflow has a fresh model try to refute the result | Medium |
Worth knowing about Stop hooks: Claude Code overrides the hook and ends the turn after 8 consecutive blocks. It will not loop forever if your check can never pass.
The prompt version works on any task right now. The /goal and Stop hook versions are what let an unattended run finish correctly while you are somewhere else. That is the real payoff.
Related habit that costs nothing: tell Claude to show the test output, the command it ran and what came back, or a screenshot of the result. Reading evidence is faster than re-running the verification yourself, and it is the only way to review a session you were not watching.
The longer Claude works without you, the more an independent check matters before you call it done. A reviewer running in a fresh subagent context sees only the diff and the criteria you give it, not the reasoning that produced the change. So it judges the result on its own terms.
Use a subagent to review the rate limiter diff against PLAN.md.
Check that every requirement is implemented, the listed edge cases
have tests, and nothing outside the task's scope changed.
Report gaps, not style preferences.
Because the reviewer is a subagent, findings come back into the same session, so Claude can fix them and re-review without you copying text between windows. There is also a bundled /code-review skill that reviews the current diff for bugs in a fresh subagent if you just want a correctness pass.
A trap to know about: a reviewer asked to find gaps will usually report some, even when the work is sound, because that is the job you gave it. Chasing every finding leads to over-engineering, extra abstraction, and tests for cases that cannot happen. Tell the reviewer to flag only gaps affecting correctness or your stated requirements, and treat the rest as optional.
The third signal the classifier looked for was direction of correction. In weaker sessions, Claude spends its time correcting the user’s misunderstanding of their own codebase. In stronger ones, the user catches Claude early and redirects.
The study found something blunt about what happens when this goes wrong. Among sessions that hit real trouble, 19% of novice-rated ones were abandoned outright with zero lines of code written, against 5 to 7% for everyone else. The gap is not in hitting problems. It is in recovering from them.
| Action | What it does |
|---|---|
| Esc | Stop Claude mid-action. Context is preserved so you can redirect. |
| Esc Esc or /rewind | Open the rewind menu. Restore conversation, code, or both. |
| “undo that” | Have Claude revert its own changes. |
| /clear | Reset context entirely between unrelated tasks. |
This is the rule that changed my sessions the most, and it is counterintuitive.
If you have corrected Claude more than twice on the same issue in one session, stop correcting. The context is now full of failed approaches, and every further attempt is reasoning against that noise. Run /clear and start fresh with a better prompt that includes what you just learned.
Try this now: Next time you are on your third correction of the same problem, resist the fourth. Copy what you have learned into a note, run /clear, and write one specific prompt that rules out the approaches that failed. Compare how that goes.
Nearly every best practice traces back to one constraint: the context window fills fast and output quality drops as it fills. Every message, every file Claude reads, every command output goes in there. One debugging session can burn tens of thousands of tokens.
When the window gets full, Claude starts forgetting earlier instructions and making more mistakes. This is the resource to manage.
| Command | When to use it |
|---|---|
| /clear | Between unrelated tasks. Cheapest and most underused. |
| /compact <instructions> | When you need history but want it condensed. Give direction: /compact Focus on the API changes |
| /context | To see what is actually loaded and what it costs |
| /btw | Side questions. The answer appears in a dismissible overlay and never enters history. |
| Esc Esc then Summarize | Condense only part of the conversation, from or up to a chosen checkpoint |
You can also tell Claude how to compact. Putting a line like “when compacting, always preserve the full list of modified files and any test commands” in CLAUDE.md means the details you rely on survive summarisation.
Since context is the constraint, subagents are one of the strongest tools available. When Claude explores a codebase it reads a lot of files, and all of that lands in your context. A subagent explores in its own separate window and reports back a summary:
Use subagents to investigate how our authentication system handles
token refresh, and whether we have existing OAuth utilities I
should reuse.
You get the finding without the hundred files. This is also the fix for the pattern where you ask Claude to “look into” something unscoped and it quietly consumes your whole window.
Explore, plan, implement, commit. Four phases, and the value is in keeping them separate. Letting Claude go straight to code is how you get a well-built solution to the wrong problem.
claude --permission-mode plan
> read /src/auth and understand how we handle sessions and login.
also look at how we manage environment variables for secrets.
> I want to add Google OAuth. What files need to change?
What's the session flow? Create a plan.
In plan mode Claude reads and answers but changes nothing. When the plan appears, press Ctrl+G to open it in your editor and change it directly before Claude acts on it. That single keystroke is the difference between reviewing a plan and actually owning it.
> implement the OAuth flow from your plan. write tests for the
callback handler, run the test suite and fix any failures.
> commit with a descriptive message and open a PR
Plan mode has real overhead and it is not always worth it. The test I use now: if I could describe the diff in one sentence, I skip the plan. Typos, log lines, renaming a variable. Just ask for it.
Planning earns its cost when you are unsure of the approach, when the change touches several files, or when you do not know the code being modified well. That is it.
These are the failure patterns worth recognising early, because each one has a specific fix and the symptoms all look like “Claude is being unhelpful today”.
| Pattern | What it looks like | Fix |
|---|---|---|
| Kitchen sink session | You start one task, ask something unrelated, then return to the first. Context is full of noise. | /clear between unrelated tasks |
| Correcting in circles | Wrong, corrected, still wrong, corrected again. Context is polluted with failed attempts. | After two failed corrections, /clear and rewrite the prompt |
| Over-specified CLAUDE.md | The file got long, so Claude ignores half of it because real rules are buried in noise. | Prune hard. If Claude already does it right without the rule, delete the rule or make it a hook. |
| Trust-then-verify gap | A plausible implementation that does not handle edge cases. | Always provide verification. If you cannot verify it, do not ship it. |
| Infinite exploration | You ask Claude to investigate without scoping it. It reads hundreds of files and fills the window. | Scope it narrowly, or delegate to a subagent |
The CLAUDE.md one is worth a second look because the symptom is misleading. If Claude keeps doing something you have an explicit rule against, the instinct is to add emphasis or repeat the rule. Usually the file is just too long and the rule is getting lost. Treat CLAUDE.md like code: review it when things break, prune it regularly, and test changes by watching whether behaviour actually shifts.
The test for every line is one question: would removing this cause Claude to make mistakes? If not, cut it. For domain knowledge that only matters sometimes, use a skill instead so it loads on demand rather than in every conversation. Claude Skills Explained covers building those.
Everything above assumes one human, one Claude, one conversation. Two patterns are worth knowing once you are past that.
Fresh context makes for better code review, because Claude is not biased toward code it just wrote. Run two sessions: one implements, one reviews with no knowledge of the implementation reasoning.
The same shape works for tests. Have one session write the tests, then another write code to pass them, with neither seeing the other’s reasoning.
For large migrations, distribute the work across many separate invocations rather than one long session:
# 1. Have Claude generate the task list first
# 2. Then loop, one invocation per file
for file in $(cat files.txt); do
claude -p "Migrate $file from React to Vue. Return OK or FAIL." \
--allowedTools "Edit,Bash(git commit *)"
done
Test on two or three files first, fix your prompt based on what goes wrong, then run the full set. The –allowedTools flag matters here because nobody is watching each invocation.
Coding agents make a coding background less relevant to shipping working software. They reward understanding the problem instead.
Most of the gain came from novice to intermediate, not intermediate to expert. A working grasp of your domain captures nearly all of it.
Which is why none of this reads like advanced technique:
The constraint was never your model or your plan tier. It’s how clearly you state what you want, what you’re willing to verify, and how fast you spot a wrong answer.
Everything in this article traces to two sources: Anthropic’s research on agentic coding and returns to expertise for the data, and the official Claude Code best practices documentation for the patterns. Both are worth reading in full.
A. Give Claude a check it can run. Put the test cases, the build command, or the comparison criteria in the prompt and ask it to run them and iterate. It converts you from the verification loop into the person reviewing evidence, and it is the difference between a session you have to watch and one you can walk away from.
A. The data says no. Across sessions that produced code, all ten of the largest occupation groups landed within seven points of software engineers on verified success. Management occupations scored slightly above them. What predicted success was task-specific domain expertise, meaning you understand the problem well enough to specify it precisely and spot a wrong answer.
A. Use /clear when the next task is unrelated to the last one, since you lose nothing you need. Use /compact when you are continuing the same work but the history has grown heavy. Give /compact instructions about what to preserve, for example /compact Focus on the API changes and the test commands.