CLI v2.1.299 20 chapters 23,808 words About 60 min read

Claude Code Complete Guide: From MCP and Hooks to Workflows and Enterprise Deployment

A continuously updated Claude Code reference: installation, MCP, CLAUDE.md, permissions, Hooks, Skills, Subagents, cost control, Sessions and Checkpoints, Plugins, models and effort, Worktrees, automation and CI, Workflows, platforms, settings, and enterprise deployment. Facts are verified against the official documentation.

Author:
Steven Chang
Type:
AI Dev Tools
Tags:
MCP, Hooks, Skills, Workflows, Config in Practice
Last updated:
November 5, 2026

What This Document Is

This is a continuously updated reference document, not a one-time tutorial. Claude Code updates very fast: in the 30 days from mid-September to mid-October 2026 alone, npm published 25 stable versions.

So I want to use this document to keep a record of the update process, and it will also serve as my own notes.

The method for this page is:

  • The header always shows the corresponding CLI version and the last updated date. If the date looks too old, go check the official documentation.
  • Every chapter has its own anchor, so you can deep-link directly to a specific section.

Sources: Version release history for @anthropic-ai/claude-code on npm (queried 2026-10-15; counts stable releases from 2026-09-15 to 10-15, excluding prereleases)

60-Second Quick Start

If you just want to get Claude Code running and see its output, follow these steps in order:

# 1. Install (pick one)
curl -fsSL https://claude.ai/install.sh | bash   # macOS, Linux, WSL
irm https://claude.ai/install.ps1 | iex          # Windows PowerShell
brew install --cask claude-code                  # Homebrew
winget install Anthropic.ClaudeCode              # WinGet
npm install -g @anthropic-ai/claude-code         # npm (Node.js 22+)

# 2. Verify: prints a version followed by (Claude Code)
claude --version
claude doctor                                    # optional full check

# 3. Launch in your project (first run opens a browser to log in)
cd ~/your-project && claude

# 4. Ask your first question
> what does this project do?

# Switch accounts later, inside Claude Code
/login

Claude Code reads the project files it needs on its own, so you don’t have to paste the code into it by hand.

Before You Install, Check Two Things

  • System: macOS 13.0 or later, Windows 10 1809 or later (or Windows Server 2019 or later), Ubuntu 20.04 or later, Debian 10 or later, Alpine Linux 3.19 or later, and 4 GB or more of memory
  • Account: You need a Claude Pro, Max, Team, or Enterprise subscription, or a Claude Console account

Choose an Install Method

The first two are the officially recommended native installs, which update automatically in the background. Homebrew and WinGet do not update automatically; afterward you need to run brew upgrade claude-code or winget upgrade Anthropic.ClaudeCode yourself. If you install with npm, don’t add sudo.

If you install with Homebrew, claude-code uses the stable version, which is usually about a week behind the latest, but it skips versions with major problems. To get the latest version, install claude-code@latest instead.

After Launch, Know That Auto Mode Is the Default

Starting from v2.1.284, when the interactive session in the terminal and VS Code has no permission mode set, the default is Auto mode regardless of plan or platform. The classifier reviews actions for you, and most file edits and commands will no longer ask you. However, the first session right after installation may still be in Manual mode.

If you want to confirm actions yourself, you can press Shift+Tab to switch to Manual, but this only affects the current conversation. To always start in Manual mode, see the later chapter, Permission System and Auto Mode.

Next step

Pick a project to open and ask it “What is this project doing?” to confirm that it can read files and answer. Once that works smoothly, connect external tools.

Sources: Claude Code official documentation “Quickstart”, the System requirements section of “Advanced setup”, and the Install with npm sections (queried 2026-09-15); the “Which mode a session starts in” section of “Choose a permission mode” (queried 2026-09-15); the 2.1.284 entry in the Claude Code CHANGELOG (queried 2026-10-02)

What Is MCP (Model Context Protocol)

If you’ve used Claude Code to connect external tools, you’ve probably run into the same problem: MCP is moving so fast that a new one appears every few days, and you have no idea which one to install.

First, what MCP is. It works like a plug: someone else builds a tool and writes it to a unified spec, and you just plug it in, and Claude Code can read data and operate the tool through the same method. Before MCP, you had to wire up each tool yourself.

I’m fairly conservative about what I install, and I don’t install things from others at random. The MCPs that end up staying are ones I’ve reviewed or that many people recommend. Ones that look very new or that few people use, I watch for a while first.

So when should you connect an MCP? The official documentation gives a practical answer: when you find yourself repeatedly copying and pasting data from another tool into the conversation, such as an issue tracker or a monitoring dashboard, that’s when to connect one. Once connected, Claude can read and operate that system directly, so you don’t have to relay the information yourself.

The Two Sides of MCP: Host, Client, Server

For MCP to work, both sides need something. MCP has three roles:

RoleWhat it isIn Claude Code
HostThe application that uses AI and manages one or more clientsClaude Code itself
ClientThe component inside the host that keeps a connection to “one” serverEach server you connect adds a client
ServerThe program that provides data or functionsMCPs written by others, such as Notion and GitHub

In other words, if you have three MCPs attached in Claude Code, there are three separate connections behind them.

What You Get After Plugging In

A server can provide three kinds of things, and they’re used differently in Claude Code:

  1. Tools: actions that can be executed, such as querying a database, calling an API, or operating on files. Claude decides for itself when to call them.
  2. Resources: data sources that provide content, such as file contents or database records. Type @ in a prompt and you can reference them just like a file.
  3. Prompts: prewritten prompt templates that become commands in Claude Code. Type / to see them; the name format is /servername:promptname.

Next step

If you’re just starting out, I suggest doing only one thing: pick a tool you use every day, such as Notion or GitHub, connect its MCP first, make sure it works smoothly, and then add a second one. How to connect is covered in the next chapter.

Sources: Claude Code official documentation “Connect Claude Code to tools via MCP”, MCP official documentation “Architecture overview”

How to Configure MCP in Claude Code

If you set up an MCP and it disappears when you switch to another project, or a colleague clones the project and suddenly has your server too, the problem almost always comes from the same place: scope.

The same server can exist in three different places. Where it lives determines which projects it applies to and whether it is shared with others.

Three Scopes

ScopeWhere it’s storedWhere it appliesShared with the team?
local (default)~/.claude.json, recorded under this project’s pathOnly this projectNo
project.mcp.json in the project rootOnly this projectYes, tracked in git
user~/.claude.jsonAll your projectsNo

One point that’s easy to confuse: MCP’s local is called local, but it is not stored in the project’s .claude/settings.local.json. It is stored in ~/.claude.json in your home directory. The official documentation also points this out specifically.

When adding a server, use --scope to specify where it goes:

# local (default): only you, only this project
claude mcp add --transport http stripe https://mcp.stripe.com

# project: written to .mcp.json, shared with the team
claude mcp add --transport http shared-server --scope project https://example.com/mcp

# user: only you, across all your projects
claude mcp add --transport http hubspot --scope user https://mcp.hubspot.com/anthropic

MCP from Someone Else’s Project Won’t Run Directly

In the previous chapter I mentioned that I don’t install other people’s things at random. Claude Code is equally conservative about this.

A project-scoped server is written in .mcp.json, so it gets cloned along with the repo. For security reasons, the official setup asks you in interactive mode whether to approve these servers before using them.

A few details to note:

  • A cloned repo cannot approve itself. Even if the repo’s .claude/settings.json contains enableAllProjectMcpServers, it is ignored until you trust the folder, and the server stops at ”⏸ Pending approval”.
  • Non-interactive mode loads them directly. When you run claude -p, the Agent SDK, or in the cloud, there is no way to show a confirmation dialog, so project servers load directly. When running someone else’s project in these contexts, first check what is written in .mcp.json.
  • To choose again, run claude mcp reset-project-choices.

Four Connection Methods

MethodBest forHow to add
HTTPRemote services; the official recommended first choiceclaude mcp add --transport http <name> <url>
SSEOlder services that only offer SSE (deprecated)Also use --transport http; Claude Code tries HTTP first and automatically switches to SSE if that fails
stdioLocal programs running on your computer, custom scriptsclaude mcp add <name> -- <command> [arguments]
WebSocketRemote services that need to push events to Claude activelyCan only be written in .mcp.json or added with claude mcp add-json; OAuth is not supported

The rule is simple: use HTTP for remote services; use stdio for local programs; consider WebSocket only when the server needs to push things to you actively.

Don’t Put API Keys Directly in .mcp.json

.mcp.json is stored in git. Putting a key directly in it makes it public to everyone who can see the repo. Use environment variables instead:

{
  "mcpServers": {
    "api-server": {
      "type": "http",
      "url": "${API_BASE_URL:-https://api.example.com}/mcp",
      "headers": {
        "Authorization": "Bearer ${API_KEY}"
      }
    }
  }
}
  • ${VAR}: replaced with the value of the environment variable VAR
  • ${VAR:-default}: uses the variable if it is set, otherwise uses the default value
  • Can be used in the command, args, env, url, and headers fields

Remote Servers That Require Sign-In

Many cloud MCPs require authentication, and Claude Code supports OAuth 2.0. After adding the server, type /mcp in Claude Code and follow the browser steps to sign in. The token refreshes automatically after sign-in. To revoke authorization, clear it from the /mcp menu as well.

Starting from v2.1.288, if an MCP server requests additional OAuth scopes partway through a tool run, Claude Code will prompt you to re-authenticate, so you don’t have to clear it manually in /mcp and sign in again.

Next step

Use claude mcp add to connect an HTTP server, for example Notion:

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

Then type /mcp in Claude Code to see whether it connected. If it doesn’t connect, continue to the next chapter.

Sources: Claude Code official documentation “Connect Claude Code to tools via MCP”, sections Installing MCP servers, MCP installation scopes, Project server approvals and workspace trust, Environment variable expansion in .mcp.json, and Authenticate with remote MCP servers; Claude Code CHANGELOG, the 2.1.288 entry (queried 2026-10-03)

Common Troubleshooting

You’ve added the MCP, but Claude still says it can’t find the tools? Don’t delete and reinstall right away. Work through the steps below in order.

1. Check the Status First

claude mcp list shows a status next to each server:

StatusMeaningWhat to do
✔ ConnectedConnectedNo action needed
! Needs authenticationSign-in requiredType /mcp in Claude Code to complete sign-in
✘ Failed to connectCannot connectSee points 2 and 3 below
⏸ Pending approvalThe project’s server is not yet approvedRun claude in the project folder and press approve

Note: seeing ✘ means Claude Code could not connect to that server. It does not mean the list command itself is broken.

If several servers went down at once (for example, after switching networks), type /mcp reconnect all in the interactive screen to retry all servers that failed to connect or need authentication (starting from v2.1.284).

Starting from v2.1.287, Claude Code supports URL prompts from MCP servers under the 2025-11-25 protocol (for example, asking you to sign in). If a server stops connecting after an update, add "bareElicitationCapability": true to that server’s MCP settings. (This field is currently documented only in the official CHANGELOG, not yet in the MCP documentation.)

2. An Environment Variable Isn’t Set

If the configuration uses ${VAR}, but that variable is neither set nor given a default value, Claude Code still loads the server, but shows a warning in claude mcp list and /mcp telling you which variable is missing. In that case, ${VAR} is used literally as text, and the server obviously can’t connect.

So when you see the warning, set that variable, or change it to ${VAR:-default}.

3. Your Own stdio Server: stdout Is Polluted

If the server is a stdio program you wrote yourself, pay special attention: stdio passes MCP messages through standard input and standard output, and the MCP spec requires that the server print nothing to stdout other than MCP messages. A single extra console.log line can break the connection.

Send all debug messages to stderr; the spec allows logging to stderr.

Also, starting from v2.1.292, local (stdio) MCP servers negotiate protocol version 2026-07-28 by default, and Bedrock, Vertex, and Foundry do the same. If a server ignores the newer protocol check, the first connection will take a bit longer, and for the next 7 days Claude Code will remember this and connect using the old method directly. To fully revert to the old behavior, set the environment variable MCP_PROTOCOL_NEGOTIATION=legacy.

4. Does Loading Many MCPs Eat Up Context?

The impact is very small. Claude Code has tool search turned on by default: at the start, it loads only the tool names and the server descriptions, and the full tool definitions are loaded only when Claude actually needs them. The official documentation also explains that there is no fixed limit on the number of tools per server; the real constraint is the context window budget.

Starting from v2.1.296, the number of characters that MCP tool descriptions and server instructions can send into context in advance has increased from 2,048 to 4,096, so servers with long descriptions are less likely to be truncated.

To see how many tools each server provides, check the panel in /mcp.

Next step

When you run into a problem, first run claude mcp list once, and use the status to decide whether you need to sign in, approve, or set an environment variable.

Sources: Claude Code official documentation “Connect Claude Code to tools via MCP”, sections Server status, Configuration warnings, Tool availability, and Scale with MCP tool search; MCP specification “stdio transport”; Claude Code CHANGELOG, entries 2.1.284, 2.1.287 (queried 2026-10-02), 2.1.292 (queried 2026-10-07), and 2.1.296 (queried 2026-10-10)

CLAUDE.md and the Memory System

If you have to tell Claude “this project uses pnpm” or “the test command is this” again every time you open a new conversation, the problem is not that Claude has a poor memory. Every session starts from a brand-new context window.

To make it remember, Claude Code has two mechanisms. Think of it like onboarding a new hire: CLAUDE.md is the handover manual you write for it, which it reads once every day when it starts work; auto memory is its own working notes, where it records on its own the things you’ve corrected.

How the Two Memory Systems Differ

CLAUDE.mdauto memory
Who writes itYouClaude
ContentInstructions and rulesLearned preferences and patterns
ScopeProject, user, or the whole organizationOne per repo; shared across worktrees of the same repo
LoadingLoaded in every sessionThe first 200 lines or 25KB of MEMORY.md are loaded in every session

For Claude, both are context, not enforced settings. It will try its best to follow them, but there is no guarantee. For any action that must be blocked no matter how Claude judges it, use a PreToolUse hook.

Where CLAUDE.md Goes

CLAUDE.md can be placed in four locations, and the location determines who reads it:

LevelLocationGood forShared with
Managed policymacOS: /Library/Application Support/ClaudeCode/CLAUDE.md
Linux and WSL: /etc/claude-code/CLAUDE.md
Windows: C:\Program Files\ClaudeCode\CLAUDE.md
Company coding standards and security policies, deployed centrally by ITEveryone in the organization
User~/.claude/CLAUDE.mdYour personal preferences that apply to all projectsOnly you
Project./CLAUDE.md or ./.claude/CLAUDE.mdProject architecture, build commands, team conventionsShared with the team through version control
Local./CLAUDE.local.mdYour personal settings for this project, such as your own test URLOnly you; remember to add it to .gitignore

They Stack, They Don’t Override

Once you know where each file goes, the next question is: when several exist at the same time, whose instructions win?

