claude-code-agent-architecture
Research repository analyzing Claude Code CLI Agent architecture, tools, telemetry, and internal mechanisms
How do I install this agent skill?
npx skills add https://github.com/reason-machines/ai-agent-skills --skill claude-code-agent-architectureIs this agent skill safe to install?
- Gen Agent Trust Hubwarn
The skill provides instructions to clone a third-party research repository and install its dependencies. While intended for educational purposes, downloading and running code from an unknown external source represents a security risk.
- Socketwarn
1 alert: gptAnomaly
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
Claude Code Agent Architecture
Skill by 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
# 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:
// 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:
- Permission System: User approval for file writes, command execution
- Streaming: Real-time token streaming with UI updates
- Concurrency: Parallel tool execution via
StreamingToolExecutor - Context Compaction: Automatic message history compression
- Sub-agents: Specialized agents (verification, review, planning)
- Persistence: Session state saved to disk
- MCP Integration: Model Context Protocol server support
- Cost Tracking: Token usage and API cost accumulation
- Analytics: Telemetry events (OpenTelemetry + Datadog)
- Remote Control: Feature flags and killswitches from server
- Error Recovery: Retry logic with exponential backoff
- Multi-transport: CLI, bridge, SDK interfaces
Tool System Architecture
Built-in Tool Categories
The research documents 40+ tools across categories:
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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"]
},
async execute({ filePath, metrics = ["complexity"] }) {
// Read file
const content = await fs.readFile(filePath, "utf-8");
// Run analysis
const results = await analyzeCode(content, metrics);
// Return structured output
return {
file: filePath,
metrics: results,
summary: `Analyzed ${metrics.length} metrics for ${filePath}`
};
},
// Tool metadata
category: "code",
risk: "low",
requiresPermission: false
});
// Register tool
toolRegistry.register("analyze_code_quality", customTool);
Implementing Sub-agents
// Sub-agent pattern (verification, review, planning)
class SubAgent {
constructor(
private role: string,
private systemPrompt: string
) {}
async run(task: string, context: any): Promise<string> {
const messages = [
{ role: "system", content: this.systemPrompt },
{ role: "user", content: this.formatTask(task, context) }
];
const response = await callClaudeAPI({
messages,
model: "claude-sonnet-4.0", // Sub-agents use specific models
max_tokens: 4096
});
return response.content[0].text;
}
private formatTask(task: string, context: any): string {
return `Task: ${task}\n\nContext:\n${JSON.stringify(context, null, 2)}`;
}
}
// Example: Code review sub-agent
const reviewAgent = new SubAgent(
"code_reviewer",
`You are a code review expert. Analyze the provided code changes for:
- Security issues
- Performance problems
- Best practice violations
Provide specific, actionable feedback.`
);
const reviewResult = await reviewAgent.run(
"Review this pull request",
{ diff, files, description }
);
Context Compaction Strategy
// Adaptive context compaction
class CompactionService {
async compact(messages: Message[], options: CompactOptions): Promise<Message[]> {
const totalTokens = this.estimateTokens(messages);
if (totalTokens < options.maxTokens) {
return messages; // No compaction needed
}
// Strategy: Keep recent messages, summarize old ones
const recentMessages = messages.slice(-10); // Keep last 10
const oldMessages = messages.slice(0, -10);
// Summarize old conversation
const summary = await this.summarizeMessages(oldMessages);
return [
{ role: "system", content: `Previous conversation summary:\n${summary}` },
...recentMessages
];
}
private async summarizeMessages(messages: Message[]): Promise<string> {
const response = await callClaudeAPI({
messages: [
{ role: "user", content: `Summarize this conversation concisely:\n${JSON.stringify(messages)}` }
],
model: "claude-haiku-4.0", // Use fast model for summaries
max_tokens: 1024
});
return response.content[0].text;
}
}
Configuration
Environment Variables
# API Configuration
ANTHROPIC_API_KEY=sk-ant-xxx # Required for Claude API
# Analytics Control
OTEL_LOG_TOOL_DETAILS=1 # Enable detailed tool logging (default: 0)
ANALYTICS_ENABLED=true # Enable telemetry (default: true)
# Feature Flags
ENABLE_FAST_MODE=true # Enable fast mode (Haiku for simple tasks)
ENABLE_VOICE_MODE=false # Enable voice input (experimental)
ENABLE_UNDERCOVER_MODE=false # Hide AI attribution in commits
# MCP Configuration
MCP_SERVER_PATH=/path/to/mcp-servers
MCP_ALLOWED_PATHS=/workspace,/home/user/projects
# Debug
DEBUG=claude:* # Enable debug logging
LOG_LEVEL=info # Log level (debug|info|warn|error)
Configuration File
// ~/.claude/config.json
{
"defaultModel": "claude-sonnet-4.0",
"autoApprove": {
"read_file": true,
"list_files": true,
"search_files": true
},
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
}
},
"maxTokens": 8192,
"compactionThreshold": 100000,
"telemetry": {
"enabled": true,
"userId": "anonymous"
}
}
Research Reports
The repository includes deep-dive reports in 4 languages:
Key Reports
01-telemetry-and-privacy: Documents two analytics sinks (OpenTelemetry + Datadog), environment fingerprinting, and why opt-out isn't exposed in UI.
02-hidden-features-and-codenames: Reveals animal codenames (Capybara, Tengu, Numbat), feature flags using random word pairs, and internal vs external user differences.
03-undercover-mode: Official employees auto-enter mode that instructs the model to hide AI authorship in public repos ("Do not blow your cover").
04-remote-control-and-killswitches: Hourly polling of settings API, blocking dialogs that exit the app on rejection, 6+ killswitches.
05-future-roadmap: Upcoming Numbat model, KAIROS autonomous mode with <tick> heartbeats, voice mode, 17 unreleased tools.
Access reports in docs/[en|ja|ko|zh]/ directories.
Troubleshooting
Understanding Agent Behavior
// Enable verbose logging to see agent decision process
process.env.DEBUG = "claude:*";
process.env.LOG_LEVEL = "debug";
// This will log:
// - API requests/responses
// - Tool execution decisions
// - Permission checks
// - Context compaction triggers
Analyzing Tool Permissions
// Check which tools require permission
const highRiskTools = Array.from(toolRegistry.entries())
.filter(([_, tool]) => tool.risk === "high")
.map(([name, _]) => name);
console.log("High-risk tools:", highRiskTools);
// Output: ["write_to_file", "execute_command", "delete_file", ...]
Debugging MCP Connections
// Test MCP server connection
const mcpManager = new MCPManager();
try {
await mcpManager.connectServer({
name: "test-server",
command: "npx",
args: ["-y", "@modelcontextprotocol/server-puppeteer"]
});
const tools = await mcpManager.listTools("test-server");
console.log("Available MCP tools:", tools);
} catch (error) {
console.error("MCP connection failed:", error.message);
// Common issues: command not found, port conflicts, auth failures
}
Inspecting Telemetry Events
# Enable full tool argument logging
export OTEL_LOG_TOOL_DETAILS=1
# Run agent and grep for tool events
claude-code | grep "tool_executed"
# You'll see:
# {"event":"tool_executed","tool":"write_to_file","argsSize":1234,...}
Additional Resources
- Repository: https://github.com/sanbuphy/learn-coding-agent
- Deep Analysis Reports:
docs/directory (EN/JA/KO/ZH) - Architecture Diagrams: Referenced in research reports
- Related Projects:
- Model Context Protocol: https://modelcontextprotocol.io
- Anthropic Claude API: https://docs.anthropic.com
Note: This is a research and educational repository. It documents publicly available information about coding agent architecture. For production coding agent development, refer to official Anthropic documentation and Claude API guides.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/reason-machines/ai-agent-skills/claude-code-agent-architecture">View claude-code-agent-architecture on skillZs</a>