Intro
Inspired by a recent HackerNews post on how browsers work, I had an idea to do a similar explanation for Claude Code. Claude Code is exploding right now and it ocurred to me that I don't fully understand how it works. I know it's a tool-based agent that runs in a loop, of course, and there's the Claude Agent SDK behind it, but how it ACTUALLY works? That warranted an investigation. So I've decided to use Claude to investigate itself. It is quite capable of doing so, it actually has a special feature that allows it to quickly reference the official docs to get up to speed on its own featureset, a specialized subagent that I Claude can spawn using the Task tool with subagent_type='claude-code-guide'. The result is this article and its twin: Claude Code in Action.
In the second article we've recorded a fairly basic Claude Code session during which it built a simple todolist app. The challenge was simple on-purpose so that the resulting breakdown would be palatable for everyone.
The Big Picture
Claude Code is deceptively simple at its core. The entire system runs on what developers call an agentic loop - a pattern so elegant it can be summarized in one line:
while (tool_call) → execute tool → feed results → repeat
That's it. The loop continues as long as Claude decides to use tools. When Claude produces a plain text response without any tool calls, the loop terminates.
Architecture Overview
The Tech Stack
Claude Code ships as a single cli.js file (~10.5MB) containing:
- Node.js/TypeScript - The agent logic and tool implementations
- Terminal UI framework - Interactive command-line interface
- Vendored ripgrep - For blazing-fast file search
- Tree-sitter WASM - For understanding code structure
Fun fact: 90% of Claude Code's code was written by Claude Code itself.
Startup & Initialization
When you run claude in your terminal, a carefully orchestrated startup sequence begins.
CLI Parsing
First, command-line arguments are parsed:
claude --permission-mode acceptEdits --append-system-prompt "Be concise"
Key flags include:
--permission-mode- How to handle tool permissions--append-system-prompt- Additional system instructions--tools- Which tools to enable--resume/--continue- Session management
Session Initialization
Claude Code creates or loads a session:
Session ID: a7f3e2d1-4b5c-6789-abcd-ef0123456789
Transcript: ~/.claude/projects/<project-id>/<session-id>.jsonl
Sessions are persistent - you can resume conversations days later with full context.
Settings Loading (Precedence Order)
- Managed settings - Enterprise policy (cannot be overridden)
- File-based managed settings - managed-settings.json
- Command-line arguments - What you typed
- Local project settings - .claude/settings.local.json
- Shared project settings - .claude/settings.json
- User settings - ~/.claude/settings.json
Memory Loading (The CLAUDE.md Hierarchy)
This is where Claude learns about your project. Memory files are loaded in order from enterprise policy down to local project memory:
- Enterprise Policy - /Library/.../ClaudeCode/CLAUDE.md
- Project Memory - ./CLAUDE.md or .claude/CLAUDE.md
- Project Rules - .claude/rules/*.md
- User Memory - ~/.claude/CLAUDE.md
- Local Project Memory - .claude/CLAUDE.local.md
Key insight: Claude Code reads memories recursively, starting from your current directory and walking up to the root. A CLAUDE.md in a parent directory applies to all subdirectories.
You Press Enter
You've typed your request. Now what?
UserPromptSubmit Hook
Before Claude even sees your prompt, it goes through the UserPromptSubmit hook. Hooks can block the prompt, add context, or validate for security issues.
System Prompt Assembly
The final system prompt is constructed from:
- Claude Code's default system prompt (internal, not published)
--append-system-promptcontent (if provided)- Output style adjustments (if configured)
Claude Code's internal system prompt is not published. Anthropic states: "To add custom instructions, use CLAUDE.md files or the --append-system-prompt flag."
Context Preparation
Claude is provided with:
- Loaded CLAUDE.md files
- Available tools
- MCP tools (if configured)
- Slash commands & skills
- Conversation history
The Agentic Loop
This is the heart of Claude Code.
while response.has_tool_calls():
for tool_call in response.tool_calls:
result = execute_tool(tool_call)
feed_result_to_model(result)
response = get_next_response()
Why Single-Threaded?
Anthropic explicitly chose this design for debuggability and reliability. There are no swarms, no competing agent personas - just one flat list of messages with a single main thread.
When parallelism helps, Claude Code can spawn multiple sub-agents concurrently via the Task tool. There is no documented limit on concurrent sub-agents.
Real-Time Steering
An asynchronous dual-buffer queue enables:
- Pause/resume functionality
- Mid-task interjections - Type new instructions while Claude is working
- Seamless plan adjustments without restarting
Tool Execution
Claude Code has 17 core tools, organized into categories:
Reading & Discovery Tools
| Tool | Purpose |
|---|---|
| Read | Read file contents (up to ~2000 lines by default) |
| Glob | Wildcard pattern matching across repositories |
| Grep | Full regex search (powered by ripgrep) |
| LS | List directory contents |
Design choice: Claude uses regex over vector databases for search. Claude understands code structure deeply enough to craft sophisticated regex patterns, making embeddings unnecessary.
Editing Tools
| Tool | Purpose |
|---|---|
| Edit | Surgical patches - targeted, minimal changes |
| Write | Create or overwrite entire files |
| NotebookEdit | Jupyter notebook cell manipulation |
Execution Tools
| Tool | Purpose |
|---|---|
| Bash | Execute shell commands with persistent working directory |
| WebFetch | Retrieve URL content |
| WebSearch | Search the web |
Critical detail: Bash maintains working directory across commands, but environment variables do not persist between calls. Each command runs in a fresh shell.
Control Flow Tools
| Tool | Purpose |
|---|---|
| TodoWrite | Create/manage structured task lists |
| Task | Spawn sub-agents for complex operations |
| AskUserQuestion | Request clarification from you |
Permissions & Safety
Claude Code is conservative by default. Actions that modify your system require explicit approval.
Permission Tiers
| Tool Type | Approval Required | "Don't Ask Again" Behavior |
|---|---|---|
| Read-only | No | N/A |
| Bash commands | Yes | Permanent per project/command |
| File modification | Yes | Until session end |
| Web operations | Yes | Domain-based |
Permission Modes
| Mode | Behavior |
|---|---|
| default | Ask on first use of each tool |
| acceptEdits | Auto-accept file edits for the session |
| plan | Analyze only - no modifications allowed |
| dontAsk | Auto-deny unless pre-approved |
| bypassPermissions | Skip all prompts (requires safe environment) |
Context Management
Claude Code maintains conversation history in a JSON transcript, but context windows fill up. Here's how it's managed.
Auto-Compaction
When the context window nears capacity, the Compressor triggers:
PreCompacthook fires (type: manual or auto)- Claude generates a summary of earlier conversation
- Older turns are removed from context
- Summary is injected as context
- Conversation continues with fresh context window
Manual Context Control
/clear- Reset context between tasks/compact- Manually trigger compaction/memory- Edit memory files
Session Persistence
Sessions are stored as .jsonl files at ~/.claude/projects/<project-id>/<session-id>.jsonl. Resume with /resume or --continue for the most recent session.
Extensibility: Hooks & MCP
The Hook System
Hooks are shell commands or prompts that execute at specific lifecycle points:
| Event | When It Fires |
|---|---|
| SessionStart | Session begins or resumes |
| UserPromptSubmit | Before Claude processes your prompt |
| PreToolUse | Before tool execution |
| PermissionRequest | When showing permission dialog |
| PostToolUse | After tool completes |
| Notification | When Claude sends notifications |
| Stop | When Claude finishes |
| SubagentStop | When a sub-agent (Task) finishes |
| PreCompact | Before context compaction |
| SessionEnd | Session ends |
Model Context Protocol (MCP)
MCP is an open protocol that standardizes how Claude Code communicates with external tools and data sources. It uses JSON-RPC 2.0 over configurable transports.
The Three Primitives:
- Tools - Functions the model can invoke (e.g., query database, send message)
- Resources - Data sources the model can read (e.g., files, API responses)
- Prompts - Pre-defined prompt templates for common workflows
Transport Options:
| Transport | Use Case |
|---|---|
| stdio | Local processes - server runs as subprocess |
| SSE (HTTP) | Remote servers - Server-Sent Events over HTTP |
Example Configuration:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "..." }
}
}
}
MCP enables integrations like GitHub operations, database queries, Slack notifications, Puppeteer browser automation, and custom internal tools - all through a standardized protocol.
Key Design Principles
Simplicity First - "Do the simple thing first - regex over embeddings, Markdown over databases."
Debuggability - Single-threaded execution with one flat message list makes issues traceable.
User Control - Conservative permissions, hook interception, and explicit tool approval keep you in charge.
Extensibility - Hooks, MCP, and custom commands let you adapt Claude Code to any workflow.
Want to see Claude Code in action? Check out our companion walkthrough where we capture 22 tool calls building a full-stack app in real-time.