The answer is that all of them are read together. None overrides the others:

  • Searching upward: Starting from the directory where you launch Claude Code, every CLAUDE.md and CLAUDE.local.md in each level above is loaded at startup.
  • From far to near: Files closer to where you launched are read later, so they come later in the order. Within the same level, CLAUDE.local.md comes after CLAUDE.md.
  • Subdirectories load later: CLAUDE.md files in subdirectories below are not loaded at the start. They are pulled in only when Claude reads a file in that subdirectory.

Because they are read together, if two files contain conflicting rules, Claude may pick one at random and follow it. So review them regularly and delete outdated or conflicting instructions.

Start with /init

If you don’t know where to begin, run /init in the project. Claude will analyze your code and generate a CLAUDE.md containing build commands, test methods, and project conventions. If a CLAUDE.md already exists, it will suggest improvements instead of overwriting it.

After generating it, add the things Claude can’t see from the code. For a more complete flow, you can first set CLAUDE_CODE_NEW_INIT=1; then /init will walk you through whether to set up CLAUDE.md, skills, or hooks step by step, and finally present a proposal for you to confirm before writing any files.

How to Write Them Effectively

CLAUDE.md is loaded in every session and consumes tokens, so how you write it directly affects whether Claude follows it. The official documentation gives several guidelines:

  • Length: Keep each file within 200 lines. The longer it is, the more context it takes up and the less reliably it is followed.
  • Structure: Use markdown headings and bullet lists to group content, rather than writing one long block.
  • Specific enough to verify:
✗ Vague✓ Specific
Keep code formatting neatUse 2-space indentation
Test after making changesRun npm test before committing
Organize files clearlyPut API handlers in src/api/handlers/

When should you add a line? The documentation gives a practical rule: when Claude makes the same mistake a second time, or when you notice yourself repeating a correction you already made in a previous conversation, write it down. Conversely, multi-step procedures, or rules that apply only to one part of the code, are better placed in a skill or in .claude/rules/.

Additional note: starting from v2.1.293, when Claude reads a file with cat, head, tail, sed -n, or grep on a single file via the Bash tool, it also loads the .claude/rules/ rules and subdirectory CLAUDE.md files that apply to that path. Previously, this only happened when using the Read tool.

Pull in Other Files with @

CLAUDE.md can reference other files with @path, and they are expanded and loaded together at startup:

See @README for project overview and @package.json for available npm commands for this project.

# Additional Instructions
- git workflow @docs/git-instructions.md
  • A relative path is relative to the file that contains the line, not to your working directory.
  • A referenced file can reference other files, up to four levels deep.
  • If you only want to mention a path without referencing it, wrap it in backticks, for example `@README`.
  • If a project’s CLAUDE.md references a file outside the working directory, an approval dialog appears the first time; if you decline, those references will not be loaded.
  • Splitting content into imports is only for better organization; it does not save context, because the referenced files are still loaded at startup.

AGENTS.md: Natively Supported Since v2.1.277

Many repos already have an AGENTS.md for agents such as Codex, Cursor, and Gemini. Previously Claude Code did not read it, so you could only reference it by writing @AGENTS.md on the first line of CLAUDE.md. Starting from v2.1.277, when a project has no CLAUDE.md (and no CLAUDE.local.md), Claude Code reads AGENTS.md directly.

Three things to clarify first:

  • It’s a replacement, not a merge. The logic is “read AGENTS.md only when there is no CLAUDE.md.” When both exist, the one read is still CLAUDE.md, and AGENTS.md is ignored. Note that CLAUDE.local.md counts too: if you add one for personal settings, AGENTS.md will no longer be read.
  • To read both, there are two approaches. One is to run /config and set Project instructions to claude-md-and-agents-md, so both are read. The other is to write @AGENTS.md on the first line of CLAUDE.md, so AGENTS.md is the only file you maintain and Claude Code-specific rules go below it. The latter does not depend on the Claude Code version or settings, so it is more stable across agents.
  • Starting from v2.1.281, cloud providers also support it. Amazon Bedrock, Google Vertex AI, Microsoft Foundry, LLM gateways, and sessions with telemetry turned off now also read AGENTS.md. If your team uses different Claude Code versions, older versions on these platforms still won’t use this mechanism, so keep CLAUDE.md in place for now.

To change which file is read, switch it under Project instructions in /config.

Auto Memory: Claude’s Own Notes

Auto memory is on by default. When you correct it, or confirm that an approach is right, it decides whether the information is worth remembering and saves it to ~/.claude/projects/<project>/memory/:

~/.claude/projects/<project>/memory/
├── MEMORY.md           # Index, one line per entry, loaded every session
├── user_role.md        # One memory
├── feedback_testing.md # One memory
└── ...
  • What it records: four types: user (your role and preferences), feedback (your corrections), project (ongoing work, deadlines, decisions), and reference (where to find external information). It does not record things that can be seen from the code or that CLAUDE.md already covers.
  • How it loads: At startup, only the first 200 lines or 25KB of MEMORY.md are read; other topic files are read only when needed.
  • Only on this computer: It is not synced to other computers or cloud environments.
  • How to turn it off: Toggle it in /memory, write "autoMemoryEnabled": false in the project settings, or set the environment variable CLAUDE_CODE_DISABLE_AUTO_MEMORY=1.

If you tell Claude “Remember: always use pnpm,” it will save that to auto memory. If you want it written into CLAUDE.md, say explicitly “Add this to CLAUDE.md.”

Check with /memory and /context

  • /memory: Lists user- and project-level files such as CLAUDE.md and CLAUDE.local.md. Select one to open it in your editor; files that don’t exist yet are created directly. You can also turn auto memory on or off here, open the auto memory folder, and see what it has actually recorded.
  • /context: Shows which files were actually loaded in this session, listed under Memory files. When Claude is not following CLAUDE.md, check here first to confirm the file was read.

Next step

If your project doesn’t have a CLAUDE.md yet, I suggest doing only one thing: run /init in the project root, open the generated file, delete anything you don’t understand or don’t need, and add one correction you repeat most often. The next time you start a new session, run /context to confirm it appears under Memory files.

Sources: Claude Code official documentation “How Claude remembers your project”, sections CLAUDE.md vs auto memory, CLAUDE.md files, Auto memory, View and edit with /memory, and Troubleshoot memory issues (queried 2026-09-15). The facts in the AGENTS.md section come from the 2.1.277 entry of the Claude Code CHANGELOG (queried 2026-09-19); the 2.1.281 entry (queried 2026-10-02) and the 2.1.293 entry (queried 2026-10-08) of the Claude Code CHANGELOG (cross-checked against the AGENTS.md section of “How Claude remembers your project” and updated on 2026-10-15.)

Permission System and Auto Mode

After using Claude Code for a while, you’ll probably end up at one of two extremes: it asks you about every single command, and you get tired of clicking approve; or you allow everything and worry that it will one day delete something it shouldn’t.

These two things are managed separately. Permission modes are like the security level of a building: they decide how strict the overall setting is. Permission rules are like an access list: they specify which doors are always open, which always require asking, and which can never be entered. Choose the mode first, then use rules to cover the specific things you care about.

Six Permission Modes

ModeActions allowed without askingGood for
default (Manual)Reading onlyWork where you want to review every action, or sensitive work
acceptEditsReading, editing files, plus common file commands such as mkdir, touch, mv, and cpReviewing all changes at once afterward with git diff
planReading; when auto mode is available, also commands approved by the classifierGetting a good understanding of the project before making changes
autoEverything, with background safety checksLong tasks where you don’t want constant interruptions
dontAskReading and pre-approved tools; anything that would ask is deniedEnvironments with no one watching, such as CI and scripts
bypassPermissionsEverythingOnly isolated containers and VMs

In the CLI, default is displayed as Manual. There is also one rule that applies in every mode: deny rules always block, even under bypassPermissions.

Switch with Shift+Tab

During a conversation, press Shift+Tab to cycle through the modes. Pressing it once from auto returns to default, then goes in order through default → acceptEdits → plan; if auto mode is available, it appears after plan, and then returns to default. The status bar shows the mode you switch to: ⏸ manual mode on, ⏵⏵ accept edits on, ⏸ plan mode on, or ⏵⏵ auto mode on.

Two modes are not part of this cycle: dontAsk can only be started with --permission-mode dontAsk; bypassPermissions appears in the cycle only if it is enabled at startup (for example, with --dangerously-skip-permissions). To start directly in a mode, pass it as an argument, for example claude --permission-mode plan.

How Auto Mode Works

Auto mode hands the decision of “whether to ask you” to another model (a classifier). Each action is handled in this order, and whichever rule matches first wins:

  1. If it matches the allow, ask, or deny rules you wrote, follow the rule directly
  2. Reading, and editing files within the working directory, is allowed directly (except writes to protected paths such as .git and .claude)
  3. Anything else is judged by the classifier
  4. If the classifier blocks it, Claude receives the reason and chooses a different approach on its own

Things the classifier blocks by default include: curl | bash style download-and-execute, sending sensitive data to external destinations, production deployments and migrations, force push, and git reset --hard. Things it allows by default include: file operations within the working directory, installing packages already declared in the lock file, read-only HTTP requests, and pushing to any branch of the repo you are working in. For the complete list, run claude auto-mode defaults.

A few limitations to know first:

  • Not guaranteed to be safe. The official position is: use it for tasks where you trust the overall direction, and do not use it to replace review of sensitive operations.
  • Overly broad allow rules are temporarily disabled. When entering auto mode, rules that effectively allow arbitrary programs, such as Bash(*) or Bash(python*), are removed, and they are restored when you leave auto mode. Narrow rules such as Bash(npm test) are not affected.
  • Saying “don’t push” in the conversation helps, but isn’t reliable. The classifier treats it as a signal to block, but it rereads the conversation log every time, so if context is compressed and that sentence is dropped, it’s gone. To be sure something is blocked, write it as a deny rule.
  • Repeated blocks fall back to manual. After 3 consecutive blocks, or 20 blocks cumulatively in one session, auto mode pauses and goes back to asking you. These numbers cannot be adjusted. Blocked actions are listed on the Recently denied tab of /permissions, and you can press r to approve and rerun them manually.
  • Model restrictions. On the Anthropic API and Claude Platform on AWS, you need Claude Opus 4.6 or later, Sonnet 4.6 or later, Haiku 5.5, or a Fable model. On Amazon Bedrock, Google Cloud Agent Platform, and Microsoft Foundry, only Sonnet 5 or later, Opus 4.7 or later, Haiku 5.5 (requires v2.1.293 or later), and Fable are supported. Sessions using other models start in Manual.
  • Organizations can turn it off. An administrator can set permissions.disableAutoMode to "disable" in managed settings, which removes auto from the Shift+Tab cycle. permissions.disableBypassPermissionsMode can likewise block bypassPermissions.
  • Reading files outside the working directory can be allowed just once. Starting from v2.1.284, this kind of prompt has an extra option, “Yes, but ask again next time”: this read goes through, but the next time a read outside the working directory comes up, it will still ask you.
  • Dangerous rm does not wait forever. Under --dangerously-skip-permissions and auto mode, when a dangerous rm is encountered, it waits 2 minutes. If no one answers, it is denied directly with a suggested rewrite, so sessions that no one is watching can keep running (starting from v2.1.281). To turn off this timeout, set CLAUDE_CODE_DISABLE_DANGEROUS_RM_TIMEOUT=1.

Does the Classifier Run Locally or on the Server

The classifier is itself a model call. Running it locally means every action that needs a decision costs one extra round of tokens, and that cost used to be charged to you.

Starting from v2.1.278, Claude API and Enterprise users, as well as Bedrock, Vertex, Foundry, and gateway users, use the server-side classifier by default, and this overhead is not billed. If it actually falls back to the billed local version, the screen shows a warning telling you so.

  • To switch back to the local classifier (Bedrock, Vertex, Foundry, and gateways only): set CLAUDE_CODE_AUTO_MODE_SERVER=0.
  • To check where this session runs: type /status and look at the Auto mode server row.

Three Other auto Mode Changes to Know

These were added gradually after v2.1.271, and you’ll run into them in practice:

  • Domains in sandbox mode are now reviewed per command. Bash, PowerShell, and Monitor have a new allowed_domains option: the hosts a command needs to connect to are reviewed together with that command, and are opened only for it, while other hosts are still denied. You no longer have to permanently allow an entire domain just for one curl.
  • ! commands in skills and slash commands are no longer handed to the classifier. They are judged by the permission rules of default mode instead; if there is no rule to judge them by, they become a tool call that you have to review. A !`git diff HEAD` you write in a skill is governed by permissions, not by the classifier.
  • Subagent results are treated with isolation. When a subagent reports back to the main conversation, it goes through a dedicated return call and is reviewed by the classifier. Starting from v2.1.278, the results are also labeled as “subagent output” and indented. The purpose is the same: text pulled back by a subagent cannot pass itself off as an instruction you gave.

Which Mode Claude Code Starts In

When you open a new session in the terminal, the mode is determined in this order:

  1. The startup arguments --permission-mode or --dangerously-skip-permissions
  2. permissions.defaultMode in the settings file
  3. The built-in default

Built-in default: starting from v2.1.284, interactive sessions in the terminal and the VS Code extension default to auto regardless of plan and platform (previously Enterprise, Console API key, and third-party platforms defaulted to default). claude -p and the Python Agent SDK also start in auto mode starting from v2.1.285 when using third-party platforms or with telemetry turned off; otherwise nothing changes. If organization policy withdraws the auto default, the session starts in default. Whatever you specify with --permission-mode still takes precedence. Also, the first session right after installing or upgrading may still be default.

One easy pitfall here: "auto" written in the project’s .claude/settings.json or .claude/settings.local.json does not take effect. It must be written in ~/.claude/settings.json. Conversely, if you want to always start in Manual, write {"permissions": {"defaultMode": "default"}} there.

How to Write allow, ask, and deny Rules

A rule has the format Tool or Tool(condition). The three lists mean: allow runs without asking, ask always prompts, and deny blocks directly.

The evaluation order is always deny → ask → allow; the first match decides the result, so a more precise rule won’t jump the queue. That means if you deny Bash(aws *), it will still be blocked even if you separately allow Bash(aws s3 ls).

{
  "permissions": {
    "allow": ["Bash(npm run *)", "Bash(git commit *)"],
    "deny": ["Bash(git push *)"]
  }
}

Common patterns:

RuleMatchesDoes not match
Bash(npm run build)npm run buildnpm run build --watch
Bash(npm run *)npm run build, npm run test --watchnpm install
Bash(ls *)ls -la, lslsof
Read(./.env)Reads .env in the current directory
WebFetch(domain:example.com)Fetches web pages from example.com
mcp__puppeteer__*All tools of the puppeteer MCP server

