Claude Code Harness


A high-level architecture report based on public research, the accidental npm source map leak (March 2026), and community analysis. 512,685 lines of TypeScript across 1,902 files -- only ~1.6% is AI decision logic; the rest is deterministic harness infrastructure.

Contents

512 Klines (leaked)
1,902TypeScript files
~66built-in tools
27hook events
5context layers
7permission modes

1. System Overview

The harness is the infrastructure layer between the Claude language model and the real world. It wires together five vertical layers: surface interfaces, the core agent loop, a safety and action layer, a state persistence layer, and a backend execution environment.

The model is not the orchestrator. It emits structured tool-use requests; the harness decides whether to execute them, then feeds results back. The model only ever sees a conversation.

flowchart TD
  U["User"] -->|"prompt"| S["Surface Layer"]
  S -->|"assembled context"| AL["Agent Loop"]
  AL -->|"tool request"| SA["Safety and Action Layer"]
  SA -->|"approved action"| BE["Backend Execution"]
  BE -->|"tool result"| SL["State Layer"]
  SL -->|"updated context"| AL
  AL -->|"final reply"| S
  S -->|"response"| U

  subgraph SurfaceLayer["Surface Layer"]
    S
  end
  subgraph Core["Core Layer"]
    AL
  end
  subgraph Safety["Safety and Action Layer"]
    SA
  end
  subgraph State["State Layer"]
    SL
  end
  subgraph Backend["Backend Execution"]
    BE
  end
        
drag to pan · scroll to zoom
Fig 1. Five-layer system overview. The Claude model lives inside the Core Layer; every other layer is deterministic infrastructure.

Surface Layer

Interactive CLI, headless CLI, Agent SDK, IDE extensions, Desktop app, Browser -- all converge on the same queryLoop().

Core Layer

The async queryLoop() generator drives every iteration. It is the only place the model is invoked.

Safety + Action

Permission system, hooks, tool pool assembly, shell sandbox, subagent spawning. Any layer can block a request.

State Layer

Context assembly, session persistence (JSONL), CLAUDE.md hierarchy, sidechain subagent transcripts.

Backend Execution

Shell execution, filesystem operations, MCP server connections, 42+ tool subdirectories implementing concrete tool logic.

Key insight

Only ~1.6% of the codebase is AI decision logic. The other 98.4% is deterministic infrastructure: permissions, context management, tool routing, and recovery logic.


2. Agent Loop

The core loop is a ReAct-inspired async generator (queryLoop()). It runs until the model returns a response with no tool calls, or until a stop condition fires. The loop has seven distinct continuation sites with separate recovery paths for token exhaustion, compaction failure, and API overload.

The orchestration code does not decide which file to read or which command to run. It faithfully executes what the model emits -- nothing more.

flowchart TD
  START(["Session Start"]) --> INIT["Init State"]
  INIT --> CTXASSEMBLE["Assemble Context"]
  CTXASSEMBLE --> COMPACT["Compaction Pass"]
  COMPACT --> INVOKE["Invoke Model API"]
  INVOKE -->|"streaming chunks"| STREAM["Stream Parser"]
  STREAM -->|"text only"| REPLY["Emit Reply"]
  REPLY --> DONE(["Loop End"])
  STREAM -->|"tool-use block"| PREHOOK["PreToolUse Hooks"]
  PREHOOK -->|"blocked"| INJECT["Inject Block Feedback"]
  INJECT --> CTXASSEMBLE
  PREHOOK -->|"allowed"| PERMCHECK["Permission Check"]
  PERMCHECK -->|"denied"| ASK{"Ask User?"}
  ASK -->|"no"| INJECT
  ASK -->|"yes"| EXEC["Execute Tool"]
  PERMCHECK -->|"approved"| EXEC
  EXEC --> POSTHOOK["PostToolUse Hooks"]
  POSTHOOK --> RESULT["Append Tool Result"]
  RESULT --> STOPCHECK{"Stop Condition?"}
  STOPCHECK -->|"no"| CTXASSEMBLE
  STOPCHECK -->|"yes - max turns"| DONE
  STOPCHECK -->|"yes - context full"| AUTOCOMPACT["Auto-Compact"]
  AUTOCOMPACT --> CTXASSEMBLE
        
