- To let commands run safely without you approving each one, new terminal and VS Code sessions start in auto mode, where a classifier reviews anything risky before it runs.
- To keep your main conversation focused while independent work happens in parallel, Claude delegates to subagents and checks in only when it has to.
- To keep a long session going without you managing it, your conversation is compacted automatically before the context window fills.
- A deploy process that lives in someoneâs head
- A file that must never be read
- A check that has to pass before anything counts as done
- A budget you need to stay under
- Claude built something different from what you had in mind, or it has to rediscover the same fact at the start of every session. Itâs missing information it canât get from reading the repo. See Tell Claude what it canât see.
- Claude said it was done and it wasnât quite, usually because it had no way to check its own work. See Give Claude a check to run.
- Claude did something that must never happen in this repo, or skipped a step that must always happen. A prompt alone canât guarantee either of those. See Enforce the rules that canât have exceptions.
- Claude got it right, but it took more time, tokens, or permission prompts than the task was worth. See Change a default.
Setup for a whole team is on a separate page: Set up Claude Code for your organization.
Deterministic and non-deterministic instructions
Every instruction you give Claude Code is one of these:- Non-deterministic: you write the instruction, and Claude (the model) reads it. This can be your prompt,
CLAUDE.md, or a skill. The model then decides what to do with this information. It usually follows your commands, and current models are good at understanding your intent without much context, but thereâs no guarantee that itâll follow your instructions. It can still decide not to do things, or do other things. - Deterministic: you configure the instruction, and Claude Code (the harness) has to execute this. This can be a hook, a deny rule, or a managed setting. Claude Code applies this every time, no matter what the model decided to do.
Most of the time, you want Claude to decide. Almost every guideline has exceptions, and current models are good at reading the code in front of them and judging whether a guideline fits the situation. With the actual code in front of it, Claude is usually better placed to make that call than a rule you wrote in advance.
The deterministic kind is for when you want to make sure certain things always happen (or never happen), no matter what the model decides. This doesnât have to be anything dramatic. Auto mode already blocks the dramatic things, like a production deploy or a force push over someoneâs work. Itâs usually something specific to your project, and it can be as niche as you want it to be:
- Never edit the generated client in
src/gen/ - Always run the license-header script after creating a file
CLAUDE.md or in your prompt, and Claude would follow it nearly every time. But no matter how strongly you word it, whether Claude follows that line on a given turn is still Claudeâs call.
Tell Claude what it canât see
Claude starts every task by reading your code, and current models are very good at this. Theyâll find your file layout, your conventions, your test framework, and how existing components are built, usually faster than you could explain them. That means Claude already knows most of what you might be tempted to write down for it. What it canât find is the information that was never in the repo:- A decision your team made in a meeting
- A deploy process that lives in one personâs head
- The environment variable your integration tests need
- Could it find this by reading the code?
- Would it actually go and look?
Write a specific prompt
A specific prompt helps for the same reason, because it gives Claude information it doesnât already have. If you name the file, describe the symptom, and say what âfixedâ looks like up front, you usually save yourself a round of corrections later. The same goes for a preference between two reasonable approaches: Claude canât read that from the code, so if you care which one it picks, say so up front.
If you already have the thing Claude needs, hand it over instead of describing it:
- A file: type
@and the path to include the file contents in your message. - An image: paste the screenshot of the design or the error into the prompt.
- Command output: pipe it in from your shell with
cat error.log | claude -p "what's going on here".
think step by step or be thorough are ordinary prompt text rather than keywords. The main control for how hard Claude thinks is the effort level, which Change the model and effort covers. Wording like that can still nudge Claude within its effort setting, but it wonât lift it past it.
One phrase that does still help is be ambitious. Claude tends to read a request conservatively and build the smallest thing that satisfies it, since it canât see how much you were hoping for. When you want the fuller version, with the edge cases handled and the natural follow-on included, say so:
what would you improve in this file? is completely fine. Youâll correct a bit more as you go, and thatâs the trade-off.
Brainstorm with Claude first
When you donât know exactly what you want yet, you donât have to work it all out before you prompt. Ask Claude to interview you instead:SPEC.md exists, start a fresh session to build from it, so the build begins with a clean context and a written definition of done. Itâs also the file youâll point the reviewer at later, in Give Claude a check to run.
Keep CLAUDE.md short
Claude Code loadsCLAUDE.md into every session, which means every line in it takes a little of Claudeâs attention on every task, whether itâs relevant or not. Thatâs why the file works best when it only holds what Claude couldnât work out from the code itself:
- How to confirm work in this repo: the exact test, typecheck, and lint commands, and how to run a single test file
- Places where the code is misleading: an old pattern thatâs everywhere but that new code must not copy, or a directory that looks unused but isnât
- Decisions that arenât in the repo: which error helper the team settled on, how deploys work, what needs a migration review
- Anything youâve had to correct twice already
CLAUDE.md that passes that test stays short:
CLAUDE.md
/context to confirm that Claude loaded the file.
Notice that the typecheck line is only the command. Claude needs to know the command so it can check its own work as it goes. If you also want Claude Code to enforce a passing typecheck before Claude finishes, thatâs a job for a Stop hook. A line like Always typecheck before you finish in this file works most of the time, not every time.
You donât have to write the file from scratch:
/initgenerates a starting version from your codebase. From there the work is mostly removing lines. The memory guide recommends staying under 200./doctorsuggests cuts for anything Claude can already work out from the code./doctor prompt-auditflags instructions that were written for older models, point at files that no longer exist, or contradict each other.
CLAUDE.local.md instead of CLAUDE.md, and you add that file to .gitignore so it stays out of the repo.
If Claude keeps ignoring a line that is in
CLAUDE.md, adding IMPORTANT probably wonât fix it. Either the file has grown long enough that the line gets lost, or the line is a rule that canât have exceptions, in which case it belongs in a hook.Scope rules to one part of the codebase
If a rule only matters in one part of the codebase, put it in.claude/rules/ with a paths: filter so it only loads when Claude is actually working there. For example, this .claude/rules/api.md loads for TypeScript files under src/api/:
.claude/rules/api.md
Put team procedures in skills
A more capable model knows more about engineering, but not how your team does a release, what your incident runbook says, or how you want API docs written. That kind of knowledge goes in a skill: a procedure or a piece of team knowledge saved at.claude/skills/<name>/SKILL.md.
Skills are also lighter on context than CLAUDE.md for this kind of thing. For a skill Claude can start on its own, it sees the name and description in every session, but only reads the full file when the task calls for it. A long release procedure sitting in a skill doesnât weigh on your unrelated bug fix the way it would in CLAUDE.md.
The
CLAUDE.md rule applies to skills too: only write down what Claude canât find on its own.disable-model-invocation: true. Claude then canât start the skill on its own, and it only runs when you type /release yourself. Saved as .claude/skills/release/SKILL.md, it could look like this:
.claude/skills/release/SKILL.md
Connect the tools Claude needs
Some of what Claude canât see lives in another system entirely, like your issue tracker or your error dashboard. If that system has a CLI, thatâs usually the easiest way in. Withgh installed and signed in, for example, Claude will open pull requests and read review comments without any explanation from you. For a CLI it hasnât seen before, pointing it at --help is enough.
For systems without a CLI, thereâs MCP. You add a server from your shell:
/mcp inside a session. Connected servers add their tool names and instructions to the context even when youâre not using them, so itâs worth turning off the ones you donât need there.
And if you work in a typed language, a code intelligence plugin lets Claude jump straight to a definition instead of reading through many files to find it.
Give Claude a check to run
Claude stops when the work looks done. If it has nothing to run that tells it whether the work actually is done, âlooks doneâ is all it has to go on. In practice that makes you the test suite, and every mistake sits there until you happen to notice it. If you give it something that comes back pass or fail, Claude can close that loop itself. It makes the change, runs the check, and if something broke it reads the output and fixes it before running the check again. The check can be almost anything, as long as Claude can read the result:- A test file
- A buildâs exit code
- A linter
- A script that diffs output against a fixture
- A browser screenshot next to the mockup
CLAUDE.md is the command that runs it.
How strict you make the check is up to you. The options go from Claude deciding for itself all the way to Claude Code enforcing it:
- In the prompt:
run the auth tests after, and keep going until they pass. Claude decides for itself when itâs satisfied. This works for any task, today, with no setup. - As a goal:
/goal all tests in tests/auth pass and lint is cleansets a condition that a separate model checks against the conversation after every turn, and Claude keeps going until itâs met. You rarely need this in the session yourself. It matters for long background runs, where Claude sometimes ends a turn with a progress summary while items are still open, and the goal sends it back. - As a Stop hook: a
Stophook runs your script whenever Claude tries to end its turn, and sends Claude back to work if the script exits with code 2. This one is enforced by Claude Code (the harness), so the turn doesnât end until the typecheck passes or the block limit is reached. Thereâs an example further down. - By someone who didnât write the code: in the terminal,
/code-reviewreviews the diff in a fresh subagent that never saw your conversation. It isnât swayed by the reasoning that produced the code.
Review against your spec
If youâd rather have the review check the work against your plan than hunt for bugs in general, write the review prompt yourself:Donât drop the
skip style part of that prompt. A reviewer thatâs asked to find problems will always find something. If you fix every finding, you end up with extra abstraction layers and tests for cases that canât happen.Enforce the check with a Stop hook
TheStop hook version of the typecheck rule is a few lines in .claude/settings.json. Exit code 2 is what blocks the stop. Whatever the command prints to stderr goes back to Claude as the reason it canât finish yet, which is why the compiler output is redirected there:
.claude/settings.json
tsc passes. If the hook blocks eight stops in a row with no tool call between them, Claude Code overrides the next block and ends the turn. To raise the cap, set CLAUDE_CODE_STOP_HOOK_BLOCK_CAP.
Enforce the rules that canât have exceptions
Take three rules you might have inCLAUDE.md today: Never read .env, Always run the formatter after editing, Don't touch the migrations folder. Claude will follow these almost every time. For the few where âalmostâ isnât good enough, move them out of CLAUDE.md and into configuration that Claude Code (the harness) applies itself. From then on, the outcome doesnât depend on what the model remembers or decides.
Enforce steps with hooks
Hooks run something of yours at fixed points in Claudeâs loop: before or after a tool call, when Claude tries to stop, when a session starts, and so on. That something can be:- A shell command (the usual case)
- A POST to an HTTP endpoint
- A tool call on one of your MCP servers
- A
promptoragenthook, which lets a model decide
prompt or agent hook asks another model to decide, so it isnât deterministic either. For real enforcement, use a command or http hook, and add onFailure: "block" if the action should also be stopped when the hook itself crashes or times out. For a hook that scans commits for secrets, say, youâd rather block the commit than let it through unscanned while the scanner is down.
Hereâs the formatter rule as a PostToolUse hook. It runs after every Edit or Write, and whether Claude remembers the rule no longer matters, because Claude isnât the one running it:
.claude/settings.json
PreToolUse hook that exits with code 2 for any path under migrations/. You donât have to write it yourself: write a hook that blocks edits to the migrations folder works as a prompt, and /hooks shows the result. Donât overdo it, though: a hook is for a rule with zero exceptions, and Prefer named exports has plenty, so that one stays in CLAUDE.md.
Limit access with permission rules and the sandbox
Permission rules decide what Claude is allowed to run, read, and fetch.deny rules hold in every permission mode, including auto and bypassPermissions, which is exactly why the .env rule belongs there:
.claude/settings.json
.env fails, through the Read tool and through cat .env alike.
Rules match tool calls, not intent, so itâs worth knowing where the edges are:
- The
Readrule does catchcat .env, because Claude Code recognizes the common file-reading commands. - It wonât catch a script that opens the file.
- A
WebFetchdeny rule for a domain does nothing aboutcurlto that same domain, unless the sandbox is on.
/sandbox in a session. It confines Claudeâs shell commands on macOS, Linux, and WSL2 and picks up your Read deny rules and WebFetch(domain:...) rules too, so for anything security-related you want both.
By default Claude can still ask to retry a blocked command outside the sandbox, and that request goes through the normal permission flow. Strict sandbox mode, in the /sandbox Overrides tab, turns that retry off.
Choose who a rule applies to
Where a rule lives decides who it applies to:.claude/settings.local.jsonand~/.claude/settings.jsonare yours alone. When you select Yes, and donât ask again for a command, Claude Code saves that rule to the local file..claude/settings.jsonand the hooks in it belong to the repo. Once you commit them, they apply to everyone who works in the repo. Its deny rules apply right away. Itsallowrules wait until each person accepts the trust dialog for that folder, and workspace trust also decides when its hooks start running on their machine.- Managed settings belong to the organization. They come from the admin console, MDM, or a
managed-settings.jsonfile, and no personal settings file can override them, which makes them the only place for a security teamâs policy. If you are the person who sets them, see Set up Claude Code for your organization.
Change a default
A new session already makes a handful of decisions for you:- Interactive terminal and VS Code sessions start in auto mode.
- It runs Claude Opus 5.5 at medium effort on most plans and providers.
- It delegates work to subagents when it sees a reason to.
- It compacts the conversation as it grows.
Change the permission mode
Both ends of the permission range have a cost:- Manual mode: you approve every edit and every command that isnât read-only yourself. Safe, but after the tenth prompt you start approving without reading, and nothing moves while youâre away from the keyboard.
bypassPermissions: approves everything your deny and ask rules donât cover, which only makes sense in a disposable container.
curl | bash- Production deploys and migrations
- Force pushes over other peopleâs work
- Sensitive data sent to external endpoints
- Actions that look driven by content Claude read rather than by you
/permissions, where you can retry it with a manual approval. After three blocks in a row (or twenty in total), auto mode pauses and goes back to asking you.
None of this replaces your deterministic controls, because it runs after them. Deny and ask rules and PreToolUse hooks apply before the classifier sees anything, so a deny rule blocks in auto mode exactly like it does everywhere else. The sandbox still confines the shell commands it wraps.
You can also say
don't push until I've reviewed in the conversation, and the classifier treats that as a block signal. Itâs still a model reading the transcript, and the sentence can get lost when the conversation compacts, so anything that matters belongs in a deny rule.autoMode.allow or describe your trusted infrastructure in the auto mode configuration. Itâs plain English rather than patterns, and /auto-mode-setup can draft the environment part for you from your project and recent sessions:
~/.claude/settings.json
Shift+Tab in the session cycles through the permission modes, Manual included, or start with claude --permission-mode manual from your shell. And if Manual then asks too often, /fewer-permission-prompts scans your recent transcripts for common read-only Bash and MCP calls and adds them to an allowlist in .claude/settings.json.
Change the model and effort
Effort is the main control for how long Claude thinks, and it replaces most of what people used to do with prompt wording. Claude Opus 5.5, Sonnet 5.5, and Haiku 5.5 default tomedium, which is plenty for everyday feature work with a clear scope. The times youâd move it, with /effort in the session:
- Raise it with
/effort highor/effort xhighwhen getting it right depends on cases that are quick to overlook. Think of a bug in code you didnât write, a flaky test, or a schema change where Claude has to find every reader of the old shape. Claude then checks more edge cases and verifies more of its work before answering, which is where the extra time and tokens go. - Lower it with
/effort lowwhen youâre going back and forth quickly and reviewing each result anyway: brainstorming, a first sketch, a rename across a few files. Claude gets you a starting point sooner, and since youâre steering every step, the extra deliberation wouldnât have changed much besides the wait. - Save
maxfor a hard problem you want Claude to work through without you, like hunting for a security vulnerability. On ordinary tasks it tends to overthink, so you pay more for an answer that may be no better thanhighwould have given you. - When only the next message needs it, like one tricky question in the middle of otherwise routine work, put
ultrathinkin that prompt instead of changing the setting.
/model fable, and Haiku is a good fit for subagents doing simple jobs. Model configuration has the full list per plan and provider.
Know what subagents cost
Claude delegates to subagents on its own:- Broad codebase searches go to the built-in Explore agent.
- Side tasks get forked while fork mode is on (the default).
- The subagents it starts run in the background by default, so your main conversation keeps moving.
- Running independent pieces of work at the same time, so the whole task finishes sooner
- Keeping long output, like a full test run or a wide search, out of your main conversation, where it would otherwise ride along for the rest of the session
- Getting a reviewer that hasnât seen how the code was written
- Giving a task fewer tools than the main session has, like a reviewer that can read but not edit
- Set
model: haikuin a subagentâs definition if its work is simple, like collecting the files that import a module or checking links in the docs. That kind of job doesnât need the bigger model, and Haiku costs a lot less per request. - Ask for short summaries back, so twenty results donât fill your context anyway.
- Check
/usageto see what share of your usage each subagent type takes, so you can tell which ones are earning their cost. - Give a custom subagent in
.claude/agents/onlytools: Read, Grep, Glob. Now itâs a reviewer that canât edit anything, and that limit is enforced by Claude Code rather than requested in a prompt.
.claude/agents/reviewer.md:
.claude/agents/reviewer.md
have the reviewer compare the rate limiter against SPEC.md and the gaps come back into your session, where Claude can fix them.
Keep cost and context down
With a 1M-token window on most current models and compaction near the top of it, youâll rarely run out of context. You can still pay for context you donât need, though. Every request sends the whole conversation, so a session thatâs collected three unrelated tasks re-reads all three on every turn of the fourth. Thatâs discounted while the cache is warm and full price once it expires./usage is the first place to look. On Pro, Max, Team, and Enterprise it breaks your usage down by skill, subagent, plugin, and MCP server. It also flags patterns like long context or frequent cache misses once one of them passes 10% of your usage. From there, the usual fixes:
/clearbetween unrelated tasks. It costs nothing, and it means the next task doesnât keep paying for the previous oneâs history./clear oauth-migrationnames the session youâre leaving, so you can come back to it later./compactwith a focus, like/compact keep the API changes and the test commands. On a long session/compactis itself a big request, since it reads the whole conversation to summarize it, and even more so once the cache has expired.- Keep an eye on background work: a
/loop, a goalâs check after every turn, and Claudeâs own subagents all keep sending requests while you arenât typing.
The prompt cache lasts about an hour on a subscription and five minutes on an API key, cloud provider, or usage credits. Subagents get five minutes unless you change it.On the one-hour cache, a session past about 200K tokens that sits idle is compacted shortly before the cache expires, so after lunch you continue from a summary. If you donât need the history at all, a fresh session still costs less.
Steer the session
No amount of configuration replaces watching the first minute and stepping in when Claude heads somewhere you didnât intend. There are only a few controls for that, and theyâre worth knowing by heart:Escstops Claude mid-action and keeps everything up to that point, so you can redirect without losing work./rewind, orEsctwice on an empty prompt, opens the rewind menu, where you roll the code, the conversation, or both back to an earlier prompt. That makes it low-risk to try the bolder approach first and rewind if it doesnât work out. The same menu can also summarize part of the conversation when it has gone stale./clearstarts over. If youâve corrected the same thing twice and itâs still wrong, a third correction mostly adds to a conversation that already contains two failed attempts for Claude to keep re-reading./clearplus one new prompt that folds in what you learned works better almost every time.
/btw answers a quick question without adding anything to the history. And for work that spans several days, /rename oauth-migration in the session names it, so that claude --resume oauth-migration from your shell picks it back up later, checkpoints included. claude --continue resumes the most recent one.
Let Claude run without you
Everything on this page matters a little more once youâre not around to catch mistakes. While youâre watching, Claude missing some piece of context isnât a big deal: you notice within a message or two and tell it. In a run you started before going to bed, nobody tells it, and you find out the next morning that it spent the whole night building on the wrong assumption. Before you leave a task running on its own, itâs worth going through these five questions with that specific task in mind:- Does it know what done looks like? A goal condition, a spec file, or a failing test it has to turn green.
- Can it check its own work? The test suite, a
Stophook, some kind of review step. - Whatâs it allowed to touch? Permission rules,
dontAsk, the sandbox, a worktree, the one branch it may push to. - What stops it?
--max-turns,--max-budget-usd, a spend limit. - Where does the result go, and who signs off? A PR, a comment, or a summary, and then a person approving the merge, the deploy, or anything else you canât take back.
Run Claude from a script
claude -p "prompt" runs once and exits, which is how Claude Code ends up in CI jobs, git hooks, and shell loops.
In a script youâll almost always want a few more flags:
--bareskips hooks, skills, plugins, MCP servers, andCLAUDE.mdfiles, the repoâs as well as the machineâs, so the run does the same thing wherever it runs. It also never touches your claude.ai login: auth comes fromANTHROPIC_API_KEY, anapiKeyHelperin the file you pass with--settings, or your cloud providerâs credentials.--append-system-prompt,--mcp-config, and--settingspass in whatever the run does need, explicitly.--allowedToolspre-approves its tools, and--permission-mode dontAskrefuses anything else that would have prompted.--output-format jsongives you a single result object to parse, andstream-jsonwith--verbosestreams events as they happen.
OK or FAIL, and a run that hits the turn limit exits with an error instead. Try it on three files first, see what goes wrong, fix the prompt, then run the rest.
Auto mode works with -p too if you pass --permission-mode auto. In a non-interactive run, a classifier block denies that one action and Claude carries on, and repeated blocks donât pause the run the way they do in a terminal. Read how the thresholds apply there before you rely on it.
Start runs on a schedule or an event
Once a run is going, Claude can handle the rest by itself. The one thing it canât do is decide to start, so something has to: you, a timer, or an event like a failed CI check or a new PR. Inside an open session thatâs/loop, which repeats a prompt on an interval:
/schedule sets up a cloud scheduled task that runs on a timer. It needs a claude.ai login rather than an API key. You can add a GitHub-event trigger by asking Claude, or an API trigger at claude.ai/code/routines.
Run sessions in parallel
When you have separate pieces of work going at once, give each its own checkout so the edits canât collide.claude -w feature-auth starts a session in a new worktree, the desktop app runs several of these side by side, and cloud sessions run them in the cloud instead of on your machine.
A worktree is a fresh checkout, which means gitignored files like .env arenât there and dependencies arenât installed. For the first, list the gitignored files you need in a .worktreeinclude at the repo root (same syntax as .gitignore) and Claude Code copies them into every worktree it creates:
.worktreeinclude
node_modules in there would mean a full copy per worktree. For large directories thereâs the worktree.symlinkDirectories setting, or keep the install command in CLAUDE.md so Claude runs it whenever it starts in a new checkout.
You rarely have to clean any of this up yourself:
- When you exit an unnamed worktree session, Claude Code removes the worktree if thereâs nothing in it. For a named session, or one with changes, it asks what to do.
- Subagent worktrees disappear when the subagent finishes without changes.
- Subagent and background-session worktrees that do get left behind are swept once theyâre older than
cleanupPeriodDaysand hold no work.
A
claude -p --worktree run is one you clean up yourself, since it exits without asking. Remove those with git worktree remove <path>, and if git refuses because the worktree is locked, git worktree unlock <path> first./batch migrate every handler to the v2 response helpers splits the work into 5 to 30 units and shows you the plan. Then it runs each unit in its own worktree and opens a PR for it. From your shell, claude agents (still a research preview) gives you one screen for everything running in the background on your machine.
A second session is also the easiest independent reviewer you can get. One session writes the rate limiter, another reviews @src/middleware/rateLimiter.ts without having watched it being written, and you paste the findings back into the first. Same idea as /code-review, with you carrying the messages.
What you can stop doing
Every one of these was good advice when it was written. Most were workarounds for something the model couldnât reliably do yet, and the models have since caught up. If a few are still habits, hereâs why itâs safe to drop them.
If any other advice on this page ever starts to feel like busywork, thatâs probably a sign it belongs in this table too.
Related resources
- How Claude Code works: the loop, the tools, and what loads at startup
- Explore the context window: what uses space in a session and when it loads
- Extend Claude Code: the choice between skills, hooks, MCP, subagents, and plugins
- Choose a permission mode and Configure permissions
- Manage costs effectively
- Run Claude Code programmatically and Automate work with cloud scheduled tasks
- For team leads and admins: Set up Claude Code for your organization