Claude Code 实现分析 ⌨️
"Claude Code 是 Anthropic 官方的终端 AI 编程助手,展示了 CLI Agent 的最佳实践。"
1. Claude Code 概述
1.1 什么是 Claude Code
Claude Code 是 Anthropic 推出的命令行 AI 编程工具:
- 终端原生: 在命令行中运行
- Agentic: 能自主规划和执行多步任务
- 权限模型: 精细的权限控制
- 迭代执行: 持续工作直到任务完成
1.2 与 Cursor 的区别
| 特性 | Claude Code | Cursor |
|---|---|---|
| 界面 | 终端 CLI | IDE GUI |
| 触发 | 显式命令 | 快捷键/对话 |
| 权限 | 显式授权 | IDE 集成 |
| 目标用户 | 命令行用户 | IDE 用户 |
2. 系统提示词分析
2.1 核心 System Prompt 结构
基于公开信息和逆向分析,Claude Code 的 System Prompt 大致结构:
markdown
You are Claude Code, an interactive CLI tool that helps users with software engineering tasks. You are running in a terminal environment.
<tool_calling>
You have tools to interact with the user's system. When using tools:
- Only use the standard tool call format
- Check that all required parameters are provided
- DO NOT make up values for required parameters
- If parameters are missing, ask the user
</tool_calling>
<making_code_changes>
1. Prefer editing existing files over creating new ones
2. NEVER proactively create documentation files unless requested
3. If you've introduced linter errors, fix them
4. Always use the edit tools to make changes
</making_code_changes>
<memory>
You have access to a persistent memory system. Use it to store:
- User preferences
- Project-specific knowledge
- Important decisions
</memory>
<context>
Information about the user's environment will be provided:
- Current working directory
- Git status
- Recent files
</context>2.2 权限模型
markdown
## Permission Levels
### Default (Safe operations)
- Read files
- Search code
- View git status
### Requires Confirmation
- Write/Edit files
- Run terminal commands
- Make git commits
### Restricted
- Network access
- System modifications
- Access to ignored files
When an operation requires permission, explain what you want to do and why, then ask for approval.3. 工具系统
3.1 文件操作工具
typescript
const fileTools = [
{
name: "read_file",
description: `Read file from local filesystem.
Usage:
- Specify full path or relative to workspace
- Can read any accessible file
- Line numbers in output start at 1
Parameters:
- target_file (required): Path to the file
- offset (optional): Starting line number
- limit (optional): Max lines to read`,
input_schema: {
type: "object",
properties: {
target_file: { type: "string" },
offset: { type: "integer" },
limit: { type: "integer" }
},
required: ["target_file"]
}
},
{
name: "write_file",
description: `Write content to a file. Overwrites if exists.
IMPORTANT:
- Read the file first if it exists
- ALWAYS prefer editing existing files
- Never create documentation unless requested`,
input_schema: {
type: "object",
properties: {
file_path: { type: "string" },
content: { type: "string" }
},
required: ["file_path", "content"]
}
},
{
name: "edit_file",
description: `Edit a file by replacing old_string with new_string.
CRITICAL:
- old_string must match EXACTLY (including whitespace)
- Include enough context for unique matching
- The edit will FAIL if old_string is not unique
- Use replace_all for multiple occurrences`,
input_schema: {
type: "object",
properties: {
file_path: { type: "string" },
old_string: { type: "string" },
new_string: { type: "string" },
replace_all: { type: "boolean" }
},
required: ["file_path", "old_string", "new_string"]
}
}
];3.2 搜索工具
typescript
const searchTools = [
{
name: "codebase_search",
description: `Semantic search that finds code by meaning.
When to Use:
- Explore unfamiliar codebases
- Find code by concept, not exact text
- Ask "how/where/what" questions
When NOT to Use:
- Exact string matches (use grep)
- Simple symbol lookups (use grep)
Examples:
- Good: "Where is user authentication handled?"
- Bad: "AuthService" (use grep for exact match)`,
input_schema: {
type: "object",
properties: {
query: {
type: "string",
description: "Complete question about what you want to find"
},
target_directories: {
type: "array",
items: { type: "string" },
description: "Limit search to specific directory"
}
},
required: ["query", "target_directories"]
}
},
{
name: "grep",
description: `Regex search in files using ripgrep.
Features:
- Full regex syntax
- Respects .gitignore
- Multiple output modes: content, files_with_matches, count
Tips:
- Escape special characters for literal match
- Use 'type' to filter by file type
- Results are capped for performance`,
input_schema: {
type: "object",
properties: {
pattern: { type: "string" },
path: { type: "string" },
type: { type: "string" },
output_mode: {
type: "string",
enum: ["content", "files_with_matches", "count"]
}
},
required: ["pattern"]
}
}
];3.3 终端工具
typescript
{
name: "run_terminal_cmd",
description: `Execute a terminal command.
Sandboxing:
- By default, runs in a sandbox with limited permissions
- Write access limited to workspace
- Network access blocked
- Git writes blocked
Permissions:
- 'network': For package installs, API calls
- 'git_write': For commits, branch changes
- 'all': Disable sandbox entirely
Guidelines:
- For long-running processes, use is_background: true
- Check existing terminals before starting servers
- Pass non-interactive flags (e.g., --yes)`,
input_schema: {
type: "object",
properties: {
command: { type: "string" },
is_background: { type: "boolean" },
required_permissions: {
type: "array",
items: {
type: "string",
enum: ["network", "git_write", "all"]
}
}
},
required: ["command", "is_background"]
}
}3.4 记忆工具
typescript
{
name: "update_memory",
description: `Create, update, or delete persistent memory.
Usage:
- Store user preferences
- Remember project-specific decisions
- Track important context
Actions:
- 'create': Add new memory
- 'update': Modify existing memory (requires existing_knowledge_id)
- 'delete': Remove memory (requires existing_knowledge_id)
Rules:
- Only create memory when user explicitly asks
- Use delete (not update) for contradictions
- Keep memories concise (one paragraph max)`,
input_schema: {
type: "object",
properties: {
action: {
type: "string",
enum: ["create", "update", "delete"]
},
title: { type: "string" },
knowledge_to_store: { type: "string" },
existing_knowledge_id: { type: "string" }
}
}
}4. 权限与安全模型
4.1 分层权限
┌─────────────────────────────────────────────────────────────────┐
│ Permission Layers │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Layer 1: Auto-Approved (无需确认) │
│ ├── read_file │
│ ├── list_dir │
│ ├── grep (read-only) │
│ └── codebase_search │
│ │
│ Layer 2: Requires Confirmation (需要用户确认) │
│ ├── write_file │
│ ├── edit_file │
│ ├── delete_file │
│ └── run_terminal_cmd (sandboxed) │
│ │
│ Layer 3: Explicit Permission (需要显式权限) │
│ ├── network access │
│ ├── git_write operations │
│ └── run_terminal_cmd (unsandboxed) │
│ │
│ Layer 4: Blocked (禁止) │
│ ├── Access ignored files │
│ ├── System modifications │
│ └── Sensitive data access │
│ │
└─────────────────────────────────────────────────────────────────┘4.2 沙箱执行
typescript
interface SandboxConfig {
// 文件系统限制
filesystem: {
writeAllowed: string[]; // 允许写入的路径
readAllowed: string[]; // 允许读取的路径
blocked: string[]; // 禁止访问的路径
};
// 网络限制
network: {
allowed: boolean;
allowedHosts?: string[];
};
// 进程限制
process: {
maxTime: number; // 最大执行时间
maxMemory: number; // 最大内存
};
// Git 限制
git: {
readAllowed: boolean;
writeAllowed: boolean;
};
}
class SandboxExecutor {
async execute(command: string, permissions: string[]) {
const config = this.buildConfig(permissions);
// 使用 firejail 或类似工具创建沙箱
const sandbox = await createSandbox(config);
try {
const result = await sandbox.run(command);
return result;
} catch (error) {
if (this.isSandboxError(error)) {
return {
success: false,
error: "Operation blocked by sandbox",
suggestion: "Request appropriate permissions"
};
}
throw error;
}
}
}4.3 用户确认流程
typescript
class ConfirmationManager {
async requestPermission(operation: Operation): Promise<boolean> {
// 描述操作
const description = this.describeOperation(operation);
// 显示给用户
console.log(`\n${chalk.yellow('⚠️ Permission Required')}`);
console.log(description);
console.log(`\n${chalk.dim('This action requires your approval.')}`);
// 等待用户输入
const { confirmed } = await prompts({
type: 'confirm',
name: 'confirmed',
message: 'Allow this operation?',
initial: false
});
// 记录决定
this.logDecision(operation, confirmed);
return confirmed;
}
describeOperation(op: Operation): string {
switch (op.type) {
case 'write_file':
return `Write to file: ${op.path}\nContent length: ${op.content.length} characters`;
case 'run_command':
return `Execute command: ${op.command}\nPermissions: ${op.permissions.join(', ')}`;
case 'delete_file':
return `Delete file: ${op.path}`;
default:
return `Perform: ${op.type}`;
}
}
}5. 任务执行模式
5.1 任务管理 (Todo List)
typescript
interface TodoItem {
id: string;
content: string;
status: 'pending' | 'in_progress' | 'completed' | 'cancelled';
}
class TodoManager {
private todos: TodoItem[] = [];
// 创建任务列表
createFromTask(task: string): TodoItem[] {
// 让 LLM 分解任务
const plan = await this.planTask(task);
this.todos = plan.steps.map((step, i) => ({
id: `${i + 1}`,
content: step,
status: i === 0 ? 'in_progress' : 'pending'
}));
return this.todos;
}
// 更新任务状态
update(id: string, status: TodoItem['status']) {
const todo = this.todos.find(t => t.id === id);
if (todo) {
todo.status = status;
}
}
// 获取进度
getProgress(): string {
const completed = this.todos.filter(t => t.status === 'completed').length;
return `${completed}/${this.todos.length} tasks completed`;
}
}5.2 迭代执行循环
typescript
class ClaudeCodeAgent {
async executeTask(task: string) {
const messages: Message[] = [];
// 添加系统上下文
messages.push({
role: 'system',
content: await this.buildSystemPrompt()
});
// 添加用户任务
messages.push({
role: 'user',
content: task
});
let iteration = 0;
const maxIterations = 100;
while (iteration < maxIterations) {
// 调用 LLM
const response = await this.llm.chat({
messages,
tools: this.tools
});
// 处理文本输出
if (response.content) {
this.displayOutput(response.content);
}
// 检查是否完成
if (response.stop_reason === 'end_turn' && !response.tool_calls) {
break;
}
// 处理工具调用
if (response.tool_calls) {
messages.push({ role: 'assistant', content: response.content });
const results = await this.executeTools(response.tool_calls);
messages.push({ role: 'user', content: results });
}
iteration++;
}
}
async executeTools(toolCalls: ToolCall[]) {
const results = [];
for (const call of toolCalls) {
// 权限检查
if (this.requiresPermission(call)) {
const granted = await this.confirmManager.requestPermission(call);
if (!granted) {
results.push({
tool_use_id: call.id,
content: "Operation cancelled by user"
});
continue;
}
}
// 执行工具
try {
const result = await this.toolExecutor.execute(call);
results.push({
tool_use_id: call.id,
content: JSON.stringify(result)
});
} catch (error) {
results.push({
tool_use_id: call.id,
content: `Error: ${error.message}`
});
}
}
return results;
}
}6. 上下文管理
6.1 环境信息收集
typescript
class EnvironmentContext {
async collect(): Promise<string> {
const info = {
// 基本信息
os: process.platform,
cwd: process.cwd(),
shell: process.env.SHELL,
// 项目信息
packageJson: await this.readPackageJson(),
gitStatus: await this.getGitStatus(),
// 文件结构
projectStructure: await this.getProjectStructure()
};
return this.format(info);
}
async getGitStatus(): Promise<string> {
try {
const branch = await exec('git branch --show-current');
const status = await exec('git status --short');
const recentCommits = await exec('git log --oneline -5');
return `Branch: ${branch}
Status:
${status}
Recent commits:
${recentCommits}`;
} catch {
return 'Not a git repository';
}
}
async getProjectStructure(): Promise<string> {
// 生成项目文件树(排除 node_modules 等)
const tree = await generateTree(process.cwd(), {
ignore: ['node_modules', '.git', 'dist', 'build']
});
return tree;
}
}6.2 终端状态追踪
typescript
class TerminalTracker {
private terminals: Map<string, TerminalState> = new Map();
track(id: string, state: TerminalState) {
this.terminals.set(id, {
...state,
lastUpdated: Date.now()
});
}
getContext(): string {
const active = [...this.terminals.values()]
.filter(t => this.isActive(t));
if (active.length === 0) {
return 'No active terminals';
}
return active.map(t => `
Terminal ${t.id}:
CWD: ${t.cwd}
Last command: ${t.lastCommand}
${t.isRunning ? `Running: ${t.currentCommand}` : `Exit code: ${t.lastExitCode}`}
`).join('\n');
}
}7. 记忆系统
7.1 持久化记忆
typescript
interface Memory {
id: string;
title: string;
content: string;
createdAt: Date;
updatedAt: Date;
tags: string[];
}
class MemoryStore {
private storePath: string;
private memories: Memory[] = [];
constructor() {
this.storePath = path.join(os.homedir(), '.claude-code', 'memories.json');
this.load();
}
async create(title: string, content: string): Promise<string> {
const memory: Memory = {
id: crypto.randomUUID(),
title,
content,
createdAt: new Date(),
updatedAt: new Date(),
tags: this.extractTags(content)
};
this.memories.push(memory);
await this.save();
return memory.id;
}
async update(id: string, content: string) {
const memory = this.memories.find(m => m.id === id);
if (memory) {
memory.content = content;
memory.updatedAt = new Date();
memory.tags = this.extractTags(content);
await this.save();
}
}
async delete(id: string) {
this.memories = this.memories.filter(m => m.id !== id);
await this.save();
}
// 相关记忆检索
async retrieve(query: string, limit: number = 5): Promise<Memory[]> {
// 简单的关键词匹配
const keywords = query.toLowerCase().split(' ');
return this.memories
.map(m => ({
memory: m,
score: this.relevanceScore(m, keywords)
}))
.filter(r => r.score > 0)
.sort((a, b) => b.score - a.score)
.slice(0, limit)
.map(r => r.memory);
}
private relevanceScore(memory: Memory, keywords: string[]): number {
const text = `${memory.title} ${memory.content}`.toLowerCase();
return keywords.filter(k => text.includes(k)).length;
}
}7.2 项目特定记忆
typescript
class ProjectMemory {
async getProjectContext(): Promise<string> {
const projectRoot = await this.findProjectRoot();
const memoryFile = path.join(projectRoot, '.claude-code', 'project.json');
if (await fs.exists(memoryFile)) {
const data = await fs.readJson(memoryFile);
return this.formatProjectMemory(data);
}
return '';
}
formatProjectMemory(data: ProjectData): string {
return `
## Project: ${data.name}
### Tech Stack
${data.techStack.join(', ')}
### Conventions
${data.conventions.map(c => `- ${c}`).join('\n')}
### Important Files
${data.importantFiles.map(f => `- ${f.path}: ${f.description}`).join('\n')}
### Recent Decisions
${data.decisions.map(d => `- ${d.date}: ${d.summary}`).join('\n')}
`;
}
}8. 用户体验
8.1 终端 UI
typescript
import { spinner, confirm, text } from '@clack/prompts';
class ClaudeCodeUI {
async displayThinking() {
const s = spinner();
s.start('Thinking...');
return s;
}
async displayToolCall(name: string, input: any) {
console.log(chalk.dim(`\n → ${name}`));
if (input.command) {
console.log(chalk.cyan(` $ ${input.command}`));
} else if (input.path || input.file_path) {
console.log(chalk.cyan(` 📄 ${input.path || input.file_path}`));
}
}
async displayToolResult(name: string, result: any) {
if (result.error) {
console.log(chalk.red(` ✗ ${result.error}`));
} else {
console.log(chalk.green(` ✓ Done`));
}
}
async displayMarkdown(content: string) {
const rendered = marked.parse(content);
console.log(rendered);
}
async displayDiff(oldContent: string, newContent: string) {
const diff = createPatch('file', oldContent, newContent);
console.log(
diff.split('\n').map(line => {
if (line.startsWith('+')) return chalk.green(line);
if (line.startsWith('-')) return chalk.red(line);
return line;
}).join('\n')
);
}
}8.2 快捷命令
typescript
const shortcuts = {
'/help': 'Show available commands',
'/clear': 'Clear conversation history',
'/undo': 'Undo last file change',
'/diff': 'Show recent changes',
'/memory': 'Manage memories',
'/model': 'Switch model',
'/exit': 'Exit Claude Code'
};
class CommandHandler {
async handle(input: string) {
if (!input.startsWith('/')) {
return null; // 不是命令
}
const [cmd, ...args] = input.split(' ');
switch (cmd) {
case '/help':
return this.showHelp();
case '/clear':
return this.clearHistory();
case '/undo':
return this.undoLastChange();
case '/diff':
return this.showDiff(args[0]);
case '/memory':
return this.manageMemory(args);
default:
return `Unknown command: ${cmd}`;
}
}
}9. 错误处理与恢复
9.1 优雅的错误处理
typescript
class ErrorHandler {
async handle(error: Error, context: ExecutionContext) {
// 分类错误
const category = this.categorize(error);
switch (category) {
case 'permission_denied':
return {
message: "Permission denied. Would you like to grant access?",
recoverable: true,
action: async () => {
const granted = await requestPermission();
if (granted) {
return await retry(context);
}
}
};
case 'file_not_found':
return {
message: `File not found: ${error.path}`,
recoverable: true,
suggestions: await this.findSimilarFiles(error.path)
};
case 'network_error':
return {
message: "Network error. Check your connection.",
recoverable: true,
action: async () => {
await sleep(2000);
return await retry(context);
}
};
default:
return {
message: `Error: ${error.message}`,
recoverable: false
};
}
}
}9.2 变更回滚
typescript
class ChangeTracker {
private changes: FileChange[] = [];
record(change: FileChange) {
this.changes.push({
...change,
timestamp: Date.now(),
backup: change.type !== 'create' ? change.originalContent : null
});
}
async undo(count: number = 1) {
const toUndo = this.changes.slice(-count);
for (const change of toUndo.reverse()) {
switch (change.type) {
case 'create':
await fs.unlink(change.path);
break;
case 'modify':
await fs.writeFile(change.path, change.backup!);
break;
case 'delete':
await fs.writeFile(change.path, change.backup!);
break;
}
}
this.changes = this.changes.slice(0, -count);
}
getSummary(): string {
const recent = this.changes.slice(-10);
return recent.map(c =>
`${c.timestamp}: ${c.type} ${c.path}`
).join('\n');
}
}10. 关键设计启示
10.1 设计原则
- 显式权限: 所有写操作都需要确认
- 沙箱隔离: 默认最小权限运行
- 持久记忆: 跨会话保持上下文
- 任务追踪: 复杂任务拆分为可追踪的步骤
- 可恢复: 所有变更可撤销
10.2 值得借鉴的模式
typescript
// 1. 分层权限
const permissionLevels = {
auto: ['read_file', 'list_dir', 'grep', 'search'],
confirm: ['write_file', 'edit_file', 'run_cmd'],
explicit: ['network', 'git_write', 'system']
};
// 2. 沙箱执行
async function sandboxedExecute(cmd, permissions) {
const sandbox = await createSandbox(permissions);
return sandbox.run(cmd);
}
// 3. 变更追踪
class UndoStack {
push(change) { this.changes.push(change); }
undo() {
const change = this.changes.pop();
return this.reverse(change);
}
}
// 4. 记忆检索
class Memory {
async recall(query) {
return this.store
.filter(m => this.matches(m, query))
.slice(0, 5);
}
}