claude-code-agent-harness-architecture
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseClaude Code Agent Harness Architecture
Claude Code Agent Harness 架构
What This Skill Covers
本Skill涵盖内容
This skill provides deep architectural knowledge for building production-grade AI Agent systems (Agent Harness), based on the comprehensive analysis of Claude Code's architecture from the claude-code-book project. You'll learn:
- Core Agent Harness patterns: conversation loops, tool systems, permission pipelines
- Context & memory management: token budgeting, compression strategies, long-term memory
- Multi-agent orchestration: fork patterns, coordinator models, sub-agent spawning
- Integration patterns: MCP protocol, hooks system, skill/plugin architecture
- Production concerns: streaming, performance optimization, safety guardrails
本Skill基于claude-code-book项目中对Claude Code架构的全面分析,提供构建生产级AI Agent系统(Agent Harness)的深度架构知识。你将学习:
- 核心Agent Harness模式:对话循环、工具系统、权限流水线
- 上下文与内存管理:Token预算、压缩策略、长期记忆
- 多Agent编排:分叉模式、协调器模型、子Agent生成
- 集成模式:MCP协议、钩子系统、Skill/插件架构
- 生产环境关注点:流式输出、性能优化、安全防护
Installation & Access
安装与访问
The knowledge base is available at:
- Online book: https://lintsinghua.github.io
- GitHub repository: https://github.com/lintsinghua/claude-code-book
bash
undefined知识库可通过以下渠道获取:
bash
undefinedClone for offline reference
Clone for offline reference
git clone https://github.com/lintsinghua/claude-code-book.git
cd claude-code-book
git clone https://github.com/lintsinghua/claude-code-book.git
cd claude-code-book
The book contains 15 chapters + 4 appendices with 139 architecture diagrams
The book contains 15 chapters + 4 appendices with 139 architecture diagrams
Key directories:
Key directories:
- 第一部分-基础篇/ (Part 1: Fundamentals)
- 第一部分-基础篇/ (Part 1: Fundamentals)
- 第二部分-核心系统篇/ (Part 2: Core Systems)
- 第二部分-核心系统篇/ (Part 2: Core Systems)
- 第三部分-高级模式篇/ (Part 3: Advanced Patterns)
- 第三部分-高级模式篇/ (Part 3: Advanced Patterns)
- 第四部分-工程实践篇/ (Part 4: Engineering Practice)
- 第四部分-工程实践篇/ (Part 4: Engineering Practice)
- 附录/ (Appendices: tools, flags, terminology)
- 附录/ (Appendices: tools, flags, terminology)
undefinedundefinedCore Architecture Patterns
核心架构模式
1. Conversation Loop (Agent Heartbeat)
1. 对话循环(Agent心跳)
The fundamental async generator pattern that drives all Agent interactions:
while(true)typescript
// Core conversation loop structure
async function* conversationLoop(deps: QueryDeps): AsyncGenerator<QueryEvent> {
while (true) {
// 1. Prepare context window (token budget management)
const context = await buildContext(deps);
// 2. Call LLM with tools
const response = await llmClient.chat({
messages: context.messages,
tools: context.availableTools,
max_tokens: context.tokenBudget
});
// 3. Yield different event types
if (response.type === 'text') {
yield { type: 'text_delta', delta: response.content };
} else if (response.type === 'tool_use') {
// 4. Execute tool with permission check
const result = await executeToolWithPermission(response.tool, deps);
yield { type: 'tool_result', result };
}
// 5. Check termination conditions (10 types)
if (shouldTerminate(response)) {
yield { type: 'done', reason: response.stopReason };
break;
}
}
}
// Five yield event types:
// - text_delta: Streaming text chunks
// - tool_use: Tool invocation request
// - tool_result: Tool execution result
// - context_compression: Token budget overflow handling
// - done: Termination with reasonTen termination reasons:
- - Natural completion
end_turn - - Token limit reached
max_tokens - - Stop token encountered
stop_sequence - - Waiting for tool result
tool_use - - Safety filter triggered
content_filter - - Time limit exceeded
timeout - - User cancellation
user_interrupt - - Fatal error
error - - API quota exceeded
rate_limit - - Context window exhausted
context_overflow
驱动所有Agent交互的基础异步生成器模式:
while(true)typescript
// Core conversation loop structure
async function* conversationLoop(deps: QueryDeps): AsyncGenerator<QueryEvent> {
while (true) {
// 1. Prepare context window (token budget management)
const context = await buildContext(deps);
// 2. Call LLM with tools
const response = await llmClient.chat({
messages: context.messages,
tools: context.availableTools,
max_tokens: context.tokenBudget
});
// 3. Yield different event types
if (response.type === 'text') {
yield { type: 'text_delta', delta: response.content };
} else if (response.type === 'tool_use') {
// 4. Execute tool with permission check
const result = await executeToolWithPermission(response.tool, deps);
yield { type: 'tool_result', result };
}
// 5. Check termination conditions (10 types)
if (shouldTerminate(response)) {
yield { type: 'done', reason: response.stopReason };
break;
}
}
}
// Five yield event types:
// - text_delta: Streaming text chunks
// - tool_use: Tool invocation request
// - tool_result: Tool execution result
// - context_compression: Token budget overflow handling
// - done: Termination with reason十种终止原因:
- - 自然结束
end_turn - - 达到Token限制
max_tokens - - 遇到停止Token
stop_sequence - - 等待工具执行结果
tool_use - - 触发安全过滤器
content_filter - - 超出时间限制
timeout - - 用户取消
user_interrupt - - 致命错误
error - - API配额耗尽
rate_limit - - 上下文窗口耗尽
context_overflow
2. Tool System (Agent's Hands)
2. 工具系统(Agent的双手)
Tools follow a strict 5-element protocol:
typescript
// Tool<Input, Output, Permission> protocol
interface Tool<I, O, P extends PermissionLevel> {
// 1. Schema: Zod v4 input validation
schema: z.ZodType<I>;
// 2. Handler: Core execution logic
handler: (input: I, deps: QueryDeps) => Promise<O>;
// 3. Metadata: LLM-visible description
metadata: {
name: string;
description: string;
parameters: JSONSchema; // Auto-generated from Zod
};
// 4. Properties: Execution characteristics
properties: {
readOnly: boolean; // Safe to run speculatively
destructive: boolean; // Irreversible side effects
concurrencySafe: boolean; // Can run in parallel
};
// 5. Permission: Required access level
permission: P; // 'read' | 'write' | 'execute' | 'admin' | 'auto'
}
// buildTool: Fault-safe factory pattern
const readFileTool = buildTool({
schema: z.object({
path: z.string(),
encoding: z.enum(['utf-8', 'base64']).default('utf-8')
}),
permission: 'read',
properties: {
readOnly: true,
destructive: false,
concurrencySafe: true
},
handler: async ({ path, encoding }, deps) => {
const absPath = deps.workspace.resolvePath(path);
// Safety check: Must be within workspace
if (!deps.workspace.contains(absPath)) {
throw new ToolError('PathOutsideWorkspace', { path });
}
return await deps.fs.readFile(absPath, encoding);
}
});
// Tool categories (12 types, 50+ total tools):
// - File I/O: read_file, write_file, list_directory
// - Shell: execute_bash, run_command
// - Search: ripgrep_search, file_search
// - Edit: apply_diff, replace_in_file
// - Browser: navigate, screenshot, click
// - Git: commit, push, checkout
// - Memory: store_memory, recall_memory
// - Agent: fork_agent, spawn_worker
// - Config: update_settings, add_skill
// - MCP: call_mcp_tool, list_mcp_resourcesConcurrent execution algorithm (partition-greedy):
typescript
// Divide tools into read-only vs. side-effecting partitions
async function executeConcurrently(tools: ToolCall[]): Promise<ToolResult[]> {
const [readOnly, sideEffecting] = partition(
tools,
t => t.properties.readOnly && t.properties.concurrencySafe
);
// Execute read-only tools in parallel
const readOnlyResults = await Promise.all(
readOnly.map(t => t.handler(t.input, deps))
);
// Execute side-effecting tools sequentially
const sideEffectingResults = [];
for (const tool of sideEffecting) {
sideEffectingResults.push(await tool.handler(tool.input, deps));
}
return [...readOnlyResults, ...sideEffectingResults];
}工具遵循严格的5元素协议:
typescript
// Tool<Input, Output, Permission> protocol
interface Tool<I, O, P extends PermissionLevel> {
// 1. Schema: Zod v4 input validation
schema: z.ZodType<I>;
// 2. Handler: Core execution logic
handler: (input: I, deps: QueryDeps) => Promise<O>;
// 3. Metadata: LLM-visible description
metadata: {
name: string;
description: string;
parameters: JSONSchema; // Auto-generated from Zod
};
// 4. Properties: Execution characteristics
properties: {
readOnly: boolean; // Safe to run speculatively
destructive: boolean; // Irreversible side effects
concurrencySafe: boolean; // Can run in parallel
};
// 5. Permission: Required access level
permission: P; // 'read' | 'write' | 'execute' | 'admin' | 'auto'
}
// buildTool: Fault-safe factory pattern
const readFileTool = buildTool({
schema: z.object({
path: z.string(),
encoding: z.enum(['utf-8', 'base64']).default('utf-8')
}),
permission: 'read',
properties: {
readOnly: true,
destructive: false,
concurrencySafe: true
},
handler: async ({ path, encoding }, deps) => {
const absPath = deps.workspace.resolvePath(path);
// Safety check: Must be within workspace
if (!deps.workspace.contains(absPath)) {
throw new ToolError('PathOutsideWorkspace', { path });
}
return await deps.fs.readFile(absPath, encoding);
}
});
// Tool categories (12 types, 50+ total tools):
// - File I/O: read_file, write_file, list_directory
// - Shell: execute_bash, run_command
// - Search: ripgrep_search, file_search
// - Edit: apply_diff, replace_in_file
// - Browser: navigate, screenshot, click
// - Git: commit, push, checkout
// - Memory: store_memory, recall_memory
// - Agent: fork_agent, spawn_worker
// - Config: update_settings, add_skill
// - MCP: call_mcp_tool, list_mcp_resources并发执行算法(分区贪心策略):
typescript
// Divide tools into read-only vs. side-effecting partitions
async function executeConcurrently(tools: ToolCall[]): Promise<ToolResult[]> {
const [readOnly, sideEffecting] = partition(
tools,
t => t.properties.readOnly && t.properties.concurrencySafe
);
// Execute read-only tools in parallel
const readOnlyResults = await Promise.all(
readOnly.map(t => t.handler(t.input, deps))
);
// Execute side-effecting tools sequentially
const sideEffectingResults = [];
for (const tool of sideEffecting) {
sideEffectingResults.push(await tool.handler(tool.input, deps));
}
return [...readOnlyResults, ...sideEffectingResults];
}3. Permission Pipeline (4-Stage Guardrails)
3. 权限流水线(4阶段防护)
typescript
// Four-stage permission pipeline
type PermissionStage =
| 'classification' // Speculative 2s pre-approval
| 'validation' // Schema + safety checks
| 'authorization' // User consent (if needed)
| 'execution'; // Actual tool call
async function permissionPipeline(
toolCall: ToolCall,
mode: PermissionMode
): Promise<ToolResult> {
// Stage 1: Classification (speculative, 2-second timeout)
const classification = await Promise.race([
classifyRisk(toolCall),
timeout(2000, { risk: 'unknown' })
]);
// Stage 2: Validation
const validated = await validateToolCall(toolCall, {
schema: toolCall.tool.schema,
bashRules: mode === 'safe' ? SAFE_BASH_RULES : null,
pathRestrictions: deps.workspace.boundaries
});
// Stage 3: Authorization (mode-dependent)
if (requiresConsent(toolCall, mode, classification)) {
const consent = await deps.ui.requestPermission({
tool: toolCall.tool.name,
input: toolCall.input,
risk: classification.risk,
preview: classification.preview
});
if (!consent.approved) {
throw new PermissionDeniedError(consent.reason);
}
}
// Stage 4: Execution
return await toolCall.tool.handler(validated.input, deps);
}
// Five permission modes (spectrum)
type PermissionMode =
| 'safe' // Auto-approve read-only, deny write/execute
| 'normal' // Ask for write, auto-approve read
| 'relaxed' // Auto-approve most, ask for destructive
| 'auto' // Auto-approve all (trust agent completely)
| 'custom'; // User-defined rules
// Bash safety rules (safe mode)
const SAFE_BASH_RULES = {
allowedCommands: ['ls', 'cat', 'grep', 'find', 'head', 'tail'],
deniedPatterns: [
/rm\s+-rf/, // Destructive deletion
/sudo/, // Privilege escalation
/curl.*\|\s*bash/, // Pipe to shell
/>\s*\/dev\/sd/ // Direct disk access
],
maxCommandLength: 500
};typescript
// Four-stage permission pipeline
type PermissionStage =
| 'classification' // Speculative 2s pre-approval
| 'validation' // Schema + safety checks
| 'authorization' // User consent (if needed)
| 'execution'; // Actual tool call
async function permissionPipeline(
toolCall: ToolCall,
mode: PermissionMode
): Promise<ToolResult> {
// Stage 1: Classification (speculative, 2-second timeout)
const classification = await Promise.race([
classifyRisk(toolCall),
timeout(2000, { risk: 'unknown' })
]);
// Stage 2: Validation
const validated = await validateToolCall(toolCall, {
schema: toolCall.tool.schema,
bashRules: mode === 'safe' ? SAFE_BASH_RULES : null,
pathRestrictions: deps.workspace.boundaries
});
// Stage 3: Authorization (mode-dependent)
if (requiresConsent(toolCall, mode, classification)) {
const consent = await deps.ui.requestPermission({
tool: toolCall.tool.name,
input: toolCall.input,
risk: classification.risk,
preview: classification.preview
});
if (!consent.approved) {
throw new PermissionDeniedError(consent.reason);
}
}
// Stage 4: Execution
return await toolCall.tool.handler(validated.input, deps);
}
// Five permission modes (spectrum)
type PermissionMode =
| 'safe' // Auto-approve read-only, deny write/execute
| 'normal' // Ask for write, auto-approve read
| 'relaxed' // Auto-approve most, ask for destructive
| 'auto' // Auto-approve all (trust agent completely)
| 'custom'; // User-defined rules
// Bash safety rules (safe mode)
const SAFE_BASH_RULES = {
allowedCommands: ['ls', 'cat', 'grep', 'find', 'head', 'tail'],
deniedPatterns: [
/rm\s+-rf/, // Destructive deletion
/sudo/, // Privilege escalation
/curl.*\|\s*bash/, // Pipe to shell
/>\s*\/dev\/sd/ // Direct disk access
],
maxCommandLength: 500
};4. Context Management (Token Budget)
4. 上下文管理(Token预算)
Effective window calculation and 4-level compression:
typescript
// Effective window formula
interface ContextWindow {
total: number; // Model's max context (200K for Claude 3.5)
systemPrompt: number; // ~2K tokens
toolDefinitions: number; // ~50 tokens per tool × N tools
reserved: number; // ~4K for output buffer
effective: number; // Available for conversation history
}
function calculateEffectiveWindow(deps: QueryDeps): ContextWindow {
const total = deps.model.contextLimit; // 200_000
const systemPrompt = estimateTokens(deps.systemPrompt);
const toolDefinitions = deps.tools.length * 50;
const reserved = 4_000;
return {
total,
systemPrompt,
toolDefinitions,
reserved,
effective: total - systemPrompt - toolDefinitions - reserved
};
}
// Four-level progressive compression
async function compressContext(
messages: Message[],
targetTokens: number
): Promise<Message[]> {
let compressed = messages;
let currentTokens = estimateTokens(compressed);
// Level 1: Snip old image content (images are 1500+ tokens each)
if (currentTokens > targetTokens) {
compressed = snipImages(compressed, { keepRecent: 3 });
currentTokens = estimateTokens(compressed);
}
// Level 2: Micro-compact (merge adjacent same-role messages)
if (currentTokens > targetTokens) {
compressed = microCompact(compressed);
currentTokens = estimateTokens(compressed);
}
// Level 3: Collapse (summarize tool results)
if (currentTokens > targetTokens) {
compressed = await collapseToolResults(compressed, {
summarizeOlderThan: 10, // Message index threshold
maxSummaryTokens: 200
});
currentTokens = estimateTokens(compressed);
}
// Level 4: Auto-compact (LLM summarization)
if (currentTokens > targetTokens) {
compressed = await autoCompact(compressed, {
targetRatio: 0.5, // Compress to 50%
preserveRecent: 5 // Keep last 5 exchanges intact
});
}
return compressed;
}
// Circuit breaker pattern (prevent infinite compression)
class CompressionCircuitBreaker {
private failureCount = 0;
private lastReset = Date.now();
async attempt<T>(fn: () => Promise<T>): Promise<T> {
if (this.failureCount >= 3) {
if (Date.now() - this.lastReset < 60_000) {
throw new Error('Compression circuit breaker open');
}
this.reset();
}
try {
const result = await fn();
this.reset();
return result;
} catch (error) {
this.failureCount++;
throw error;
}
}
private reset() {
this.failureCount = 0;
this.lastReset = Date.now();
}
}有效的窗口计算与4级压缩:
typescript
// Effective window formula
interface ContextWindow {
total: number; // Model's max context (200K for Claude 3.5)
systemPrompt: number; // ~2K tokens
toolDefinitions: number; // ~50 tokens per tool × N tools
reserved: number; // ~4K for output buffer
effective: number; // Available for conversation history
}
function calculateEffectiveWindow(deps: QueryDeps): ContextWindow {
const total = deps.model.contextLimit; // 200_000
const systemPrompt = estimateTokens(deps.systemPrompt);
const toolDefinitions = deps.tools.length * 50;
const reserved = 4_000;
return {
total,
systemPrompt,
toolDefinitions,
reserved,
effective: total - systemPrompt - toolDefinitions - reserved
};
}
// Four-level progressive compression
async function compressContext(
messages: Message[],
targetTokens: number
): Promise<Message[]> {
let compressed = messages;
let currentTokens = estimateTokens(compressed);
// Level 1: Snip old image content (images are 1500+ tokens each)
if (currentTokens > targetTokens) {
compressed = snipImages(compressed, { keepRecent: 3 });
currentTokens = estimateTokens(compressed);
}
// Level 2: Micro-compact (merge adjacent same-role messages)
if (currentTokens > targetTokens) {
compressed = microCompact(compressed);
currentTokens = estimateTokens(compressed);
}
// Level 3: Collapse (summarize tool results)
if (currentTokens > targetTokens) {
compressed = await collapseToolResults(compressed, {
summarizeOlderThan: 10, // Message index threshold
maxSummaryTokens: 200
});
currentTokens = estimateTokens(compressed);
}
// Level 4: Auto-compact (LLM summarization)
if (currentTokens > targetTokens) {
compressed = await autoCompact(compressed, {
targetRatio: 0.5, // Compress to 50%
preserveRecent: 5 // Keep last 5 exchanges intact
});
}
return compressed;
}
// Circuit breaker pattern (prevent infinite compression)
class CompressionCircuitBreaker {
private failureCount = 0;
private lastReset = Date.now();
async attempt<T>(fn: () => Promise<T>): Promise<T> {
if (this.failureCount >= 3) {
if (Date.now() - this.lastReset < 60_000) {
throw new Error('Compression circuit breaker open');
}
this.reset();
}
try {
const result = await fn();
this.reset();
return result;
} catch (error) {
this.failureCount++;
throw error;
}
}
private reset() {
this.failureCount = 0;
this.lastReset = Date.now();
}
}5. Memory System (Long-term Memory)
5. 内存系统(长期记忆)
Four closed-type memory categories:
typescript
// Memory types (closed set - only these four)
type MemoryType =
| 'code_patterns' // Architecture decisions, idioms
| 'user_preferences' // Settings, workflow habits
| 'project_context' // Goals, constraints, history
| 'task_progress'; // Ongoing work state
interface Memory {
type: MemoryType;
key: string; // Unique identifier
content: string; // Natural language
metadata: {
created: string; // ISO timestamp
accessed: string; // Last retrieval
confidence: number; // 0-1, for pruning
};
}
// "Only store what cannot be derived" principle
async function shouldStore(content: string, deps: QueryDeps): Promise<boolean> {
// Don't store if:
// - Can be read from files
// - Can be inferred from code
// - Is ephemeral state
const derivable = [
() => deps.workspace.files.includes(content), // File content
() => /^(let|const|function)/.test(content), // Code snippets
() => isTemporary(content) // Timestamps, PIDs
];
return !derivable.some(check => check());
}
// MEMORY.md index structure
/*四类封闭型内存分类:
typescript
// Memory types (closed set - only these four)
type MemoryType =
| 'code_patterns' // Architecture decisions, idioms
| 'user_preferences' // Settings, workflow habits
| 'project_context' // Goals, constraints, history
| 'task_progress'; // Ongoing work state
interface Memory {
type: MemoryType;
key: string; // Unique identifier
content: string; // Natural language
metadata: {
created: string; // ISO timestamp
accessed: string; // Last retrieval
confidence: number; // 0-1, for pruning
};
}
// "Only store what cannot be derived" principle
async function shouldStore(content: string, deps: QueryDeps): Promise<boolean> {
// Don't store if:
// - Can be read from files
// - Can be inferred from code
// - Is ephemeral state
const derivable = [
() => deps.workspace.files.includes(content), // File content
() => /^(let|const|function)/.test(content), // Code snippets
() => isTemporary(content) // Timestamps, PIDs
];
return !derivable.some(check => check());
}
// MEMORY.md index structure
/*Agent Memory
Agent Memory
Code Patterns
Code Patterns
- [architecture-decision-rest-api] Decided to use REST over GraphQL
- [error-handling-strategy] All errors use custom Error subclasses
- [architecture-decision-rest-api] Decided to use REST over GraphQL
- [error-handling-strategy] All errors use custom Error subclasses
User Preferences
User Preferences
- [editor-choice] User prefers VSCode with Vim keybindings
- [commit-style] Conventional commits with emoji prefixes
- [editor-choice] User prefers VSCode with Vim keybindings
- [commit-style] Conventional commits with emoji prefixes
Project Context
Project Context
- [migration-status] Currently migrating from Express to Fastify
- [tech-debt] Known issue: N+1 queries in user dashboard
- [migration-status] Currently migrating from Express to Fastify
- [tech-debt] Known issue: N+1 queries in user dashboard
Task Progress
Task Progress
- [feature-auth] OAuth2 implementation 60% complete */
// Fork memory mechanism (sub-agent inherits parent context)
async function forkAgent(parentDeps: QueryDeps): Promise<Agent> {
const childDeps = {
...parentDeps,
memory: {
// Byte-level context inheritance
messages: structuredClone(parentDeps.memory.messages),
// Selective memory copying (only project_context + code_patterns)
stored: parentDeps.memory.stored.filter(
m => ['project_context', 'code_patterns'].includes(m.type)
),
// Fresh task_progress
taskState: {}
}
};
return new Agent(childDeps);
}
undefined- [feature-auth] OAuth2 implementation 60% complete */
// Fork memory mechanism (sub-agent inherits parent context)
async function forkAgent(parentDeps: QueryDeps): Promise<Agent> {
const childDeps = {
...parentDeps,
memory: {
// Byte-level context inheritance
messages: structuredClone(parentDeps.memory.messages),
// Selective memory copying (only project_context + code_patterns)
stored: parentDeps.memory.stored.filter(
m => ['project_context', 'code_patterns'].includes(m.type)
),
// Fresh task_progress
taskState: {}
}
};
return new Agent(childDeps);
}
undefined6. Hook System (Lifecycle Extension)
6. 钩子系统(生命周期扩展)
26 lifecycle events across 5 categories:
typescript
// Five hook categories
type HookCategory =
| 'lifecycle' // conversation_start, query_begin, query_end
| 'tool' // tool_before, tool_after, tool_error
| 'content' // message_sent, message_received, context_compressed
| 'system' // config_changed, skill_loaded, mcp_connected
| 'agent'; // agent_forked, agent_terminated
interface Hook {
event: string; // e.g., 'tool_before_execute'
handler: string; // Path to executable
config?: {
priority: number; // 0-5 (higher = earlier)
async: boolean; // Run without blocking
timeout: number; // Max execution time (ms)
};
}
// JSON response protocol
interface HookResponse {
allow?: boolean; // For before_* hooks: veto execution
modify?: { // For content hooks: transform data
input?: unknown;
output?: unknown;
};
metadata?: Record<string, unknown>; // Arbitrary data for next hooks
}
// Example: Audit hook (log all tool executions)
// .claude/hooks/audit-tools.ts
export default async function auditHook(event: HookEvent): Promise<HookResponse> {
if (event.type === 'tool_before_execute') {
await fs.appendFile(
'.claude/audit.log',
JSON.stringify({
timestamp: new Date().toISOString(),
tool: event.data.tool.name,
input: event.data.input,
user: process.env.USER
}) + '\n'
);
}
return { allow: true }; // Don't block execution
}
// Security: Three-layer sandbox
// 1. Process isolation (separate Node.js process)
// 2. Permission restrictions (can't access parent env vars)
// 3. Timeout enforcement (default 5s)5类共26个生命周期事件:
typescript
// Five hook categories
type HookCategory =
| 'lifecycle' // conversation_start, query_begin, query_end
| 'tool' // tool_before, tool_after, tool_error
| 'content' // message_sent, message_received, context_compressed
| 'system' // config_changed, skill_loaded, mcp_connected
| 'agent'; // agent_forked, agent_terminated
interface Hook {
event: string; // e.g., 'tool_before_execute'
handler: string; // Path to executable
config?: {
priority: number; // 0-5 (higher = earlier)
async: boolean; // Run without blocking
timeout: number; // Max execution time (ms)
};
}
// JSON response protocol
interface HookResponse {
allow?: boolean; // For before_* hooks: veto execution
modify?: { // For content hooks: transform data
input?: unknown;
output?: unknown;
};
metadata?: Record<string, unknown>; // Arbitrary data for next hooks
}
// Example: Audit hook (log all tool executions)
// .claude/hooks/audit-tools.ts
export default async function auditHook(event: HookEvent): Promise<HookResponse> {
if (event.type === 'tool_before_execute') {
await fs.appendFile(
'.claude/audit.log',
JSON.stringify({
timestamp: new Date().toISOString(),
tool: event.data.tool.name,
input: event.data.input,
user: process.env.USER
}) + '\n'
);
}
return { allow: true }; // Don't block execution
}
// Security: Three-layer sandbox
// 1. Process isolation (separate Node.js process)
// 2. Permission restrictions (can't access parent env vars)
// 3. Timeout enforcement (default 5s)7. Sub-Agent Fork Pattern
7. 子Agent分叉模式
Byte-level context inheritance with recursive protection:
typescript
// Three agent sources
type AgentSource =
| 'builtin' // Four built-in agents: coordinator, worker, researcher, reviewer
| 'skill' // Defined in SKILL.md files
| 'fork'; // Cloned from current agent
// Fork with context inheritance
async function forkCurrentAgent(
purpose: string,
deps: QueryDeps
): Promise<Agent> {
// Recursive fork depth protection
if (deps.forkDepth >= 3) {
throw new Error('Max fork depth exceeded (prevents infinite recursion)');
}
const childAgent = new Agent({
...deps,
forkDepth: deps.forkDepth + 1,
// Inherit full message history (byte-level copy)
context: {
messages: structuredClone(deps.context.messages),
tokenBudget: deps.context.tokenBudget * 0.8 // 80% of parent budget
},
// Inherit selective memory
memory: forkMemory(deps.memory, ['project_context', 'code_patterns']),
// New task-specific system prompt
systemPrompt: `${deps.systemPrompt}\n\nForked for: ${purpose}`,
// Inherit parent's tool access
tools: deps.tools,
permissions: deps.permissions
});
return childAgent;
}
// Four built-in agents
const BUILTIN_AGENTS = {
coordinator: {
role: 'Orchestrate multiple workers, never execute tools directly',
tools: ['fork_agent', 'send_message_to_agent', 'collect_results'],
constraints: ['no_file_access', 'no_shell_access']
},
worker: {
role: 'Execute specific tasks assigned by coordinator',
tools: ['all'], // Full tool access
constraints: ['report_progress_every_5min']
},
researcher: {
role: 'Gather information, no side effects',
tools: ['read_file', 'search', 'browse', 'read_memory'],
constraints: ['read_only_mode']
},
reviewer: {
role: 'Analyze code, suggest improvements',
tools: ['read_file', 'run_linter', 'run_tests'],
constraints: ['no_modifications']
}
};字节级上下文继承与递归保护:
typescript
// Three agent sources
type AgentSource =
| 'builtin' // Four built-in agents: coordinator, worker, researcher, reviewer
| 'skill' // Defined in SKILL.md files
| 'fork'; // Cloned from current agent
// Fork with context inheritance
async function forkCurrentAgent(
purpose: string,
deps: QueryDeps
): Promise<Agent> {
// Recursive fork depth protection
if (deps.forkDepth >= 3) {
throw new Error('Max fork depth exceeded (prevents infinite recursion)');
}
const childAgent = new Agent({
...deps,
forkDepth: deps.forkDepth + 1,
// Inherit full message history (byte-level copy)
context: {
messages: structuredClone(deps.context.messages),
tokenBudget: deps.context.tokenBudget * 0.8 // 80% of parent budget
},
// Inherit selective memory
memory: forkMemory(deps.memory, ['project_context', 'code_patterns']),
// New task-specific system prompt
systemPrompt: `${deps.systemPrompt}\n\nForked for: ${purpose}`,
// Inherit parent's tool access
tools: deps.tools,
permissions: deps.permissions
});
return childAgent;
}
// Four built-in agents
const BUILTIN_AGENTS = {
coordinator: {
role: 'Orchestrate multiple workers, never execute tools directly',
tools: ['fork_agent', 'send_message_to_agent', 'collect_results'],
constraints: ['no_file_access', 'no_shell_access']
},
worker: {
role: 'Execute specific tasks assigned by coordinator',
tools: ['all'], // Full tool access
constraints: ['report_progress_every_5min']
},
researcher: {
role: 'Gather information, no side effects',
tools: ['read_file', 'search', 'browse', 'read_memory'],
constraints: ['read_only_mode']
},
reviewer: {
role: 'Analyze code, suggest improvements',
tools: ['read_file', 'run_linter', 'run_tests'],
constraints: ['no_modifications']
}
};8. MCP Integration (External Protocol Bridge)
8. MCP集成(外部协议桥接)
Model Context Protocol for external tool/resource integration:
typescript
// Eight transport protocols
type MCPTransport =
| 'stdio' // Standard I/O pipes
| 'http' // REST API
| 'websocket' // WebSocket
| 'grpc' // gRPC
| 'ipc' // Inter-process communication
| 'tcp' // Raw TCP
| 'udp' // UDP datagrams
| 'sse'; // Server-sent events
// Five-state connection management
type MCPConnectionState =
| 'disconnected'
| 'connecting'
| 'connected'
| 'error'
| 'reconnecting';
class MCPConnection {
state: MCPConnectionState = 'disconnected';
retryCount = 0;
maxRetries = 3;
async connect(config: MCPServerConfig) {
this.state = 'connecting';
try {
const transport = createTransport(config.transport);
await transport.initialize();
// Handshake: Exchange capabilities
const serverInfo = await transport.request({
method: 'initialize',
params: {
clientInfo: { name: 'claude-code', version: '1.0' },
capabilities: ['tools', 'resources', 'prompts']
}
});
this.state = 'connected';
return serverInfo;
} catch (error) {
this.state = 'error';
if (this.retryCount < this.maxRetries) {
this.retryCount++;
this.state = 'reconnecting';
await sleep(1000 * this.retryCount); // Exponential backoff
return this.connect(config);
}
throw error;
}
}
}
// Three-segment tool naming (namespace isolation)
// Format: mcp://{server_name}/{tool_name}
const mcpTool = {
name: 'mcp://github/create_issue',
handler: async (input, deps) => {
const connection = deps.mcpConnections.get('github');
return await connection.call('create_issue', input);
}
};
// Bridge pattern (bidirectional communication)
class MCPBridge {
// Forward: Agent → MCP Server
async callTool(server: string, tool: string, input: unknown) {
const conn = this.connections.get(server);
return await conn.request({
method: 'tools/call',
params: { name: tool, arguments: input }
});
}
// Reverse: MCP Server → Agent (notifications)
async handleNotification(notification: MCPNotification) {
if (notification.method === 'resources/updated') {
// Invalidate cached resources
await this.invalidateCache(notification.params.uri);
}
}
}用于外部工具/资源集成的Model Context Protocol:
typescript
// Eight transport protocols
type MCPTransport =
| 'stdio' // Standard I/O pipes
| 'http' // REST API
| 'websocket' // WebSocket
| 'grpc' // gRPC
| 'ipc' // Inter-process communication
| 'tcp' // Raw TCP
| 'udp' // UDP datagrams
| 'sse'; // Server-sent events
// Five-state connection management
type MCPConnectionState =
| 'disconnected'
| 'connecting'
| 'connected'
| 'error'
| 'reconnecting';
class MCPConnection {
state: MCPConnectionState = 'disconnected';
retryCount = 0;
maxRetries = 3;
async connect(config: MCPServerConfig) {
this.state = 'connecting';
try {
const transport = createTransport(config.transport);
await transport.initialize();
// Handshake: Exchange capabilities
const serverInfo = await transport.request({
method: 'initialize',
params: {
clientInfo: { name: 'claude-code', version: '1.0' },
capabilities: ['tools', 'resources', 'prompts']
}
});
this.state = 'connected';
return serverInfo;
} catch (error) {
this.state = 'error';
if (this.retryCount < this.maxRetries) {
this.retryCount++;
this.state = 'reconnecting';
await sleep(1000 * this.retryCount); // Exponential backoff
return this.connect(config);
}
throw error;
}
}
}
// Three-segment tool naming (namespace isolation)
// Format: mcp://{server_name}/{tool_name}
const mcpTool = {
name: 'mcp://github/create_issue',
handler: async (input, deps) => {
const connection = deps.mcpConnections.get('github');
return await connection.call('create_issue', input);
}
};
// Bridge pattern (bidirectional communication)
class MCPBridge {
// Forward: Agent → MCP Server
async callTool(server: string, tool: string, input: unknown) {
const conn = this.connections.get(server);
return await conn.request({
method: 'tools/call',
params: { name: tool, arguments: input }
});
}
// Reverse: MCP Server → Agent (notifications)
async handleNotification(notification: MCPNotification) {
if (notification.method === 'resources/updated') {
// Invalidate cached resources
await this.invalidateCache(notification.params.uri);
}
}
}Practical Patterns
实践模式
Building a Custom Tool
构建自定义工具
typescript
import { buildTool } from './tool-factory';
import { z } from 'zod';
// Example: Jira integration tool
const createJiraIssueTool = buildTool({
schema: z.object({
project: z.string(),
summary: z.string(),
description: z.string(),
issueType: z.enum(['Bug', 'Task', 'Story']).default('Task'),
priority: z.enum(['Low', 'Medium', 'High']).default('Medium')
}),
permission: 'write', // Requires write access
properties: {
readOnly: false,
destructive: false, // Can be undone (delete issue)
concurrencySafe: true // Multiple issues can be created in parallel
},
handler: async (input, deps) => {
// Use environment variables for secrets
const jiraClient = new JiraClient({
host: process.env.JIRA_HOST,
auth: {
username: process.env.JIRA_USERNAME,
apiToken: process.env.JIRA_API_TOKEN
}
});
try {
const issue = await jiraClient.issues.create({
fields: {
project: { key: input.project },
summary: input.summary,
description: input.description,
issuetype: { name: input.issueType },
priority: { name: input.priority }
}
});
return {
success: true,
issueKey: issue.key,
url: `${process.env.JIRA_HOST}/browse/${issue.key}`
};
} catch (error) {
throw new ToolError('JiraCreateFailed', {
message: error.message,
statusCode: error.statusCode
});
}
}
});typescript
import { buildTool } from './tool-factory';
import { z } from 'zod';
// Example: Jira integration tool
const createJiraIssueTool = buildTool({
schema: z.object({
project: z.string(),
summary: z.string(),
description: z.string(),
issueType: z.enum(['Bug', 'Task', 'Story']).default('Task'),
priority: z.enum(['Low', 'Medium', 'High']).default('Medium')
}),
permission: 'write', // Requires write access
properties: {
readOnly: false,
destructive: false, // Can be undone (delete issue)
concurrencySafe: true // Multiple issues can be created in parallel
},
handler: async (input, deps) => {
// Use environment variables for secrets
const jiraClient = new JiraClient({
host: process.env.JIRA_HOST,
auth: {
username: process.env.JIRA_USERNAME,
apiToken: process.env.JIRA_API_TOKEN
}
});
try {
const issue = await jiraClient.issues.create({
fields: {
project: { key: input.project },
summary: input.summary,
description: input.description,
issuetype: { name: input.issueType },
priority: { name: input.priority }
}
});
return {
success: true,
issueKey: issue.key,
url: `${process.env.JIRA_HOST}/browse/${issue.key}`
};
} catch (error) {
throw new ToolError('JiraCreateFailed', {
message: error.message,
statusCode: error.statusCode
});
}
}
});Implementing a Permission Strategy
实现权限策略
typescript
// Custom permission strategy with role-based access
class RBACPermissionStrategy implements PermissionStrategy {
private userRole: 'developer' | 'senior' | 'admin';
constructor(role: string) {
this.userRole = role as any;
}
async authorize(toolCall: ToolCall): Promise<AuthResult> {
const permissions = {
developer: {
allowed: ['read_file', 'search', 'run_tests'],
denied: ['execute_bash', 'write_file', 'git_push']
},
senior: {
allowed: ['read_file', 'write_file', 'execute_bash', 'git_commit'],
denied: ['git_push', 'delete_file', 'modify_settings']
},
admin: {
allowed: ['*'], // All tools
denied: []
}
};
const config = permissions[this.userRole];
if (config.denied.includes(toolCall.tool.name)) {
return { allowed: false, reason: 'Role restriction' };
}
if (config.allowed.includes('*') || config.allowed.includes(toolCall.tool.name)) {
// Additional check for destructive operations
if (toolCall.tool.properties.destructive) {
return {
allowed: true,
requireConfirmation: this.userRole !== 'admin'
};
}
return { allowed: true };
}
return { allowed: false, reason: 'Tool not in allowed list' };
}
}typescript
// Custom permission strategy with role-based access
class RBACPermissionStrategy implements PermissionStrategy {
private userRole: 'developer' | 'senior' | 'admin';
constructor(role: string) {
this.userRole = role as any;
}
async authorize(toolCall: ToolCall): Promise<AuthResult> {
const permissions = {
developer: {
allowed: ['read_file', 'search', 'run_tests'],
denied: ['execute_bash', 'write_file', 'git_push']
},
senior: {
allowed: ['read_file', 'write_file', 'execute_bash', 'git_commit'],
denied: ['git_push', 'delete_file', 'modify_settings']
},
admin: {
allowed: ['*'], // All tools
denied: []
}
};
const config = permissions[this.userRole];
if (config.denied.includes(toolCall.tool.name)) {
return { allowed: false, reason: 'Role restriction' };
}
if (config.allowed.includes('*') || config.allowed.includes(toolCall.tool.name)) {
// Additional check for destructive operations
if (toolCall.tool.properties.destructive) {
return {
allowed: true,
requireConfirmation: this.userRole !== 'admin'
};
}
return { allowed: true };
}
return { allowed: false, reason: 'Tool not in allowed list' };
}
}Context Compression Strategy
上下文压缩策略
typescript
// Aggressive compression for long conversations
class AggressiveCompressionStrategy {
async compress(messages: Message[], targetTokens: number): Promise<Message[]> {
let result = messages;
const steps = [
{ name: 'Remove images', fn: this.removeAllImages },
{ name: 'Summarize tool outputs', fn: this.summarizeToolOutputs },
{ name: 'Collapse redundant exchanges', fn: this.collapseRedundant },
{ name: 'Semantic compression', fn: this.semanticCompress }
];
for (const step of steps) {
const currentTokens = estimateTokens(result);
if (currentTokens <= targetTokens) {
break; // Target reached
}
console.log(`Compression step: ${step.name} (${currentTokens} → target ${targetTokens})`);
result = await step.fn(result, targetTokens);
}
return result;
}
private async semanticCompress(
messages: Message[],
targetTokens: number
): Promise<Message[]> {
// Use LLM to summarize conversation history
const summary = await llmClient.chat({
messages: [
{
role: 'user',
content: `Summarize this conversation history in ${targetTokens * 0.3} tokens:\n\n${formatMessages(messages)}`
}
]
});
return [
{
role: 'assistant',
content: `[Conversation summary]: ${summary.content}`
},
...messages.slice(-5) // Keep last 5 messages intact
];
}
}typescript
// Aggressive compression for long conversations
class AggressiveCompressionStrategy {
async compress(messages: Message[], targetTokens: number): Promise<Message[]> {
let result = messages;
const steps = [
{ name: 'Remove images', fn: this.removeAllImages },
{ name: 'Summarize tool outputs', fn: this.summarizeToolOutputs },
{ name: 'Collapse redundant exchanges', fn: this.collapseRedundant },
{ name: 'Semantic compression', fn: this.semanticCompress }
];
for (const step of steps) {
const currentTokens = estimateTokens(result);
if (currentTokens <= targetTokens) {
break; // Target reached
}
console.log(`Compression step: ${step.name} (${currentTokens} → target ${targetTokens})`);
result = await step.fn(result, targetTokens);
}
return result;
}
private async semanticCompress(
messages: Message[],
targetTokens: number
): Promise<Message[]> {
// Use LLM to summarize conversation history
const summary = await llmClient.chat({
messages: [
{
role: 'user',
content: `Summarize this conversation history in ${targetTokens * 0.3} tokens:\n\n${formatMessages(messages)}`
}
]
});
return [
{
role: 'assistant',
content: `[Conversation summary]: ${summary.content}`
},
...messages.slice(-5) // Keep last 5 messages intact
];
}
}Configuration
配置
Setting Up Agent Harness
设置Agent Harness
typescript
// .claude/config.json
{
"version": "1.0",
"agent": {
"model": "claude-3-5-sonnet-20241022",
"contextWindow": 200000,
"permissionMode": "normal", // safe | normal | relaxed | auto
"features": {
"toolCalling": true,
"memorySystem": true,
"subAgents": true,
"mcpIntegration": true
}
},
"tools": {
"enabled": [
"read_file",
"write_file",
"execute_bash",
"ripgrep_search",
"git_*" // Wildcard pattern
],
"disabled": [
"delete_file" // Explicitly disabled
],
"concurrency": {
"maxParallel": 5,
"partitionStrategy": "read-write-split"
}
},
"context": {
"compression": {
"strategy": "progressive", // progressive | aggressive | minimal
"levels": ["snip", "micro-compact", "collapse", "auto-compact"],
"targetUtilization": 0.9 // 90% of effective window
}
},
"memory": {
"storageBackend": "filesystem", // filesystem | sqlite | postgres
"indexFile": ".claude/MEMORY.md",
"pruneStrategy": {
"confidenceThreshold": 0.3,
"maxAge": "30d"
}
},
"hooks": {
"enabled": true,
"directory": ".claude/hooks",
"defaultTimeout": 5000
},
"mcp": {
"servers": {
"github": {
"transport": "http",
"url": "https://localhost:3000/mcp",
"auth": {
"type": "bearer",
"token": "${GITHUB_TOKEN}" // Environment variable reference
}
},
"database": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"POSTGRES_URL": "${DATABASE_URL}"
}
}
}
}
}typescript
// .claude/config.json
{
"version": "1.0",
"agent": {
"model": "claude-3-5-sonnet-20241022",
"contextWindow": 200000,
"permissionMode": "normal", // safe | normal | relaxed | auto
"features": {
"toolCalling": true,
"memorySystem": true,
"subAgents": true,
"mcpIntegration": true
}
},
"tools": {
"enabled": [
"read_file",
"write_file",
"execute_bash",
"ripgrep_search",
"git_*" // Wildcard pattern
],
"disabled": [
"delete_file" // Explicitly disabled
],
"concurrency": {
"maxParallel": 5,
"partitionStrategy": "read-write-split"
}
},
"context": {
"compression": {
"strategy": "progressive", // progressive | aggressive | minimal
"levels": ["snip", "micro-compact", "collapse", "auto-compact"],
"targetUtilization": 0.9 // 90% of effective window
}
},
"memory": {
"storageBackend": "filesystem", // filesystem | sqlite | postgres
"indexFile": ".claude/MEMORY.md",
"pruneStrategy": {
"confidenceThreshold": 0.3,
"maxAge": "30d"
}
},
"hooks": {
"enabled": true,
"directory": ".claude/hooks",
"defaultTimeout": 5000
},
"mcp": {
"servers": {
"github": {
"transport": "http",
"url": "https://localhost:3000/mcp",
"auth": {
"type": "bearer",
"token": "${GITHUB_TOKEN}" // Environment variable reference
}
},
"database": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"POSTGRES_URL": "${DATABASE_URL}"
}
}
}
}
}Feature Flags (89 total)
功能标志(共89个)
typescript
// Runtime feature flags (13 categories)
const FEATURE_FLAGS = {
// Core features
'agent.tool_calling': true,
'agent.sub_agents': true,
'agent.memory_system': true,
// Safety features
'safety.permission_pipeline': true,
'safety.bash_validation': true,
'safety.path_restrictions': true,
// Performance
'perf.lazy_tool_loading': true,typescript
// Runtime feature flags (13 categories)
const FEATURE_FLAGS = {
// Core features
'agent.tool_calling': true,
'agent.sub_agents': true,
'agent.memory_system': true,
// Safety features
'safety.permission_pipeline': true,
'safety.bash_validation': true,
'safety.path_restrictions': true,
// Performance
'perf.lazy_tool_loading': true,