drag to pan · scroll to zoom
Fig 2. Agent loop lifecycle. Tools that finish streaming are dispatched immediately -- execution overlaps with model generation via the StreamingToolExecutor.

Loop Steps in Detail

#StepWhat happens
1Settings resolutionMerge managed, user, project, CLI, and session permission rules into a single policy
2State initRestore or create session JSONL, load CLAUDE.md hierarchy, inject git status and date
3Context assemblyLayer system prompt, tool definitions, memory files, message history, and prior tool results
4Compaction passApply five-stage pipeline to keep token count under budget before calling the model
5Model invocationPOST to Claude API with assembled context; response arrives as an event stream
6Tool dispatchCompleted tool-use blocks route through PreToolUse hooks, then permission check, then execution
7Result integrationTool outputs wrap as tool-result blocks and re-enter context for next iteration
8Stop checkEnd if model returns text-only, max iterations hit, or manual stop signal received

3. Tool System

Claude Code registers approximately 66 built-in tools at session start. Tools are split into concurrent (read-only, up to 10 parallel) and serialized (write/mutating, one at a time). External tools arrive via MCP servers, plugins, and skills.

Tools must explicitly declare themselves safe for concurrency. The default is fail-closed: unless a tool opts in, it serializes.

flowchart LR
  MODEL["Claude Model"] -->|"tool-use block"| ROUTER["Tool Router"]

  ROUTER --> BUILTIN["Built-in Tools"]
  ROUTER --> MCP["MCP Server Tools"]
  ROUTER --> AGENT["Subagent Tool"]

  BUILTIN --> FIO["File I/O"]
  BUILTIN --> SHELL["Shell Exec"]
  BUILTIN --> GIT["Git Ops"]
  BUILTIN --> SEARCH["Search and Web"]
  BUILTIN --> NB["Notebook Edit"]
  BUILTIN --> TASK["Task and Memory"]

  MCP -->|"stdio or HTTP"| MSERVER["External MCP Server"]

  AGENT -->|"fork or worktree"| SUB["Subagent Loop"]

  FIO --> PERM["Permission Gate"]
  SHELL --> PERM
  GIT --> PERM
  SEARCH --> PERM
  NB --> PERM
  TASK --> PERM
  MSERVER --> PERM

  PERM -->|"approved"| EXEC["Execute"]
  PERM -->|"denied"| BLOCK["Block"]
        
drag to pan · scroll to zoom
Fig 3. Tool system. Every tool category -- built-in, MCP, and subagent -- routes through the same permission gate before execution.

Tool lifecycle

Input validation (Zod schema) → PreToolUse hooks → Permission resolution → Execution → PostToolUse hooks → Error handling

Concurrency model

Read-only tools: up to 10 concurrent. Mutating tools: strictly serialized. The StreamingToolExecutor dispatches tool blocks as they finish streaming -- before the model stops generating.

MCP limits

Recommended cap: 5-6 active servers (subprocess overhead). Tool schemas load on-demand. Output capped at 25,000 tokens per call; large results spill to disk with a reference in context.


4. Permission Model

Permissions enforce deny-first authorization across seven independent layers. Any single layer can block a request regardless of what other layers allow. The design ensures a compromised or jailbroken model cannot bypass safety checks by being persuasive -- enforcement is structural, not conversational.

