A coding agent like Claude Code has one small core, the agent loop. Every other part feeds the loop, guards it, extends it, or makes it cheap to run. This page lists 18 parts. Sections 5, 6, 11 and 14 cover the four hard parts: the cache, decision making, subagent orchestration and settings.json.
Each fact about Claude Code and the Claude API was checked against the official docs. The last section lists the sources.
0. The architecture
1. Model API
- The model is the brain. Your code sends it a list of tools, a system prompt and the messages.
- The model answers with text, or with one or more requests to call a tool (
tool_useblocks). stop_reasontells you why it stopped:tool_use(run the tools),end_turn(done),max_tokens(cut off),refusal.- Use streaming, so the user sees the answer while the model writes it.
- Thinking depth is set by an effort level (
low,medium,high,xhigh,max). Higher effort thinks longer and costs more. The levels you can use depend on the model.
2. Agent loop (the core)
while (true) {
const reply = await model.create({ tools, system, messages }); // 1
messages.push(reply);
const calls = reply.content.filter(b => b.type === "tool_use");
if (calls.length === 0) { // the model wants to stop
if (await stopHookBlocks(reply)) { messages.push(reason); continue; } // 8
break;
}
const results = await Promise.all(calls.map(gateThenRun)); // 6 → 3/9/11/12
messages.push({ role: "user", content: results }); // all results in ONE message
}
- The model can ask for several tools in one reply. Run them at the same time, and return all results in one message. If you split them, the model learns to stop asking in parallel.
- A failed tool still returns a result, marked as an error. The model then decides what to try next.
3. Tools
- Files: read, write, and edit by exact text replacement. An exact replacement fails loudly if the text moved, which is safer than rewriting the whole file.
- Search: glob for file names, ripgrep for content.
- Shell: a time limit, and a background mode that tells the loop when a long job ends.
- Web: fetch a page, search the web.
- Planning: a to-do list the model updates, so long tasks stay on track.
- Tool search: with many tools (for example 300 MCP tools), send only their names. The model calls a search tool to load the full definition of the few it needs. Claude Code does this ("deferred tools" plus
ToolSearch). It keeps the tool list small and stable, which also protects the cache (section 5). - Each tool has a name, a description and a JSON schema. The model picks tools from the description, so the description says when to use the tool and when not to.
4. Context builder: what goes into every request
The order matters, because the cache works on the start of the request (section 5).
- Tools: the tool list, always in the same order.
- System prompt: who the agent is, how it works, its rules. Frozen for the whole session.
- Project instructions: CLAUDE.md or AGENTS.md, from the user folder, the repo root and parent folders.
@pathlines import other files. Claude Code reads AGENTS.md when a folder has no CLAUDE.md. - Catalogues: one line per skill, per subagent type and per deferred tool. Only the names and descriptions, never the full text.
- Memory index: the first 200 lines or 25 KB of MEMORY.md, whichever comes first.
- Messages: the conversation so far, including every tool result.
- Reminders: new facts (a file changed, today's date, a new tool) are added as a small note at the end of the newest message. Earlier messages are never edited.
5. Cache management
How the model provider's prompt cache works
- The cache matches the start of the request (a prefix match), in the order tools → system → messages.
- Change one byte early in the request, and everything after it misses the cache.
- You mark up to 4 cache points (
cache_control) in a request. - A cached part lives 5 minutes by default, or 1 hour if you ask (
"ttl": "1h"). Each hit refreshes the timer at no extra cost. The timer starts at the start of the request, not at the end of the reply. - If you mix the two, put every 1-hour cache point before the 5-minute ones.
Price, from the Claude API docs
| Token type | Price, as a multiple of the normal input price |
|---|---|
| Cache write, 5 minutes | 1.25× |
| Cache write, 1 hour | 2× |
| Cache read, most models | 0.1× |
| Cache read, Claude Opus 5.5 and Claude Sonnet 5.5 | 0.05× |
| Cache read, Claude Fable 5.1 and Claude Mythos 5.1 | 0.025× |
Example, Claude Opus 5.5: input $4, 5-minute write $5, 1-hour write $8, cache read $0.20, all per million tokens.
Minimum length to cache
The start of the request must be long enough. A shorter one does not cache, and gives no error.
| Model | Minimum tokens |
|---|---|
| Claude Fable 5.1, Mythos 5.1, Opus 5.5, Opus 5, Sonnet 5.5, Fable 5, Mythos 5, Haiku 5.5 | 512 |
| Claude Opus 4.8, Sonnet 5, Sonnet 4.6, Sonnet 4.5, Opus 4.1, Opus 4, Sonnet 4 | 1,024 |
| Claude Mythos Preview, Opus 4.7 | 2,048 |
| Claude Opus 4.6, Opus 4.5, Haiku 4.5 | 4,096 |
How the agent uses it
- Point 1: at the end of the frozen part (tools + system prompt + instructions). Every turn and every session in the same project reads this from the cache.
- Point 2: at the end of the newest message. Each turn reads all earlier turns from the cache, and writes only the new turn.
- In a loop of 50 tool calls, turn 50 sends the whole conversation, but pays full price only for its newest part.
Rules that keep the cache working
- No date, time or random id in the system prompt. Put them in a reminder at the end.
- Same tools, same order, same JSON key order, every turn. Tool search adds tools without changing the start.
- Same model all session. A cache belongs to one model, so a switch starts from zero.
- Append, never edit. A reminder is a new note, not a change to an old message.
- Compaction (section 16) rewrites history. That costs one full-price turn, then the new, shorter history caches again.
- A subagent has its own context, so it has its own cache. Give each subagent type a fixed system prompt, so its helpers share one cached start.
Check it
- The API returns
cache_creation_input_tokens(written to the cache) andcache_read_input_tokens(read from the cache), next toinput_tokens. cache_read_input_tokensstays 0 for the same start: something in the start changes every turn.- Both fields are 0: the start is shorter than the minimum length, so nothing caches.
6. Decision making: who decides what
There are two deciders. The model decides what to do next. The harness decides if it may.
What the model decides from
- The system prompt and CLAUDE.md rules.
- The tool, skill and subagent descriptions. A skill or subagent is picked when its description matches the task, so the description is the routing rule.
- The conversation and the tool results so far.
- The effort level: more thinking before each step on hard tasks.
- The to-do list it keeps, and plan mode: in plan mode the model reads and explores, but does not edit source files until the user accepts a plan.
What the harness does with each tool call
model asks for a tool
└► PreToolUse hooks ── exit 2 blocks here, before any rule
│ JSON can deny, allow, ask, defer, or change the input
└► permission rules ── deny, then ask, then allow; the first match wins
│ a hook "allow" does NOT skip a matching deny or ask rule
└► permission mode ── decides the calls no rule matched (section 7)
└► ask the user ── yes once · yes, don't ask again (saves a rule) · no (the model is told why)
└► run the tool ──► PostToolUse hooks ──► result back to the model
- A rule's specificity does not change the order. A broad deny still beats a narrow allow.
- A deny in any settings file beats an allow in any other file.
- In plan mode, a hook "allow" has no effect on an edit or another call that is not read-only.
When the loop stops
- The model answers with no tool call.
- A Stop hook can refuse the stop with
"decision": "block"and a reason. The loop then goes on. For example, a hook can send the agent back when the tests still fail. - Hard limits: maximum turns, a token or money budget (
--max-budget-usdin headless mode), or the user presses Esc.
7. Permissions and safety
Modes (permissions.defaultMode)
| Mode | What it does |
|---|---|
default |
Asks the first time each tool is used. Shown as "Manual"; manual is an alias |
acceptEdits |
Accepts file edits and common file commands (mkdir, touch, mv, cp) in the working folders |
plan |
Reads and runs read-only commands; does not edit source files |
auto |
No routine prompts. A background classifier checks shell commands and network requests against your request |
dontAsk |
Denies every call that would ask. Allowed rules and calls that need no approval still run. Good for locked-down CI |
bypassPermissions |
Skips prompts, except for a few actions no mode approves. Use it only in a sandbox |
auto and bypassPermissions do not take effect from project or local settings files. Set them in user settings, managed settings, or with --permission-mode for one session.
Rules
allow,askanddenylists per tool and per pattern, for exampleBash(git status)orRead(./.env).Bash(npm test *)matches every command that starts withnpm test. The space before*matters:Bash(git diff*)also matchesgit diff-index.Bash(npm test:*)is the older way to write the same rule.:*works only at the end of a pattern.- A deny rule with only a tool name, such as
"Bash", removes the tool. The model never sees it.
Other guards
- Sandbox: limits which folders and network hosts a shell command can reach. Deny rules match the command text only, so use the sandbox when a block must hold.
- Approval screen: shows the exact command or diff before it runs.
8. Hooks
Hooks are your scripts that the harness runs at fixed moments. They enforce team rules without a change to the agent.
The events Claude Code has
| Group | Events |
|---|---|
| Session | SessionStart, Setup, SessionEnd |
| User input | UserPromptSubmit, UserPromptExpansion |
| Tool calls | PreToolUse, PermissionRequest, PermissionDenied, PostToolUse, PostToolUseFailure, PostToolBatch |
| Stopping | Stop, StopFailure, SubagentStart, SubagentStop, TeammateIdle |
| Tasks | TaskCreated, TaskCompleted |
| Context | InstructionsLoaded, PreCompact, PostCompact, PreModelSwitch, PostModelSwitch |
| Files and folders | ConfigChange, CwdChanged, DirectoryAdded, FileChanged, WorktreeCreate, WorktreeRemove |
| Interface | Notification, MessageDisplay |
| MCP | Elicitation, ElicitationResult |
The ones most agents need first:
SessionStart: a session starts or resumes. Its plain-text output is added to the context.UserPromptSubmit: before the model sees the user's message. Its plain-text output is added to the context.PreToolUse,PostToolUse: before and after each tool call. Amatcherpicks the tools, for exampleBashorEdit|Write.Stop,SubagentStop: when the main agent or a subagent wants to finish.PreCompact: before history is summarised.Notification: when the agent waits for the user.
How a hook talks to the harness
- The harness sends the event as JSON on stdin. Every event has
session_id,transcript_path,cwd,permission_modeandhook_event_name. Tool events addtool_name,tool_inputandtool_use_id.
| Exit code | Result |
|---|---|
| 0 | Go on. A single JSON object on stdout is read as a decision |
| 2 | Block, on events that can block. The text on stderr goes to the model as the reason |
| Any other, also 1 | Not a block. The action goes on, and the user sees a hook error notice |
PreToolUseJSON:hookSpecificOutput.permissionDecisionisallow,deny,askordefer, with apermissionDecisionReason.updatedInputchanges the tool's arguments before it runs.StopJSON:{"decision": "block", "reason": "..."}keeps the agent working. Withoutdecision, the stop goes ahead.
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Database writes are not allowed"
}
}
Where hooks are wired: settings.json
{
"hooks": {
"SessionStart": [{ "hooks": [{ "type": "command", "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/sync-main.sh\"" }] }],
"PreToolUse": [
{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/block-db-delete.sh\"" }] }
]
}
}
$CLAUDE_PROJECT_DIR is the project root. Quote it, so a path with spaces stays one argument.
9. Skills
- A skill is a folder with a
SKILL.mdfile. The file starts with frontmatter, then the instructions. - No frontmatter field is required. Always write a
description: the model uses it to decide when to use the skill. Without one, Claude Code uses the first line of the text. - It can hold more files: scripts, templates, reference docs.
- Three load levels, so 100 skills cost little context:
- The one-line description is always in the context (section 4, catalogues).
- The full SKILL.md loads only when the model calls the
Skilltool, or the user types/name. - The extra files load only when the instructions point to them.
- Use a skill for knowledge: how to do a kind of task.
Where they live
| Scope | Path |
|---|---|
| Personal, all your projects | ~/.claude/skills/<name>/SKILL.md |
| Project, commit it for the team | .claude/skills/<name>/SKILL.md |
| A sub-folder of the project | <subdir>/.claude/skills/<name>/SKILL.md |
| Plugin | <plugin>/skills/<name>/SKILL.md, called as plugin:skill |
| Organization | .claude/skills/ in the managed settings folder |
---
name: simplified-technical-english
description: Writes and rewrites text in Simplified Technical English. Use when the user asks for STE or plain technical writing...
---
# The rules...
10. Slash commands
- Built-in commands are part of the harness:
/help,/clear,/compact,/model,/config. - Your own commands are Markdown files with a saved prompt, for example
.claude/commands/review.md, typed as/review. $ARGUMENTSputs the words typed after the command into the prompt./fix-issue 123with "Fix GitHub issue $ARGUMENTS" sends "Fix GitHub issue 123".- Custom commands are now merged into skills.
.claude/commands/deploy.mdand.claude/skills/deploy/SKILL.mdboth create/deployand work the same way. Old command files still work; write new ones as skills. - Use a command for a repeated action that the user starts. Use a skill for knowledge the model may pick up by itself.
11. Subagents and orchestration
What a subagent is
- A second agent loop with its own fresh context, its own system prompt and its own tool list.
- It gets one task, works with its own tools, and returns one final message. Only that message enters the main conversation.
- So 40 files read by a helper cost the main context one short summary.
How a subagent type is defined: a Markdown file with frontmatter
---
name: code-reviewer
description: Reviews a diff for bugs. Use after code changes.
tools: Read, Grep, Glob
model: sonnet
---
You are a code reviewer. Report only real bugs, each with file and line...
| Where the file lives | Scope | Wins a name clash |
|---|---|---|
| Managed settings | Organization | 1st |
--agents flag |
This session | 2nd |
.claude/agents/ |
This project | 3rd |
~/.claude/agents/ |
All your projects | 4th |
A plugin's agents/ |
Where the plugin is on | 5th |
- Only
nameanddescriptionare required. - Useful optional fields:
tools,disallowedTools,model(sonnet,opus,haiku,fable, a full model id, orinherit),permissionMode,maxTurns,skills,mcpServers,hooks,effort,isolation: worktree,background. - Field names are camelCase and must match exactly. Claude Code ignores an unknown field without an error.
How orchestration runs, step by step
- The main model sees the list of subagent types and their descriptions (section 4).
- It calls the
Agenttool with a type, a short description and a full task prompt. The prompt must hold everything, because the helper does not see the main conversation. - The harness starts a new loop: that type's system prompt, its allowed tools, and the task as the first message.
- The helper runs to its end. Its hooks, permissions and the user's approvals still apply.
- Its final message comes back to the main model as the
Agenttool's result. - The main model checks the result and decides the next step. The user does not see the helper's report unless the main model passes it on.
The patterns
- Parallel fan-out: several
Agentcalls in one reply run at the same time. For example, three helpers search three parts of the repo. - Background: the call returns at once. When the helper ends, the harness adds a notice to the main conversation, which starts a new turn.
- Continue a helper: send it a new message by its id (
SendMessage), with its context still there. - Fork: a helper that starts with a copy of the main conversation instead of a fresh one.
- Worktree isolation: the helper works in its own git worktree, so its edits do not touch your checkout.
- Read-only types: the search type
Explorecannot edit files. - Scripted workflows: for big jobs, a script decides the order instead of the model. Claude Code's
Workflowtool runs a JavaScript script withagent(),parallel()andpipeline(). For example: review in 4 areas at once, then a verify helper checks each finding.
Limits
- A subagent can start its own subagents, up to 3 levels below the main conversation. At that depth, the harness removes the
Agenttool. CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTHchanges the depth. Set it to1to stop nesting.- To stop one type from starting helpers, leave
Agentout of itstools, or add it todisallowedTools. CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTSlimits how many run at the same time. The default is 20.
Cost
- Each helper pays for its own context and its own cache.
- Use a cheaper model and lower effort for reading and searching. Keep the strong model for the main loop.
12. MCP servers
- MCP (Model Context Protocol) connects outside tools: GitHub, a database, a browser, a ticket system.
- A server runs as a local process (stdio) or a web endpoint (HTTP). It lists its tools, and the harness adds them to the tool list as
mcp__<server>__<tool>. - Configure servers per user, per project (
.mcp.json) or in a plugin. - With many servers, use tool search (section 3), or the tool list grows too large.
13. Plugins and marketplaces
- A plugin is one package of skills, commands, subagent types, hooks and MCP servers.
- The manifest is
.claude-plugin/plugin.json. It is optional; onlynameis required in it. Without it, Claude Code loads what it finds in the standard layout. - Check a plugin with
claude plugin validate ./my-plugin. - A marketplace is a git repo that lists plugins. A user adds the marketplace, then installs plugins from it.
Standard layout
my-plugin/
├── .claude-plugin/plugin.json manifest (optional)
├── skills/<name>/SKILL.md
├── commands/ old form; prefer skills/
├── agents/<name>.md
├── hooks/hooks.json
├── .mcp.json
└── bin/ on the shell PATH while the plugin is on
Paths inside a plugin
| Variable | Points to | Use it for |
|---|---|---|
${CLAUDE_PLUGIN_ROOT} |
The installed plugin folder. It changes on each update | Bundled scripts and config. Never write state here |
${CLAUDE_PLUGIN_DATA} |
~/.claude/plugins/data/<id>/. Kept across updates |
Installed packages, caches |
${CLAUDE_PROJECT_DIR} |
The project root | Project scripts and config |
14. settings.json
The layers, strongest first
- Managed: set by the company, cannot be changed by the user.
- Command line: JSON passed with
--settings <file-or-json>, for this run only. - Local project:
.claude/settings.local.json, not committed. - Project:
.claude/settings.json, committed and shared with the team. - User:
~/.claude/settings.json, for all your projects.
- A key set in a higher layer replaces the same key below it.
- Lists, such as
permissions.allow, are combined across layers. A deny anywhere wins. - A flag such as
--modelor an environment variable such asANTHROPIC_MODELis not a layer. Each key's docs entry says which one wins. - Run
/statusto see which files loaded. Runclaude doctorto see entries that were rejected.
Where the user files are
| macOS and Linux | Windows | |
|---|---|---|
| User settings | ~/.claude/settings.json |
%USERPROFILE%\.claude\settings.json |
| Auto memory, default | ~/.claude/projects/<project>/memory/ |
%USERPROFILE%\.claude\projects\<project>\memory\ |
CLAUDE_CONFIG_DIR moves the whole ~/.claude folder to another place.
What goes in it
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"model": "claude-opus-5-5",
"permissions": {
"allow": ["Bash(git status)", "Bash(npm test *)"],
"ask": ["Bash(git push *)"],
"deny": ["Read(./.env)", "Read(./.env.*)", "Bash(rm -rf *)"],
"defaultMode": "default"
},
"hooks": { "PreToolUse": [ ... ] },
"env": { "NODE_ENV": "development" },
"autoMemoryDirectory": "~/claude-memory",
"statusLine": { "type": "command", "command": "~/.claude/statusline.sh" }
}
- Settings files are strict JSON. A
//comment or a trailing comma is an error. - The
$schemaline gives autocomplete and checks in most editors. autoMemoryDirectorywith an exact path:- macOS:
"/Users/<you>/claude-memory" - Linux:
"/home/<you>/claude-memory" - Windows:
"C:/Users/<you>/claude-memory". Use forward slashes, or write each backslash twice (\\).
- macOS:
15. Memory and instructions
- CLAUDE.md / AGENTS.md: rules you write. They load at the start of every session. They guide the model; they do not enforce anything. To block an action every time, use a PreToolUse hook.
- Auto memory: facts the agent saves for itself, one file per fact, with an index file (MEMORY.md).
- Default folder:
~/.claude/projects/<project>/memory/. All worktrees of one git repo share it. autoMemoryDirectory(section 14) moves it.- Only the first 200 lines or 25 KB of MEMORY.md load at session start.
- Default folder:
- Keep both short. Every line costs context in every request.
16. Sessions and compaction
- Save each session as a transcript, one JSON line per message (a
.jsonlfile). Resume it later from that file. - In Claude Code:
--continueresumes the latest session,--resume <id>resumes a named one. - Keep a copy of each file before the agent edits it, so the user can undo.
- Compaction: near the context limit, the model summarises the old part. The summary replaces it, and work goes on.
/compactstarts it by hand.
17. Surfaces
- Terminal UI: a full-screen terminal app.
- Headless:
claude -p "task"runs once, for scripts and CI.--output-formatistext,json(result, session id, cost) orstream-json.--allowedTools "Read,Edit,Bash"approves tools for the run.--bareskips local hooks, skills, plugins, MCP servers and CLAUDE.md, so every machine gives the same result.
- SDK: the Claude Agent SDK is the same harness as a library, for Python and TypeScript: loop, tools, permissions, hooks, MCP and subagents.
- IDE, desktop and web: other front ends on the same harness.
18. Distribution, cost and telemetry
- Ship one program file per platform, with auto-update.
- Show tokens and cost per session. Log errors and tool results, so you can see where the agent fails.
Build order
- Model API, the loop, and read, edit and shell tools. You now have a working agent.
- Permissions, the approval screen and settings.json, before anyone else uses it.
- The context builder with cache points, and CLAUDE.md. Check
cache_read_input_tokensnow, not later. - Search tools, the to-do list, sessions and compaction.
- Hooks.
- Skills and slash commands.
- Subagents, then background helpers and scripted workflows.
- MCP, tool search and plugins.
- Headless mode, the SDK and other surfaces.
Build it, or build on it
- From zero: call the model API yourself. You control every part.
- On the Claude Agent SDK: you get sections 2 to 16 ready-made, and add your own tools, prompts and front end.
- Language: TypeScript for a terminal app and the Agent SDK. Rust for one small, fast program file. Python to try ideas quickly.
Where each fact comes from
| Topic | Source |
|---|---|
| Cache order, cache points, lifetimes, prices, minimum length, usage fields | Claude API docs, prompt caching: https://platform.claude.com/docs/en/build-with-claude/prompt-caching |
| Hook events, exit codes, JSON decisions | Claude Code docs, hooks: https://code.claude.com/docs/en/hooks |
| Rule order, modes, hooks and rules together | Claude Code docs, permissions: https://code.claude.com/docs/en/permissions |
| Settings layers, file paths, list merging | Claude Code docs, settings: https://code.claude.com/docs/en/settings |
| Subagent files, fields, nesting limits | Claude Code docs, subagents: https://code.claude.com/docs/en/sub-agents |
| Skill paths, commands merged into skills | Claude Code docs, skills: https://code.claude.com/docs/en/skills |
| Auto memory folder, MEMORY.md limit | Claude Code docs, memory: https://code.claude.com/docs/en/memory |
| Plugin layout and variables | Claude Code docs, plugin reference: https://code.claude.com/docs/en/plugins-reference |
| Headless flags, resume | Claude Code docs, headless: https://code.claude.com/docs/en/headless |
| Status line shape | Claude Code docs, status line: https://code.claude.com/docs/en/statusline |
Deferred tools, ToolSearch, Agent, SendMessage, Workflow, background notices, reminders |
Seen in a running Claude Code session |
| How the parts are built inside | A suggested design, not Anthropic's code. Anthropic does not publish all of it |
The docs change often. Check the source pages before you rely on a number.