- name
- claude-code-architecture-patterns
- description
- Architectural patterns and design principles from Anthropic's Claude Code agent, reverse-engineered for building production AI coding agents
- triggers
- ["how does Claude Code architecture work","show me AI agent patterns from Claude Code","implement async generator agent loop","build multi-agent orchestration system","show me Claude Code state management","implement tool execution pipeline like Claude Code","how to build production AI coding agent","explain Claude Code internals"]
# Claude Code Architecture Patterns
> Skill by [ara.so](https://ara.so) — Claude Code Skills collection.
This skill provides expertise in the architectural patterns, design principles, and implementation strategies extracted from Anthropic's Claude Code agent. Use these patterns to build production-grade AI coding agents with robust state management, efficient tool execution, multi-agent orchestration, and context management.
## What This Provides
**Claude Code from Source** is a comprehensive technical analysis of Claude Code's architecture, distilled into 18 chapters covering:
- **Agent Loop Architecture**: AsyncGenerator-based control flow
- **Tool Execution**: Concurrent-safe batching and speculative execution
- **Multi-Agent Orchestration**: Fork agents, task coordination, swarms
- **State Management**: Two-tier architecture with bootstrap singleton and AppState
- **Context Management**: 4-layer compression, prompt cache optimization
- **Memory Systems**: File-based memory with LLM recall
- **Performance**: Token budgets, cache sharing, rendering optimization
## Installation
```bash
# Clone the repository
git clone https://github.com/alejandrobalderas/claude-code-from-source.git
cd claude-code-from-source
# Install dependencies
npm install
# Build the book site (optional)
npm run build
# Start dev server to read online
npm run dev
```
## Key Architectural Patterns
### 1. AsyncGenerator Agent Loop
The core pattern for agent execution - yields messages during execution, returns terminal state.
```typescript
async function* agentLoop(
query: string,
context: ExecutionContext
): AsyncGenerator<Message, TerminalState> {
let conversationHistory: Message[] = [];
let tokenBudget = context.maxTokens;
while (tokenBudget > 0) {
// Compress context if needed
if (shouldCompress(conversationHistory)) {
conversationHistory = await compressContext(conversationHistory);
}
// Stream response from LLM
const stream = await streamCompletion({
messages: conversationHistory,
tools: context.availableTools,
});
let currentMessage = { role: 'assistant', content: '' };
let toolCalls: ToolCall[] = [];
for await (const chunk of stream) {
if (chunk.type === 'text') {
currentMessage.content += chunk.text;
yield { ...currentMessage, streaming: true };
} else if (chunk.type === 'tool_use') {
toolCalls.push(chunk.toolCall);
}
tokenBudget -= chunk.tokensUsed;
}
yield { ...currentMessage, streaming: false };
conversationHistory.push(currentMessage);
// Execute tools if present
if (toolCalls.length > 0) {
const results = await executeToolsConcurrent(toolCalls, context);
for (const result of results) {
const toolMessage = {
role: 'user',
content: formatToolResult(result),
};
yield toolMessage;
conversationHistory.push(toolMessage);
}
} else {
// No tools - agent is done
return {
status: 'complete',
finalMessage: currentMessage,
tokensUsed: context.maxTokens - tokenBudget,
};
}
}
return { status: 'budget_exceeded', tokensUsed: context.maxTokens };
}
```
### 2. Concurrent-Safe Tool Execution
Partition tools by safety guarantees, execute reads in parallel, serialize writes.
```typescript
interface ToolCall {
id: string;
name: string;
args: Record<string, unknown>;
}
interface ToolDefinition {
name: string;
execute: (args: Record<string, unknown>) => Promise<unknown>;
readonly: boolean;
requiresConfirmation: boolean;
}
async function executeToolsConcurrent(
calls: ToolCall[],
context: ExecutionContext
): Promise<ToolResult[]> {
// Partition by safety
const readOnly = calls.filter(c =>
context.tools[c.name]?.readonly === true
);
const writeOps = calls.filter(c =>
context.tools[c.name]?.readonly !== true
);
const results: ToolResult[] = [];
// Execute all read-only tools in parallel
if (readOnly.length > 0) {
const readResults = await Promise.all(
readOnly.map(call => executeTool(call, context))
);
results.push(...readResults);
}
// Execute write operations serially
for (const call of writeOps) {
// Check if confirmation needed
if (context.tools[call.name]?.requiresConfirmation) {
const approved = await requestUserConfirmation(call);
if (!approved) {
results.push({
id: call.id,
status: 'rejected',
error: 'User declined permission',
});
continue;
}
}
const result = await executeTool(call, context);
results.push(result);
}
return results;
}
async function executeTool(
call: ToolCall,
context: ExecutionContext
): Promise<ToolResult> {
const tool = context.tools[call.name];
if (!tool) {
return { id: call.id, status: 'error', error: 'Unknown tool' };
}
try {
const output = await tool.execute(call.args);
return { id: call.id, status: 'success', output };
} catch (error) {
return {
id: call.id,
status: 'error',
error: error instanceof Error ? error.message : 'Unknown error'
};
}
}
```
### 3. Speculative Tool Execution
Start read-only tools during streaming, before response completes.
```typescript
async function* agentLoopWithSpeculation(
query: string,
context: ExecutionContext
): AsyncGenerator<Message, TerminalState> {
const stream = await streamCompletion({
messages: context.history,
tools: context.availableTools,
});
const toolCalls: ToolCall[] = [];
const speculativeResults = new Map<string, Promise<ToolResult>>();
for await (const chunk of stream) {
if (chunk.type === 'tool_use') {
const call = chunk.toolCall;
toolCalls.push(call);
// Start read-only tools immediately
const tool = context.tools[call.name];
if (tool?.readonly) {
speculativeResults.set(
call.id,
executeTool(call, context)
);
yield {
role: 'system',
content: `⚡ Started ${call.name} speculatively`,
};
}
}
}
// Wait for speculative results
const results: ToolResult[] = [];
for (const call of toolCalls) {
if (speculativeResults.has(call.id)) {
results.push(await speculativeResults.get(call.id)!);
} else {
results.push(await executeTool(call, context));
}
}
return { status: 'complete', results };
}
```
### 4. Fork Agents for Cache Sharing
Spawn parallel agents with byte-identical prompt prefixes to share prompt cache.
```typescript
interface ForkAgentConfig {
parentContext: ConversationHistory;
tasks: string[];
sharedPrefix: Message[];
}
async function forkAgents(
config: ForkAgentConfig
): Promise<AgentResult[]> {
// Build byte-identical prefix
const sharedPrefix = config.sharedPrefix.map(msg => ({
role: msg.role,
content: msg.content,
// Ensure exact JSON serialization
_cacheKey: JSON.stringify({ role: msg.role, content: msg.content }),
}));
// Spawn parallel agents
const agents = config.tasks.map(async (task) => {
const childMessages = [
...sharedPrefix,
{ role: 'user', content: task },
];
const result: AgentResult = {
task,
messages: [],
status: 'running',
};
// Run agent loop
const loop = agentLoop(task, {
...config.parentContext,
history: childMessages,
});
for await (const msg of loop) {
result.messages.push(msg);
}
const terminal = await loop.next();
result.status = terminal.value.status;
return result;
});
return Promise.all(agents);
}
// Usage
const results = await forkAgents({
parentContext: mainContext,
sharedPrefix: conversationHistory.slice(0, -1),
tasks: [
'Analyze the authentication module',
'Review error handling patterns',
'Document the API endpoints',
],
});
```
### 5. Four-Layer Context Compression
Progressive compression strategies to fit within token budget.
```typescript
type CompressionLevel = 'snip' | 'microcompact' | 'collapse' | 'autocompact';
interface CompressionStrategy {
level: CompressionLevel;
apply: (messages: Message[]) => Promise<Message[]>;
estimatedReduction: number; // 0.0 to 1.0
}
const compressionStrategies: CompressionStrategy[] = [
{
level: 'snip',
estimatedReduction: 0.3,
apply: async (messages) => {
// Remove middle portions of long tool outputs
return messages.map(msg => {
if (msg.role === 'user' && msg.toolResult) {
const output = msg.toolResult.output as string;
if (output.length > 4000) {
const head = output.slice(0, 1500);
const tail = output.slice(-1500);
return {
...msg,
toolResult: {
...msg.toolResult,
output: `${head}\n\n[... ${output.length - 3000} chars omitted ...]\n\n${tail}`,
},
};
}
}
return msg;
});
},
},
{
level: 'microcompact',
estimatedReduction: 0.5,
apply: async (messages) => {
// Use LLM to summarize old messages
const cutoff = messages.length - 10;
const toCompress = messages.slice(0, cutoff);
const toKeep = messages.slice(cutoff);
if (toCompress.length === 0) return messages;
const summary = await summarizeWithLLM(toCompress);
return [
{ role: 'system', content: `[Prior context]: ${summary}` },
...toKeep,
];
},
},
{
level: 'collapse',
estimatedReduction: 0.7,
apply: async (messages) => {
// Merge consecutive messages from same role
const collapsed: Message[] = [];
for (const msg of messages) {
const last = collapsed[collapsed.length - 1];
if (last && last.role === msg.role) {
last.content += '\n\n' + msg.content;
} else {
collapsed.push({ ...msg });
}
}
return collapsed;
},
},
{
level: 'autocompact',
estimatedReduction: 0.85,
apply: async (messages) => {
// Aggressive: keep only last 5 messages + system prompt
const system = messages.find(m => m.role === 'system');
const recent = messages.slice(-5);
return system ? [system, ...recent] : recent;
},
},
];
async function compressContext(
messages: Message[],
targetTokens: number
): Promise<Message[]> {
let current = messages;
let currentTokens = estimateTokens(current);
for (const strategy of compressionStrategies) {
if (currentTokens <= targetTokens) break;
console.log(`Applying ${strategy.level} compression...`);
current = await strategy.apply(current);
currentTokens = estimateTokens(current);
}
return current;
}
```
### 6. Two-Tier State Management
Bootstrap singleton for process-level config, AppState for runtime state.
```typescript
// Bootstrap singleton - loaded once at startup
class Bootstrap {
private static instance: Bootstrap;
readonly config: {
apiKey: string;
model: string;
maxTokens: number;
enableCache: boolean;
};
readonly tools: Map<string, ToolDefinition>;
readonly skills: Map<string, SkillDefinition>;
private constructor() {
// Load from env/config files
this.config = {
apiKey: process.env.ANTHROPIC_API_KEY!,
model: process.env.MODEL || 'claude-3-5-sonnet-20241022',
maxTokens: parseInt(process.env.MAX_TOKENS || '100000', 10),
enableCache: process.env.ENABLE_CACHE !== 'false',
};
this.tools = this.loadTools();
this.skills = this.loadSkills();
}
static getInstance(): Bootstrap {
if (!Bootstrap.instance) {
Bootstrap.instance = new Bootstrap();
}
return Bootstrap.instance;
}
private loadTools(): Map<string, ToolDefinition> {
// Load tool definitions from disk
return new Map();
}
private loadSkills(): Map<string, SkillDefinition> {
// Load skills with frontmatter only
return new Map();
}
}
// AppState - runtime mutable state
class AppState {
conversationHistory: Message[] = [];
tokenBudget: number;
costTracking: {
inputTokens: number;
outputTokens: number;
cacheReads: number;
cacheWrites: number;
} = {
inputTokens: 0,
outputTokens: 0,
cacheReads: 0,
cacheWrites: 0,
};
// Sticky latches - once set, never unset
betaHeaders = new Set<string>();
constructor() {
Auf GitHub ansehen