flowchart TD
  REQ["Tool Request"] --> PREFILTER["Layer 1: Pre-filter"]
  PREFILTER -->|"tool not denied"| DENY1["Layer 2: Deny Rules"]
  PREFILTER -->|"globally denied"| BLOCKED(["Blocked"])
  DENY1 -->|"no deny match"| MODE["Layer 3: Permission Mode"]
  DENY1 -->|"deny matches"| BLOCKED
  MODE --> TIER{"Tier?"}
  TIER -->|"Tier 1 - safe"| AUTOAPPROVE(["Auto-approved"])
  TIER -->|"Tier 2 - modify"| CLASSIFIER["Layer 4: ML Classifier"]
  TIER -->|"Tier 3 - risky"| BLOCKED
  CLASSIFIER -->|"predicted safe"| SANDBOX["Layer 5: Shell Sandbox"]
  CLASSIFIER -->|"predicted risky"| ASK["Ask User"]
  ASK -->|"approved"| SANDBOX
  ASK -->|"denied"| BLOCKED
  SANDBOX -->|"passes"| HOOKCHECK["Layer 6: Hook Intercept"]
  SANDBOX -->|"fails"| BLOCKED
  HOOKCHECK -->|"allowed"| EXEC(["Execute"])
  HOOKCHECK -->|"blocked by hook"| BLOCKED
        
drag to pan · scroll to zoom
Fig 4. Seven-layer permission model. Layers run in series; any block terminates the chain. The ML classifier (Layer 4) runs on a separate model instance and never sees model prose -- preventing prompt injection from influencing safety evaluation.

Five Permission Rule Sources

Rules merge from five sources in priority order. Higher-priority sources override lower ones.

PrioritySourceScope
1 (highest)Managed / Policy settingsAdmin-locked, non-overridable
2User settings (~/.claude/settings.json)Cross-project user preferences
3Project settings (.claude/settings.json)Per-repo rules, checked into git
4CLI arguments (--allow / --deny)Single session, invocation-time
5 (lowest)Session rules (transient)Granted interactively, not persisted

External Trust Modes

plan

Read-only. No file edits, no shell. Designed for exploration and planning.

default

Standard mode. Reads auto-approved; writes and shell prompt the user.

acceptEdits

File edits auto-approved; shell still prompts.

dontAsk

ML classifier decides autonomously. User is not prompted.

bypassPermissions

All checks skipped. Intended for sandboxed CI environments only.


5. Context and Memory

The context window (200K-1M tokens) is the binding resource constraint. Every agent iteration must fit within it. The system uses a five-stage compaction pipeline to shed information before calling the model, and a file-based memory system to persist knowledge across sessions.

Compaction Pipeline

Five stages run in sequence from cheapest to most expensive. Earlier stages execute before later ones to minimize cost.

flowchart LR
  CONV["Conversation History"] --> B1["Stage 1: Budget Reduction"]
  B1 -->|"trim large tool outputs"| B2["Stage 2: Snip"]
  B2 -->|"drop old history blocks"| B3["Stage 3: Microcompact"]
  B3 -->|"fine-grained compress"| B4["Stage 4: Context Collapse"]
  B4 -->|"read-time projection"| B5["Stage 5: Auto-Compact"]
  B5 -->|"model-generated summary"| FIT{"Fits in window?"}
  FIT -->|"yes"| CALL["Model Call"]
  FIT -->|"no"| ERR["Error - stop loop"]

  B1 -.->|"enforce per-message size cap"| B1
  B3 -.->|"cache-aware compression"| B3
        
drag to pan · scroll to zoom
Fig 5. Five-stage compaction pipeline. Each stage sheds information at a different fidelity cost. Stage 5 (Auto-Compact) asks the model to produce a semantic summary -- expensive but highest quality.

Memory Hierarchy

Persistent knowledge lives in files on disk, not in the model. The model reads these files as part of context assembly at session start and during the loop.

