TellWorldAI World Archive
Ask中文

Home›Practice›Practice

Practice

Claude Code best practices

Defaults handle most work. When a project has rules the model cannot see, add them to configuration: tell Claude what it lacks, give it a check it can run, and enforce non-negotiable rules with hooks and permissions.

Who this is for and what you will take away

This guide suits people who have used Claude Code for a while and find that it sometimes builds the wrong thing, says a task is done when it is not, or spends more time and tokens than expected. After reading it you should be able to decide whether a piece of information belongs in CLAUDE.md, in a skill, or in a hook, and how to give Claude a check that decides right from wrong [1].

Separate what the model decides from what configuration enforces

The docs split instructions into two kinds. Non-deterministic instructions, such as your prompt, CLAUDE.md and skills, are read by the model, which decides how to apply them. Deterministic ones, such as hooks, deny rules and managed settings, are executed by Claude Code every time [1].

Most of the time the model should decide. When something must always happen, or must never happen, a line in CLAUDE.md is not enough. The docs say that if you keep adding emphasis to a line and Claude still misses it, the line probably belongs in a hook. A hook that only expresses a preference can be removed so the model can weigh the case itself [1].

Tell Claude what it cannot see

Claude reads your code at the start of each task, so it already knows the file layout, the conventions and the test framework. Before writing something down, ask whether Claude could find it by reading the code, and whether it would actually go and look. If both answers are yes, leave it out [1].

What belongs in the file is information that is not in the repo: a decision made in a meeting, a deploy process that lives in one person's head, or the environment variable integration tests need. The docs give this example of a short CLAUDE.md:

# Commands
- Install: pnpm install
- Run one test file: pnpm vitest run path/to/file.test.ts
- Typecheck: pnpm tsc --noEmit
# Conventions
- Use the error helpers in src/lib/errors.ts, never throw raw strings
- src/legacy/ is still live but don't copy its patterns into new code
# Gotchas
- Integration tests need DATABASE_URL set, see .env.example

CLAUDE.md is loaded into every session, so every line competes for attention on every task. /init generates a starting file from the codebase, and /doctor suggests cuts for content Claude can work out from the code. Personal preferences go in CLAUDE.local.md, which you add to .gitignore [1].

A rule that matters in only one part of the codebase can go in .claude/rules/ with a paths: filter, so it loads only when Claude works on matching files. A team procedure, such as a release, fits better as a skill saved at .claude/skills/<name>/SKILL.md. If the procedure has side effects, add disable-model-invocation: true so that Claude cannot start it on its own and it runs only when you type the command [1].

For systems that have a CLI, such as gh for GitHub, the CLI is the easiest connection. Otherwise use MCP, for example claude mcp add --transport http notion https://mcp.notion.com/mcp. Connected servers add their tool names to the context even when unused, so turn off the ones you do not need [1].

Give Claude a check it can run

Claude stops when the work looks done. Without something that returns pass or fail, "looks done" is all it has. The docs suggest giving it a test file, a build's exit code, a linter, a script that compares output with a fixture, or a browser screenshot next to a mockup. With a pass-or-fail result, Claude can make a change, run the check, read the output and try again [1].

Enforcement can be graded. You can ask in the prompt, for example "run the auth tests after, and keep going until they pass". You can set a /goal condition that a separate model checks after each turn. You can add a Stop hook. Or you can run /code-review, which reviews the diff in a fresh subagent that never saw the conversation [1].

Whatever you choose, ask Claude for evidence, meaning the command it ran and its output. "All tests pass" on its own says very little [1].

The docs' Stop hook is a single command in .claude/settings.json: pnpm tsc --noEmit 1>&2 || exit 2. When the script exits with code 2, Claude is sent back to work, and what the script prints to stderr is given to it as the reason it cannot finish. The turn therefore does not end until the typecheck passes [1].

Enforce non-negotiable rules with hooks and permissions

A hook runs your code at fixed points, such as before or after a tool call, when Claude tries to stop, or when a session starts. A hook can be a shell command, a POST to an HTTP endpoint, a call to an MCP tool, or a prompt or agent hook. The last two let a model decide, so they are not deterministic. For real enforcement, use a command or http hook [1].

The formatting rule becomes a PostToolUse hook with the matcher Edit|Write and the command f=$(jq -r '.tool_input.file_path') && npx prettier --write --ignore-unknown "$f". Formatting then no longer depends on Claude remembering the rule [1].

Permission rules back this up. A deny rule holds in every permission mode, including auto mode and bypassPermissions. The docs' example is "deny": ["Read(./.env)", "Read(./.env.local)", "Read(./secrets/**)"]. Rules match tool calls, not intent. A Read deny rule catches cat .env, but it does not stop a script that opens the file. A WebFetch deny rule for a domain does not stop curl to that domain unless the sandbox is on. To limit filesystem and network access at the operating-system level, turn on the sandbox with /sandbox [1].

Where a rule lives decides who it applies to. .claude/settings.local.json and ~/.claude/settings.json apply to one person. .claude/settings.json and its hooks belong to the repo, and everyone who works in it is bound by them. Managed settings come from the organization, and no personal settings file can override them. Keep the enforced set small, since every hook and deny rule can misfire and needs upkeep [1].

Adjust defaults only when a task costs too much

Change the defaults when a task costs more time, tokens or interruptions than it should. The main levers are these [1].

On permissions, manual mode asks you to approve every edit and command. bypassPermissions approves whatever your deny and ask rules do not cover. Auto mode uses a classifier model to judge each action. It blocks things such as curl | bash, production deploys and migrations, and force pushes over other people's work. A blocked action appears under Recently blocked in /permissions, where you can approve it so Claude may retry. Deny and ask rules and PreToolUse hooks run before the classifier, so they still apply [1].

On effort, /effort high or /effort xhigh suits tricky problems where cases are easy to overlook, and /effort low suits quick back-and-forth. To deepen a single message, include ultrathink in it [1].

On subagents, a model: haiku setting suits simple work such as collecting files or checking links. A custom subagent with tools: Read, Grep, Glob is a reviewer that cannot edit, and Claude Code enforces that limit [1].

On cost, /usage shows where tokens went, broken down by skill, subagent, plugin and MCP server. Use /clear between unrelated tasks and /compact with a focus when a session grows [1].

Before you leave a task running

A mistake that you would catch in a minute while watching can run for hours unattended. The docs suggest answering five questions first: does Claude know what done looks like, can it check its own work, what is it allowed to touch, what stops it, and where does the result go and who signs off [1].

For scripts, claude -p runs once and exits. The docs recommend flags such as --bare, --allowedTools, --permission-mode dontAsk and --max-turns. A loop that migrates a list of files can call claude --bare -p "Migrate $file to the new logger API and commit. Reply OK or FAIL." --allowedTools "Read,Edit,Bash(git add *),Bash(git commit *)" --permission-mode dontAsk --max-turns 20 for each one. To run separate pieces of work in parallel without collisions, claude -w feature-auth starts a session in a new worktree. A worktree is a fresh checkout, so git-ignored files such as .env are missing unless you list them in .worktreeinclude [1].

Next steps

Start by trimming CLAUDE.md to what the code cannot tell Claude, give it a check command, and move rules that must always hold into hooks or permissions. Then adjust effort and subagents as needed. The official best-practices page has the full guidance [1].

Sources

  1. 1
    Best practices for Claude CodeAnthropic Claude Code docs

Cite this page: Claude Code best practices. TellWorld, https://www.tellworld.net/practice/practice-claude-code-best-practices. Updated 2026-11-14

Related news

View all