Blog/Anthropic Harness Architecture
EngineeringApril 1, 202612 min read

The Anthropic agent harness just leaked. Here's what the architecture actually tells us.

The internal system powering Claude Code leaked and got rewritten as open source in under 24 hours. 50K GitHub stars in two hours. I've been going through the architecture all morning — here's what's genuinely interesting about it.

Forget the drama around the leak. What's inside is the real story. This is the most complete public reference we've ever had for how a production coding agent actually works on the inside. Regardless of how you feel about how it got out, it's worth studying if you're building anything with agents.

The five layers

At a high level the harness has five pieces, but the devil is in how they're wired together.

The turn loop

The core of the system is a ConversationRuntime that manages multi-turn execution between the LLM and a set of tools. The loop is straightforward: submit a message, get a response, check if the response contains tool calls, execute them, feed results back, repeat until the model returns a final response or you hit a budget limit.

What's less obvious is the control flow around it. The runtime tracks stop_reason — whether a turn ended because the model finished, hit max turns, or exhausted its token budget. There's a compact_after_turns threshold that triggers automatic summarisation of earlier context. And crucially, every turn produces a TurnResult that bundles together matched commands, matched tools, permission denials, and usage stats. It's a surprisingly clean data model for something that could easily become a mess of side effects.

The tool registry

Tools are defined as JSON manifests — each one has a name, description, parameter schema, and source hint. The registry holds around 800+ tool definitions and 1000+ command definitions loaded from snapshot files.

The routing system is interesting. When a prompt comes in, it gets tokenised and matched against tool manifests using keyword overlap scoring. It's not embedding-based semantic search — it's simpler than that, more like a weighted keyword index. Fast, predictable, and good enough when your tool names are descriptive.

There are about 15 built-in tools: BashTool, ReadFile, WriteFile, EditFile, GlobSearch, GrepSearch, WebSearch, WebFetch, Agent (for sub-agent delegation), TodoWrite, NotebookEdit, plus a few more. Each tool implementation handles its own execution and returns structured results back to the turn loop.

The Agent tool deserves its own mention — it lets the harness spawn sub-agents as separate processes with their own context windows. This is how Claude Code parallelises work: spin up a sub-agent for a research task, keep working in the main context, collect results when it's done. The sub-agents get their own tool permissions and token budgets.

Session persistence

This is where it gets architecturally interesting.

The harness maintains two separate data structures for conversation history:

  • TranscriptStore — an immutable, append-only log of every message in the conversation. This gets flushed to disk and never modified. It's the complete record.
  • mutable_messages — the current working context that actually gets sent to the model. When this grows past a threshold, the harness compacts it — summarising older turns into a shorter representation and discarding the originals from the active window.

The transcript is your audit trail. The mutable messages are your working memory. One is permanent, the other is lossy by design. Sessions get serialised as StoredSession objects — session ID, message list, token counts — and written to JSON files on disk.

This separation is the most important architectural decision in the whole system and I'll come back to it.

MCP integration

The harness supports Model Context Protocol servers via stdio transport. MCP lets external tools register themselves with the harness at runtime — so you can plug in a database explorer, a Figma integration, a custom API client, whatever, without modifying the harness itself.

The MCPClient handles bootstrapping, capability discovery, and method dispatch. Tools provided by MCP servers get merged into the same registry as built-in tools, so from the model's perspective there's no difference between a native tool and an MCP-provided one. Clean abstraction.

The permission system

Three modes: read-only, workspace-write, and danger-full-access. Controlled by a ToolPermissionContext that maintains a blocklist of tool names and prefixes. Before any tool executes, the context checks whether it's allowed.

It's simple and it works. Tools can be blocked by exact name or by prefix (so you can block all mcp__* tools in one go). Permission denials get tracked and reported back in the TurnResult, so the model knows when it tried something it wasn't allowed to do.

There's also a CLAUDE.md discovery system — the harness walks up the directory tree looking for instruction files that get injected into the system prompt. This is how per-project configuration works: you drop a CLAUDE.md in your repo root and it becomes part of the agent's context automatically.

The event sourcing pattern

OK — this is the bit that made me sit up.

That separation between TranscriptStore and mutable_messages? That's event sourcing.

The transcript is an append-only event log. The mutable messages are a projection — a derived view of current state that gets rebuilt (via compaction) from the underlying history. The StoredSession is a snapshot that lets you resume without replaying from zero.

If you've worked with event stores, CQRS, or append-only ledgers in distributed systems, you'll recognise this pattern immediately. Anthropic independently arrived at the same primitive that the distributed systems world has used for decades.