flowchart TD
  DISK["Disk-Based Memory"] --> L1["Managed Settings"]
  DISK --> L2["CLAUDE.md Files"]
  DISK --> L3["MEMORY.md Index"]
  DISK --> L4["Session JSONL"]
  DISK --> L5["Sidechain Transcripts"]

  L2 --> L2A["Repo root CLAUDE.md"]
  L2 --> L2B["Subdirectory CLAUDE.md"]
  L2 --> L2C["Auto-memory entries"]
  L2 --> L2D["Lazy nested rules"]

  L3 --> L3A["Topic files on-demand"]
  L3A -->|"loaded when relevant"| CTX["Context Assembly"]

  L4 --> L4A["Append-only turns"]
  L4A -->|"resume or fork"| CTX

  L1 --> CTX
  L2 --> CTX
  L3 --> CTX
        
drag to pan · scroll to zoom
Fig 6. Memory hierarchy. MEMORY.md is a lightweight index -- always loaded. Topic files load on-demand to avoid burning the context budget. Session JSONL enables resume and fork operations.
MEMORY.md max size25 KB / 200 lines (index only)
CLAUDE.md capacity~40,000 characters per file
MCP tool output cap25,000 tokens; larger results spill to disk
Git status injectionmax 2,000 chars at context assembly
Auto-compact trigger~98% context window fill
Cache boundaryStatic instructions (cacheable) split from dynamic user context

The system tracks 14 cache-break vectors and uses sticky latches to prevent mode toggles from invalidating the prompt cache -- a significant cost optimization given Claude API's cache pricing.


6. Hooks System

Hooks are deterministic callbacks the harness fires at fixed lifecycle points. They convert probabilistic model behavior into enforceable rules -- e.g., run the formatter after every file edit, block any shell command touching production, log every tool call for audit. The model cannot override a hook decision.

Hooks make enforcement deterministic where prompts make it probabilistic. A PreToolUse hook that exits 2 blocks the action regardless of what the model was told.

flowchart LR
  SESSION_START(["SessionStart"]) --> PROMPT_SUBMIT["UserPromptSubmit"]
  PROMPT_SUBMIT --> PROMPT_EXPAND["UserPromptExpansion"]
  PROMPT_EXPAND --> INSTR_LOAD["InstructionsLoaded"]
  INSTR_LOAD --> PRE["PreToolUse"]
  PRE -->|"exit 0 - allow"| PERM["PermissionRequest"]
  PRE -->|"exit 2 - block"| FEEDBACK["Inject Feedback"]
  PERM -->|"granted"| EXEC_TOOL["Tool Execution"]
  PERM -->|"denied"| PERM_DENIED["PermissionDenied"]
  EXEC_TOOL -->|"success"| POST["PostToolUse"]
  EXEC_TOOL -->|"fail"| POST_FAIL["PostToolUseFailure"]
  POST --> BATCH["PostToolBatch"]
  POST_FAIL --> BATCH
  BATCH --> NOTIFY["Notification"]
  NOTIFY --> STOP_CHECK{"Stop?"}
  STOP_CHECK -->|"continue"| PRE
  STOP_CHECK -->|"done"| STOP_EV["Stop"]
  STOP_EV --> SESSION_END(["SessionEnd"])
  STOP_CHECK -->|"error"| STOP_FAIL["StopFailure"]
        
drag to pan · scroll to zoom
Fig 7. Hook lifecycle events (27 total). Exit code 2 from any PreToolUse hook injects feedback directly into model context -- teaching it why the action was rejected.

Hook Implementation Types

TypeMechanismUse case
commandShell subprocess, JSON via stdin/stdoutFormatters, linters, audit loggers
promptLLM evaluation with injected $ARGUMENTSSemantic rule checks, content policies
httpHTTP POST to external URLRemote policy servers, webhooks
agentFull nested agent loopDeep verification, complex pre-flight checks
Additional hook events (beyond the main lifecycle)
SubagentStart, SubagentStop, TaskCreated, TaskCompleted, TeammateIdle, ConfigChange, CwdChanged, FileChanged, WorktreeCreate, WorktreeRemove, PreCompact, PostCompact, Elicitation, ElicitationResult

7. Multi-Agent and Subagent Model

Claude Code supports delegating work to subagents via the AgentTool. Subagents re-enter queryLoop() with an isolated context window, preventing parent context inflation. Only a text summary returns to the parent; the full subagent conversation goes to a sidechain JSONL file.

