| name | claude-code-agent-harness |
| description | Deep architectural knowledge of AI Agent Harness design patterns, implementation strategies, and Claude Code internals for building production-grade AI agents |
| triggers | ["how do I build an agent harness","explain the agent conversation loop","implement tool system for my agent","set up agent permission pipeline","design agent context management","create MCP integration for agent","build sub-agent fork mechanism","implement agent memory system"] |
Claude Code Agent Harness Architecture
Skill by ara.so — Claude Code Skills collection.
Overview
This project is a comprehensive 420,000-word architectural analysis of AI Agent Harness design, using Claude Code as the reference implementation. It provides production-ready patterns for building agent systems with conversation loops, tool execution, permission management, context compression, memory systems, and multi-agent orchestration.
Key Capabilities:
- Agent conversation loop architecture (async generator pattern)
- Tool system design with 50+ tool implementations
- Four-stage permission pipeline
- Context management and compression strategies
- Memory systems and fork mechanisms
- MCP (Model Context Protocol) integration
- Sub-agent orchestration patterns
- Streaming architecture and performance optimization
Installation
git clone https://github.com/lintsinghua/claude-code-book.git
cd claude-code-book
Core Architecture Patterns
1. Conversation Loop (Agent Heartbeat)
The conversation loop is an async generator that drives agent execution:
async function* conversationLoop(
deps: QueryDeps
): AsyncGenerator<YieldEvent, void, void> {
while (true) {
const response = await deps.llm.generate({
messages: deps.context.messages,
tools: deps.tools.available,
});
for (const chunk of response.stream) {
yield { type: 'text_delta', delta: chunk };
}
if (response.toolCalls) {
for (const call of response.toolCalls) {
const result = await deps.tools.execute(call);
yield { type: 'tool_result', result };
deps.context.addMessage({ role: 'tool', content: result });
}
;
}
((response, deps)) {
{ : , : (response) };
;
}
}
}
=
| { : ; : }
| { : ; : }
| { : ; : }
| { : ; : }
| { : ; : };
=
|
|
|
|
|
|
|
|
|
| ;
2. Tool System (Agent's Hands)
Tools follow a five-element protocol:
interface Tool<TInput, TOutput, TParams> {
name: string;
description: string;
inputSchema: z.ZodSchema<TInput>;
execute: (input: TInput, params: TParams) => Promise<TOutput>;
metadata: ToolMetadata;
}
interface ToolMetadata {
readOnly: boolean;
destructive: boolean;
concurrencySafe: boolean;
requiresConfirmation: boolean;
category: ToolCategory;
}
function buildTool<TInput, TOutput>(
config: ToolConfig<TInput, TOutput>
): Tool<TInput, TOutput> {
return {
name: config.name,
description: config.description,
: config.,
: (input, params) => {
{
validated = config..(input);
(config. && !params.) {
approved = params..({
: config.,
: validated,
});
(!approved) ();
}
.([
config.(validated, params),
(params. || ),
]);
} (error) {
(error, config.);
}
},
: config.,
};
}
readFileTool = ({
: ,
: ,
: z.({
: z.(),
: z.([, ]).(),
}),
: {
: ,
: ,
: ,
: ,
: ,
},
: (input, params) => {
fs = ();
content = fs.(input., input.);
{ content, : content. };
},
});
3. Permission Pipeline (Agent's Guardrails)
Four-stage permission management:
type PermissionMode =
| 'autonomous'
| 'interactive'
| 'strict'
| 'read_only'
| 'sandbox';
interface PermissionPipeline {
checkRules(tool: ToolCall): Promise<RuleDecision>;
classify(tool: ToolCall): Promise<RiskLevel>;
requestApproval(tool: ToolCall): Promise<boolean>;
logExecution(tool: ToolCall, result: ToolResult): Promise<void>;
}
class FourStagePermissionPipeline implements PermissionPipeline {
async checkRules(tool: ): <> {
( rule .) {
((rule., tool.)) {
rule.;
}
}
{ : , : };
}
(: ): <> {
classification = .([
..(tool),
(, { : }),
]);
classification.;
}
(: ): <> {
(. === ) ;
(. === && tool..) {
;
}
..({
: ,
: tool.,
: .(tool),
});
}
(
: ,
:
): <> {
..({
: .(),
: tool.,
: tool.,
: result,
: result.,
: .,
});
}
}
4. Context Management (Working Memory)
Progressive compression with circuit breaker:
interface ContextWindow {
total: number;
reserved: {
system: number;
tools: number;
recent: number;
};
available: number;
}
class ContextManager {
private stages: CompressionStage[] = [
{ name: 'snip', threshold: 0.7, handler: this.snipOldMessages },
{ name: 'micro_compact', threshold: 0.8, handler: this.microCompact },
{ name: 'collapse', threshold: 0.9, handler: this.collapseBlocks },
{ name: 'auto_compact', threshold: 0.95, handler: this.autoCompact },
];
async compress(
messages: Message[],
:
): <[]> {
usage = .(messages);
ratio = usage / budget.;
( stage .) {
(ratio >= stage.) {
messages = stage.(messages, budget);
}
}
(.(messages) > budget.) {
();
}
messages;
}
(
: [],
:
): <[]> {
recent = messages.(-budget..);
important = messages.( m.?.);
system = messages.( m. === );
[...system, ...important, ...recent];
}
(
: []
): <[]> {
messages.( {
(msg. === && msg.. > ) {
{
...msg,
: .(msg., ),
: { ...msg., : },
};
}
msg;
});
}
}
5. Memory System (Long-term Memory)
Four closed-form memory types:
interface MemorySystem {
facts: Map<string, Fact>;
preferences: Map<string, any>;
context: Map<string, Context>;
learned: Map<string, Learned>;
}
class AgentMemory {
private index: MemoryIndex;
async save(key: string, value: MemoryEntry): Promise<void> {
if (this.isDerived(value)) {
return;
}
await this.store.set(key, value);
await this.updateIndex(key, value);
}
async (: ): <> {
forked = ();
forked. = parentMemory.;
forked. = (parentMemory.);
forked. = (parentMemory.);
forked. = ();
forked;
}
(
: ,
:
): <> {
index = .();
index.[key] = {
: value.,
: value.,
: .(value),
};
.(index);
}
}
6. Sub-Agent Fork Pattern
Recursive agent spawning with inheritance:
interface SubAgentConfig {
type: 'custom' | 'builtin';
agentPath?: string;
builtinName?: 'coordinator' | 'specialist' | 'reviewer' | 'planner';
inheritContext: boolean;
inheritMemory: boolean;
inheritTools: boolean;
}
class AgentFork {
async spawn(
parent: Agent,
config: SubAgentConfig
): Promise<Agent> {
const agentDef = config.type === 'builtin'
? await this.loadBuiltin(config.builtinName!)
: await this.loadCustom(config.agentPath!);
const child = new Agent({
...agentDef,
context: config.inheritContext
? parent.context.fork()
: new Context(),
: config.
? parent..()
: (),
: config.
? [...parent..]
: agentDef.,
});
child.. = (parent.. || ) + ;
(child.. > .) {
();
}
child;
}
}
(): <> {
coordinator = agentFork.(mainAgent, {
: ,
: ,
: ,
: ,
: ,
});
plan = coordinator.(task);
workers = .(
plan..(
agentFork.(coordinator, {
: ,
: ,
: ,
: ,
: ,
})
)
);
results = .(
workers.( worker.(plan.[i]))
);
coordinator.(results);
}
7. MCP Integration
Model Context Protocol bridge for external tools:
type MCPTransport =
| 'stdio'
| 'http'
| 'websocket'
| 'grpc'
| 'ipc'
| 'sse'
| 'stdio+stderr'
| 'custom';
type ConnectionState =
| 'disconnected'
| 'connecting'
| 'connected'
| 'error'
| 'reconnecting';
class MCPBridge {
private connections = new Map<string, MCPConnection>();
async connect(server: MCPServerConfig): Promise<void> {
const conn = new MCPConnection(server);
conn.on('state', (state) => {
if (state === 'error') {
this.reconnect(conn);
}
});
await conn.connect();
this.connections.set(server.name, conn);
tools = conn.();
( tool tools) {
.({
: ,
: tool.,
: tool.,
: conn.(tool., input),
});
}
}
(
: ,
:
): <> {
[_mcp, serverName, mcpToolName] = toolName.();
conn = ..(serverName);
(!conn) ();
conn.(mcpToolName, input);
}
(: ): <> {
conn. = ;
( (r, ));
conn.();
}
}
8. Skill System
Plugin architecture with frontmatter metadata:
interface Skill {
metadata: SkillMetadata;
content: string;
tools?: Tool[];
hooks?: Hook[];
}
interface SkillMetadata {
name: string;
description: string;
triggers: string[];
version?: string;
dependencies?: string[];
}
class SkillLoader {
async load(path: string): Promise<Skill> {
const raw = await this.readFile(path);
const { frontmatter, content } = this.parseFrontmatter(raw);
const processed = await this.substitute(content, {
env: process.env,
config: this.config,
runtime: this.getRuntimeVars(),
});
return {
: frontmatter ,
: processed,
: .(processed),
: .(processed),
};
}
(
: ,
:
): <> {
content = content.(,
context.[key] ||
);
content = content.(,
context.[key] ||
);
content = content.(,
context.[key] ||
);
content;
}
}
Configuration
Agent configuration follows six-layer priority chain:
const config = mergeConfig([
runtimeOverrides,
environmentVariables,
projectConfig,
userConfig,
skillDefaults,
systemDefaults,
]);
interface FeatureFlags {
enable_mcp: boolean;
enable_sub_agents: boolean;
enable_plan_mode: boolean;
auto_approve: boolean;
debug_mode: boolean;
trace_tools: boolean;
}
interface AgentConfig {
model: ModelConfig;
tools: ToolConfig;
permissions: PermissionConfig;
context: ContextConfig;
memory: MemoryConfig;
features: FeatureFlags;
security: {
maxForkDepth: number;
allowedPaths: [];
: [];
: ;
};
}
Performance Optimization
Startup Optimization
class LazyAgentLoader {
private loaded = new Set<string>();
async loadOnDemand(module: string): Promise<void> {
if (this.loaded.has(module)) return;
switch (module) {
case 'tools':
await this.loadTools();
break;
case 'mcp':
await this.loadMCP();
break;
case 'skills':
await this.loadSkills();
break;
}
this.loaded.add(module);
}
private async loadTools(): Promise<void> {
const toolModules = [
,
,
,
,
];
.(
toolModules.( ())
);
}
}
{
() {}
executeInBatches<T>(
: ( <T>)[],
): <T[]> {
: T[] = [];
( i = ; i < tasks.; i += .) {
batch = tasks.(i, i + .);
batchResults = .(
batch.( ())
);
results.(...batchResults);
}
results;
}
}
Observability
Four-layer monitoring system:
interface Observability {
logger: Logger;
metrics: MetricsCollector;
tracer: DistributedTracer;
debugger: AgentDebugger;
}
class AgentObservability implements Observability {
logger = new Logger({
level: process.env.LOG_LEVEL || 'info',
format: 'json',
fields: {
agent_id: this.agentId,
session_id: this.sessionId,
},
});
metrics = new MetricsCollector({
counters: [
'tool_executions',
'permission_denials',
'context_compressions',
],
histograms: [
'turn_duration',
'tool_latency',
'context_size',
],
});
tracer = new DistributedTracer({
service: 'agent-harness',
samplingRate: 0.1,
: [
({ : process.. }),
],
});
trace<T>(
: ,
: <T>
): <T> {
span = ..(operation);
{
result = ();
span.({ : });
result;
} (error) {
span.({ : , : error. });
error;
} {
span.();
}
}
}
Common Patterns
Pattern 1: Graceful Degradation
async function executeWithFallback<T>(
primary: () => Promise<T>,
fallback: () => Promise<T>,
timeout: number = 5000
): Promise<T> {
try {
return await Promise.race([
primary(),
new Promise<T>((_, reject) =>
setTimeout(() => reject(new TimeoutError()), timeout)
),
]);
} catch (error) {
console.warn('Primary failed, using fallback:', error);
return await fallback();
}
}
const result = await executeWithFallback(
() => mcpBridge.invoke('mcp.search.web', query),
() => localSearch.execute(query),
3000
);
Pattern 2: Dependency Injection
interface QueryDeps {
llm: LLMClient;
tools: ToolRegistry;
permissions: PermissionPipeline;
context: ContextManager;
memory: AgentMemory;
ui: UserInterface;
config: AgentConfig;
}
class Agent {
constructor(private deps: QueryDeps) {}
async run(query: string): Promise<void> {
for await (const event of conversationLoop(this.deps)) {
await this.deps.ui.render(event);
}
}
}
const testAgent = new Agent({
llm: new MockLLM(),
tools: new MockToolRegistry(),
: (),
: (),
: (),
: (),
: testConfig,
});
Pattern 3: Hook-Based Extension
type HookEvent =
| 'agent:init'
| 'agent:start'
| 'turn:start'
| 'llm:request'
| 'llm:response'
| 'tool:call'
| 'tool:result'
| 'permission:check'
| 'context:compress'
| 'memory:save'
class HookSystem {
private hooks = new Map<HookEvent, Hook[]>();
register(event: HookEvent, hook: Hook): void {
const hooks = this.hooks.get(event) || [];
hooks.push(hook);
hooks.sort((a, b) => a.priority - b.priority);
this.hooks.set(event, hooks);
}
async trigger(event: HookEvent, data: unknown): Promise<void> {
const hooks = this.hooks.(event) || [];
( hook hooks) {
{
hook.(data);
} (error) {
.(, error);
}
}
}
}
hookSystem.(, {
: ,
: ,
: (data) => {
auditLog.({
: .(),
: data.,
: data.,
});
},
});
Troubleshooting
Context Overflow
const config = {
context: {
total: 200000,
reserved: {
system: 2000,
tools: 5000,
recent: 10000,
},
},
};
const config = {
features: {
enable_auto_compact: true,
compression_threshold: 0.7,
},
};
class CustomCompressor extends ContextManager {
async compress(messages: Message[]): Promise<Message[]> {
return messages.filter(m => m.metadata.important);
}
}
Permission Deadlock
class TimeoutPermissions extends PermissionPipeline {
async requestApproval(tool: ToolCall): Promise<boolean> {
try {
return await Promise.race([
super.requestApproval(tool),
timeout(30000, false),
]);
} catch (error) {
console.error('Permission timeout:', tool.name);
return false;
}
}
}
MCP Connection Failures
class ResilientMCPBridge extends MCPBridge {
async reconnect(
conn: MCPConnection,
attempt: number = 0
): Promise<void> {
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
try {
await new Promise(r => setTimeout(r, delay));
await conn.connect();
} catch (error) {
if (attempt < 5) {
await this.reconnect(conn, attempt + 1);
} else {
throw new MaxRetriesError();
}
}
}
}
Memory Leak in Long Sessions
class BoundedMemory extends AgentMemory {
private maxSize = 1000;
async save(key: string, value: MemoryEntry): Promise<void> {
await super.save(key, value);
if (this.store.size > this.maxSize) {
const sorted = [...this.store.entries()]
.sort((a, b) => a[1].timestamp - b[1].timestamp);
const toDelete = sorted.slice(0, this.store.size - this.maxSize);
for (const [key] of toDelete) {
this.store.delete(key);
}
}
}
}
Advanced Usage
Building a Custom Harness
Six-step implementation roadmap:
interface CustomAgent {
run(query: string): Promise<void>;
addTool(tool: Tool): void;
fork(config: SubAgentConfig): Promise<CustomAgent>;
}
class CustomAgentImpl implements CustomAgent {
async run(query: string): Promise<void> {
const deps = this.buildDeps();
for await (const event of conversationLoop(deps)) {
await this.handleEvent(event);
}
}
}
class CustomToolRegistry extends ToolRegistry {
}
class CustomPermissions extends {
}
agent = ({
: (),
});
agent.();
References