Three things to watch for when writing Bash rules:

  • Put * after the subcommand. Bash(git log *) only allows git log; Bash(git *) allows every git command.
  • Chained commands are checked separately. Bash(safe-cmd *) does not allow safe-cmd && other-cmd; every segment has to match.
  • Bash rules are not a security boundary. Bash(git push *) blocks git push origin main, but does not block git -C . push origin main. To truly block something, the official recommendation is to combine it with the sandbox or a PreToolUse hook.

Also be careful with path syntax for Read and Edit: a leading // denotes an absolute filesystem path, ~/ denotes your home directory, and a single leading / is relative to the location of the settings file. So /Users/alice/file is not an absolute path; write //Users/alice/file instead. Claude Code enforces the rules; the model is not the one choosing to follow them. Writing “don’t do X” in CLAUDE.md only influences what Claude decides to do; it does not actually block anything.

Which Settings File Holds Rules

Settings fileScopeNotes
managed settingsEntire organizationDeployed by administrators; no other level can override them
~/.claude/settings.jsonAll your projectsPersonal settings
.claude/settings.jsonThis project, shared with the team through gitAllow rules in it take effect only after you trust this folder
.claude/settings.local.jsonThis repo, only youWhen you choose “Yes, and don’t ask again” in a prompt, the rule is saved here

Wherever a rule is written, if any one level has a deny, the other levels cannot allow it. For example, if user settings allow something and project settings deny it, the result is blocked; the reverse also holds. To see which file each rule comes from, enter /permissions.

Next step

Open Claude Code and check which mode the status bar shows, then type /permissions to see which rules are already saved. Next, pick something you absolutely don’t want to happen, such as reading .env, and add Read(./.env) to the deny list in ~/.claude/settings.json. Write the deny rules first, then decide whether you feel comfortable using auto mode.

Sources: Claude Code official documentation “Choose a permission mode”, sections Available modes, Which mode a session starts in, Switch permission modes, and Eliminate permission prompts with auto mode; and “Configure permissions”, sections Manage permissions, Permission rule syntax, Tool-specific permission rules, Settings precedence, and Project allow rules and workspace trust (queried 2026-09-15). The facts about where the classifier runs, allowed_domains, ! commands, and subagent return handling come from the 2.1.271 and 2.1.278 entries of the Claude Code CHANGELOG (queried 2026-09-19); the 2.1.281, 2.1.284, and 2.1.285 entries of the Claude Code CHANGELOG (queried 2026-10-02) (cross-checked against the “Choose a permission mode” page for the auto mode model requirements and updated on 2026-10-15.)

Hooks: The Deterministic Layer

If you have written “run the formatter after editing files” or “do not touch .env” in CLAUDE.md, you have probably run into the same problem: you wrote it down, but there is no way to guarantee that Claude follows it every time.

Hooks solve this. They work like sensors installed on your workflow: you decide where to install one, for example “after Claude edits a file.” Whenever execution reaches that point, the shell command you wrote runs without fail. Claude does not have to remember it, and it does not depend on how Claude judges the situation at that moment.

Why “deterministic”

The official documentation states it directly: hooks make certain actions always happen, instead of leaving it up to the LLM to choose whether to do them. A rule written in CLAUDE.md is something Claude reads and then decides how to apply. A rule written as a hook is executed directly by Claude Code at fixed points in time, and it can even block a tool before it runs. So the rule of thumb is simple: things that should happen “every time” or are “never allowed” belong in a hook; things that depend on the situation stay in CLAUDE.md.

The three most common events

A hook is attached to an “event.” The official documentation lists more than thirty, but when you are starting out, you only need to know these three:

EventWhen it firesCan it block?Common uses
PreToolUseBefore a tool runsYes, cancels this call directlyBlocking dangerous commands, protecting files
PostToolUseAfter a tool succeedsNo, the tool has already finishedAutomatic formatting, writing logs
StopEvery time Claude finishes a reply (not only when the task is complete; pressing interrupt does not trigger it)Yes, makes Claude keep workingChecking whether the work was actually done

Writing the settings file

Hooks are written in the hooks section of a settings file, which has three levels: event → matcher (filter condition) → the command to run. Below is the official example of “automatically run Prettier after editing a file”:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

Claude Code passes the event data to your command as JSON through stdin, so here jq (installed on macOS with brew install jq) extracts the path of the file that was just edited and hands it to Prettier. As for where to put it: ~/.claude/settings.json applies to all of your projects; the project’s .claude/settings.json applies only to that project and can be committed to git to share with the team; if you do not want to share it, use .claude/settings.local.json. After setting it up, type /hooks to confirm the hook appears. This menu is view-only. To make changes, edit the JSON directly or ask Claude to change it for you.

matcher: fire only when needed

If you leave out the matcher (or write "" or "*"), the hook fires on every occurrence of the event. For PreToolUse and PostToolUse, the matcher compares against the tool name:

  • Only letters, digits, _, -, |, ,: exact match. Edit|Write matches only these two tools.
  • Contains other characters: treated as a regular expression, and not anchored at either end. Edit.* also matches NotebookEdit; for an exact match, write ^Edit$.
  • Case matters. If you mistype the case, the hook will not fire. Stop does not support a matcher, so it always runs.
  • Claude may also use Bash to modify files. Matching only Edit|Write will miss those cases.

How to block an action

Your command uses the exit code to tell Claude Code what to do next:

Exit codeMeaningEffect on PreToolUse
exit 0No objectionProceeds through the normal permission flow; this does not mean approval
exit 2BlockCancels the tool call; stderr is returned to Claude so it can try a different approach
Other (including exit 1)Non-blocking errorIf there is no valid JSON output, the action still runs; only a hook error notice appears

The most common mistake is the third row. In Unix convention, exit 1 means failure, but in hooks it does not block anything. To block, you must use exit 2. The same exit 2 behaves differently for other events: PostToolUse only shows stderr to Claude; Stop keeps Claude from stopping, and stderr becomes the reason it keeps working. For finer control, switch to exit 0 and print JSON to stdout. For example, in PreToolUse, returning "permissionDecision": "deny" (wrapped in hookSpecificOutput) rejects the call, and permissionDecisionReason tells Claude why. The official recommendation is to pick one approach per hook: either exit 2, or exit 0 with JSON.

Block when the hook itself fails: onFailure: "block" (since v2.1.295)

By default, if a hook fails to start, times out, or returns an unexpected exit code, the action still runs. If the hook is a safety check and you do not want it to “let things through when it breaks,” add "onFailure": "block" to the settings of a command-type or HTTP-type hook. When the hook cannot start, times out, or exits with an unexpected exit code, the action is blocked outright. When unset, the default is "continue", which means the action runs as usual. This setting has no effect on Stop, SubagentStop, TaskCompleted, TeammateIdle, or async hooks. When a PermissionRequest hook fails, the result is deny.

Full example: stop Claude from editing .env

First create .claude/hooks/protect-files.sh, then run chmod +x .claude/hooks/protect-files.sh to make it executable:

#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
FILE_PATH="${FILE_PATH//\\//}"
PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")
for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
  fi
done
exit 0

Next, register it as a PreToolUse hook in .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}

$CLAUDE_PROJECT_DIR is the project root directory at the start of this session. Using it means the script will not go missing if the working directory changes. Finally, ask Claude to add a comment line to .env. It should be blocked and receive the Blocked: message.

Security reminders

  • It has the full permissions of your account. Any file you can delete, the hook can delete too. Before adding a command to your settings, read and test it yourself.
  • A wrong path silently disables the protection. If the script cannot be found, that is only a non-blocking error, and the action still runs. A PreToolUse hook that is cancelled after timing out also fails to block. After setting it up, trigger it at least once to confirm it works.
  • Be careful with -p in someone else’s repo. In interactive mode, hooks do not run until you trust the folder; but claude -p or the SDK treats it as trusted directly. Before running, review the settings in .claude/, or turn hooks off with --settings '{"disableAllHooks": true}'.
  • Hooks can only tighten, never loosen. If PreToolUse returns deny, it blocks even in bypassPermissions mode; but returning allow cannot override a deny rule in settings.

Next step

If you are just starting out, do only one thing: paste the “automatically run Prettier after editing files” snippet into your project’s .claude/settings.json, type /hooks to confirm it appears, then ask Claude to edit a JS file and check whether the formatting was cleaned up automatically. Once that works, add the PreToolUse hook that blocks .env.

Sources: Claude Code official documentation, “Automate actions with hooks”, sections Auto-format code after edits, Block edits to protected files, How hooks work, Filter hooks with matchers, Configure hook location, and Limitations and troubleshooting; Hooks reference, sections Matcher patterns, Exit code 2, Exit code 2 behavior per event, Stop, and Security considerations (queried 2026-09-15); and Claude Code CHANGELOG, version 2.1.295 (queried 2026-10-09)

How Skills Work

If you have used Claude Code for a while, you have probably run into the same problem: the same checklist or the same deployment steps have to be pasted into every new conversation; or CLAUDE.md keeps growing until it is full of processes that are only needed some of the time.

Skills are the solution to this. A skill is like a manual on a bookshelf: Claude normally only sees the summary on the spine, and when a situation calls for it, Claude takes out the whole thing and follows it. You can also name one directly and ask Claude to open that particular manual.

The official documentation gives a practical rule: when you keep pasting the same instructions, checklists, or multi-step processes into the conversation, or a section of CLAUDE.md has turned from “facts” into “procedures,” it is time to write a skill.

How it differs from CLAUDE.md, slash commands, and subagents

  • CLAUDE.md: its content is always in the conversation. A skill normally holds only its description, and the full content loads when it is used, so long reference material costs almost nothing when it is not needed.
  • Slash commands (custom commands): these have been merged into skills. .claude/commands/deploy.md and .claude/skills/deploy/SKILL.md both create /deploy, and they work the same way. Old .claude/commands/ files still work. Skills add three things: a folder for supporting files, frontmatter that controls who can invoke them, and the ability for Claude to load them automatically when relevant. For new work, use skills.
  • Subagents: a skill runs in your current conversation by default, so it can see what was discussed earlier. Adding context: fork to the frontmatter makes it run in a new subagent instead. The contents of SKILL.md become that subagent’s task, but it cannot see your conversation history, so the instructions must stand on their own. In the other direction, a subagent can preload skills with the skills field to use them as reference material.

A minimal working example

The following skill summarizes uncommitted git changes and flags anything risky. First create the folder in the personal skills location, so it works in all of your projects:

mkdir -p ~/.claude/skills/summarize-changes

Save this as ~/.claude/skills/summarize-changes/SKILL.md:

---
description: Summarizes uncommitted changes and flags anything risky. Use when the user asks what changed, wants a commit message, or asks to review their diff.
---

## Current changes

!`git diff HEAD`

## Instructions

Summarize the changes above in two or three bullet points, then list any risks you notice such as missing error handling, hardcoded values, or tests that need updating. If the diff is empty, say there are no uncommitted changes.

For the line !`git diff HEAD`, Claude Code runs the command first and substitutes its output, so Claude receives your actual diff, not a guess.

Open a git project, change any file, and run claude. There are two ways to test: ask a question that matches the description, such as What did I change?, and let Claude load the skill on its own; or type /summarize-changes directly.

Structure of SKILL.md

A SKILL.md has two parts: the YAML frontmatter enclosed by --- at the top, which tells Claude when to use it; and the markdown below, which contains the instructions to follow when it runs. The frontmatter must begin on the first line of the file with ---, or the entire file will be treated as content.

All fields are optional, and the official documentation only recommends always writing a description. These are the more commonly used ones:

FieldPurpose
descriptionWhat it does and when to use it. Claude relies on this to decide whether to load the skill; if omitted, the first non-blank line of the content is used
disable-model-invocationSet to true: only you can invoke it with /name; Claude will not load it on its own
user-invocableSet to false: hidden from the / menu; only Claude can use it
allowed-toolsFor the turn in which this skill is invoked, the listed tools do not ask for permission again; it stops applying once you send your next message
context / agentcontext: fork runs it in a subagent; agent specifies which kind of subagent to use, and if omitted it is general-purpose
pathsGlob pattern; the skill loads automatically only when files matching the pattern are being worked on

The description decides whether Claude uses it automatically

In a normal conversation, the descriptions of all skills are loaded so Claude knows which ones are available; the full content is loaded only when a skill is invoked. This means that whether Claude uses a skill on its own depends only on its description, so how you write it directly determines whether the skill gets used:

  • Put the key purpose first. The description field, together with the when_to_use field that adds more trigger situations, is cut off in the list if it exceeds 1,536 characters. When many skills are installed, the list also has an overall budget, and the descriptions of the least-used skills are removed first.
  • Use the keywords people naturally say. If the skill does not trigger, first ask Claude What skills are available? to confirm it can see the skill, then adjust the description or rephrase your request.
  • If it triggers too often, make the description more specific, or add disable-model-invocation: true.

The two control fields differ as follows. For workflows with side effects, such as deployment or commits, the official recommendation is disable-model-invocation: true. You would not want Claude to decide the code looks ready and deploy it on its own.

FrontmatterYou can invokeClaude can invokeWhen it enters the conversation
(default)YesYesThe description is always present; full content loads when invoked
disable-model-invocation: trueYesNoThe description is not present; loads only when you invoke it
user-invocable: falseNoYesThe description is always present; full content loads when invoked

Where to put it

The location determines which sessions can load the skill:

ScopePathWhere it applies
Personal~/.claude/skills/<skill-name>/SKILL.mdAll of your projects on this computer
Project.claude/skills/<skill-name>/SKILL.mdThis repo; anyone on the team gets it when it is committed
Plugin<plugin>/skills/<skill-name>/SKILL.mdWherever the plugin is enabled; the name is /plugin-name:skill-name
  • When names collide, personal overrides project (and enterprise skills deployed by an organization override personal). Plugin skills have a prefix, so they do not clash with other names.
  • Personal skills do not follow you to the cloud. Cowork and cloud sessions do not read ~/.claude/skills/ on your computer.
  • The other direction does sync. Starting with v2.1.275, terminal sessions logged in with a claude.ai account sync in the skills and plugins you have enabled on your account. To turn this off, set "syncClaudeAiSkills": false in settings (the plugin switch is syncClaudeAiPlugins). Note that what gets synced is a copy: editing the files in that folder directly does not save them back to your account.
  • No restart needed after changes. Adding, editing, or deleting a skill in ~/.claude/skills/ or the project’s .claude/skills/ takes effect in the current session right away. Only the first creation of a top-level skills folder that did not previously exist requires restarting Claude Code.

How to invoke manually

Type / followed by the skill name. For personal and project skills, the command name comes from the folder name; the name in frontmatter only changes the display name. Any text after the command is passed into $ARGUMENTS. To take a single argument, use $0 or $1:

---
name: fix-issue
description: Fix a GitHub issue
disable-model-invocation: true
---

Fix GitHub issue $ARGUMENTS following our coding standards.

Running /fix-issue 123 gives Claude “Fix GitHub issue 123 following our coding standards.” If the content does not include any argument placeholder, Claude Code appends ARGUMENTS: <your input> at the end, so nothing is lost.