flowchart TD
  PARENT["Parent Agent Loop"] -->|"AgentTool call"| SPAWN{"Spawn Mode"}
  SPAWN -->|"Fork"| FORK["Fork Subagent"]
  SPAWN -->|"Worktree"| WT["Worktree Subagent"]
  SPAWN -->|"Teammate"| TM["Teammate Subagent"]

  FORK --> FLOOP["Isolated queryLoop"]
  WT --> WLOOP["Isolated queryLoop"]
  TM --> TLOOP["Isolated queryLoop"]

  FLOOP -->|"inherits parent system prompt"| CACHE["Shared Prompt Cache"]
  WLOOP -->|"overlay filesystem"| OVERLAY["Isolated File Overlay"]
  TLOOP -->|"collaborative channel"| SHARED["Shared Scratchpad"]

  FLOOP -->|"summary text only"| PARENT
  WLOOP -->|"summary + overlay diff"| PARENT
  TLOOP -->|"summary + escalations"| PARENT

  FLOOP --> SCHAIN1["Sidechain JSONL"]
  WLOOP --> SCHAIN2["Sidechain JSONL"]
  TLOOP --> SCHAIN3["Sidechain JSONL"]

  PARENT -->|"permission bubble"| USER["User Terminal"]
        
drag to pan · scroll to zoom
Fig 8. Three subagent execution models. Each runs its own queryLoop in an isolated context. Only summaries return to the parent -- the full subagent transcript lives in a sidechain file. Worktree subagents write to an overlay filesystem and merge diffs on acceptance.

Subagent Delegation Modes

Fork

Lightweight child agent. Inherits the parent's exact system prompt bytes for prompt cache reuse. Receives a restricted tool set. Changes commit before summary returns.

Worktree

Isolated filesystem overlay. Write tools modify file copies; reads hit the real filesystem. Max 20 turns, 100 messages. Overlay merges to disk on acceptance. Used for speculative execution.

Teammate

Collaborative channel with shared scratchpad directory. Multiple workers can coordinate. Permission requests escalate upstream to the parent terminal.

Built-in Specialized Agent Types

Agent TypePurposeTools
ExploreCodebase search and file locationRead-only subset
PlanStrategy design and task decompositionRead-only + planning tools
GeneralMulti-step implementation tasksFull tool set
GuideFeature assistance and code reviewRead + comment tools

Coordination logic in multi-agent setups lives entirely in prompts, not code. The coordinator instructs workers via natural language directives. There is no message-passing protocol; agents communicate through the shared scratchpad directory or by returning summaries.


Sources

This report synthesizes public research, community analysis, and findings from the accidental npm source map exposure (March 2026). No proprietary or confidential material was used.

SourceType
Dive into Claude Code - arXiv 2604.14228Academic paper (VILA-Lab)
VILA-Lab/Dive-into-Claude-Code - GitHubOpen research repo
512K Lines Reveal About Claude Code - SuperframeworksTechnical analysis
The Claude Code Source Leak - Layer5Engineering blog
Claude Code Source Leak Findings - Alex KimTechnical blog
Claude Code Source Leak (Mechanics) - ClaudeFastTechnical analysis
Inside Claude Code's Architecture - CallSphereArchitecture deep dive
Claude Code Agent Harness Architecture - WaveSpeedArchitecture analysis
Claude Code Architecture Deep Dive - BarneyCommunity analysis
Claude Code Source Leak - VentureBeatNews coverage
Claude Code Hooks Complete Guide - KonishiHooks reference
Harness Engineering Guide - DEV CommunityEngineering guide
Anthropic Accidentally Exposes Claude Code Source - InfoQNews analysis
A Look Inside Claude's Leaked AI Coding Agent - VaronisSecurity analysis

Report generated 2026-07-03. Architecture described reflects findings from the March 2026 leak and community analysis. Anthropic may have changed internal implementation since then.