Claude Code
Anatomy
Interactive technical breakdown of Anthropic's agentic CLI. ~512K lines of TypeScript, one while(true) loop, and a bet that the model is the orchestrator.
This interactive visualization is a deep dive into Claude Code's architecture — the ~512K lines of TypeScript that power Anthropic's agentic CLI. It was motivated by the excellent conceptual overview at Claude Code Unpacked, going deeper into the subsystems that the high-level agent loop diagram doesn't capture: the five-layer compaction system, the concurrent tool executor, the LLM-based permission classifier, and the feature flags that reveal what's coming next.
Architecture Explorer
Click around the source tree to explore what's inside.
src/. Size is proportional to file count.Tool Registry & Dispatch
From tool definition to execution result. Every tool call passes through an 8-stage pipeline with permission gates, concurrency partitioning, and result feedback. Click any stage to expand.
Tool<Input, Output, Progress> interface via the buildTool() factory. The process involves two files:
- Create a tool directory at
src/tools/YourTool/YourTool.ts. Define the tool usingbuildTool({ name, inputSchema, call, description, prompt, checkPermissions, renderToolUseMessage, maxResultSizeChars, ... }). TheinputSchemais a Zod schema that validates model-provided input before execution. - Register the tool in
src/tools.tsinsidegetAllBaseTools()(line 193). This is the single source of truth for the built-in tool registry. Add it unconditionally, or behind a feature gate usingfeature('YOUR_FLAG')for build-time tree-shaking.
name— unique identifierinputSchema— Zod schemacall()— async executiondescription()— model-facing textprompt()— system prompt contributioncheckPermissions()— permission behaviorrenderToolUseMessage()— UI renderingmaxResultSizeChars— output size limit
isEnabled()→trueisConcurrencySafe()→false(fail-closed)isReadOnly()→falseisDestructive()→falseshouldDefer→ not deferredalwaysLoad→ false
claudeai scope.
- Discovery at startup:
fetchClaudeAIMcpConfigsIfEligible()(services/mcp/claudeai.ts:39) calls Claude.ai's/v1/mcp_serversAPI endpoint with the user's OAuth token (requiresuser:mcp_serversscope). The response is memoized for the session. - Proxy transport: These servers connect via a special
claudeai-proxytransport type (mcp/types.ts:116) that routes through Claude.ai's infrastructure rather than spawning a local subprocess. - Native wrapping: Each MCP tool is wrapped as a native
Toolobject viafetchToolsForClient()(mcp/client.ts:1765). The naming convention ismcp__<server>__<tool>— e.g.,mcp__claude_ai_Gmail__authenticate. - Tool pool merge:
assembleToolPool()(tools.ts:345) merges MCP tools with built-ins. Built-in tools win name collisions. MCP tools are sorted alphabetically and appended after built-ins for prompt-cache stability.
claudeai— Claude.ai org-managed servers (first-party integrations)managed— Enterprise-managed servers (MDM/policy controlled)local/user/project— User-configured servers
allowManagedMcpServersOnly— locks to managed-onlyallowManagedSandboxDomainsOnly— network lockdown- Deny rules always merged from all scope levels
Context & Memory Management
Five compaction mechanisms and a persistent memory system keep the model working within its context window. The gauge below shows how the context window is managed.
Compaction Mechanisms
Ordered from least to most aggressive. Each layer activates when the previous one isn't sufficient.
Persistent Memory System
Four memory types stored as markdown files with YAML frontmatter. findRelevantMemories() uses Sonnet to select up to 5 relevant files per query.
System Prompt Construction
The system prompt is assembled from static base layers plus dynamic context, rebuilt for each API call. A cache boundary separates globally-cached static content from per-org dynamic content.
Static Layers — cached globally across users
Dynamic Layers — cached per-org, rebuilt each turn
Context Injection
Error Handling & Retry Logic
10 retries with exponential backoff, error classification by HTTP status, and multi-stage recovery for context overflow. Click any error class to see the recovery path.
Permissions & Sandboxing
Multiple permission modes, one pipeline. Toggle modes to see how BashTool("rm -rf /") flows differently.
rm -rf / flagged as destructive by bash classifier. Must be explicitly approved.Pipeline Stages Explained
Each tool call passes through five gates in order. A call can be blocked at any stage. Here's what each stage does and where it lives in the source code.
All Permission Modes
Seven modes govern how tool calls are authorized. Some are user-facing, others internal to the agent coordination system.
Sandboxing
The SandboxManager enforces filesystem, network, and git-level constraints on every tool execution.
Dangerous Pattern Library
40+ patterns from dangerousPatterns.ts matched by the bash classifier and auto-mode permission system.
Hooks System
28 hook events with three execution backends. Hooks can intercept, modify, and extend every tool call. Configured in settings.json.
Execution Backends
Each hook can run as a shell command, a Claude agent, or an HTTP webhook. All support async execution with configurable timeouts.
Hook Event Timeline
Events grouped by lifecycle phase. Click any event to see capabilities and exit code semantics.
Workflows & Skills
Reusable prompt workflows and multi-step task automation. Skills are the extensibility primitive for user-defined behaviors.
Skill Lifecycle
From definition to execution. Click each phase for details.
Bundled Skills
SKILL.md markdown file with YAML frontmatter inside .claude/skills/<skill-name>/. Skills are discovered from three locations, in priority order:
- Project skills —
.claude/skills/in the repo root (shared via git). Claude Code also walks parent directories up to$HOME, so monorepo sub-packages inherit root-level skills. - User skills —
~/.claude/skills/for personal skills that apply across all projects. - Managed skills — Enterprise-managed path for organization-wide skills injected via MDM policy.
description— shown to model & userwhenToUse— trigger condition for auto-invocationargumentHint— e.g."[pr-url]"userInvocable— show as/skill-namecommanddisableModelInvocation— user-only, model can't call it
allowedTools— restrict which tools the skill can usemodel—"inherit"or specific model IDexecutionContext—"fork"for isolated subagentagent— run via a named custom agenthooks— session-scoped hooks active during skill
${CLAUDE_SKILL_DIR} (resolved to skill's directory), ${CLAUDE_SESSION_ID} (current session). Inline shell via ! backticks is supported for file-based skills but disabled for MCP-sourced skills for security.
paths frontmatter field with gitignore-style glob patterns. These conditional skills remain dormant until the model reads or modifies a file matching the pattern — then they activate for the rest of the session.
- Path declaration: Add
paths: src/**/*.tsin SKILL.md frontmatter. Multiple patterns supported (one per line). - Activation trigger: When file operations (Read, Write, Edit) fire,
discoverSkillDirsForPaths()walks the directory tree from the touched file, discovers new.claude/skills/directories, and activates matching conditional skills. - Session persistence: Once activated, a conditional skill stays active for the session (tracked in
activatedConditionalSkillNamesset). Dynamic discovery directories are cached indynamicSkillDirsto avoid repeated filesystem stat calls.
.claude/skills/ directory — skills activate only when the model enters that package's code.
.claude/agents/<name>.md) are a separate extensibility mechanism from skills. Both use markdown with YAML frontmatter, but they serve different purposes:
- Single-turn prompt expansion
- Invoked via
/skill-nameor auto-triggered - Runs inline or in a forked subagent
- Limited tool set via
allowedTools - Lightweight — prompt in, response out
- Multi-turn agentic loops with their own
query() - Spawned via
AgentToolwith isolated context - Custom system prompt, model, permission mode
- Can declare MCP servers, hooks, max turns
- Supports
isolation: worktreefor git isolation
name, description, tools/disallowedTools, model, permissionMode (always/ask/deny), mcpServers, hooks, maxTurns, skills (to preload), initialPrompt, memory scope, and background: true for always-backgrounded agents.
- Bundled skills — Ship with Claude Code. Registered via
registerBundledSkill()inbundledSkills.ts. Include/commit,/review-pr,/simplify,/loop, etc. Files lazily extracted to temp directory with per-process nonce security. - File-based skills — User-authored
SKILL.mdfiles in.claude/skills/directories (project, user, managed). Auto-discovered at startup and dynamically during file operations. Support inline shell execution and template variable substitution. - MCP skills — Exposed by MCP servers as prompt resources. Same frontmatter parsing as file-based skills. Inline shell execution disabled for security (untrusted source). Merged via
appState.mcp.commands. - Legacy commands —
.claude/commands/directory (deprecated format, still loaded). Created withloadedFrom: 'commands_DEPRECATED'. Converted to skill format internally.
Task Types
Seven task types represent different execution contexts. Each tracks status via TaskStateBase.
Command Reference
All slash commands, organized by category.
Data Flows
How data moves through the system. Expand any flow to trace the path.
Claude Code vs OpenCode
OpenCode (sst/opencode, 138K stars, MIT licensed) is the most direct open-source competitor. Same stack - TypeScript, Bun, Ink. Very different philosophy.
| Dimension | Claude Code | OpenCode |
|---|---|---|
| Stack | TypeScript, Bun, React/Ink | TypeScript, Bun, Ink |
| Model Support | Anthropic-only (hard-coupled) | 75+ providers via Models.dev |
| Open Source | No (proprietary) | Yes (MIT license) |
| Core Loop | 1,490-line while(true) with 7 recovery transitions | Standard agent loop, simpler recovery |
| Architecture | Monolithic CLI with embedded UI | Client/server split (enables future clients) |
| Context Mgmt | 5 compaction mechanisms + circuit breaker | Auto-compact at 95% threshold |
| Session Storage | JSONL transcripts on disk | SQLite database |
| Memory System | Persistent file-based (MEMORY.md + types + team sync) | Session history only |
| Codebase | ~512K lines, 1,884 files | Smaller, monorepo with packages |
| Dimension | Claude Code | OpenCode |
|---|---|---|
| Built-in Tools | 50+ (Bash, FileEdit, FileRead, Grep, Glob, WebFetch, Agent, MCP, Notebook, LSP, etc.) | 14 (bash, edit, write, read, grep, glob, list, lsp, apply_patch, skill, todowrite, webfetch, websearch, question) |
| Custom Tools | Via MCP servers or plugins | Define in config file + MCP servers |
| Slash Commands | 103 built-in | ~5 built-in + custom via .opencode/commands/ |
| MCP Integration | 6 transports (stdio, SSE, HTTP, WS, SDK, proxy) + OAuth + resources | Stdio-based servers via config |
| LSP | Experimental (feature-gated) | Built-in, auto-loads language servers |
| Tool Concurrency | Partition-based: reads concurrent (max 10), writes serial | Not documented |
| Deferred Loading | Yes - rarely used tools loaded on demand via ToolSearch | No |
| Undo/Redo | /rewind (restore files to message state) | /undo and /redo commands |
| Dimension | Claude Code | OpenCode |
|---|---|---|
| Permission Modes | 4 modes: default, auto (AI classifier), bypass, acceptEdits | 3 outcomes: allow, ask, deny |
| Pattern Matching | Tool name + content matching, e.g. Bash(git:*) | Glob patterns on tool inputs, e.g. "git *": "allow" |
| AI Classification | Yes - bashClassifier, yoloClassifier for auto-mode | No |
| Hook Overrides | PreToolUse hooks can approve/deny/modify | Not documented |
| Denial Tracking | Counts consecutive denials, falls back to prompting | No |
| Enterprise MDM | Yes - managed policies, remote settings | No |
| Per-Agent Perms | Yes - each agent gets restricted tool set | Yes - per-agent permission overrides |
| External Dirs | Via --add-dir flag and settings | external_directory permission type with ask default |
| Dimension | Claude Code | OpenCode |
|---|---|---|
| Agent System | Hub-and-spoke coordinator, 7 task types, git worktree isolation, Dream tasks | 2 primary (Build, Plan) + 2 subagents (General, Explore) + system agents |
| IDE Integration | VS Code + JetBrains extensions, WebSocket bridge | VS Code extension, desktop app beta |
| Desktop App | Mac + Windows | Mac + Windows + Linux (beta) |
| Web App | claude.ai/code | None |
| Voice Input | Yes (feature-gated, requires OAuth) | Not documented |
| Hooks System | 28 event types (PreToolUse, PostToolUse, SessionStart...) | Not documented |
| Cost Tracking | Per-model, session persistence, budget limits | Not documented |
| Enterprise | MDM, policy limits, managed MCP, remote settings | None |
| Hidden Features | 14+ (Kairos, Coordinator, Bridge, Dream, Buddy, Voice...) | Simpler feature set |
| Pricing | Anthropic API key or subscription required | Free (BYOK), optional Zen service |
| Custom Agents | Via .claude/agents/ markdown files | Via config JSON or markdown files + opencode agent create |
| Theming | /theme command | Themes + per-agent colors |
Landscape Comparison
Where Claude Code stands vs. the broader ecosystem. Click rows to expand.
| Capability | Claude Code | Landscape |
|---|
Settings & Hooks
Key configuration options and lifecycle hook events.