It's not a coincidence — it's convergent evolution. When you need auditability, replayability, and the ability to derive current state from a complete history, you end up here every time. Databases figured this out. Financial systems figured this out. Now agent infrastructure is figuring it out too.

What's purpose-built and what's missing

It's worth being clear: this harness is designed for a coding assistant, and it's very good at that job. The codebase is the persistent state. The git diff is the audit trail. The human developer reviews every output. Those are powerful assumptions that make a lot of hard infrastructure problems disappear.

But if you're thinking about agents beyond coding — and a lot of people are — the gaps are worth understanding:

Memory is lossy. Compaction summarises earlier turns and permanently discards detail from the active context. The transcript keeps everything, but it's a flat log — there's no indexing, no semantic retrieval, no confidence scoring, no way to ask "what did the agent know and decide three sessions ago?" For a coding assistant the code itself is the long-term memory. For other use cases, you'd want memory that decays gracefully and can be queried, rather than getting truncated.

Tool decisions are fire-and-forget. A tool executes, returns a result, the conversation moves on. There's no structured telemetry layer, no record of what decision led to the tool call, no way to detect drift across thousands of sessions. The human reviews the diff — that's the observability model. For autonomous agents where no human is checking every output, you'd want something more.

The tool registry is keyword-matched, not semantic. The routing uses tokenised keyword overlap, which is fast and predictable but means you can't find tools by describing what you need in natural language. This is probably fine when you have 15 well-named built-in tools, but it's a limitation if you're building a system where hundreds of domain-specific tools need to be discoverable.

Permissions are configuration, not isolation. Three modes in a config file. No container boundaries, no network policies, no egress controls. The sub-agent system inherits permissions from the parent. Perfectly sensible for a local dev tool running on your own machine. Very different requirements for anything running on production data or in a multi-tenant environment.

No cross-session learning. Each session starts with the same base context (system prompt + CLAUDE.md files). There's no knowledge graph, no shared memory across sessions, no mechanism for the agent to get better at a task over time. The transcript store preserves history but nothing reads from it to inform future sessions.

None of these are criticisms — they're design choices that make perfect sense for what this harness does. But they're worth understanding clearly if you're looking at this architecture as a starting point for something else.

The commodity question

Here's what I keep coming back to: the harness pattern itself is probably becoming a commodity.

Anthropic built one internally. It leaked. It got faithfully rewritten in under 24 hours. The core patterns — turn loops, tool registries, MCP integration, sub-agent delegation — are well understood now. The Rust rewrite is about 20K lines of code across six crates. It's not trivial, but it's not mysterious either. Anyone can build one.

The interesting question is what sits around the harness. Persistent memory that survives across sessions and improves over time. Observability over agent decisions at scale. Governance and compliance infrastructure for regulated industries. Real security boundaries between agents and the systems they operate on.

Those are the layers that determine whether an agent can run in production on things that actually matter — and they're significantly harder to get right than the harness loop itself.

What we're working on

Full disclosure — this is exactly what we've been building at Pentatonic, so take this with the appropriate grain of salt.

TES (Thing Event System) is an immutable event spine with the same append-only architecture the Anthropic harness uses for transcripts — but designed for the persistence and observability layers around the agent, not just the turn loop.

Our AI Agent SDK wraps LLM clients and automatically emits every call as a structured, immutable event — tokens, latency, tool calls, model, session context. Agent Memory adds 7-layer persistent memory on top, with a knowledge graph, vector search, and confidence decay. And NemoClaw, built with NVIDIA, adds the enterprise security boundary that a config file can't provide.

Two lines to instrument any LLM client
import { TESClient } from "@pentatonic-ai/ai-agent-sdk";
import OpenAI from "openai";

const tes = new TESClient({ clientId, apiKey, endpoint });
const ai = tes.wrap(new OpenAI(), { sessionId: "my-agent" });

// Every call is now an auditable, immutable event
const result = await ai.chat.completions.create({
  model: "gpt-4o",
  messages: [{ role: "user", content: "..." }],
});

If any of that sounds interesting: github.com/Pentatonic-Ltd/ai-agent-sdk (MIT) and thingeventsystem.ai.

But honestly, even if you never look at our stuff, go read the harness code. The event sourcing pattern alone is worth your time. The sub-agent delegation model is clever. The tool registry design is cleaner than most open source alternatives I've seen. It's a really elegant piece of engineering and I think it'll influence how a lot of agent infrastructure gets built from here.

What a time to be alive.

Philip — co-founder at Pentatonic

Build on the event spine

The harness pattern is the easy part.

The persistent memory, the observability layer, the audit trail — that's where TES sits. Free tier is live. Drop one env var into your client and start.