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.

1,884
TypeScript files
512K
Lines of code
50+
Built-in tools
103
Slash commands
87
React hooks
01

Architecture Explorer

Click around the source tree to explore what's inside.

Tools & Commands
Core Processing
UI Layer
Infrastructure
Support & Utilities
Personality & UX
Click a module to explore
Each block represents a top-level directory in src/. Size is proportional to file count.
02

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.

How-To
Adding a New Tool to Claude Code
Every tool is a TypeScript module that satisfies the 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 using buildTool({ name, inputSchema, call, description, prompt, checkPermissions, renderToolUseMessage, maxResultSizeChars, ... }). The inputSchema is a Zod schema that validates model-provided input before execution.
  • Register the tool in src/tools.ts inside getAllBaseTools() (line 193). This is the single source of truth for the built-in tool registry. Add it unconditionally, or behind a feature gate using feature('YOUR_FLAG') for build-time tree-shaking.
Required Methods
  • name — unique identifier
  • inputSchema — Zod schema
  • call() — async execution
  • description() — model-facing text
  • prompt() — system prompt contribution
  • checkPermissions() — permission behavior
  • renderToolUseMessage() — UI rendering
  • maxResultSizeChars — output size limit
Defaults from buildTool()
  • isEnabled()true
  • isConcurrencySafe()false (fail-closed)
  • isReadOnly()false
  • isDestructive()false
  • shouldDefer → not deferred
  • alwaysLoad → false
Tool.ts:362 (interface) · Tool.ts:757 (defaults) · tools.ts:193 (registry)
Architecture Note
MCP as the Internal Tool Extension Mechanism
Claude Code doesn't just consume MCP servers — it uses MCP as a first-party extension mechanism. Claude.ai's own services (Gmail, Google Calendar, and other integrations) are exposed to the CLI as MCP tools via a dedicated claudeai scope.
  • Discovery at startup: fetchClaudeAIMcpConfigsIfEligible() (services/mcp/claudeai.ts:39) calls Claude.ai's /v1/mcp_servers API endpoint with the user's OAuth token (requires user:mcp_servers scope). The response is memoized for the session.
  • Proxy transport: These servers connect via a special claudeai-proxy transport 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 Tool object via fetchToolsForClient() (mcp/client.ts:1765). The naming convention is mcp__<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.
Three MCP scopes control tool visibility:
Scope Hierarchy
  • claudeai — Claude.ai org-managed servers (first-party integrations)
  • managed — Enterprise-managed servers (MDM/policy controlled)
  • local / user / project — User-configured servers
Policy Controls
  • allowManagedMcpServersOnly — locks to managed-only
  • allowManagedSandboxDomainsOnly — network lockdown
  • Deny rules always merged from all scope levels
mcp/claudeai.ts:39 · mcp/client.ts:1765 · mcp/types.ts:10-19 · tools.ts:345
03

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.

04

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

05

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.

06

Permissions & Sandboxing

Multiple permission modes, one pipeline. Toggle modes to see how BashTool("rm -rf /") flows differently.

BashTool("rm -rf /")
Validate
Deny Rules
Hooks
?
Classifier
Execute
Default mode: Passes validation and deny rules, but user is prompted with a permission dialog. 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.

07

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.

08

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

How-To
User-Defined Skills
Users create custom skills by placing a 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.
SKILL.md frontmatter fields:
Identity & Trigger
  • description — shown to model & user
  • whenToUse — trigger condition for auto-invocation
  • argumentHint — e.g. "[pr-url]"
  • userInvocable — show as /skill-name command
  • disableModelInvocation — user-only, model can't call it
Execution & Constraints
  • allowedTools — restrict which tools the skill can use
  • model"inherit" or specific model ID
  • executionContext"fork" for isolated subagent
  • agent — run via a named custom agent
  • hooks — session-scoped hooks active during skill
Template variables in markdown body: ${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.
skills/loadSkillsDir.ts:185 (frontmatter) · skills/loadSkillsDir.ts:638 (discovery) · skills/loadSkillsDir.ts:270 (execution)
Advanced
Conditional Skills & Dynamic Discovery
Skills can declare a 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/**/*.ts in 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 activatedConditionalSkillNames set). Dynamic discovery directories are cached in dynamicSkillDirs to avoid repeated filesystem stat calls.
This enables monorepo setups where each package has its own .claude/skills/ directory — skills activate only when the model enters that package's code.
loadSkillsDir.ts:159 (path parsing) · loadSkillsDir.ts:861 (dynamic discovery) · loadSkillsDir.ts:771 (conditional activation)
Architecture Note
Custom Agents vs Skills
Custom agents (.claude/agents/<name>.md) are a separate extensibility mechanism from skills. Both use markdown with YAML frontmatter, but they serve different purposes:
Skills
  • Single-turn prompt expansion
  • Invoked via /skill-name or auto-triggered
  • Runs inline or in a forked subagent
  • Limited tool set via allowedTools
  • Lightweight — prompt in, response out
Custom Agents
  • Multi-turn agentic loops with their own query()
  • Spawned via AgentTool with isolated context
  • Custom system prompt, model, permission mode
  • Can declare MCP servers, hooks, max turns
  • Supports isolation: worktree for git isolation