Real-world example: what a production skill looks like

The example above is a single file. To see what a skill in real use looks like, you can look at security-audit-skill, open-sourced by Cloudflare. It turns the coding agent into a security auditor, and it is the single-repo starting point of Cloudflare’s internal vulnerability discovery system.

It is worth studying because it illustrates several points from this chapter:

  • The description defines two modes. The same skill serves only as reference material when answering security questions, and runs the full six-stage process only when it is explicitly asked to “audit the entire codebase.” Loading the skill does not authorize it to take action; this boundary is written in the description and in the Operating modes at the start of the content.
  • Reference material is split across multiple files and read only when needed. SKILL.md is only 192 lines and holds the principles, terminology, and process overview. Ten domains, including memory safety, AI and LLMs, HTTP and authentication, supply chain, and cloud deployment, each have their own file, pointed to by SKILL.md. Files the audit target does not need are never loaded. Altogether it is about 1,778 lines, which does not normally take up context.
  • Folders can contain code. Besides markdown, it includes a JSON schema and two zero-dependency Node validation scripts. When the process reaches certain stages, it runs them to check whether the output findings.json and the coverage records have the correct format. A skill is not limited to instructions.
  • Subagent roles are built into the process. Finding vulnerabilities and verifying them are assigned to different agents, and the one doing verification is tasked with trying to overturn the previous agent’s conclusions. It describes the roles using neutral terms such as parent and Task tool, so it is not tied to Claude Code.

Install it with the Skills CLI, matching the two locations described in the “Where to put it” section above:

# project-level
npx skills add https://github.com/cloudflare/security-audit-skill --skill security-audit

# personal, all projects
npx skills add https://github.com/cloudflare/security-audit-skill --skill security-audit --global

It is licensed under MIT, so you can use its SKILL.md directly as a template to see how a production skill separates “when to use it” from “what to do when it runs.”

Next step

Do just one thing: find a set of instructions you paste into conversations most often, and follow the example above to create a personal skill in ~/.claude/skills/. First run it with /skill-name to confirm the content is correct, then open a new conversation and use a natural phrasing to see whether Claude loads it on its own. If it does not, go back and revise the description.

Sources: Claude Code official documentation, “Extend Claude with skills”, sections Create your first skill, Choose where skills load, Frontmatter reference, Control who invokes a skill, Pass arguments to skills, Edit a skill during a session, Run skills in a subagent, and Troubleshooting (queried 2026-09-15). The facts in the real-world example section come from the README and SKILL.md of cloudflare/security-audit-skill (queried 2026-09-19). The facts about claude.ai syncing come from version 2.1.275 in the Claude Code CHANGELOG (queried 2026-09-19)

Subagents and Parallelism

If you have had Claude Code run tests or go through a large batch of logs, you have probably run into the same problem: once the work is done, the conversation is clogged with output you will never look at again, and later answers start to slow down and get dull.

Subagents are the solution to this. Think of one as an assistant you send out on errands: you give it a job, it goes off to read files and run commands on its own, and it comes back with only a one-page summary. The raw material it went through stays with it and does not pile up on your desk.

Why this saves context in the main conversation

Each subagent has its own independent context window, its own system prompt, its own available tools, and its own permissions. When it starts work, it cannot see your earlier conversation, nor any files Claude has already read. What it receives is:

ContentDescription
System promptThe subagent’s own prompt, plus environment information such as the working directory; this is not Claude Code’s original system prompt
Task messageThe task description Claude wrote when delegating
CLAUDE.md, git statusLoaded the same way as in the main conversation (the built-in Explore and Plan are exceptions)
Preloaded skillsThe full text of the skills listed in the frontmatter skills field

Files read and output produced during the work stay in the subagent’s context; only the final result returns to the main conversation. So if a rule must be known to the subagent, such as “do not touch the vendor/ folder,” repeat it in the prompt when you delegate.

Built-in subagents

No setup is needed; Claude will send them out on its own when appropriate:

TypeToolsUsed for
ExploreRead-only; cannot Write or EditFinding files, searching code, understanding the codebase
PlanRead-only; cannot Write or EditIn plan mode, researching the codebase before proposing a plan
general-purposeAll tools available to subagentsTasks that need both exploration and modification, with dependent steps

To keep things fast and cheap, Explore and Plan skip CLAUDE.md and git status. They are also one-shot: they do not return an agent ID, so once they finish you cannot continue with them. For work that requires follow-up questions partway through, use general-purpose or a custom subagent.

Custom subagents: where to put them

A subagent is a Markdown file with YAML frontmatter. Where you put it determines who can use it; when names collide, the higher-priority one wins:

LocationScopePriority
Managed settingsThe entire organization1 (highest)
--agents CLI argumentThis session only2
.claude/agents/This project3
~/.claude/agents/All of your projects4
Plugin’s agents/ folderWherever the plugin is enabled5 (lowest)

Put project-specific subagents in .claude/agents/ and check them into version control so the whole team can use them; put the ones you use often personally in ~/.claude/agents/. Both folders are scanned recursively, but a subagent’s identity is determined only by its name field, regardless of which subfolder it is in.

What the file looks like

---
name: code-reviewer
description: Reviews code for quality and best practices
tools: Read, Glob, Grep
model: sonnet
---

You are a code reviewer. When invoked, analyze the code and provide
specific, actionable feedback on quality, security, and best practices.

The frontmatter holds the configuration, and the body below it is the subagent’s system prompt. Only name and description are required. Other commonly used fields:

FieldPurpose
descriptionClaude uses this to decide when to delegate; to have it delegate proactively, include “use proactively.” This text takes up context, so keep it short
toolsList of allowed tools; if omitted, all tools available to subagents are inherited
disallowedToolsTools to remove, for example Write, Edit
modelsonnet, opus, haiku, fable, a full model ID, or inherit (same as the main conversation)
memoryScope of cross-conversation memory: user, project, or local
isolationSet to worktree to work in a separate git worktree
autoCompactWindowMakes this subagent auto-compact its context earlier than the main conversation (since v2.1.296; also available in --agents definitions)

/agents no longer opens a wizard; ask Claude to create one

Before v2.1.197, /agents opened an interactive creation wizard. Starting with v2.1.198, running it only reminds you to ask Claude to create one directly, or to edit .claude/agents/ yourself. The file format and storage locations have not changed. So the fastest approach is to tell Claude:

Create a personal code-improver subagent in ~/.claude/agents/ that scans files and suggests improvements. Make it read-only and have it use Sonnet.

The new file takes effect within a few seconds of being saved; no restart is needed. The exception is when the agents folder did not exist at the start of the session; in that case, restart Claude Code so it can be read. Once created, there are three ways to call it: name it directly in your prompt (Claude decides whether to delegate); type @ and pick it from the menu, for example @"code-reviewer (agent)" look at the auth changes, which guarantees it is used for that request; or run claude --agent code-reviewer so that the entire session switches to its system prompt, tool restrictions, and model.

Running in parallel

Subagents run either in the foreground or in the background. A foreground subagent blocks the main conversation until it finishes; background subagents can run at the same time, and when a background subagent needs a tool that requires permission, the question appears in the main conversation and indicates which subagent is asking. In interactive mode, fork mode is enabled by default, so subagents that Claude sends out run in the background. A task that is already running can also be moved to the background by pressing Ctrl+B.

For investigations that do not depend on each other, you can dispatch several at once:

Research the authentication, database, and API modules in parallel using separate subagents

Each subagent investigates its own area, and Claude combines the results at the end. However, the results still return to the main conversation. Sending out many subagents that each return a long write-up will still consume context, so when delegating, ask them to report only the key points. The default limit on concurrent subagents is 20; if you exceed it, you will see Concurrent subagent limit reached, which you can adjust with CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS.

Starting with v2.1.292, the Agent tool has an effort parameter. You can simply tell Claude “run this investigation at low effort,” and it will start that subagent at the specified effort level instead of following the main conversation’s level. Lower it for simple searching or data gathering to save cost, and raise it for reviews that require deep reasoning.

When to use it and when not to

Keep in the main conversationHand off to a subagent
Work that needs continuous back-and-forth discussion and repeated editsWork that produces large amounts of output you will not need later
Planning, implementation, and testing that share a lot of contextYou want to limit which tools or permissions it has
Quick small changes, or when speed matters (a subagent has to gather context from scratch)Work that can be completed independently, where a summary is enough

If you want a reusable workflow that runs in the main conversation, Skills are a better fit. If you just want to ask a question about content already in the conversation, use /btw.

Next step

Start with a read-only code reviewer: ask Claude to create a subagent in ~/.claude/agents/ that has only Read, Grep, Glob tools. After you change some code, type @ to pick it out and have it review your changes. Once you confirm that what it reports is useful, start trying to dispatch multiple subagents in parallel to research data.

Sources: Claude Code official documentation, “Create custom subagents”, sections Built-in subagents, Quickstart: create your first subagent, Configure subagents, and Work with subagents (queried 2026-09-15); Claude Code CHANGELOG, versions 2.1.292 and 2.1.296 (queried 2026-10-10)

Cost Control and Context Management

If you leave Claude Code running all day, you will probably notice something: even when you ask only a one-line question, your usage is much higher than you expected.

The cause is context. Think of context as a notebook of the conversation: every time you ask something, Claude Code hands the entire notebook to Claude to read again. The thicker the notebook, the more expensive each handoff. So controlling cost really comes down to managing how thick that notebook gets.

First, check how much you have used

To manage the thickness, you first need to know how thick it is now. The official documentation mentions these tools:

What you want to knowWhat to use
How many tokens this session has used and its estimated cost/usage
What is taking up context/context
Seeing context usage at any time without a commandConfigure the status line
Your own usage habits and where you tend to get stuck/insights

The Session section at the top of /usage looks like this:

Total cost:            $0.55
Total duration (API):  6m 20s
Total duration (wall): 6h 33m 10s
Total code changes:    0 lines added, 0 lines removed
Usage by model:
   claude-sonnet-4-6:  1.2k input, 5.3k output, 940.0k cache read, 50.0k cache write ($0.55)

Three things to know when reading this screen:

  • The amount is an estimate. Claude Code multiplies token counts by pricing and calculates it locally. For the official bill, use the Usage page in the Claude Console.
  • Subscription plans do not need this amount. Usage on Pro and Max is included in the subscription, so the Session amount has nothing to do with your bill. The same screen separately shows a plan usage bar, activity statistics, and a usage breakdown.
  • /clear resets it to zero. /clear starts a new session, and the amount is calculated again from $0. Versions before v2.1.211 did not reset; the amount kept accumulating until Claude Code was closed.

If you are on a Pro, Max, Team, or Enterprise plan, the usage breakdown in /usage is more useful. It lists what percentage of usage comes from skills, subagents, plugins, and each MCP server. Behaviors such as long context or cache misses are also flagged when they account for 10% or more of recent usage, with suggestions for reducing them. Press d or w to switch between the last 24 hours and the last 7 days. Starting with v2.1.299, /usage also shows warnings about max effort, workflows, always-on context, and oversized tool results. These numbers come only from session records on this computer; usage on other devices and on claude.ai is not included.

How context gets consumed

Once you know how much you have used, the next question is why it is so much. The official documentation lists several reasons usage climbs over a long session:

CauseWhat happens
Long contextEvery request sends the entire conversation; each time Claude uses a tool, it sends another request that again includes the batch of tool results
Cache missThe first message after a break longer than the cache lifetime requires the entire context to be processed again. Subscription plans have a 1-hour cache; after you start using usage credits, it drops to 5 minutes; API keys or cloud providers default to 5 minutes
Scheduled tasksEven when the session is idle, scheduled tasks still fire at their intervals, and each time they send the entire context
Agent teammatesEvery teammate still running keeps consuming tokens until it finishes
Compaction/compact has to read the entire conversation in order to summarize it, so it is itself a large request

The first item is the one most often overlooked. Claude Code has prompt caching, so repeated content is read at a cheaper cache rate, but cheaper does not mean free. In a session that has been open all day, even asking a one-line question still consumes usage for the entire conversation.

Beyond the conversation itself, CLAUDE.md is loaded at the start of the session. MCP tool definitions are lazy-loaded by default; before Claude actually uses a tool, only the tool name and the server description enter the context.

/clear and /compact: start fresh, or condense the old one

/clear/compact
What it doesStarts a brand-new session; the conversation begins from zeroSummarizes the earlier conversation and continues the same work
CostUses no tokensHas to read the entire conversation; the larger the context, the larger this request
When to useSwitching to unrelated workThe same task is continuing, but the conversation has become too long

The rule of thumb is simple: does what you are about to do need the earlier conversation? If not, use /clear. The official documentation also notes that unusually high costs on API or cloud plans usually come from sessions left open for a long time without clearing. Before using /clear, you can use /rename to give the session a name; later, if you want to return to it, /resume will find it.

When using /compact, you can tell Claude what to keep after the command:

/compact Focus on code samples and API usage

You can also write this in the CLAUDE.md at the project root so that every summary follows the same direction:

# Compact instructions

When you are using compact, please focus on test output and code changes

In addition, Claude Code automatically performs compaction once the conversation approaches the context limit. Seeing an auto-compact warning does not mean you have hit the usage limit; it only means the context is nearly full.

Long idle conversations: idle compaction (since v2.1.299)

If a terminal conversation has more than 200K tokens and has been idle for about 54 minutes, Claude Code compacts it once before the 1-hour prompt cache expires, so the first message you send when you return does not require reprocessing the entire context.

  • The minimum threshold defaults to 200K tokens and can be adjusted with the environment variable CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS
  • To turn off this behavior, set "idleCompaction": false in settings.json
  • Both of these settings are recognized only in v2.1.290 and later

Choosing the right model

Another common reason API or cloud costs are high is keeping Opus as the default model. The official recommendation: use Sonnet for most coding work, since it is cheaper than Opus; reserve Opus for complex architecture decisions or multi-step reasoning.

  • To switch models in the middle of a conversation: /model
  • To set the default model: /config
  • For simple subagent tasks: set model: haiku in the subagent configuration

Extended thinking also costs money. Thinking tokens are billed as output tokens, and the default budget varies by model, so a single request can reach tens of thousands of tokens. For simple work that does not need deep reasoning, lower the effort level with /effort or in /model, or turn off thinking in /config. The Fable model always uses extended thinking, and it cannot be turned off.

Concrete ways to reduce tokens

