- name
- claude-code-agent-architecture
- description
- Research repository analyzing Claude Code CLI Agent architecture, tools, telemetry, and internal mechanisms
- triggers
- ["how does claude code agent work internally","analyze claude code architecture","what tools does claude code use","claude code agent system design","understanding coding agent architecture","claude code tool permissions and execution","implement coding agent like claude code","claude code feature flags and telemetry"]
# Claude Code Agent Architecture
> Skill by [ara.so](https://ara.so) — AI Agent Skills collection.
## Overview
`sanbuphy/learn-coding-agent` is a research repository that reverse-engineers and documents the architecture of Claude Code (the CLI coding agent). It provides deep technical analysis of:
- **Core agent loop**: How messages, tools, and API calls form the execution cycle
- **Tool system**: 40+ built-in tools with permission flows
- **Telemetry & privacy**: What data is collected and how
- **Hidden features**: Undercover mode, killswitches, remote control
- **Architecture patterns**: Production-grade harness mechanisms
This is a **learning resource** for understanding production coding agents, not the actual Claude Code source code.
## Installation
```bash
# Clone the research repository
git clone https://github.com/sanbuphy/learn-coding-agent.git
cd learn-coding-agent
# Install dependencies (if you want to explore the documented structure)
npm install
# or
bun install
```
**Note**: This is a documentation/research project. The TypeScript files are reconstructed architecture examples, not a runnable agent.
## Core Agent Loop Pattern
The fundamental agent pattern documented in this research:
```typescript
// The minimal agent loop
async function agentLoop(userMessage: string, messages: Message[]) {
messages.push({ role: "user", content: userMessage });
while (true) {
const response = await callClaudeAPI(messages);
if (response.stop_reason === "tool_use") {
// Execute tools
const toolResults = await executeTools(response.content);
messages.push({ role: "assistant", content: response.content });
messages.push({ role: "user", content: toolResults });
// Loop continues
} else {
// Return final text response
return response.content;
}
}
}
```
### The 12 Progressive Harness Mechanisms
Claude Code wraps the basic loop with production features:
1. **Permission System**: User approval for file writes, command execution
2. **Streaming**: Real-time token streaming with UI updates
3. **Concurrency**: Parallel tool execution via `StreamingToolExecutor`
4. **Context Compaction**: Automatic message history compression
5. **Sub-agents**: Specialized agents (verification, review, planning)
6. **Persistence**: Session state saved to disk
7. **MCP Integration**: Model Context Protocol server support
8. **Cost Tracking**: Token usage and API cost accumulation
9. **Analytics**: Telemetry events (OpenTelemetry + Datadog)
10. **Remote Control**: Feature flags and killswitches from server
11. **Error Recovery**: Retry logic with exponential backoff
12. **Multi-transport**: CLI, bridge, SDK interfaces
## Tool System Architecture
### Built-in Tool Categories
The research documents **40+ tools** across categories:
```typescript
// Tool registry structure
const toolRegistry = {
// File operations
"read_file": { category: "file", risk: "low" },
"write_to_file": { category: "file", risk: "high", requiresPermission: true },
"list_files": { category: "file", risk: "low" },
// Command execution
"execute_command": { category: "command", risk: "high", requiresPermission: true },
"spawn_agent": { category: "agent", risk: "medium" },
// Search & analysis
"search_files": { category: "search", risk: "low" },
"list_code_definition_names": { category: "code", risk: "low" },
// Browser control (via MCP)
"browser_navigate": { category: "browser", risk: "medium" },
"browser_click": { category: "browser", risk: "medium" },
// Memory & context
"store_memory": { category: "memory", risk: "low" },
"compact_context": { category: "system", risk: "low" }
};
```
### Permission Flow
```typescript
// Permission checking pattern
interface ToolPermission {
toolName: string;
approved: boolean;
autoApprove?: boolean; // User set in config
risk: "low" | "medium" | "high";
}
async function checkPermission(tool: Tool, args: any): Promise<boolean> {
// 1. Check auto-approve rules
if (config.autoApprove?.[tool.name]) {
return true;
}
// 2. Low-risk tools auto-approved
if (tool.risk === "low") {
return true;
}
// 3. Show permission dialog
const approved = await showPermissionDialog({
tool: tool.name,
description: tool.description,
args: sanitizeArgs(args),
risk: tool.risk
});
// 4. Log decision
analytics.track("tool_permission_decision", {
tool: tool.name,
approved,
autoApprove: false
});
return approved;
}
```
### Tool Execution with Streaming
```typescript
// StreamingToolExecutor pattern
class StreamingToolExecutor {
async executeTools(toolCalls: ToolUse[]): Promise<ToolResult[]> {
const results: ToolResult[] = [];
// Group by parallelizable vs sequential
const parallel = toolCalls.filter(t => this.canRunInParallel(t));
const sequential = toolCalls.filter(t => !this.canRunInParallel(t));
// Execute parallel tools concurrently
if (parallel.length > 0) {
const parallelResults = await Promise.all(
parallel.map(tc => this.executeSingleTool(tc))
);
results.push(...parallelResults);
}
// Execute sequential tools one by one
for (const toolCall of sequential) {
const result = await this.executeSingleTool(toolCall);
results.push(result);
}
return results;
}
private async executeSingleTool(toolCall: ToolUse): Promise<ToolResult> {
const tool = toolRegistry.get(toolCall.name);
// Permission check
const approved = await checkPermission(tool, toolCall.input);
if (!approved) {
return {
tool_use_id: toolCall.id,
content: "Permission denied by user",
is_error: true
};
}
// Execute
try {
const output = await tool.execute(toolCall.input);
return {
tool_use_id: toolCall.id,
content: output
};
} catch (error) {
return {
tool_use_id: toolCall.id,
content: error.message,
is_error: true
};
}
}
}
```
## Key Architectural Components
### 1. Query Engine
```typescript
// QueryEngine.ts - SDK/headless query lifecycle
class QueryEngine {
private messages: Message[] = [];
private state: TaskState;
async runQuery(input: string, options?: QueryOptions): Promise<QueryResult> {
// Add user message
this.messages.push({ role: "user", content: input });
// Context compaction if needed
if (this.shouldCompact()) {
await this.compactContext();
}
// Main loop
while (true) {
const response = await this.callAPI();
if (response.stop_reason === "tool_use") {
const toolResults = await this.toolExecutor.executeTools(
response.content.filter(c => c.type === "tool_use")
);
this.messages.push({ role: "assistant", content: response.content });
this.messages.push({ role: "user", content: toolResults });
} else {
return { output: response.content, messages: this.messages };
}
}
}
private async compactContext(): Promise<void> {
const compactedMessages = await this.compactionService.compact(
this.messages,
{ strategy: "adaptive" }
);
this.messages = compactedMessages;
}
}
```
### 2. MCP Integration
```typescript
// MCP (Model Context Protocol) server management
interface MCPServer {
name: string;
command: string;
args: string[];
env?: Record<string, string>;
}
class MCPManager {
private servers: Map<string, MCPServerInstance> = new Map();
async connectServer(config: MCPServer): Promise<void> {
const instance = await this.spawn({
command: config.command,
args: config.args,
env: { ...process.env, ...config.env }
});
// Register tools from server
const tools = await instance.listTools();
tools.forEach(tool => {
toolRegistry.register(`mcp_${config.name}_${tool.name}`, tool);
});
this.servers.set(config.name, instance);
}
async callMCPTool(serverName: string, toolName: string, args: any): Promise<any> {
const server = this.servers.get(serverName);
return await server.callTool(toolName, args);
}
}
// Example MCP configuration
const mcpConfig = {
"mcpServers": {
"puppeteer": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-puppeteer"]
},
"filesystem": {
"command": "node",
"args": ["/path/to/mcp-server-filesystem/dist/index.js"],
"env": {
"ALLOWED_PATHS": "/workspace"
}
}
}
};
```
### 3. Telemetry System
```typescript
// Analytics infrastructure
interface AnalyticsEvent {
event: string;
properties: Record<string, any>;
userId?: string;
sessionId: string;
timestamp: number;
}
class AnalyticsService {
private sinks = {
firstParty: new OpenTelemetryClient(),
datadog: new DatadogClient()
};
track(event: string, properties: Record<string, any>): void {
const payload: AnalyticsEvent = {
event,
properties: {
...properties,
// Automatic fingerprinting
os: process.platform,
arch: process.arch,
nodeVersion: process.version,
appVersion: packageJson.version,
repoHash: this.getRepoHash(), // SHA256 of git remote URL
},
sessionId: this.sessionId,
timestamp: Date.now()
};
// Send to both sinks
this.sinks.firstParty.send(payload);
this.sinks.datadog.send(payload);
// Detailed tool logging if enabled
if (process.env.OTEL_LOG_TOOL_DETAILS === "1") {
this.logToolDetails(payload);
}
}
trackToolUse(tool: string, args: any, result: any): void {
this.track("tool_executed", {
tool,
argsSize: JSON.stringify(args).length,
resultSize: JSON.stringify(result).length,
success: !result.is_error
});
}
}
```
### 4. Feature Flags & Remote Control
```typescript
// Remote settings management
interface RemoteSettings {
killswitches: {
disable_bypass_permissions?: boolean;
disable_fast_mode?: boolean;
disable_analytics?: boolean;
};
modelOverrides?: {
defaultModel?: string;
enabledModels?: string[];
};
experimentFlags?: Record<string, any>;
}
class SettingsSyncService {
private pollInterval = 60 * 60 * 1000; // 1 hour
async poll(): Promise<void> {
const settings = await fetch(
"https://api.claude.ai/api/claude_code/settings",
{ headers: { Authorization: `Bearer ${this.token}` } }
).then(r => r.json());
// Apply killswitches
if (settings.killswitches?.disable_bypass_permissions) {
config.bypassPermissions = false;
}
// Show blocking dialog for dangerous changes
if (this.isDangerousChange(settings)) {
const accepted = await showBlockingDialog({
title: "Critical Update Required",
message: "Claude Code settings have changed. Accept to continue.",
actions: ["Accept", "Reject (Exit)"]
});
if (!accepted) {
process.exit(1); // User rejected = app exits
}
}
// Apply GrowthBook experiments
this.applyExperiments(settings.experimentFlags);
}
}
```
## Common Patterns
### Building a Custom Tool
```typescript
// Tool.ts pattern
import { buildTool } from "./Tool";
const customTool = buildTool({
name: "analyze_code_quality",
description: "Analyzes code quality metrics for a given file",
parameters: {
type: "object",
properties: {
filePath: { type: "string", description: "Path to file" },
metrics: {
type: "array",
items: { type: "string" },
description: "Metrics to analyze (complexity, coverage, etc.)"
}
},
required: ["filePath"]
},
Auf GitHub ansehen