Custom agents define: 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.
AgentTool/loadAgentsDir.ts:541 (parsing) · loadAgentsDir.ts:296 (loading) · .claude/agents/*.md
Skill Sources
Four Origins for Skills
Skills can come from four sources, all merged and deduplicated by name (first wins):
  • Bundled skills — Ship with Claude Code. Registered via registerBundledSkill() in bundledSkills.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.md files 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 with loadedFrom: 'commands_DEPRECATED'. Converted to skill format internally.
bundledSkills.ts:53 (bundled) · loadSkillsDir.ts:638 (file) · mcpSkillBuilders.ts (MCP) · loadSkillsDir.ts:566 (legacy)

Task Types

Seven task types represent different execution contexts. Each tracks status via TaskStateBase.

09

Command Reference

All slash commands, organized by category.

10

Hidden Features

Stuff that's in the code but not shipped yet. Feature-flagged, env-gated, or just commented out.

11

Data Flows

How data moves through the system. Expand any flow to trace the path.

12

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.

DimensionClaude CodeOpenCode
StackTypeScript, Bun, React/InkTypeScript, Bun, Ink
Model SupportAnthropic-only (hard-coupled)75+ providers via Models.dev
Open SourceNo (proprietary)Yes (MIT license)
Core Loop1,490-line while(true) with 7 recovery transitionsStandard agent loop, simpler recovery
ArchitectureMonolithic CLI with embedded UIClient/server split (enables future clients)
Context Mgmt5 compaction mechanisms + circuit breakerAuto-compact at 95% threshold
Session StorageJSONL transcripts on diskSQLite database
Memory SystemPersistent file-based (MEMORY.md + types + team sync)Session history only
Codebase~512K lines, 1,884 filesSmaller, monorepo with packages
DimensionClaude CodeOpenCode
Built-in Tools50+ (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 ToolsVia MCP servers or pluginsDefine in config file + MCP servers
Slash Commands103 built-in~5 built-in + custom via .opencode/commands/
MCP Integration6 transports (stdio, SSE, HTTP, WS, SDK, proxy) + OAuth + resourcesStdio-based servers via config
LSPExperimental (feature-gated)Built-in, auto-loads language servers
Tool ConcurrencyPartition-based: reads concurrent (max 10), writes serialNot documented
Deferred LoadingYes - rarely used tools loaded on demand via ToolSearchNo
Undo/Redo/rewind (restore files to message state)/undo and /redo commands
DimensionClaude CodeOpenCode
Permission Modes4 modes: default, auto (AI classifier), bypass, acceptEdits3 outcomes: allow, ask, deny
Pattern MatchingTool name + content matching, e.g. Bash(git:*)Glob patterns on tool inputs, e.g. "git *": "allow"
AI ClassificationYes - bashClassifier, yoloClassifier for auto-modeNo
Hook OverridesPreToolUse hooks can approve/deny/modifyNot documented
Denial TrackingCounts consecutive denials, falls back to promptingNo
Enterprise MDMYes - managed policies, remote settingsNo
Per-Agent PermsYes - each agent gets restricted tool setYes - per-agent permission overrides
External DirsVia --add-dir flag and settingsexternal_directory permission type with ask default
DimensionClaude CodeOpenCode
Agent SystemHub-and-spoke coordinator, 7 task types, git worktree isolation, Dream tasks2 primary (Build, Plan) + 2 subagents (General, Explore) + system agents
IDE IntegrationVS Code + JetBrains extensions, WebSocket bridgeVS Code extension, desktop app beta
Desktop AppMac + WindowsMac + Windows + Linux (beta)
Web Appclaude.ai/codeNone
Voice InputYes (feature-gated, requires OAuth)Not documented
Hooks System28 event types (PreToolUse, PostToolUse, SessionStart...)Not documented
Cost TrackingPer-model, session persistence, budget limitsNot documented
EnterpriseMDM, policy limits, managed MCP, remote settingsNone
Hidden Features14+ (Kairos, Coordinator, Bridge, Dream, Buddy, Voice...)Simpler feature set
PricingAnthropic API key or subscription requiredFree (BYOK), optional Zen service
Custom AgentsVia .claude/agents/ markdown filesVia config JSON or markdown files + opencode agent create
Theming/theme commandThemes + per-agent colors
Claude Code wins on depth
50+ tools, 5 compaction mechanisms, 28 hook types, enterprise MDM, coordinator mode with git worktree isolation. Built for production-scale agentic sessions.
OpenCode wins on openness
75+ model providers, MIT licensed, client/server architecture, built-in LSP, custom tools in config. Built for flexibility and provider freedom.
The verdict: Claude Code for depth, enterprise features, and sophisticated context management. OpenCode for provider flexibility, open-source transparency, and simpler extensibility. Same stack, different bets - Claude Code bets on Anthropic models getting better; OpenCode bets on model commoditization.
13

Landscape Comparison

Where Claude Code stands vs. the broader ecosystem. Click rows to expand.

CapabilityClaude CodeLandscape
14

Settings & Hooks

Key configuration options and lifecycle hook events.

Hook Events (28 types)

Key Settings