MethodWhy it saves tokens
Move instructions for specific workflows out of CLAUDE.md and into skillsCLAUDE.md is loaded every time, while skills load only when used. The official recommendation is to keep CLAUDE.md within 200 lines
Prefer CLI tools when they are availableTools such as gh, aws, gcloud, and sentry-cli add no entries to the tool list, so they use less context than MCP servers
Turn off MCP servers you are not usingRun /mcp to view and disable them
Hand verbose work to subagentsLarge outputs from running tests, fetching documentation, or processing logs stay in the subagent, and the main conversation receives only a summary
Filter data with hooks firstFor example, pass only the log lines containing ERROR to Claude, which can reduce context from tens of thousands of tokens to a few hundred
Write specific prompts“Improve this codebase” makes Claude scan broadly; “add input validation to the login function in auth.ts” requires reading very few files
Enter plan mode for complex tasksPress Shift+Tab to switch to plan mode and confirm the approach first, so you do not have to redo everything if the direction was wrong
Stop early when the direction is wrongPress Escape to stop; use /rewind or press Escape twice to return to an earlier checkpoint

Next step

The next time you open Claude Code, do two things first: type /context to see what is taking up your context; then type /model to confirm the default model is not stuck on Opus. From now on, whenever you switch to unrelated work, run /rename first, then /clear.

Sources: Claude Code official documentation, “Manage costs effectively”, sections Track your costs, When a developer asks about a limit, Reduce token usage, and Why usage climbs in a long session (queried 2026-09-15); Claude Code CHANGELOG, version 2.1.299 (queried 2026-10-14)

Session Management and Checkpoint Rewind

If you follow the previous chapter’s advice and run /clear before switching to new work, you will probably run into the next question: can you pick up yesterday’s conversation today?

Yes. Claude Code saves each conversation as a session, like individual notebooks stored on your computer. As long as you know how to flip back to them, closing the window will not lose the earlier context. The same mechanism also lets you roll back: if Claude broke a file, you can return to the state before a certain message.

Naming sessions

You can resume a session without naming it, but the list will be full of machine-generated titles, and you will not be able to tell which notebook is which. There are a few times to name one:

claude -n auth-refactor     # name it at startup
/rename auth-refactor

In the session picker, move the cursor to a conversation and press Ctrl+R to rename it. In addition, when you accept a plan in plan mode and the conversation does not have a name yet, Claude Code names it automatically.

Unnamed sessions get two labels: one is the working directory name plus a two-character suffix, such as my-app-3f, which is for display only and cannot be used to resume (since v2.1.196); the other is a title generated from your first message by a model such as Haiku, which you can use directly to resume.

If a name collides, do not worry about overwriting: if another conversation still running on this machine already uses the name, Claude Code keeps that conversation’s name, changes the new one to a variant with a two-character suffix, such as auth-refactor-graceful-unicorn, and tells you.

Three ways to resume

CommandWhich session it resumes
claude --continue (-c)The most recent conversation in this directory; no selection needed
claude --resume (-r)Opens the picker so you can choose
claude --resume <name or session ID>Resumes the specified session directly
/resumeAlready inside a conversation; switches to another session

--continue skips sessions created with claude -p or the Agent SDK, and also skips sessions whose first message is /loop. Background sessions that have already finished can be resumed only in v2.1.257 and later.

The picker by default looks only at the current worktree and at directories you added with /add-dir. If you cannot find a session, press Ctrl+W to widen the search to all worktrees of this repo, or Ctrl+A to widen it to all projects on this machine. When resuming by session ID, starting with v2.1.223 Claude Code first looks in the current project and its worktrees, and then in other projects if needed; earlier versions look only in the current directory, so you have to return to the original directory to resume it.

There are two parameters you rarely need but that can be useful to know about: --session-id lets you specify the ID of the conversation yourself, and it must be a valid UUID; --fork-session creates a new session ID while resuming, leaving the original session unchanged, which is useful when you want to try a different direction from the same starting point.

What resuming restores

RestoredDescription
Conversation historyThe full history, including tool calls and their results
ModelUses the same model as the original session
AgentA session opened with --agent continues as that agent, with its tool restrictions and model
Permission modeDetermined by the mode the session ended in; see the rules below
Scheduled tasksThose that have not expired come back, except background Bash and monitoring tasks

The model may not stay the same in some cases: the original model has been deprecated, availableModels does not allow it, you specified a different model with --model or ANTHROPIC_MODEL at startup, or you are on a platform that uses deployment IDs, such as Bedrock, Google Cloud, or Microsoft Foundry.

Not every startup argument is restored. If the conversation relied on --mcp-config, --settings, --plugin-dir, or --fallback-model, or on directories added with --add-dir, you must supply them again when resuming. Directories added with /add-dir partway through a conversation do not come back. Settings files such as settings.json and settings.local.json are reread on every startup.

As for permission modes, which connect to the table in Chapter 7: in the terminal, a session that was in bypassPermissions resumes in whatever mode a new session starts in; a session that was in plan mode resumes still in plan mode (but not when forked with --fork-session); a session that was in auto stays in auto if the account conditions are still met; a session that was in Manual resumes in Manual, unless defaultMode in the settings file specifies otherwise.

If the original session used --agent and that agent cannot be found in either the original directory or the current one, Claude Code shows a warning and resumes the conversation with default tools.

Also, tool calls that were in progress are not continued. A command that was half-finished when things crashed will not be rerun or completed on resume; Claude will continue without that output.

If you have been away too long, you will be asked whether to condense first

On Pro and Max plans, when you resume a conversation that has been idle for more than an hour and is over 100K tokens, Claude Code shows a dialog before you send your first message, with three options:

  • Resume from summary: the equivalent of running /compact immediately. Tokens are much cheaper, but the details the summary drops are no longer in the context.
  • Resume in full: loads everything back as it was; every subsequent request is billed based on the full conversation size.
  • Don’t ask again: resume in full this time and stop showing this dialog from now on.

When something breaks: use /rewind to go back

Each time you send a message and start a new turn, Claude Code saves a checkpoint. To go back, type /rewind, or press Esc twice while the input box is empty. (If the input box has text, pressing Esc twice clears it; the cleared text goes into input history, and you can get it back with Up.)

The menu has six options:

OptionWhat it does
Restore code and conversationReturns both the code and the conversation to that point
Restore conversationRewinds only the conversation; the code stays as it is now
Restore codeRestores only the files; the conversation is kept
Summarize from hereCondenses the conversation after this point into a summary, freeing context
Summarize up to hereCondenses the conversation before this point into a summary, keeping the later messages intact
Never mindReturns to the list without doing anything

If the checkpoint did not track any file changes, the menu shows only Restore conversation, the two summary options, and Never mind.

Summarizing does not touch files on disk, and the original messages remain in the transcript. To give the summary specific focus, move the cursor to the Summarize row, type your instructions, and press Enter; if you select it with a number key, it summarizes immediately without your instructions.

There is also a recovery entry point: if you ran /clear earlier in the same Claude Code process, the top of the rewind menu gains an extra row, /resume <session-id> (previous session). Selecting it returns you to the conversation from before /clear. This row is valid only until you exit Claude Code or switch to another session, and it requires v2.1.191 or later.

What checkpoints cannot recover

Know this beforehand, or you will treat checkpoints as a universal restore point:

  • Files changed by Bash commands are not tracked. If Claude runs rm, mv, or cp on files, rewind cannot restore them. Only changes made directly through Claude’s file editing tools are tracked.
  • Changes made by subagents usually cannot be rewound. Only a skill with context: fork that runs in the foreground has its edits made within its own turn, so rewind can undo them; other subagents (including fork skills that run in the background by default, and background /code-review --fix) must be restored with git.
  • External changes are not tracked. Changes you make outside Claude Code, or changes made by another conversation at the same time, are generally not recorded.
  • Messages sent mid-turn have no checkpoint. If you queue a message while Claude is working, it is merged into the turn that was running, and it does not appear in the menu. To undo it, rewind to the prompt that started that turn, which undoes the whole turn.
  • Symlinks and hard links are skipped. When you choose Restore code, these paths are skipped and Restored the code, but skipped N files is displayed; those files keep their current contents. To see which ones were skipped, first use /debug to turn on debug logging; the log is stored at ~/.claude/debug/<session-id>.txt.

The official documentation is also blunt: checkpoints are designed for quick restoration within the same conversation; long-term version history and collaboration should be handled by git. So for work that will involve major changes, make a commit before you start, and save rewind for small mistakes within the same conversation.

Where it is stored and how long it is kept

Transcripts are stored by default at ~/.claude/projects/<project>/<session-id>.jsonl, where <project> is the working directory path with every non-alphanumeric character replaced by -. Each line is a JSON object, but this is an internal format that changes between versions. To export, use /export; do not write your own code to parse it.

What you want to doSetting
Move the storage location out of ~/.claudeCLAUDE_CONFIG_DIR
Name the <project> directory yourselfCLAUDE_CODE_PROJECT_DIR_NAME (since v2.1.234; CLAUDE_CONFIG_DIR must be set first)
Change the default 30-day retention periodcleanupPeriodDays in settings.json
Never write transcriptsCLAUDE_CODE_SKIP_PROMPT_HISTORY
Keep no record for a single claude -p run--no-session-persistence

Checkpoint file snapshots keep the most recent 100, and they are also cleared along with the 30-day retention period above. If you try to rewind after the snapshots have been cleared, it will fail with No files were restored. If you really need them kept longer, increase cleanupPeriodDays.

Next step

Before starting your next piece of work, do one thing: launch it with claude -n <work-name>, or run /rename as soon as you are inside. That way, tomorrow when you use claude --resume, you will be able to tell which session is which. Then find a moment when you have broken something, press Esc twice, and look through the six rewind options once, so you know which one rewinds only the conversation and which one also restores files. That way you will not panic when you actually need it.

Sources: Claude Code official documentation, “Sessions”, sections Resume a session, What a resumed session restores, Permission mode on resume, Resume from a summary, Name your sessions, Where transcripts are stored, and Where the session picker looks; and Checkpointing, sections Automatic tracking, Rewind and summarize, Rewind past a cleared conversation, How checkpoints work, Limitations, and Not a replacement for version control (queried 2026-09-18). (Cross-checked and updated on 2026-10-15 against the Permission mode on resume section of Manage sessions.)

Plugins and Marketplaces

After writing skills and subagents in Chapters 9 and 10, you will probably run into the same problem: they all sit in your own ~/.claude/ folder, and moving to a new computer or sharing them with a colleague means copying the folders one by one.

Plugins are a way to package them up. A plugin is a self-contained bundle you can take with you. It can include skills, subagents, hooks, MCP servers, and default settings all at once. A marketplace is a list of these bundles: you point to a source, and you can choose what to install from it.

What a plugin can contain

Each of the following goes at the root of the plugin and corresponds to one feature:

LocationWhat goes there
.claude-plugin/plugin.jsonRequired manifest file; holds the name, description, version, and author
skills/Agent Skills; Claude decides for itself when to use them
agents/Custom subagents
hooks/hooks.jsonEvent handlers
.mcp.jsonMCP server configuration
.lsp.jsonLSP server configuration
monitors/monitors.jsonBackground monitoring configuration
settings.jsonDefault settings to apply when this plugin is enabled

Skills in a plugin get a prefix, so they are invoked as /<plugin name>:<skill name>. If the whole package contains only one skill, you can skip the skills/ folder and place SKILL.md directly at the root.

Installing someone else’s plugin

Typing /plugin opens a panel with tabs for Discover, Installed, Marketplaces, Errors, and Stats, which you can navigate by clicking. If you prefer typing commands:

/plugin install github@claude-plugins-official   # install from a marketplace
/plugin list --enabled                           # what is on right now
/plugin disable <name>@<marketplace>             # turn it off, keep it installed
/plugin uninstall <name>@<marketplace>

The official marketplace is called claude-plugins-official. It is maintained by Anthropic and is registered automatically the first time you start interactive mode. If it was not installed automatically, add it manually:

/plugin marketplace add anthropics/claude-plugins-official
/plugin marketplace add anthropics/claude-plugins-community   # community one, add it yourself

A marketplace source can be a GitHub owner/repo, a Git URL, a remote URL, or a local path. You can also manage them with /plugin marketplace list, update <name>, and remove <name>.

The first time you install a plugin in a directory, Claude Code asks whether you trust that directory. If you answer in a git repo, the answer applies to the whole repo.

Be a bit cautious here. A plugin can include hooks and MCP servers, which means that once installed, it can run commands on your computer. Check the source before installing: the official marketplace, or plugins that many people already use, are safer. For something new with few users, open its hooks/ and .mcp.json and review them before deciding.

Starting with v2.1.271, the security of installation was tightened in several areas worth knowing about:

  • Plugins from npm sources no longer run install scripts. They are now downloaded with npm pack --ignore-scripts and verified for integrity, so a postinstall script in the package will not run on your computer.
  • --marketplace can be passed in one step. /plugin install <plugin> --marketplace <source> asks whether to add a marketplace you have not yet added, so you do not need two steps. Starting with v2.1.292, the command-line claude plugin install --marketplace <source> also supports this: when needed, it adds the marketplace first (applying the same policy checks as claude plugin marketplace add), then installs the plugin from it.
  • Fill in settings at install time. claude plugin configure <plugin> lists the plugin’s options and the items that have not been set yet; adding --values-stdin lets you store new values from standard input (since v2.1.285). claude plugin install --config can also set parameters for an MCP server bundled as .mcpb inside the plugin, using <server>.<key>=<value>, so you do not have to go through /plugin → Configure after installing.
  • Do not use -y in CI. claude plugin install and claude plugin update support --accept-command <sha256>, which accepts only the command shown in an earlier --json run. If the content changes, it will not pass, which gives automation a verification step.
  • Plugins enabled on your claude.ai account sync to the terminal. This uses the same mechanism as the skill sync in Chapter 9; you can turn it off with "syncClaudeAiPlugins": false.

After you change a plugin’s contents, you do not need to restart:

/reload-plugins            # apply changes in the current session
/reload-plugins --force    # when the cache needs rebuilding too

Packaging your own

The directory layout looks like this:

my-plugin/
├── .claude-plugin/
│   └── plugin.json
├── skills/
│   └── hello/
│       └── SKILL.md
├── agents/
├── hooks/
│   └── hooks.json
└── .mcp.json

plugin.json is actually optional. Without it, Claude Code loads whatever components it finds in the standard locations. If you do write it, only name is required, though filling in the other fields is recommended. A fuller example:

{
  "name": "my-plugin",
  "description": "What this plugin does",
  "version": "1.0.0",
  "author": { "name": "Your Name" }
}

You can leave out version; if you do, the git SHA is used as the version. name also determines the skill prefix, so keep it short.

You do not need to publish during development. Point to a local folder directly to test:

claude --plugin-dir ./my-plugin     # load one plugin for this session
claude --plugin-dir ./plugins       # v2.1.265+: load every plugin in the folder
claude plugin validate ./my-plugin  # check the structure and schema

When you point to a folder, Claude Code first checks whether that level contains plugin content. If not, it treats the folder as a collection of plugins, and each subfolder that contains .claude-plugin/plugin.json counts as one plugin.

Verifying with claude plugin eval

Once skills and hooks are written, the hardest question is whether they actually make Claude perform better. claude plugin eval does exactly this: it runs your plugin against a set of test cases, runs each case three times by default, also runs a control round without the plugin installed, and then reports the difference between the two. It requires v2.1.269 or later.

