[Back to Main README](../README.md)
# Architecture Overview
> The core agent loop is a simple while-loop. Most of the code lives in the systems around it.
This chapter describes **Claude Code v2.1.88**, the source snapshot analyzed in our paper. For later developments and broader design choices, see the [builder's guide](./build-your-own-agent.md) and [source notes](./agent-design-space-source-notes.md).
## Four Design Questions Every Coding Agent Must Answer
| Design Question | Claude Code's Answer | Alternatives |
|:----------------|:---------------------|:-------------|
| **Where does reasoning live?** | Model reasons; harness enforces. ~1.6% AI decision logic, 98.4% infrastructure. | LangGraph: explicit state graphs. Devin: multi-step planners. |
| **How many execution engines?** | One `queryLoop` for all interfaces (CLI, SDK, IDE). | Mode-specific engines per surface. |
| **What is the default safety posture?** | Deny-first: deny > ask > allow. Strictest rule wins. | Container isolation (SWE-Agent), git rollback (Aider). |
| **What is the binding resource constraint?** | A finite context window. Five pre-model stages apply according to configuration and context pressure. | Compute budget, explicit scratchpad. |
## High-Level System Structure (7 Components)
1. **User** -- Submits prompts, approves permissions, reviews output
2. **Interfaces** -- Interactive CLI, headless CLI (`claude -p`), Agent SDK, IDE/Desktop/Browser
3. **Agent Loop** -- `queryLoop` async generator in `query.ts`: model call → tool dispatch → result collection → repeat
4. **Permission System** -- Deny-first rules + auto-mode ML classifier + hook interception
5. **Tools** -- Up to 54 built-in + MCP-provided, assembled via `assembleToolPool`
6. **State & Persistence** -- Append-only JSONL transcripts, prompt history, subagent sidechains
7. **Execution Environment** -- Shell (with sandbox), filesystem, web fetching, MCP connections
All interfaces converge on the same `queryLoop` -- the interactive CLI, headless mode, SDK, and IDE all share the same code path. `QueryEngine` is a conversation wrapper, not the engine itself.
## 5-Layer Subsystem Decomposition (21 Subsystems)
| Layer | Responsibility | Key Components |
|:------|:---------------|:---------------|
| **Surface** | Entry points & rendering | CLI, headless, SDK, IDE (React + Ink terminal UI) |
| **Core** | Context assembly & agent loop | `queryLoop`, 5-stage compaction pipeline, subagent spawning |
| **Safety/Action** | Permissions & tools | 7 permission modes, auto-mode classifier, 27 hook events, tool pool, shell sandbox |
| **State** | Runtime state & persistence | JSONL transcripts, CLAUDE.md hierarchy, auto-memory, sidechain files |
| **Backend** | Execution environments | Shell execution, MCP connections (7 transport types), 42 tool subdirectories |
## Seven Safety Layers
The paper groups protection mechanisms into seven layers. The checks that apply depend on the tool, mode, and configuration; separate layers can still share failure modes.
1. **Tool pre-filtering** -- Blanket-denied tools removed from model's view entirely
2. **Deny-first rule evaluation** -- Deny always overrides allow, even when allow is more specific
3. **Permission mode constraints** -- Active mode determines baseline handling
4. **Auto-mode ML classifier** -- Separate LLM call evaluating safety independently
5. **Shell sandboxing** -- Filesystem + network isolation for shell commands
6. **Session-scoped permission state** -- The [session app allowlist](https://github.com/chauncygu/collection-claude-code-source-code/blob/53faa8b2162fc7a4dce2e79b55b7101bb8f9e2bf/claude-code-source-code/src/state/AppStateStore.ts#L260) is not restored on resume; the [session bypass flag](https://github.com/chauncygu/collection-claude-code-source-code/blob/53faa8b2162fc7a4dce2e79b55b7101bb8f9e2bf/claude-code-source-code/src/bootstrap/state.ts#L132) is not persisted.
7. **Hook-based interception** -- PreToolUse hooks can modify or block actions
In the [legacy Bash parsing path](https://github.com/chauncygu/collection-claude-code-source-code/blob/53faa8b2162fc7a4dce2e79b55b7101bb8f9e2bf/claude-code-source-code/src/tools/BashTool/bashPermissions.ts#L2162), commands that split into more than 50 subcommands return an `ask` decision, keeping per-subcommand analysis from overwhelming the event loop.
## Turn Execution: 9-Step Pipeline
Each turn follows a **9-step pipeline**:
1. Settings resolution → 2. State initialization → 3. Context assembly → 4. Applicable pre-model context stages → 5. Model call → 6. Tool dispatch → 7. Permission gate → 8. Tool execution → 9. Stop condition check
### Five Pre-Model Context Shapers
The [query loop](https://github.com/chauncygu/collection-claude-code-source-code/blob/53faa8b2162fc7a4dce2e79b55b7101bb8f9e2bf/claude-code-source-code/src/query.ts#L369) considers these stages in order before a model call. Each changes the context only when its conditions are met:
| Stage | Strategy | Trigger |
|:------|:---------|:--------|
| Budget Reduction | Per-message tool-result size caps | Budget state enabled and limits exceeded |
| Snip | Trim older history | Feature-gated (`HISTORY_SNIP`) |
| Microcompact | Clear older tool results | Time threshold on eligible main-thread requests, or an optional cache-editing path |
| Context Collapse | Read-time virtual projection (non-destructive) | Feature-gated (`CONTEXT_COLLAPSE`) |
| Auto-Compact | Model-generated summary | Enabled and above threshold, subject to mode and failure guards |
### Recovery Mechanisms
- Max output token escalation (up to 3 retries per turn)
- Reactive compaction (fires at most once per turn)
- Prompt-too-long: tries context-collapse overflow → reactive compaction → terminate
- Streaming fallback and fallback model switching
## Permission System Deep Dive
### 7 Permission Modes
| Mode | Behavior | Trust Level |
|:-----|:---------|:------------|
| `plan` | User approves all plans before execution | Lowest |
| `default` | Standard interactive approval | Low |
| `acceptEdits` | File edits + filesystem shell auto-approved | Medium |
| `auto` | ML classifier evaluates tool safety | High |
| `dontAsk` | No prompting, deny rules still enforced | Higher |
| `bypassPermissions` | Skips most prompts, safety-critical checks remain | Highest |
| `bubble` | Internal: subagent escalation to parent | Special |
### Authorization Pipeline
4-stage flow: **Pre-filtering** (strip denied tools from model's view) → **PreToolUse hooks** (can return `permissionDecision`) → **Rule evaluation** (deny-first) → **Permission handler** (4 branches: coordinator, swarm worker, speculative classifier, interactive)
### Auto-Mode Classifier
`yoloClassifier.ts`: loads base system prompt + permission templates (separate internal/external). Two-stage evaluation: fast-filter + chain-of-thought. Races pre-computed classification against a timeout.
## Extensibility: MCP, Plugins, Skills, and Hooks
### Four Extension Mechanisms
Context cost depends on the text the model receives and when it is loaded. Hooks can inject context, and model-based hooks can also incur separate inference cost.
| Mechanism | What Can Enter the Model's Context | Key Capability |
|:----------|:-------------|:---------------|
| **Hooks** | Optional context returned by a hook | 27 events, 4 execution types (shell, LLM, webhook, subagent verifier) |
| **Skills** | Descriptions and relevant skill instructions | SKILL.md with 15+ YAML frontmatter fields, injected via SkillTool meta-tool |
| **Plugins** | Context from the components they enable | 10 component types (commands, agents, skills, hooks, MCP, LSP, styles...) |
| **MCP Servers** | Tool schemas and results, depending on discovery and loading | External tools via 7 transport types (stdio, SSE, HTTP, WebSocket, SDK, IDE) |
### Tool Pool Assembly (5-step pipeline)
Base enumeration (up to 54 tools) → Mode filtering → Deny rule pre-filtering → MCP integration → Deduplication
### Three Injection Points
- **assemble()** -- What the model sees: CLAUDE.md, skill descriptions, MCP resources, hook-injected context
- **model()** -- What the model can reach: built-in tools, MCP tools, SkillTool, AgentTool
- **execute()** -- Whether/how an action runs: permission rules, PreToolUse/PostToolUse hooks, Stop hooks
## Context Construction and Memory
### 9 Ordered Context Sources
System prompt → Environment info → CLAUDE.md hierarchy → Path-scoped rules → Auto-memory → Tool metadata → Conversation history → Tool results → Compact summaries
### CLAUDE.md Hierarchy (4 Levels)
| Level | Path | Scope |
|:------|:-----|:------|
| Managed | `/etc/claude-code/CLAUDE.md` | System-wide (enterprise) |
| User | `~/.claude/CLAUDE.md` | Per-user |
| Project | `CLAUDE.md`, `.claude/CLAUDE.md`, `.claude/rules/*.md` | Per-project |
| Local | `CLAUDE.local.md` | Personal (gitignored) |
**Instructions and enforcement are separate.** CLAUDE.md is [injected as user context](https://github.com/chauncygu/collection-claude-code-source-code/blob/53faa8b2162fc7a4dce2e79b55b7101bb8f9e2bf/claude-code-source-code/src/utils/api.ts#L449). Both this context and the system prompt guide the model; instruction priority does not make compliance deterministic. Permission checks and sandbox restrictions constrain actions at execution time.
### File-Based Memory
- No embeddings, no vector DB -- uses LLM-based scan of memory-file headers
- Selects up to 5 relevant files on demand
- Fully inspectable, editable, version-controllable by the user
## Subagent Delegation
### 6 Built-in Types + Custom Agents
Built-in: Explore, Plan, General-purpose, Claude Code Guide, Verification, Statusline-setup.
Custom: `.claude/agents/*.md` with YAML frontmatter supporting tools, model, permissions, hooks, skills, and more.
### Key Design: SkillTool vs AgentTool
- **SkillTool**: Injects instructions into the current conversation.
- **AgentTool**: Runs a subtask in a separate conversation, with model and coordination costs that depend on the task.
Conversation separation limits how much intermediate work enters the parent context. Filesystem access and permissions depend on the execution backend and configuration.
### Three Isolation Modes
| Mode | Mechanism | Default |
|:-----|:----------|:--------|
| Worktree | Git worktree (filesystem isolation) | No |
| Remote | Remote execution (internal-only) | No |
| In-process | Shared filesystem, isolated conversation | Yes |
### Sidechain Transcripts
Subagent transcripts use separate `.jsonl` files. The parent receives result content through AgentTool; transcript storage and the returned result serve different purposes. Multi-instance coordination via POSIX `flock()` -- zero external dependencies.
## Session Persistence
### Three Persistence Channels
| Channel | Format | Purpose |
|:--------|:-------|:--------|
| Session transcripts | Append-only JSONL | Full conversation, chain-patched compaction boundaries |
| Global prompt history | `history.jsonl` | Cross-session prompt recall (reverse-read for Up-arrow) |
| Subagent sidechains | Separate JSONL per subagent | Isolated subagent histories |
### Session-scoped Grants on Resume
In the v2.1.88 snapshot, the session app allowlist is not restored on resume, and the session bypass flag is not persisted. Neither is written to the transcript, so a new process started with `--resume` begins without them; resuming or forking inside a running session keeps the grants already given. These specific rules concern temporary session state; they do not establish a general rule for restoring persistent policies or operating modes.
### Design Trade-off
Append-only JSONL favors **auditability and simplicity over query power**. Every event is human-readable, version-controllable, and reconstructable without specialized tooling.