ES

Claude Code best practices, to move fast without losing quality

Leo G.11 minLeer en español

A precision lathe machining a metal rod, close up.
A precision lathe machining a metal rod, close up.

Claude Code can write an entire function in ten seconds. That’s not the problem. The problem is that “fast” and “good” are different axes: you can finish a task extremely fast and end up with code nobody understands a month from now, yourself included. Moving fast with an agent and staying a good programmer aren’t contradictory, but they don’t happen on their own either. They depend on a handful of concrete habits.

This isn’t a list of prompt tricks. It’s what changes once you stop treating Claude Code like a chat that answers questions and start treating it like a program you have to direct: what to configure once, what to ask for on each task, and what to check before calling something done.

Give it a CLAUDE.md, don’t repeat the rules every time

CLAUDE.md is a file Claude reads on its own, at the start of every conversation. It’s where you put what it can’t guess by reading the code: your project’s commands, conventions that deviate from the standard, how to run the tests.

# Code style
- ES modules (import/export), not CommonJS (require)
- Destructure imports when possible (e.g. import { foo } from 'bar')

# Workflow
- Run the typecheck after a series of code changes
- Prefer running a single test, not the whole suite, for speed

The temptation is to write a huge one with everything you can think of. That’s exactly what not to do: a bloated CLAUDE.md makes Claude ignore half of it, because the important rules get lost among the ones that aren’t. For every line, ask: would removing this cause Claude to make a mistake? If not, cut it.

Goes in Doesn’t go in
Shell commands Claude can’t guess Anything already clear from reading the code
Style rules that differ from the language’s standard Standard conventions Claude already knows
How to run the tests, and with which runner Detailed API docs (link to them instead)
Architectural decisions specific to the project A file-by-file description of the project

Run /init to have Claude draft a first version from your project, and /context to confirm it loaded. Check it into version control: the file gets more useful over time, as the team adds what it learns to it.

Don’t let it jump straight to coding

Letting Claude go straight from request to code often produces code that solves the wrong problem. Separating “understand” from “write” is the difference between a task you correct three times and one that comes out right the first time.

Explore, plan, implement, commit 01 Explore reads, changes nothing 02 Plan writes it, you review it 03 Implement codes and runs the tests 04 Commit message, PR
Every non-trivial task goes through these four stages. A one-line task — a typo fix, a rename — doesn't need it.

Explore: Shift+Tab until the status bar shows “plan mode on”, or start the session with claude --permission-mode plan. Claude reads files and answers questions, without touching anything:

read /src/auth and understand how we handle sessions and login.
also look at how we manage environment variables for secrets.

Plan: ask for the plan, and you can edit it directly with Ctrl+G before Claude moves on.

I want to add Google login. What files need to change?
What's the session flow? Write a plan.

Implement: exit plan mode (by approving, or with Shift+Tab again) and let it code, checking against its own plan.

Commit: a descriptive message and a PR, not a “misc changes” commit.

Planning isn’t free: for a typo, a log line, or renaming a variable, ask for it directly. It’s worth planning when you’re unsure of the approach, the change touches several files, or you don’t know that part of the code well. If you could describe the diff in one sentence, skip the plan.

Be specific, and give it something to verify against

Two habits that go together: ask for things precisely, and give it a way to confirm it did them right without you having to check every line yourself.

Before After
“add tests for foo.py” “write a test for foo.py covering the case where the user is logged out. no mocks.”
“fix the login bug” “users report login fails after the session expires. check the flow in src/auth/, especially token refresh. write a test that reproduces the issue, then fix it”
“make the dashboard look better” “[paste a screenshot] implement this design. take a screenshot of the result and compare it to the original. list the differences and fix them”

The general rule: name the file, the scenario, and what counts as “done”. Claude infers intent, but it doesn’t read minds.

The second habit is giving it a way to verify that doesn’t depend on you: a test that runs, a build that compiles, a linter, a screenshot to compare against a design. Without that, “looks done” is the only signal it has, and you become the only quality check — every mistake waits for you to notice it. With a check that returns pass/fail, Claude runs the check, reads the result, and keeps going on its own until it passes.

Ask it to show the evidence — the test output, the command it ran and what it returned — instead of just asserting it’s done. Reviewing evidence is faster than re-running the verification yourself, and it works even for sessions you weren’t watching.

The tools worth keeping active