claude plugin eval init                        # interview, writes cases and graders
claude plugin eval .                           # run every case
claude plugin eval . --runs 1 --ablation none  # single arm, cheaper
claude plugin eval . --trust-plugin            # for CI, skips the trust prompt

Cases live in evals/<case name>/. Inside, prompt.md holds the prompt, and the graders/ folder holds one grader per file. There are six kinds of graders:

TypeCosts extra?Passing condition
regexNoThe regular expression is found in the target text
tool_usedNoThe number of calls to a tool falls between min and max
tool_orderNoThe tool in before is called before the tool in after
file_existsNoA file created by Claude matches the glob
llmYesTwo-thirds of the votes from the grading model are passing
baselineYesThe score beats the round where the plugin was not installed

Running it produces aggregate-result.json and report.html under evals/results/<timestamp>/. The exit code can be used directly in CI: 0 means all cases met the threshold; 1 means the threshold was not met or the trust prompt was declined; 2 means only part of the run completed (for example, because of a cost limit or an authentication failure).

Keep in mind that every eval run and every call to the grading model costs money. Evals run in an isolated environment, so your personal settings, other plugins, memory, and MCP servers are not loaded; what you measure is the effect of this plugin on its own.

Next step

Start by installing one plugin: type /plugin, pick one you will use every day from the official marketplace (for example, one related to GitHub), install it, and use it for a week. Once you are sure it works well, add a second one. When your personal ~/.claude/skills/ contains two or three frequently used skills, move them into a plugin folder, test them locally with claude --plugin-dir, and then decide whether to publish them to a marketplace for others to use.

Sources: Claude Code official documentation, “Create plugins”, section Create your first plugin; Discover and install prebuilt plugins, sections on installation and marketplaces; and Test plugins with evals, sections Requirements, Graders, and Run evals (queried 2026-09-18). The facts for the installation security section come from versions 2.1.271 and 2.1.275 in the Claude Code CHANGELOG (queried 2026-09-19); versions 2.1.285 (queried 2026-10-02) and 2.1.292 (queried 2026-10-07) in the Claude Code CHANGELOG. (Cross-checked and updated on 2026-10-15 against the Manifest section of Plugins reference.)

Models, Effort Levels, and Fast Mode

The previous chapter covered packaging tools into plugins. But no matter how complete your tools are, the two things that ultimately determine answer quality and the size of your bill are which model you use and how long it is allowed to think.

Claude Code separates these two things. The model sets the foundation, and the effort level determines how much effort it puts into thinking before it answers. Understanding these two is more useful than agonizing over whether to use Opus or Sonnet.

Which models are available

You do not need to memorize full model IDs; just remember the aliases: default, best, fable, opus, sonnet, haiku, opusplan, plus the long-context versions sonnet[1m] and opus[1m].

The model each alias actually resolves to depends on your platform:

Platformopussonnethaiku
Anthropic APIOpus 5.5Sonnet 5.5Haiku 5.5
Claude Platform on AWSOpus 5.5Sonnet 4.6Haiku 4.5
Amazon Bedrock, Google Cloud Agent PlatformOpus 5.5Sonnet 4.5Haiku 4.5
Microsoft FoundryOpus 4.6Sonnet 4.5Haiku 4.5

fable has no per-platform mapping; by default it resolves to Fable 5.1, and only sessions on the Claude apps gateway resolve to Fable 5.

The default model depends on your plan and platform: Pro, Max, Team, Enterprise, the Anthropic API, Claude Platform on AWS, Amazon Bedrock, and Google Cloud Agent Platform all default to Opus 5.5; Microsoft Foundry defaults to Sonnet 4.5. Fable is not the default for any plan or platform. Starting with v2.1.280, the default for Pro and Team Standard also changed from Sonnet to Opus. The latest models are Opus 5.5 (claude-opus-5-5, v2.1.280) and Sonnet 5.5 (claude-sonnet-5-5, v2.1.284), both with a 1M context. API prices per million tokens: Opus 5.5 is $4 input and $20 output; Sonnet 5.5 is $2 input and $10 output.

In addition, starting with v2.1.285, sessions that use a custom ANTHROPIC_BASE_URL use the long context of models with a 1M window directly (Opus 4.7 and above, Sonnet 5 and above, and Fable). If your gateway only supports 200K, enter /autocompact 200k. On Bedrock, Vertex, Foundry, and the Claude apps gateway, Opus 4.7 and above and Fable also default to 1M starting with v2.1.287, so you do not need to add [1m]; to stay at 200K, set CLAUDE_CODE_DISABLE_1M_CONTEXT=1. Also, starting with v2.1.288, /autocompact settings are stored separately for each model, so switching models does not overwrite them.

The lightweight Haiku has also been updated. Starting with v2.1.293, the haiku alias on the Anthropic API resolves to Haiku 5.5 (claude-haiku-5-5), with a 1M context, priced at $0.10 per million input tokens and $0.50 per million output tokens. For any single request with a prompt over 100K tokens, the entire request is billed at $0.50/$2.50, not only the portion above the threshold. When judging length, cache read and write tokens are also counted.

There are several ways to switch models, from most immediate to most persistent: /model <alias> changes only the current conversation; claude --model <alias> specifies it at startup; the environment variable ANTHROPIC_MODEL; the model setting in settings.json; and finally ANTHROPIC_DEFAULT_MODEL (since v2.1.236, which affects only the default for new conversations).

It is worth remembering the opusplan alias: it uses Opus for planning and switches back to Sonnet for implementation, which suits work where you think things through first before making changes.

Effort levels: how long it thinks

For the same model, you can adjust how hard it thinks:

ModelAvailable levels
Fable 5.1, Fable 5, Opus 5.5, Sonnet 5.5, Haiku 5.5, Opus 5, Sonnet 5, Opus 4.8, Opus 4.7low, medium, high, xhigh, max
Opus 4.6, Sonnet 4.6low, medium, high, max

Most models default to high, but Opus 5.5, Sonnet 5.5, and Haiku 5.5 default to medium, and Opus 4.7 defaults to xhigh. To switch:

claude --effort xhigh                  # at startup
export CLAUDE_CODE_EFFORT_LEVEL=medium # environment variable
/effort          # interactive slider
/effort high     # set it directly

In the settings file, the corresponding keys are effortLevel (the default value), modelSettings (the level each model remembers for itself), and maxEffortLevel (the upper limit).

Thinking itself costs money: thinking tokens are billed at the output token rate. So setting simple work to low or medium is cheaper and faster than always using high. To turn extended thinking off entirely, set MAX_THINKING_TOKENS=0; but Opus 5.5, Sonnet 5.5, Haiku 5.5, and Fable are exceptions, and thinking cannot be turned off for these models (/config shows Thinking can't be turned off).

ultracode is not an effort level. It is a switch that lets Claude automatically use a dynamic workflow to coordinate a whole batch of subagents. Starting with v2.1.284, it is a separate toggle in /effort (press Tab, or enter /effort ultracode on / off), no longer forcing xhigh, and it can stay on at any effort level. The next chapter covers it in detail.

In addition, starting with v2.1.280, /effort remembers the level separately for each model. Levels saved in older versions are not applied to newly released models such as Opus 5.5; they start from the default level, and you must choose again.

Fast mode: the same Opus, 2.5 times faster

Fast mode is not a different model. It is the same Opus running under a different API configuration that puts speed ahead of cost, with responses up to 2.5 times faster. It supports Opus 5.5, Opus 5, and Opus 4.8, but not Sonnet or Haiku; starting with v2.1.280, the default is Opus 5.5. Fast mode for Opus 4.7 was removed on July 24, 2026. This is a research preview, and features, pricing, and availability may change.

Pricing per million tokens: Opus 5.5 is $8 input and $40 output; Opus 5 and Opus 4.8 are $10 input and $50 output. Note that at the moment you turn it on, the entire conversation context is charged once as uncached input, so enable it at the start of a conversation; turning it on partway through costs more.

/fast        # toggle
/fast on     # in a cloud session

In the settings file, fastMode determines whether it is on by default, and fastModePerSessionOptIn can require you to turn it on manually for each conversation (since v2.1.257).

Pro and Max users must first enable usage credits in Settings under Usage; Team and Enterprise owners enable it in Admin Settings. Bedrock, Google Cloud Agent Platform, Microsoft Foundry, and Claude Platform on AWS do not support it.

Fallback when a model fails

When the primary model is overloaded, temporarily unavailable, or returns a server error that is not worth retrying, a fallback can take over automatically:

claude --fallback-model sonnet,haiku
{ "fallbackModel": ["claude-sonnet-5", "claude-haiku-4-5"] }

A chain can contain up to three models. Switching affects only the current turn, and subagents apply it as well. Errors such as authentication, billing, rate limits, and requests that are too large do not trigger a fallback, because switching models would not solve them.

There is also automatic switching based on content. Fable 5.1, Fable 5, and Opus 5.5 are routed to Opus 5 when biology is involved and to Opus 4.8 when cybersecurity is involved; Sonnet 5.5 routes to Sonnet 5 for cybersecurity, and for biology it refuses directly; Opus 5 routes to Opus 4.8 for cybersecurity, and for biology it likewise refuses. If you do not want this behavior, turn off the model-switching item in /config, or set "switchModelsOnFlag": false.

Configuring for lower cost

Normally, stay on the default model and do not keep switching. For work that really requires careful thought (architecture, hard-to-find bugs), switch to opusplan or raise the effort to xhigh; for tasks like editing copy or running tests, lower the effort to medium, which saves time as well as money. Fast mode suits times when you are in a hurry, and you should turn it on at the start of a conversation, since turning it on partway through costs more.

Next step

Take inventory now: type /model to see which model is active, and type /effort to see which level is set. Then pick a small task you did today and rerun it with the effort lowered to medium, and compare whether the result got worse. Work that does not need high effort can be turned down, and both /context and your bill will look better.

Sources: Claude Code official documentation, “Model configuration”, sections Model Aliases, Model Resolution by Provider, Effort Levels, Fallback Model Chains, and Automatic Model Fallback; the full text of Fast mode; and the pricing page (queried 2026-10-15); Claude Code CHANGELOG, versions 2.1.280, 2.1.284, 2.1.285, and 2.1.287 (queried 2026-10-02), 2.1.288 (queried 2026-10-03), and 2.1.293 (queried 2026-10-08)

Worktrees and Running Multiple Sessions in Parallel

The subagents in Chapter 10 solve the problem of “one task split into many steps.” But if you have two unrelated jobs at the same time, such as reworking the login flow on one side and fixing CI on the other, opening two windows that each run Claude Code and both edit the same working directory will cause them to step on each other partway through.

A Git worktree is a solution that already exists: the same repo, with several working directories, each on its own branch, sharing history and the remote. Claude Code has built this in, so each conversation can stay in its own worktree, and their files won’t clash.

Open a worktree and work in it

claude --worktree auth-refactor   # create a named worktree and start there
claude -w auth-refactor           # same thing, short form
claude --worktree                 # no name: one is generated, e.g. bright-running-fox
claude --worktree "#1234"         # branch from a PR

By default it is created at .claude/worktrees/<name>/ in the repo root, on a branch named worktree-<name>. Add this folder to .gitignore.

If you are already in a conversation and want isolation, you can also ask Claude to create one, and it will use EnterWorktree to do so. To see which ones exist and remove one by hand, use the regular git commands:

git worktree list
git worktree remove <path>

Which branch it branches from, and how to clean up

By default, a new worktree branches from the default branch. To branch from your current HEAD instead, change the setting:

{ "worktree": { "baseRef": "head" } }

When you leave: a clean, unnamed worktree is removed automatically; for a named one or one with changes, you are asked whether to keep it or delete it. Non-interactive mode such as claude -p does not clean up, so you have to run git worktree remove yourself. Worktrees used by subagents and background sessions are cleared periodically according to cleanupPeriodDays.

There is one more useful file: .worktreeinclude. A worktree is a new working directory, and files ignored by git do not carry over, so things like .env will be missing. List them using .gitignore syntax, and a copy will be made each time you open a new worktree:

.env
.env.local
config/secrets.json

Resuming a session inside a worktree requires v2.1.212 or later; older versions had problems tracking the transcript location.

Use agent view to see all sessions

After you run several conversations at once, the next question is: which one has finished, and which one is waiting for your answer?

claude agents              # full-screen dashboard
claude agents --cwd <path> # only sessions under this directory
claude agents --json       # for scripts

On the screen, each conversation has a status symbol in front of it, and the shape reflects the state of the process: ✻ or the animated ✽ means the session is running or waiting for your input; ∙ means the process has ended (when you reply or attach, it restarts from the saved conversation); ✢ means /loop is sleeping between two runs (it shows the run count and a countdown). Completed, failed, and stopped are told apart by color: green for completed, red for failed, gray for stopped, and yellow for waiting for your input. A dimmed icon means idle. Common keys: Enter or → to enter that session, Space to toggle the preview, Ctrl+R to rename, Ctrl+X to stop (press again to delete), Ctrl+S to switch the grouping method, and ? to see all shortcuts.

If you don’t want to open the screen, there are matching commands:

claude attach <id>     # open that session in this terminal
claude logs <id>       # print its recent output
claude stop <id>       # stop it
claude rm <id>         # remove it from the list
claude daemon status   # check the supervisor process

Starting with v2.1.290, claude attach and claude logs also accept part of a session name in place of the full id.

Agent teams: have several sessions coordinate with each other

One level up are agent teams: one conversation acts as the lead, handling task division and consolidation, while the other teammates each have their own independent context and can message each other directly. This feature is off by default and must be turned on yourself:

{ "env": { "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" } }

Once it is on, describe the task and the roles you want in natural language, and Claude will create the teammates. Tasks go into a shared task list with three states: pending, in progress, and completed. You can also set dependencies: until the earlier task is completed, the later one cannot be claimed. File locks are used to prevent two teammates from editing the same file at once. Tasks and inboxes are stored in ~/.claude/tasks/{team-name}/ and ~/.claude/teams/{team-name}/inboxes/, respectively.

You can choose where teammates are displayed: the default in-process runs all of them in the same terminal; auto splits the window automatically when running under tmux or iTerm2; you can also specify tmux or iterm2 (iTerm2 requires v2.1.186 or later, plus it2 and the iTerm2 Python API). The VS Code built-in terminal, Windows Terminal, and Ghostty do not support split panes.

Know the limitations first: /resume and /rewind cannot reconnect to teammates, so a resumed conversation no longer has its teammates; under claude -p, teammates degrade into regular subagents; teammates cannot spawn their own teammates; and a conversation can only have one team.

Four ways to parallelize, and how to choose

ApproachWhat it isolatesWhen to use
SubagentcontextDivide one task among workers; each reports back a summary
WorktreefilesTwo tasks changing the same repo at the same time
Agent viewnothing; it is only an overviewRunning many conversations and needing to know who is waiting for you
Agent teamscontext plus a coordination mechanismMulti-person work where members discuss with each other and share a task list

Be prepared for the cost: subagent results converge back into the main conversation, so they are relatively economical; each agent teams teammate is a separate instance, so token usage is noticeably higher.

Next step

The next time you have two things to do at once, don’t open another window for the second one. Instead, open a worktree with claude -w <name>. Remember to add .claude/worktrees/ to .gitignore first, and list .env in .worktreeinclude. Once both sides are running, open another terminal, enter claude agents, and use the status symbols to decide which side to respond to first.

Sources: Claude Code official docs, “Run parallel sessions with worktrees”, sections Start Claude in a worktree, Customize worktree creation, Copy gitignored files into worktrees, and Clean up worktrees; “Agent View”, sections Opening Agent View, Key Commands, State Icons, and Keyboard Shortcuts; and “Orchestrate teams of Claude Code sessions”, sections Enable agent teams, Assign and claim tasks, Choose a display mode, Compare with subagents, and Limitations (queried 2026-09-18); and the Claude Code CHANGELOG for 2.1.290 (queried 2026-10-06). (Also checked against the Read session state section of Agent view on 2026-10-15 to update the status icons.)

Automation: Headless Mode, CI, and Scheduling

Everything covered so far has assumed you are sitting at the terminal, telling it things one step at a time. But some work does not need you present: every morning summarizing yesterday’s issues, running a review round automatically each time a PR is opened, or scheduling a fixed set of checks in CI.

This chapter covers turning Claude Code from a conversation tool into a program that can be called: how to run it without anyone interacting, how to connect it to GitHub, and how to schedule it to run on its own.

Headless mode: claude -p

Adding -p (or --print) skips the interactive interface, runs to completion, and prints the result. It returns 0 on success and a non-zero value on failure, so it can be used directly in a shell script.

claude -p "summarise today's git log" --output-format json
cat error.log | claude -p "what failed here?"   # stdin, up to 10MB

--output-format has three options: text (the default), json, and stream-json. To fix the output format, you can use --json-schema together with --output-format json.

Be careful with permissions here: with -p, nobody can click to approve, and if you don’t specify a permission mode, it starts in the built-in starting mode (which may be auto). So it’s best to state it explicitly: either pre-approve permissions, or say outright that it must not ask:

claude -p "run the tests" --allowedTools "Read,Bash"   # pre-approve
claude -p "..." --permission-mode dontAsk               # no prompts
claude -p "..." --permission-prompts none               # refuse everything that needs asking

There is one more flag that makes CI faster and more stable: --bare. It skips the automatic loading of hooks, skills, custom commands, subagents, plugins, MCP servers, auto memory, and CLAUDE.md, which gives you a clean environment, so results are the same no matter which machine it runs on. Note that bare mode does not read OAuth login or the system keychain, so you must set ANTHROPIC_API_KEY yourself.

When you run it and it exits: claude -p waits for background work to finish before it ends. Background commands started by the main conversation (such as a dev server) are waited on until they exit or hit the time limit; subagents and workflows are waited on until they complete, because their results count toward the final output. Monitoring-style tasks and idle waits are waited on for at most 10 consecutive minutes (CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS can change this, and setting it to 0 removes the limit). To continue a previous conversation, --continue and --resume <session-id> work under -p as well.

Connect to GitHub Actions

The faster setup is to enter /install-github-app in interactive mode: it installs the GitHub App for you, adds the authentication secret, and opens a PR that adds the workflow file. This requires the GitHub CLI and admin permission on the repo. To install manually, you install the App yourself, add the ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN secret, and copy the workflow file in.

A workflow can run in two modes, and the only difference is whether you provide a prompt:

  • No prompt provided: interactive mode; it waits for someone to comment @claude on an issue or PR before acting
  • prompt provided: automation mode; it runs as soon as the event triggers, without waiting for anyone

There are also limits on who can trigger it. By default, only people with write access can trigger it; other users must be listed in allowed_non_write_users; bot accounts must be listed in allowed_bots.

If you run on a cloud vendor, change the corresponding switch in the workflow: for Bedrock, use use_bedrock: "true" together with OIDC’s AWS_ROLE_TO_ASSUME; for Google Cloud Agent Platform, use use_vertex: "true" together with Workload Identity Federation; for Microsoft Foundry, use use_foundry: "true" together with the variables for the Entra application.

Authentication material always goes in GitHub Secrets and never into the files; give the workflow only the permissions it needs; and review any changes Claude opens before merging them.

Scheduling: have it run on its own on a timer

Cloud scheduling is called routines. You can create one at claude.ai/code/routines, or use /schedule in the CLI. It runs in an Anthropic-hosted cloud environment (or a self-hosted environment provided by your organization), so your computer does not need to stay on. There are three trigger types:

TriggerDescription
ScheduleDefault frequencies such as hourly, daily, weekdays, and weekly, or set a cron with /schedule update; the minimum interval is one hour
APISend a POST to the /fire endpoint; the response gives you a new session ID and URL
GitHub eventPull requests and releases, which can be filtered by author, title, body, branch, label, whether it is a draft, and whether it has been merged

A one-time run is disabled automatically once its time arrives. Runs share the hourly cap with other scheduled runs (100 per account per hour), so they are not free of quota. By default, environments allow common domains such as package managers and cloud APIs; to add a custom domain, change it under Network access in the environment settings.

If you only want to repeat something within “this conversation,” use /loop; you don’t need a cloud schedule:

/loop 5m <prompt>   # every five minutes
/loop <prompt>      # Claude picks the interval, between 1 minute and 1 hour

You can also just say “remind me to check the deployment at three o’clock,” and it will create a reminder. Scheduled tasks like this expire after seven days; when you return to the conversation, any that have not expired come back with it, and they are all cleared when the conversation ends.

Channels: send work in from places like Telegram

Channels let messages from Telegram, Discord, and iMessage flow into a conversation that is already running, so you can hand it work even when you are away. This is a research preview, requires Bun, and is not supported on Bedrock, Vertex, or Foundry.

/plugin install telegram@claude-plugins-official
/telegram:configure <token>

Then exit Claude Code and reopen it with --channels; the bot will only start receiving messages after that:

claude --channels plugin:telegram@claude-plugins-official

Send a message to the bot to get a pairing code, then come back and pair:

/telegram:access pair <code>

Understand the security mechanism: each channel has its own sender allowlist, and only IDs on the list can get messages through. Telegram and Discord add people to the list with a pairing code; for iMessage, a conversation with yourself is allowed automatically, and other contacts are added manually. /telegram:access policy allowlist can lock it down so that only people on the list can use it. People on the list can also approve tool calls remotely, so treat this list as a permission list and don’t add people carelessly. For Team and Enterprise, channels are off by default, and the Owner must turn on channelsEnabled in the admin console.

Next step

Start with the smallest step: take a check you do by hand every day, write it as a single-line claude -p, add --allowedTools granting it read-only permission, and run it to see whether the output is correct. Once it is stable, decide whether to put it into CI or turn it into a routine that runs on a timer. Before you touch GitHub Actions, confirm the secret is set and that the workflow’s permissions are not too broad.

Sources: Claude Code official docs, “Headless mode”, sections Basic usage, Start faster with bare mode, Get structured output, Auto-approve tools, and Background tasks at exit; “GitHub Actions”, sections Setup, Interactive and automation modes, and Protect your credentials; “Routines”, sections Add a schedule trigger, Add an API trigger, Add a GitHub trigger, and Usage and limits; “Scheduled tasks”, sections /loop and Seven-day expiry; and “Channels”, sections Supported channels, Security, and Enterprise controls (queried 2026-09-18) (Updated 2026-10-15 after checking Headless mode, Routines, and Channels.)

Dynamic Workflows and ultracode

The subagents in Chapter 10 are for “send one person to look something up,” which is fine for three or five at a time. But if you want to “scan 500 files” or “check the same question from six angles and then cross-verify,” relying on the main conversation to decide each next step round by round will fill the context with intermediate results, and a mistake in one place means starting over.

Dynamic workflows take a different approach: Claude first writes a JavaScript script for you, and the script decides how many agents to spawn, which goes first, and how the results are collected. The script runs in the background, and your conversation can keep going. Intermediate results are stored in the script’s variables, so they don’t take up your context.

When to use a workflow, and when to use a subagent

SubagentWorkflow
Who decides the next stepClaude judges each round itselfLoops and branches in the script
Where intermediate results goThe main conversation’s contextThe script’s variables
ScaleA fewDozens to hundreds

A workflow is only worth it for work that spawns dozens of agents and follows a fixed process.

How to start one

The simplest way is to include the keyword ultracode in your sentence, and Claude will write a workflow script for that task. Other ways:

MethodDescription
ultracode keywordApplies only to this one task
/effort ultracodeEvery substantial task afterward goes through a workflow (since v2.1.284 it is a separate switch and no longer tied to xhigh)
claude --effort ultracodeSet up at startup
/deep-researchA built-in workflow: researches from multiple angles, cross-verifies, and returns a report with sources
/<name>Runs a saved workflow, stored in .claude/workflows/ or ~/.claude/workflows/

The keyword only triggers when a real person types it (interactive input, IDE extensions, Remote Control, and input marked { kind: "human" } in the Agent SDK). Typing it in -p, webhooks, PR comments, or scheduled tasks does not count (since v2.1.210). This is intentional: it prevents someone putting the keyword in an issue comment and making your automation burn a large amount of tokens.

If you see the keyword flagged but don’t want to use it this time, press Option+W (macOS) or Alt+W to cancel it; to turn it off entirely, go to /config and disable the Ultracode keyword trigger.

Before running, Claude will show you a plan first: in auto mode it asks the first time; in manual mode it asks every time; in bypass mode it doesn’t ask.

What the script looks like

A script always begins with a meta block, which must be a pure object literal containing name and description. If you write it as a variable or a function call, the workflow will not appear in the / autocomplete list.

There are five commonly used functions:

FunctionWhat it does
agent(prompt, options)Spawns a subagent; if you give it a schema, it returns JSON that matches the structure
parallel(tasks)Runs a group of tasks at the same time; continues only when all are complete
pipeline(items, callback)Runs once for each item in a list
phase(title)Groups the following agents under the same phase heading, so the progress screen is easier to read
log(message)Prints one line at the top of the progress screen

There are two restrictions that trip up people used to writing Node: a script cannot dynamically load modules, so an import() will fail before it runs; and Date.now(), Math.random(), and new Date() without arguments will throw an error. When you need a timestamp, pass it in from outside using args. Put all the actual work into the agents’ tasks, and let the script only handle scheduling.

If schema validation fails, it retries; if it still fails after five attempts, it returns an error. You can adjust the number of attempts with MAX_STRUCTURED_OUTPUT_RETRIES.

Scale, cost, and how to resume after an interruption

By default, 16 agents run at the same time (reduced according to CPU). You can set this to anywhere from 1 to 256 with CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS (requires v2.1.269 or later). A single parallel or pipeline call can handle up to 4,096 items; beyond that it is rejected outright rather than silently truncated. One run can spawn at most 1,000 agents, which prevents a runaway loop. If the estimate shows 25 agents or 1.5 million tokens, a warning appears, but it does not block the run.

The workflowSizeGuideline setting in your settings file gives Claude a sense of scale: small means fewer than 5, medium (the default; for the Pro plan it is small) means fewer than 10, large means fewer than 50, and unrestricted means no limit.

If you want all workflow agents to use the same model while other subagents keep their own settings, set CLAUDE_CODE_WORKFLOW_SUBAGENT_MODEL (since v2.1.296).

The key to saving money is the prompt cache: when a group of agents shares the same prompt prefix, the second and later ones can read from the cache. By default, starts are staggered by 5 seconds so the first agent can create the cache first (CLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS). The cache lasts 5 minutes by default; subagentPromptCacheTtl can be set to 1h. When billing through the API, the write rate for a one-hour cache is higher, so weigh that yourself.

If a run hits your usage limit partway through, it pauses rather than failing, and resumes automatically once the quota resets (requires v2.1.271 or later, interactive mode, and autoContinueAtUsageLimit turned on). It will wait at most twice; the third time, it fails.

To continue a run that didn’t finish: completed agents return their saved results directly; agents that were interrupted or failed are rerun, and any agents after them are rerun as well. Results are stored in ~/.claude/projects/<session>/. If no saved record is found, it reports nothing to resume and does not silently start over from the beginning.

All paid plans, the API, Bedrock, Google Cloud Agent Platform, and Microsoft Foundry can use this. Pro users must turn it on in /config first; organization admins can turn it off entirely with managed settings.

Next step

Don’t write a script yourself the first time. Pick a large task you normally ask Claude to do but always find slow, such as “scan the entire repo for places still using the old API.” Add ultracode to the sentence, and see how many agents the plan spawns and which phases it is split into. If the scale seems too large, first set workflowSizeGuideline to small, and loosen it once you are familiar with it.

Sources: Claude Code official docs, “Orchestrate subagents at scale with dynamic workflows”, sections When to use a workflow, Have Claude write a workflow, Let Claude decide with ultracode, Where the keyword works, What the saved script looks like, Edit a saved script, Behavior and limits, Prompt caching in a fan-out, Set a size guideline, When a run hits your usage limit, and Resume after a pause (queried 2026-09-18); Claude Code CHANGELOG for 2.1.284 and 2.1.296 (queried 2026-10-10)

Where else you can use Claude Code besides the terminal

Up to this point, this whole document has covered Claude Code in the terminal. But the same account and the same settings can also be used in the IDE, the desktop app, the browser, on your phone, and even in Slack, each with different capabilities.

This chapter is a comparison table to help you decide which one to use in which situation.

VS Code and JetBrains

VS Code requires version 1.94 or later; search for Claude Code in the extensions marketplace to install it. Once installed, you can view inline diffs in the editor, mention files with @, review plans, open multiple tabs each running a separate conversation, and see your conversation history. The limitation is that some CLI-only commands are unavailable (for example /plugin and /resume), and the CLI bundled with the extension is only for the graphical interface, so you need to install the terminal version separately.

JetBrains IDEs (IntelliJ, PyCharm, WebStorm, and others) require you to install the CLI first, then install the plugin from the JetBrains Marketplace and restart the IDE. Press Cmd+Esc or Ctrl+Esc to bring it up. It shows changes with the IDE’s own diff viewer, automatically brings the code you have selected into the conversation, and can read the IDE’s lint and syntax errors. For remote development, install the plugin on the remote host; WSL2’s default NAT networking needs a separate firewall rule.

Both require a paid plan (Pro, Max, Team, or Enterprise) or a Claude Console account; no API key is needed.

Desktop app

Download it from claude.com/download. In addition to arranging work into workspaces and starting preview servers, the notable feature is computer control: it can click, type, drag, press keyboard shortcuts, and open native applications, and on macOS it can run in the background. Turn it on under General in Settings; macOS also requires accessibility and screen recording permissions.

This is a research preview. Computer control has no sandbox, is available only on Pro and Max, and is not supported on Team or Enterprise. The terminal has a matching feature: enter /mcp, find computer-use, and enable it. It is limited to macOS and interactive mode (it cannot be used with -p), and only one conversation at a time can lock the screen.

Cloud sessions and Slack

Cloud sessions run in an Anthropic-hosted environment (or a self-hosted one from your organization), so they keep running after you turn off your computer. Open claude.ai/code in a browser, or run claude --cloud "task description" in the terminal. This is suited to sending several tasks out at once; the environment comes with git, npm, Python, and other tools ready, and once connected to the GitHub App, it can even fix PRs automatically. Limitations: it supports only GitHub (including GitHub Enterprise Server), not GitLab or Bitbucket; usage shares the quota with your other use; and if your organization has an IP allowlist set, it will be blocked.

Slack lets you hand off work by @Claude-mentioning it in a channel. It reads the context of the thread itself, then routes the work to a cloud session, where it can open a PR; the records remain at claude.ai/code. There are quite a few limitations: only GitHub is supported, each conversation can open only one PR, it can only be used in trusted conversations, and direct messages are not supported. This older version also only responds to Pro and Max accounts, and the workspace must not already be connected to Claude Tag. Team and Enterprise should use Claude Tag instead; for workspaces already connected to Claude Tag, the old bot has been disabled since 2026-10-05.

Remote Control: pick up the local conversation from your phone

This one is different from cloud sessions, so be clear about the distinction: Remote Control is the conversation you are running locally on your machine right now, which you connect to remotely through claude.ai/code or the mobile app. The program still runs on your computer, and the files and tools are local, so local MCP servers still work.

claude remote-control      # standby mode in a local terminal
claude --remote-control    # start an interactive session with it on

If you are already in a conversation, enter /remote-control; in VS Code it is /rc. Once connected, the conversation’s progress syncs across devices: you can send messages from any device, attach files or photos, and view git diffs. If the connection drops, it reconnects automatically, and messages sent in the meantime are queued until it reconnects. Bedrock, Vertex AI, and Foundry are not supported; for Team and Enterprise it is off by default and must be enabled by an admin.

Chrome extension

Install the Chrome extension (Chrome, Edge, Brave, Arc, Vivaldi, and Opera are all supported; version 1.0.36 or later is required), then run claude --chrome in the terminal to control the browser: click, type, take screenshots, read the console, fill in forms, upload files, record GIFs, and act on sites you are already logged into. Enter /chrome to check the status or turn it on by default. Not supported under WSL; you must sign in with /login, and API key authentication does not work; Bedrock, Vertex, and Foundry are also not supported. Starting with v2.1.290, settings files in a project (such as .claude/settings.json) can no longer turn on Chrome for you; use --chrome, /chrome, or your own user settings instead.

Comparison table

SituationWhich one to use
Coding and making changes at the same timeVS Code or JetBrains
Having it operate native apps or run simulatorsDesktop app or the CLI’s computer-use (macOS only, Pro/Max)
Checking on the local session while awayRemote Control
Computer needs to be turned off, but the work keeps runningCloud session
Assigning work in a team channelSlack
Operating web pages or testing the frontendChrome extension

How sessions move between platforms: --teleport pulls a cloud session back into the local terminal to continue, but this is one-way; later changes do not sync back to the cloud. --cloud starts a new cloud session from the terminal. The Continue in menu in the desktop app can send a local session up to the cloud. VS Code can also pick up a cloud session; likewise, once pulled back, it no longer syncs back to claude.ai.

Next step

You don’t need to install all of them. Pick the one closest to how you work. If you spend the whole day in an IDE, install the IDE extension. If you often need to step away from your desk, try Remote Control first: run claude remote-control locally and connect from your phone to see how it feels. When you actually run into “the computer needs to shut down but the work isn’t finished,” then set up a cloud session.

Sources: Claude Code official docs, “VS Code”, “JetBrains IDEs”, “Desktop”, “Claude Code on the web”, “Remote control”, “Claude Code with Chrome”, “Computer use”, and “Slack”, sections Prerequisites, Get started, Capabilities, and Limitations on each page (queried 2026-09-18); and the Claude Code CHANGELOG for 2.1.290 (queried 2026-10-06). (Also checked against “Claude Code in Slack” on 2026-10-15 for updates.)

The full picture of settings.json

Earlier chapters mentioned a number of settings in passing: permissions go under permissions, hooks under hooks, and the retention period is cleanupPeriodDays. But the same setting can be written in several different files, and if you write it in the wrong place, it simply won’t take effect. The example in Chapter 7 where auto only works when written at the user level comes from exactly this.

This chapter lays out the whole settings system: what the layers are, which overrides which, and which common keys exist.

Five layers of settings: which overrides which

From highest to lowest priority, higher layers override lower ones:

PrioritySourceLocationScope
1Managed settingsmanaged-settings.json, MDM, claude.ai admin consoleThe entire organization
2Command-line flagsclaude --settings <json>This one session
3Project local settings.claude/settings.local.jsonYou, this project
4Project shared settings.claude/settings.jsonEveryone on the team, this project
5User settings~/.claude/settings.jsonYou, all projects

Environment variables are not part of this stack; each key decides for itself. For example, ANTHROPIC_MODEL overrides the model in the settings file, while ANTHROPIC_DEFAULT_MODEL only takes effect when the settings file does not specify it.

How the files are created

The three kinds of files are created in different ways: user settings are created the first time you run /config; project local settings are created automatically the first time you approve a persistent permission, and Claude Code adds them to .gitignore for you; project shared settings you create yourself.

The format is strict JSON: // comments are not allowed, and there can be no extra commas. You can add a line $schema pointing to https://json.schemastore.org/claude-code-settings.json, and your editor will check your spelling.

Common keys

KeyPurpose
modelDefault model for new conversations
availableModelsRestricts which models can be picked in the /model menu
fallbackModelFallback chain used when the primary model is unavailable
permissions.defaultModeDefault permission mode
permissions.allow / deny / askPermission rules; layers are merged
hooksLifecycle hooks
envVariables to pass into the environment; layers are merged by key
cleanupPeriodDaysHow many days transcripts and snapshots are kept
autoMemoryEnabledWhether it writes its own notes
autoCompactEnabledAutomatically compacts when the context is nearly full
idleCompactionSetting it to false turns off automatic compaction while idle (since v2.1.299; requires v2.1.290 or later)
sandbox.enabledBash sandbox isolation
statusLineCustom status line
effortLevel / maxEffortLevelDefault thinking effort and its upper limit
fastMode / fastModePerSessionOptInFast mode default and per-session confirmation
workflowSizeGuidelineSize guidance for workflows
maxProseWidthOn wide screens, limits the width of Claude’s text; tables and code are not affected (since v2.1.282)
attributionSetting it to false hides attribution on all commits and PRs (since v2.1.281); older CLI versions skip settings files containing this value, so keep the object form for files shared across versions

List-type keys (such as permissions.allow) are merged across layers rather than overwritten; only single-value keys are overridden by higher layers. This determines where you should write your rules: a deny rule that the whole team should follow goes in the project shared settings, and your personal habits go in user settings.

When a setting doesn’t take effect

Don’t rush to edit files. Three commands will tell you what is happening:

/config    # open the config UI; also /config verbose=true for one-liners
/status    # shows which settings files were loaded (the Setting sources line)
claude doctor   # find broken or invalid settings files

The Setting sources line in /status is the most useful: it lists which files were actually loaded this time. If the file you expected to take effect does not appear in the list, the problem is usually a wrong path or the wrong layer. If the JSON is malformed, claude doctor will point it out.

What each of the three files is for

  • ~/.claude/settings.json: the default permission mode and your model and effort preferences; these follow the person.
  • .claude/settings.json: this project’s hooks, deny rules, and settings that everyone should share; committed to version control.
  • .claude/settings.local.json: things that only apply to this machine, such as a local test URL; not committed to version control.

Next step

Run /status once right now and check which files Setting sources lists, and whether they match what you expected. Then open ~/.claude/settings.json and add the $schema line, so that from now on your editor will flag typos directly. If you do break something, claude doctor will tell you where the problem is.

Sources: Claude Code official docs, “Settings”, sections Settings files and precedence, Find or create your settings files, and Use the /config menu; and “Settings reference”, for the description of each settings key (queried 2026-09-18); Claude Code CHANGELOG for 2.1.281 and 2.1.282 (queried 2026-10-02) and 2.1.299 (queried 2026-10-14)

Enterprise Deployment and Security

In the five-layer settings from the previous chapter, the highest layer is managed settings. Individual users rarely need them, but if you are working on projects for enterprise clients, or your company is rolling out Claude Code to the whole team, the questions become: can you require everyone to use only certain models? Can you prohibit certain commands? Will data leak out?

This chapter covers the administrator side. Individual users only need to know these mechanisms exist.

Where managed settings live

Operating systemPath
macOS/Library/Application Support/ClaudeCode/managed-settings.json
Linux, WSL/etc/claude-code/managed-settings.json
WindowsC:\Program Files\ClaudeCode\managed-settings.json

To split the settings into several files, create a managed-settings.d/ folder in the same location and put *.json files in it; they are merged in filename order.

There are four delivery methods, which differ in how long they take to take effect: a file change takes effect immediately; MDM or OS policy and the Windows registry take about 30 minutes; server-side settings from the claude.ai admin console take about 60 minutes (read once at startup, then polled every hour).

When multiple managed sources exist at the same time, managedSourcesBehavior decides how they are handled. The default, first-wins, uses only the source with the highest priority; setting it to merge merges key by key: for single values the higher layer wins, lists are merged, and locks take the strictest value. The priority order from highest to lowest is: server-side, MDM, the managed-settings.json file, and the Windows HKCU registry.

What administrators can lock

A group of settings can only be set by managed sources, and users cannot change them:

  • Permissions: permissions.deny, allowManagedPermissionRulesOnly, permissions.disableBypassPermissionsMode
  • MCP: allowedMcpServers, deniedMcpServers, managedMcpServers, allowManagedMcpServersOnly
  • Models: availableModels, enforceAvailableModels, modelPicker, plus availableModelsMatch (when set to "exact", each entry in availableModels allows only the exact version it names; new models must be listed to be used; since v2.1.283) and deniedModels (models that are blocked even if availableModels allows them; since v2.1.283)
  • API providers: allowedProviders restricts which providers this machine can use, such as the Anthropic API, custom endpoints, Bedrock, Vertex AI, Foundry, or a gateway (since v2.1.285)
  • Sandbox: sandbox.filesystem.allowManagedReadPathsOnly, sandbox.network.allowManagedDomainsOnly
  • Plugins and marketplaces: blockedMarketplaces, strictKnownMarketplaces, allowManagedHooksOnly, allowedChannelPlugins
  • Login and version: forceLoginMethod, disableSideloadFlags, requiredMinimumVersion, requiredMaximumVersion

In practice, the three most worth setting first are: permissions.deny to block paths and commands that must never be touched, disableBypassPermissionsMode so that no one can skip permission checks entirely, and requiredMinimumVersion to prevent anyone from getting stuck on a problematic older version.

Running on Bedrock or Vertex

A common requirement for enterprise clients is to run through their own cloud account. Both are configured with environment variables:

export CLAUDE_CODE_USE_BEDROCK=1
export AWS_REGION=us-east-1
export AWS_PROFILE=my-profile
export ANTHROPIC_DEFAULT_OPUS_MODEL='us.anthropic.claude-opus-4-8'   # pin the version
export ANTHROPIC_DEFAULT_SONNET_MODEL='us.anthropic.claude-sonnet-4-6'
export CLAUDE_CODE_USE_VERTEX=1
export CLOUD_ML_REGION=global
export ANTHROPIC_VERTEX_PROJECT_ID=YOUR-PROJECT-ID
export ANTHROPIC_DEFAULT_OPUS_MODEL='claude-opus-5'
export ANTHROPIC_DEFAULT_SONNET_MODEL='claude-sonnet-5'

The IAM permissions Bedrock requires are bedrock:InvokeModel, InvokeModelWithResponseStream, ListInferenceProfiles, and GetInferenceProfile, scoped to the ARNs of inference profiles and foundation models. Authentication is checked in this order: AWS profile, environment variables, Bedrock API key, and IAM Identity Center SSO. On Vertex, the minimum permission is roles/aiplatform.user, and authentication uses Application Default Credentials, gcloud configuration, or a service account key.

Pinning the model version is deliberate: aliases can switch to a different version when the platform changes, and pinning prevents everyone’s behavior from suddenly changing one morning.

Some features from earlier chapters are not supported on these two platforms, so confirm before planning: fast mode, Remote Control, the Chrome extension, and channels are not supported on Bedrock, Vertex, or Foundry.

A few security mechanisms

  • /security-review: runs a security check on the current branch to find unsafe code.
  • /sandbox: sets the boundaries of the Bash sandbox; by default the filesystem is limited to the working directory and the network to specific domains; managed sources can lock these down.
  • /permissions: views and edits the permission rules currently in effect.
  • claude doctor: diagnoses settings file problems.
  • cleanupPeriodDays: determines how many days local transcripts are kept. Cloud sessions run in isolated virtual machines, and authentication uses short-lived scoped tokens.

Compliance documents such as authentication information, SOC 2, and ISO 27001 are in Anthropic’s Trust Center (https://trust.anthropic.com); when a client asks for these, it is quicker to give them this link.

Next step

If you are helping a company adopt Claude Code: first place a managed-settings.json on one machine containing only three things: a blocklist in permissions.deny, disableBypassPermissionsMode, and requiredMinimumVersion. Use /status to confirm it appears in Setting sources, then roll it out to everyone else. If you are an individual user, this chapter only requires you to remember one thing: on a company-issued computer, some settings you change will not take effect, so check /status before you go to IT.

Sources: Claude Code official docs, “Managed settings”, sections Where each mechanism stores the policy, Choose a delivery mechanism, Keys only a managed source can set, and How Claude Code combines managed sources; “Security”, sections Privacy safeguards; and “Amazon Bedrock” and “Google Vertex AI”, sections Configure Claude Code (queried 2026-09-18); Claude Code CHANGELOG for 2.1.283 and 2.1.285 (queried 2026-10-02)

Maintained by Steven Chang

Last updated November 5, 2026 · for Claude Code CLI v2.1.299

Read the blog post (Traditional Chinese) →

Share

Claude Code Complete Guide: From MCP and Hooks to Workflows and Enterprise Deployment
Claude Code Complete Guide: From MCP and Hooks to Workflows and Enterprise Deployment

A continuously updated Claude Code reference: installation, MCP, CLAUDE.md, permissions, Hooks, Skills, Subagents, cost control, Sessions and Checkpoints, Plugins, models and effort, Worktrees, automation and CI, Workflows, platforms, settings, and enterprise deployment. Facts are verified against the official documentation.

Gooliya