Each one solves a different problem. You don’t need all of them from day one, but it’s worth knowing which exists for which case:

  • CLI tools for the external services you use (gh, aws, gcloud) — Claude already knows how to use them to create issues, open PRs, read logs. Without the GitHub CLI, for example, it still works through the API but hits rate limits faster.
  • MCP servers to connect external tools — a database, Figma, Notion — that Claude can query directly. We already wrote about the protocol behind this.
  • Hooks for things that must happen every time, no exceptions. Unlike an instruction in CLAUDE.md, which is a suggestion, a hook is deterministic: it runs your script at an exact point in the workflow. “Write a hook that runs eslint after every edit” is a request Claude can handle on its own.
  • Skills for domain knowledge or repeatable workflows — your API’s conventions, how your team builds a component. They load only when needed, without taking up context the rest of the time. We already wrote how to build one step by step.
  • Subagents for isolated research or a fresh-eyes review. They run in their own context, so they don’t clutter your main conversation with files that only needed reading once.
---
name: security-reviewer
description: Reviews code for security vulnerabilities
tools: Read, Grep, Glob, Bash
model: opus
---
You are a senior security engineer. Review code for:
- Injection vulnerabilities (SQL, XSS, command injection)
- Authentication and authorization flaws
- Secrets or credentials in code
- Insecure data handling

Provide specific line references and suggested fixes.

Keep the session clean

Context is the resource that runs out fastest, and performance drops as it fills up. A couple of habits are enough:

  • /clear between unrelated tasks. If you start one task, then ask for something unrelated, then go back to the first one, the context ends up full of information that’s useless for either.
  • Correct it the moment you notice it’s off track, not after three attempts. Esc stops it mid-action without losing context. If you’ve already corrected the same thing twice, /clear and start over with a more precise request that includes what you learned: a clean context with a better prompt beats a long session full of accumulated corrections almost every time.
  • /rewind (or Esc twice) to go back to an earlier point in the conversation or the code, if something went wrong and you’d rather redo it differently than keep correcting.

We already wrote about the commands for this in detail.

Before calling something done: a fresh-eyes review

The longer Claude worked unattended, the more an independent check matters before you count it as finished. A subagent starting in a fresh context sees only the diff and the criteria you gave it, not the reasoning that produced it — so it judges the result on its own terms, not because it “sounds convincing.”

use a subagent to review the rate limiter diff against PLAN.md.
Check that every requirement is implemented, the edge cases have
tests, and nothing outside the task's scope changed. Report gaps,
not style preferences.

The /code-review command does exactly this for a general review: it runs in a separate subagent and hands you the findings back in the same session, without copying anything between windows. We already wrote about how to thoroughly review code an AI wrote.

One warning: a reviewer you asked to find gaps will almost always find some, even when the work is solid — that’s what you asked it to do. Chasing every finding ends in over-engineering: extra layers of abstraction, defensive code for cases that can’t happen. Tell the reviewer to flag only what affects correctness or the stated requirements, and treat the rest as optional.

Common mistakes, and how to fix them

  • The kitchen-sink session. You start with one task, ask for something unrelated, go back to the first. Fix: /clear between tasks.
  • Correcting in a loop. Claude gets it wrong, you correct it, still wrong, you correct again. Fix: after two failed corrections, /clear and a better initial prompt.
  • The bloated CLAUDE.md. If it’s too long, Claude ignores half of it because the important rules get lost in the noise. Fix: prune ruthlessly. If Claude already does something right without the instruction, delete it or turn it into a hook.
  • Trusting without verifying. The code looks reasonable but doesn’t cover the edge cases. Fix: always verify — tests, a script, a screenshot. If you can’t verify it, don’t ship it.
  • Infinite exploration. You ask it to “investigate” something without scoping it, and it ends up reading hundreds of files. Fix: scope the investigation, or hand it to a subagent so it doesn’t eat your main context.

Working as a team, at scale

Everything above is enough for working solo. For this to work at a company, with more than one person and more than one task running at once, there are three more things:

  • Parallel sessions, each in its own git worktree: changes that don’t collide with each other because each session works in its own isolated copy of the repository.

  • Non-interactive mode, to integrate into CI or a pre-commit hook:

    claude -p "explain what failed in this build" --output-format json

    The json format returns a single object with the result, ready for a script to parse instead of a person reading it.

  • Splitting the work across several sessions for large migrations: generate the list of files to change, then have a script loop over that list invoking claude -p once per file, with the allowed tools explicitly scoped — it matters when it’s running unattended.

    for file in $(cat files.txt); do
      claude -p "Migrate $file from Python 2 to Python 3. Return OK or FAIL." \
        --allowedTools "Edit,Bash(git commit *)"
    done

None of this replaces regular code review. The difference is that now part of that review can also be done by a subagent, before the change ever reaches a person.

Comments