目录
- [从现象出发:Claude Code 是什么?](#从现象出发:Claude Code 是什么? "#1-%E4%BB%8E%E7%8E%B0%E8%B1%A1%E5%87%BA%E5%8F%91claude-code-%E6%98%AF%E4%BB%80%E4%B9%88")
- 项目结构:模块化的插件仓库
- 整体架构:可扩展的能力注册系统
- 记忆系统:三层记忆架构
- 上下文管理:动态压缩与快照
- [通信协议:流式 API 与实时交互](#通信协议:流式 API 与实时交互 "#6-%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE%E6%B5%81%E5%BC%8F-api-%E4%B8%8E%E5%AE%9E%E6%97%B6%E4%BA%A4%E4%BA%92")
- [UI 层:Ink 驱动的终端渲染](#UI 层:Ink 驱动的终端渲染 "#7-ui-%E5%B1%82ink-%E9%A9%B1%E5%8A%A8%E7%9A%84%E7%BB%88%E7%AB%AF%E6%B8%B2%E6%9F%93")
- 核心模块一:Commands(命令系统)
- 核心模块二:Agents(智能代理)
- 核心模块三:Skills(技能系统)
- 核心模块四:Hooks(钩子与治理)
- [MCP 协议:连接外部世界](#MCP 协议:连接外部世界 "#12-mcp-%E5%8D%8F%E8%AE%AE%E8%BF%9E%E6%8E%A5%E5%A4%96%E9%83%A8%E4%B8%96%E7%95%8C")
- 工具系统:执行引擎
- [实战案例:Feature-Dev 插件剖析](#实战案例:Feature-Dev 插件剖析 "#14-%E5%AE%9E%E6%88%98%E6%A1%88%E4%BE%8Bfeature-dev-%E6%8F%92%E4%BB%B6%E5%89%96%E6%9E%90")
- [CLI 使用方式与最佳实践](#CLI 使用方式与最佳实践 "#15-cli-%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F%E4%B8%8E%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5")
- [总结:Markdown 驱动的 AI 应用新范式](#总结:Markdown 驱动的 AI 应用新范式 "#16-%E6%80%BB%E7%BB%93markdown-%E9%A9%B1%E5%8A%A8%E7%9A%84-ai-%E5%BA%94%E7%94%A8%E6%96%B0%E8%8C%83%E5%BC%8F")
- [三足鼎立:Claude Code vs Codex vs Gemini CLI](#三足鼎立:Claude Code vs Codex vs Gemini CLI "#17-%E4%B8%89%E8%B6%B3%E9%BC%8E%E7%AB%8Bclaude-code-vs-codex-vs-gemini-cli")
1. 从现象出发:Claude Code 是什么?
1.1 大白话解释
如果说传统的 AI 编程助手(如 GitHub Copilot)是一个"智能的代码补全工具",那么 Claude Code 就是一个住在你终端里的全职程序员。
它不仅能写代码,还能:
- 🔍 理解项目结构:自动分析代码库架构
- 🤖 自主执行任务:通过工具调用完成复杂操作(git commit、运行测试、创建 PR)
- 🧠 记住上下文:跨会话记住项目规范和待办事项
- 🔌 连接外部服务:通过 MCP 协议集成数据库、API 等外部资源
- 🛡️ 安全治理:通过 Hook 系统拦截危险操作
1.2 核心差异
| 特性 | GitHub Copilot | Claude Code |
|---|---|---|
| 交互模式 | 代码补全(被动) | 对话式 + 自主执行(主动) |
| 执行能力 | 无 | 可执行 Bash、读写文件、调用 API |
| 记忆系统 | 无状态 | 项目级配置(CLAUDE.md)+ 会话历史 |
| 可扩展性 | 固定功能 | 插件系统,用户可自定义 |
| 安全机制 | 无 | Hook 系统拦截 + 权限控制 |
1.3 应用场景
2. 项目结构:模块化的插件仓库
2.1 目录树与功能划分
通过逆向分析 claude-code 项目,我们发现这是一个插件仓库 而非核心引擎代码库。核心引擎是 Bun 编译的闭源 CLI 工具(源码可通过逆向提取到 extracted/src/),而这个仓库提供了 13+ 官方插件。核心引擎的源码包含 30+ 内置工具、插件加载器、Hook 执行引擎、MCP 客户端等完整实现。
perl
claude-code/
├── .claude/ # 根级别命令定义
│ └── commands/ # 全局 Slash 命令
│ ├── commit-push-pr.md # Git 工作流
│ ├── oncall-triage.md # Issue 分类
│ └── dedupe.md # 重复检测
├── .claude-plugin/ # 插件市场配置
│ └── marketplace.json # 13 个插件的注册清单
├── plugins/ # 插件目录(核心)
│ ├── feature-dev/ # 功能开发工作流
│ ├── code-review/ # 代码审查
│ ├── hookify/ # 用户自定义规则引擎
│ ├── security-guidance/ # 安全警告
│ ├── plugin-dev/ # 插件开发工具包
│ └── ... # 其他 8 个插件
├── examples/ # 示例配置
├── scripts/ # 自动化脚本
└── doc/ # 文档
2.2 插件类型分类
7阶段功能开发] PD[plugin-dev
插件脚手架] ASD[agent-sdk-dev
SDK项目生成] MIG[claude-opus-4-5-migration
模型迁移] end subgraph Productivity["⚡ 生产力插件 (3)"] CR[code-review
自动PR审查] PRT[pr-review-toolkit
6种专业审查] CC[commit-commands
Git提交工作流] end subgraph Learning["📚 学习增强插件 (2)"] EO[explanatory-output-style
教学模式] LO[learning-output-style
互动学习] end subgraph Security["🔐 安全治理插件 (2)"] HF[hookify
自定义行为规则] SG[security-guidance
安全模式拦截] end subgraph Design["🎨 设计辅助插件 (1)"] FE[frontend-design
UI/UX设计指导] end subgraph Other["🔮 其他插件 (1)"] RW[ralph-wiggum
自引用迭代] end Core["🎯 Claude Code 核心引擎
插件注册中心"] Core -.加载.-> DevTools Core -.加载.-> Productivity Core -.加载.-> Learning Core -.加载.-> Security Core -.加载.-> Design Core -.加载.-> Other
| 类别 | 插件名称 | 核心功能 |
|---|---|---|
| 开发工具 | feature-dev | 7 阶段功能开发工作流 |
| plugin-dev | 插件开发脚手架 | |
| agent-sdk-dev | Claude Agent SDK 项目生成 | |
| claude-opus-4-5-migration | 模型迁移工具 | |
| 生产力 | code-review | 自动化 PR 审查 |
| pr-review-toolkit | 6 种专业审查 Agent | |
| commit-commands | Git 提交工作流 | |
| 学习增强 | explanatory-output-style | 教学模式 |
| learning-output-style | 互动学习 | |
| 安全治理 | hookify | 用户自定义行为规则 |
| security-guidance | 安全模式拦截 | |
| 设计辅助 | frontend-design | UI/UX 设计指导 |
| 其他 | ralph-wiggum | 自引用迭代循环 |
3. 整体架构:可扩展的能力注册系统
3.1 架构分层
Claude Code 采用微内核 + 插件的架构模式。核心引擎负责:
- 🧠 LLM 交互(流式请求、上下文管理)
- 🔧 工具执行(Bash, Read, Write, Edit 等)
- 🔌 MCP 客户端(连接外部服务)
- 📦 插件加载器(动态发现和注册)
而业务逻辑全部由插件提供。
命令行交互"] VSCode["📝 VSCode 扩展
IDE 集成"] GitHub["🤖 GitHub Bot
CI/CD 自动化"] end subgraph Layer2["⚙️ 核心引擎层 - Core Engine Layer (闭源)"] direction TB subgraph Router_Group["🎯 请求路由模块"] Router["Intent Router
智能意图识别"] end subgraph Context_Group["🧠 上下文管理模块"] Context["Context Manager
记忆压缩·注入"] PluginLoader["Plugin Loader
动态插件发现"] end subgraph Execution_Group["⚡ 执行引擎模块"] ToolEngine["Tool Execution Engine
工具调用·沙箱隔离"] MCPClient["MCP Client
外部服务桥接"] end end subgraph Layer3["🧩 插件生态层 - Plugin Ecosystem Layer (开源)"] direction TB Registry["📋 Capability Registry
能力注册中心"] subgraph Plugin_Types["插件能力矩阵"] direction LR Commands["⚡ Commands
显式调用"] Agents["🤖 Agents
自主决策"] Skills["📚 Skills
隐式注入"] Hooks["🪝 Hooks
行为拦截"] end end subgraph Layer4["🌐 外部服务层 - External Services Layer"] direction LR LLM["🧠 Claude API
Sonnet 4.6/Opus 4.6/Haiku 4.5"] MCP["🔌 MCP Servers
GitHub·DB·FS"] OS["💾 Operating System
文件系统·Shell"] end %% 交互层到核心层 CLI ==>|stdin/stdout| Router VSCode ==>|MCP SDK Protocol| Router GitHub ==>|Webhooks| Router %% 核心层内部流转 Router -->|分发请求| Context Router -->|触发加载| PluginLoader Context -.实时同步.-> PluginLoader PluginLoader ==>|注册能力| Registry %% 插件层到执行引擎 Registry -->|路由| Plugin_Types Commands ==>|Tool Calls| ToolEngine Agents ==>|Tool Calls| ToolEngine Skills -.Prompt注入.-> Context Hooks -.拦截.-> ToolEngine %% 执行引擎到外部服务 Context ==>|API 请求| LLM ToolEngine ==>|MCP 协议| MCPClient ToolEngine ==>|系统调用| OS MCPClient ==>|stdio/SSE/HTTP| MCP
3.2 插件发现与加载流程
核心引擎通过约定优于配置 的方式自动发现插件。实际源码中并不存在独立的 "Capability Registry" 类或 "Intent Router" 类------插件的各组件(Commands、Agents、Skills、Hooks)分别由对应的加载器(loadPluginCommands、loadPluginAgents、loadSkillsDir、loadPluginHooks)加载后,通过 React hooks(useMergedCommands、useMergedTools)在 REPL 运行时合并到工具池和命令列表中:
3.3 核心数据结构
typescript
// 实际源码中的插件元数据结构(src/types/plugin.ts + src/utils/plugins/schemas.ts)
// 通过 Zod Schema 验证
interface PluginManifest {
name: string; // 插件名称
version?: string; // 版本号(可选)
description?: string; // 描述
author?: { // 作者信息
name: string;
email?: string;
};
mcpServers?: { // MCP 服务器配置
[serverName: string]: MCPServerConfig;
};
}
// 实际加载结果类型(src/types/plugin.ts)
interface LoadedPlugin {
name: string;
dir: string;
manifest: PluginManifest;
components: PluginComponent[]; // 包含 commands, agents, skills, hooks
source: {
type: 'marketplace' | 'session' | 'builtin';
marketplace?: string;
};
}
// ⚠️ 注意:源码中没有独立的 "CapabilityRegistry" 类
// 插件组件加载后分别存入不同系统:
// - Commands/Skills → 通过 useMergedCommands() 合并到命令列表
// - Agents → 通过 loadPluginAgents() 注册到 AgentDefinitionsResult
// - Hooks → 通过 loadPluginHooks() 注入到 getAllHooks() 结果
// - Tools → 通过 useMergedTools() + assembleToolPool() 合并到工具池
4. 记忆系统:三层记忆架构
4.1 大白话解释
Claude Code 的记忆就像人脑一样分层存储:
- 🧬 长期记忆(硬盘):用户全局偏好,永久保存
- 📚 中期记忆(项目文件):项目规范和待办事项,跨会话持久化
- 💭 短期记忆(RAM):当前对话历史,会话结束即清空
这种设计让 AI 既能记住你的编码习惯,又能适应每个项目的特殊规范。
4.2 三层记忆架构图
~/.claude/config.json
📌 用户偏好 · API配置 · 模型设置"] subgraph ProjectLevel["📁 项目级存储"] direction LR L2["📜 L2-A: Project Constitution
CLAUDE.md
🎯 代码规范 · 架构原则"] L2T["✅ L2-B: Todo List
.claude/todos.json
📋 任务队列 · 断点续传"] end end subgraph RAM["⚡ 运行时内存层 - Runtime Memory (RAM)"] direction TB L1["🧬 L1: System Prompt
核心身份定义
🛠️ 工具定义 · Skill SOP · 安全策略"] L0["💭 L0: Session History
对话上下文
💬 用户消息 · AI响应 · 工具调用结果"] end subgraph Pipeline["🔄 上下文处理流水线 - Context Pipeline"] direction TB subgraph Injection["📥 注入阶段"] Injector["Prompt Injector
多源上下文融合器"] end subgraph Compression["📦 压缩阶段"] Monitor["Token Monitor
Token 使用率监控
⚠️ 90%阈值触发"] Compressor["Context Compressor
智能压缩引擎
📸 Summary + Snapshot"] end end FinalContext["🎯 Final Context
最终上下文包
📤 发送给 Claude API"] %% 数据流 - 持久化层到注入器 L3 ==>|"① 用户偏好注入"| Injector L2 ==>|"② 项目规范注入"| Injector L2T ==>|"③ 待办事项注入"| Injector %% 数据流 - 运行时层 L1 ==>|"④ 系统提示词(基座)"| Injector L0 -->|"⑤ 实时监控"| Monitor %% 压缩流程 Monitor -.->|"超过90%"| Compressor Compressor ==>|"压缩结果"| L0 L0 ==>|"⑥ 历史对话"| Injector %% 最终输出 Injector ==>|"⑦ 组装完成"| FinalContext
4.3 记忆层级详解
L3: Global Memory(全局偏好)
存储位置:
~/.claude/CLAUDE.md:全局记忆文档(Markdown 格式,跨项目指令)~/.claude/settings.json:配置文件(JSON 格式,模型、权限规则等)
作用 :跨项目的通用配置和全局指令。CLAUDE.md 类似 Shell 的 .bashrc,而 settings.json 管理结构化配置。
json
// ~/.claude/settings.json 结构示例
{
"model": "claude-sonnet-4-6",
"permissions": {
"allow": ["Bash(git *)"],
"deny": []
},
"hooks": {
"PreToolUse": [...]
},
"plugins": {
"code-review@claude-code-marketplace": { "enabled": true }
}
}
markdown
<!-- ~/.claude/CLAUDE.md 示例 -->
# 全局偏好
- 使用中文回复
- 代码风格:简洁
- 提交信息遵循 Conventional Commits
生命周期 :永久存储。CLAUDE.md 通过 loadMemoryPrompt() 在每次 API 请求时注入 System Prompt;settings.json 通过 enableConfigs() 在启动时加载。
L2: Project Memory(项目规范)
存储位置:
CLAUDE.md:项目规范文档.claude/todos.json:待办事项队列
CLAUDE.md 示例:
markdown
# 项目规范:MyApp
## 代码风格
- TypeScript 严格模式
- 使用 Prettier + ESLint
- 组件命名:PascalCase
## 架构原则
- 每个组件单一职责
- 所有函数必须有类型定义
- 错误使用 Result 类型而非异常
## 禁止操作
- ❌ 不要使用 `any` 类型
- ❌ 不要直接修改 package.json
- ❌ 不要提交 .env 文件
## Git 规范
遵循 Conventional Commits:
- feat: 新功能
- fix: Bug 修复
- docs: 文档更新
todos.json 示例:
json
{
"version": 1,
"todos": [
{
"content": "实现用户登录功能",
"status": "in_progress",
"activeForm": "实现用户登录功能",
"createdAt": "2026-01-11T10:00:00Z"
},
{
"content": "编写单元测试",
"status": "pending",
"activeForm": "编写单元测试",
"createdAt": "2026-01-11T10:01:00Z"
}
]
}
作用:这是项目的"宪法",AI 必须遵守这些规则。每次会话启动时重新读取。
L1 & L0: Session Memory(会话记忆)
存储位置:内存中的消息数组
数据结构:
typescript
// 实际源码中的消息类型(src/types/message.ts)
// 注意:不使用简单的 role 字段,而是使用 discriminated union
type Message =
| UserMessage // 用户输入 + 工具结果
| AssistantMessage // LLM 响应(文本 + 工具调用)
| ProgressMessage // 工具执行进度(Hook进度等)
| AttachmentMessage // 附件(记忆注入、Hook结果)
| SystemMessage // 系统消息(本地命令输出等)
| ToolUseSummaryMessage // 工具使用摘要
| TombstoneMessage // 已删除消息占位
// AssistantMessage 的核心结构
interface AssistantMessage {
type: 'assistant';
uuid: string;
message: {
content: Array<TextBlock | ToolUseBlock>; // 可同时包含文本和工具调用
stop_reason: 'end_turn' | 'tool_use' | 'max_tokens';
};
costUsd: number;
durationMs: number;
}
// UserMessage 承载用户输入和工具结果
interface UserMessage {
type: 'user';
uuid: string;
message: {
content: Array<TextBlock | ToolResultBlock>;
};
}
生命周期 :仅在当前 CLI 进程存活。消息数组存储在 ToolUseContext.messages 中,一旦 Token 超限(90% 阈值),触发自动压缩机制(autoCompact)。
4.4 上下文组装逻辑
核心引擎在每次调用 Claude API 前,通过 getSystemPrompt() 和 query() 函数组装完整上下文:
typescript
// 实际源码逻辑(src/constants/prompts.ts + src/query.ts 精简)
async function getSystemPrompt(tools: Tools, model: string): Promise<SystemPrompt> {
const sections: SystemPromptSection[] = [];
// 1. 核心身份(模型名称、版本、能力说明)
sections.push(systemPromptSection('core_identity', getCoreIdentity(model)));
// 2. 工具定义(30+ 工具的 prompt 文本)
for (const tool of tools) {
sections.push(systemPromptSection(`tool_${tool.name}`, await tool.prompt(ctx)));
}
// 3. Skill 元数据(名称 + 描述,供 LLM 判断是否调用)
const skills = getSkillToolCommands(commands);
if (skills.length > 0) {
sections.push(systemPromptSection('skills', buildSkillSection(skills)));
}
// 4. 安全规则
sections.push(systemPromptSection('security', CYBER_RISK_INSTRUCTION));
// 5. 输出样式(如果安装了 output-style 插件)
const outputStyle = getOutputStyleConfig();
if (outputStyle) {
sections.push(systemPromptSection('output_style', outputStyle.instructions));
}
// 6. MCP 服务器指令
for (const client of mcpClients) {
if (client.instructions) {
sections.push(systemPromptSection(`mcp_${client.name}`, client.instructions));
}
}
return resolveSystemPromptSections(sections);
}
// CLAUDE.md 通过 loadMemoryPrompt() 在 query() 中作为 attachment 注入
// 不是作为 system message,而是通过 AttachmentMessage 机制
async function loadMemoryPrompt(): Promise<string | null> {
const parts: string[] = [];
// 1. ~/.claude/CLAUDE.md(全局)
// 2. ./CLAUDE.md(项目)
// 3. 向上遍历到 $HOME 的所有 CLAUDE.md
return parts.join('\n\n');
}
纠正 :原文描述将 CLAUDE.md 作为
<project_rules>标签注入 system message。实际源码中,CLAUDE.md 的内容通过loadMemoryPrompt()(位于src/memdir/memdir.ts)加载,并作为AttachmentMessage附加到消息列表中,由query()在normalizeMessagesForAPI()时合并。
4.5 核心洞察
Claude Code 的"记忆"是一种错觉
它并没有真正的数据库,而是通过每次请求前疯狂读取文件 并塞入 System Prompt,来模拟一个"记得项目背景"的 AI。这种 Stateless to Stateful 的转换技巧,是其架构的精髓。
优势:
- ✅ 简单:无需维护数据库
- ✅ 透明:记忆内容就是文件内容
- ✅ 可控:用户可直接编辑 CLAUDE.md
劣势:
- ⚠️ 每次启动都要重新读取
- ⚠️ 无法存储超大历史记录
- ⚠️ 依赖文件系统
5. 上下文管理:动态压缩与快照
5.1 为什么需要上下文压缩?
LLM 的 Context Window 是稀缺资源。Claude Sonnet 4.6 的默认上下文为 200K tokens(1M context 版本可扩展到 1M),看似很多,但在实际开发中:
diff
一次完整的功能开发对话可能消耗:
- System Prompt: 5K tokens
- CLAUDE.md: 2K tokens
- 代码文件读取: 20K tokens
- 工具调用结果: 10K tokens
- 对话历史: 每轮 2-5K tokens
假设 30 轮对话 = 5K + 2K + 20K + 10K + (30 × 3K) = 127K tokens
当超过 **90% 阈值(180K tokens)**时,必须压缩,否则下一轮对话会失败。
5.2 压缩策略流程图
保留关键信息和决策" LLM-->>Compressor: 5. 返回摘要(Summary) Compressor->>Compressor: 6. 生成环境快照(Snapshot)
- Git 状态
- 文件树
- 待办事项 Compressor->>Compressor: 7. 丢弃旧对话历史
保留最近 5 轮 Compressor->>Engine: 8. 重构 Context:
[Summary] + [Snapshot] + [Recent 5] Engine->>Monitor: 9. 重置 Token 计数器 Monitor-->>Engine: 继续对话 end
5.3 压缩器核心实现
typescript
// [伪代码] Context Compressor
class ContextCompressor {
private readonly THRESHOLD = 0.9; // 90% 阈值
private readonly CONTEXT_LIMIT = 200000; // 200K tokens
private readonly KEEP_RECENT = 5; // 保留最近 5 轮对话
// 检查是否需要压缩
async checkAndCompress(history: Message[]): Promise<Message[]> {
const currentTokens = this.estimateTokens(history);
if (currentTokens < this.CONTEXT_LIMIT * this.THRESHOLD) {
return history; // 无需压缩
}
console.log(`Token 使用达到 ${(currentTokens / this.CONTEXT_LIMIT * 100).toFixed(1)}%,触发压缩...`);
// 1. 生成对话摘要
const summary = await this.generateSummary(history);
// 2. 生成环境快照
const snapshot = await this.generateSnapshot();
// 3. 保留最近的对话
const recentMessages = history.slice(-this.KEEP_RECENT * 2); // 每轮包含 user + assistant
// 4. 重构上下文
return [
{
role: 'system',
content: `<conversation_summary>\n${summary}\n</conversation_summary>`
},
{
role: 'system',
content: `<environment_snapshot>\n${snapshot}\n</environment_snapshot>`
},
...recentMessages
];
}
// 生成对话摘要(调用 LLM)
private async generateSummary(history: Message[]): Promise<string> {
const summaryPrompt = `
请总结之前的对话内容,保留以下关键信息:
1. 用户的核心需求和目标
2. 已经完成的工作和决策
3. 遇到的问题和解决方案
4. 待完成的任务
保持简洁,突出重点。
<previous_conversation>
${this.formatHistoryForSummary(history)}
</previous_conversation>
`;
const response = await this.llm.chat([
{ role: 'user', content: summaryPrompt }
], {
model: 'haiku', // 使用 Haiku 降低成本
maxTokens: 2000
});
return response.content;
}
// 生成环境快照
private async generateSnapshot(): Promise<string> {
const parts: string[] = [];
// Git 状态
try {
const gitStatus = await exec('git status --short');
const gitBranch = await exec('git branch --show-current');
parts.push(`## Git 状态\n分支:${gitBranch}\n变更:\n${gitStatus}`);
} catch (e) {
// 非 Git 项目
}
// 文件树(简化)
try {
const tree = await exec('tree -L 2 -I "node_modules|.git"');
parts.push(`## 项目结构\n${tree}`);
} catch (e) {
// tree 命令不存在
}
// 待办事项
const todos = await loadTodos('.claude/todos.json');
if (todos.length > 0) {
const todoList = todos.map((t, i) =>
`${i + 1}. [${t.status}] ${t.content}`
).join('\n');
parts.push(`## 待办事项\n${todoList}`);
}
return parts.join('\n\n');
}
// 估算 Token 数量(简化版)
private estimateTokens(messages: Message[]): number {
let total = 0;
for (const msg of messages) {
const content = typeof msg.content === 'string'
? msg.content
: JSON.stringify(msg.content);
// 粗略估算:1 token ≈ 4 字符
total += Math.ceil(content.length / 4);
}
return total;
}
}
5.4 压缩前后对比
压缩前(180K tokens):
css
[System Prompt: 5K]
[CLAUDE.md: 2K]
[Todos: 1K]
[第1轮对话: 3K]
[第2轮对话: 4K]
...
[第30轮对话: 5K]
总计:~180K tokens
压缩后(40K tokens):
css
[System Prompt: 5K]
[CLAUDE.md: 2K]
[Todos: 1K]
[对话摘要: 2K] ← 替代前 25 轮对话
[环境快照: 3K] ← Git/文件树/待办
[第26轮对话: 3K] ← 保留最近 5 轮
[第27轮对话: 4K]
[第28轮对话: 3K]
[第29轮对话: 5K]
[第30轮对话: 5K]
总计:~40K tokens
压缩比:77.8%(节省 140K tokens)
5.5 用户触发的手动压缩
用户可以通过 /compact 命令手动触发压缩:
bash
# 感觉 AI 反应变慢或开始产生幻觉时
/compact
这会强制执行压缩流程,让 AI"清醒"过来。
6. 通信协议:流式 API 与实时交互
6.1 为什么使用流式 API?
传统的 Request-Response 模式会让用户等待很久才看到结果,而流式 API可以边生成边显示:
css
传统模式:
用户提问 → [等待 10 秒] → 完整回答一次性显示
流式模式:
用户提问 → [0.5秒] → "我" → [0.5秒] → "会" → [0.5秒] → "帮" → ...
6.2 通信流程图
stream=true loop 流式返回 API-->>CLI: 4. SSE chunk: text CLI->>UI: 5. 更新显示 UI-->>User: 实时渲染文本 API-->>CLI: 6. SSE chunk: tool_use CLI->>UI: 7. 显示 "正在执行工具..." CLI->>CLI: 8. 执行工具调用 CLI->>API: 9. 继续对话(附带结果) API-->>CLI: 10. SSE chunk: more text CLI->>UI: 11. 继续渲染 end API-->>CLI: 12. SSE: stop_reason=end_turn CLI->>UI: 13. 对话完成
6.3 流式 API 调用实现
typescript
// [伪代码] Streaming API Client
class ClaudeStreamClient {
async chat(
messages: Message[],
options: {
model?: string;
maxTokens?: number;
onChunk?: (chunk: StreamChunk) => void;
}
): Promise<string> {
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey,
'anthropic-version': '2023-06-01',
// 注意:CLI 不使用 anthropic-dangerous-direct-browser-access 头
},
body: JSON.stringify({
model: options.model || 'claude-sonnet-4-6-20250514',
max_tokens: options.maxTokens || 8192,
messages,
stream: true, // 关键:启用流式
tools: this.getToolDefinitions() // 工具定义
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let fullText = '';
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
// 解析 SSE 格式
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || ''; // 保留不完整的行
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.slice(6);
if (data === '[DONE]') continue;
try {
const chunk = JSON.parse(data);
// 处理不同类型的 chunk
switch (chunk.type) {
case 'content_block_start':
// 新的内容块开始
if (chunk.content_block.type === 'text') {
// 文本块
} else if (chunk.content_block.type === 'tool_use') {
// 工具调用块
options.onChunk?.({
type: 'tool_use_start',
toolName: chunk.content_block.name
});
}
break;
case 'content_block_delta':
// 内容增量更新
if (chunk.delta.type === 'text_delta') {
const text = chunk.delta.text;
fullText += text;
options.onChunk?.({
type: 'text',
text
});
}
break;
case 'content_block_stop':
// 内容块结束
break;
case 'message_stop':
// 消息结束
options.onChunk?.({
type: 'done',
stopReason: chunk.stop_reason
});
break;
}
} catch (e) {
console.error('Parse SSE error:', e);
}
}
}
}
return fullText;
}
}
6.4 SSE (Server-Sent Events) 协议
Claude API 使用 SSE 协议进行流式传输:
css
事件格式:
data: {"type": "content_block_start", ...}
data: {"type": "content_block_delta", "delta": {"type": "text_delta", "text": "Hello"}}
data: {"type": "content_block_delta", "delta": {"type": "text_delta", "text": " World"}}
data: {"type": "message_delta", "delta": {"stop_reason": "end_turn"}}
data: {"type": "message_stop"}
关键事件类型:
| 事件类型 | 说明 |
|---|---|
message_start |
消息开始 |
content_block_start |
内容块开始(文本或工具调用) |
content_block_delta |
内容增量更新 |
content_block_stop |
内容块结束 |
message_delta |
元数据更新(如 Token 使用) |
message_stop |
消息结束 |
6.5 错误处理与重试
typescript
class StreamErrorHandler {
async retryWithBackoff<T>(
fn: () => Promise<T>,
maxRetries: number = 3
): Promise<T> {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (i === maxRetries - 1) throw error;
// 指数退避
const delayMs = Math.pow(2, i) * 1000;
console.log(`请求失败,${delayMs}ms 后重试...`);
await sleep(delayMs);
}
}
throw new Error('Max retries exceeded');
}
handleStreamError(error: any): void {
if (error.status === 429) {
console.error('⚠️ API 速率限制,请稍后再试');
} else if (error.status === 500) {
console.error('⚠️ API 服务器错误,请稍后再试');
} else if (error.message.includes('overloaded')) {
console.error('⚠️ API 负载过高,请稍后再试');
} else {
console.error(`❌ 通信错误: ${error.message}`);
}
}
}
7. UI 层:Ink 驱动的终端渲染
7.1 为什么选择 Ink?
传统 CLI 工具使用 console.log() 线性打印,无法实现:
- ❌ 动态更新(如进度条、Spinner)
- ❌ 彩色输出和格式化
- ❌ 交互式选择(如多选菜单)
重要纠正 :Claude Code 并非直接使用
inknpm 包,而是基于react-reconciler自建了一套完整的终端渲染引擎(位于src/ink/目录,包含 40+ 个文件)。它借鉴了 Ink 的设计理念,但包含自定义的 Yoga 布局引擎(src/ink/layout/)、ANSI 渲染器、滚动容器、超链接支持等。用 JSX 编写 CLI 界面的概念相同:
tsx
// 传统方式
console.log('Loading...');
// 无法更新这行文本
// Ink 方式
<Text color="cyan">
<Spinner /> Loading...
</Text>
// 可以实时更新 Spinner 动画
7.2 Ink 架构原理
Box, Text, ScrollBox] VirtualDOM[Virtual DOM] end subgraph "Custom Ink Engine (src/ink/)" Reconciler[react-reconciler
自定义 Reconciler] Layout[Yoga Layout Engine
src/ink/layout/] Renderer[render-node-to-output.ts
渲染到缓冲区] end subgraph "Terminal Layer" ANSI[ANSI Escape Codes
chalk + 自定义 colorize.ts] Stdout[stdout] end JSX -->|"渲染"| VirtualDOM VirtualDOM -->|"Diff 计算"| Reconciler Reconciler -->|"布局计算"| Layout Layout -->|"生成渲染指令"| Renderer Renderer -->|"转换为"| ANSI ANSI -->|"render-to-screen.ts"| Stdout style Reconciler fill:#61dafb style Layout fill:#4caf50
7.3 核心 UI 组件
tsx
// [伪代码] Claude Code 的主 UI 组件
// 注意:Box、Text 等组件来自 src/ink/components/,不是 npm 的 ink 包
import { Box, Text } from '../ink/components';
import { Spinner } from '../components/Spinner';
import { useState, useEffect } from 'react';
function ClaudeCodeUI() {
const [messages, setMessages] = useState<Message[]>([]);
const [isThinking, setIsThinking] = useState(false);
const [toolStatus, setToolStatus] = useState<string | null>(null);
return (
<Box flexDirection="column">
{/* 对话历史 */}
{messages.map((msg, i) => (
<Message key={i} message={msg} />
))}
{/* 工具执行状态 */}
{toolStatus && (
<Box marginTop={1}>
<Text color="cyan">
<Spinner type="dots" /> {toolStatus}
</Text>
</Box>
)}
{/* AI 思考状态 */}
{isThinking && (
<Box marginTop={1}>
<Text color="yellow">
<Spinner type="simpleDotsScrolling" /> Claude 正在思考...
</Text>
</Box>
)}
</Box>
);
}
// 消息组件
function Message({ message }: { message: Message }) {
if (message.role === 'user') {
return (
<Box marginTop={1}>
<Text bold color="green">You: </Text>
<Text>{message.content}</Text>
</Box>
);
} else if (message.role === 'assistant') {
return (
<Box marginTop={1}>
<Text bold color="blue">Claude: </Text>
<MarkdownText>{message.content}</MarkdownText>
</Box>
);
}
return null;
}
// Markdown 渲染组件
function MarkdownText({ children }: { children: string }) {
// 简化版:实际会解析 Markdown 并应用样式
const lines = children.split('\n');
return (
<>
{lines.map((line, i) => {
// 代码块
if (line.startsWith('```')) {
return <Text key={i} color="gray" backgroundColor="black">{line}</Text>;
}
// 标题
if (line.startsWith('#')) {
return <Text key={i} bold>{line}</Text>;
}
// 普通文本
return <Text key={i}>{line}</Text>;
})}
</>
);
}
7.4 乐观更新(Optimistic UI)
Claude Code 使用乐观更新策略,在工具实际执行前就显示"正在执行"状态:
tsx
// [伪代码] 工具调用的乐观更新
function ToolCallHandler() {
const [toolCalls, setToolCalls] = useState<ToolCall[]>([]);
// 当 LLM 返回 tool_use 时立即更新 UI
useEffect(() => {
claudeAPI.on('tool_use_start', (toolCall) => {
// 立即显示"正在执行"
setToolCalls(prev => [...prev, {
...toolCall,
status: 'pending'
}]);
// 异步执行工具
executeToolAsync(toolCall).then(result => {
// 完成后更新状态
setToolCalls(prev => prev.map(tc =>
tc.id === toolCall.id
? { ...tc, status: 'completed', result }
: tc
));
});
});
}, []);
return (
<Box flexDirection="column">
{toolCalls.map(tc => (
<Box key={tc.id} marginTop={1}>
{tc.status === 'pending' && (
<Text color="cyan">
<Spinner /> 执行中: {tc.name}
</Text>
)}
{tc.status === 'completed' && (
<Text color="green">
✓ 完成: {tc.name}
</Text>
)}
</Box>
))}
</Box>
);
}
7.5 实时性能优化
Ink 使用 React Fiber 架构,可以优先渲染重要的更新:
tsx
// 高优先级:用户输入反馈
<Text color="green">{userInput}</Text>
// 中优先级:工具执行状态
<Spinner /> Executing git status...
// 低优先级:日志输出
<Text dimColor>{debugLog}</Text>
7.6 ANSI 颜色与样式
Ink 底层使用 ANSI Escape Codes 实现终端样式:
typescript
// ANSI 颜色代码
const ANSI = {
RESET: '\x1b[0m',
BOLD: '\x1b[1m',
RED: '\x1b[31m',
GREEN: '\x1b[32m',
YELLOW: '\x1b[33m',
BLUE: '\x1b[34m',
CYAN: '\x1b[36m',
};
// 示例输出
console.log(`${ANSI.BOLD}${ANSI.GREEN}✓ Success${ANSI.RESET}`);
// 显示为:粗体绿色的 "✓ Success"
Ink 封装了这些复杂的转义码,提供声明式的 API:
tsx
<Text bold color="green">✓ Success</Text>
8. 核心模块一:Commands(命令系统)
8.1 什么是 Command?
重要说明 :在 v2.1.88 的源码中,
commands/目录已被标记为commands_DEPRECATED(见src/skills/loadSkillsDir.ts),新的推荐方式是使用skills/目录。两者的 Frontmatter 格式相同,但 Skills 提供了更丰富的元数据(whenToUse、model、version等)。为保持文档的历史连贯性,本章仍以 Command 术语描述。
Command(现称 Skill) 是用户通过 Slash 命令 (如 /commit、/review)直接调用的预定义 Prompt。它类似于 ChatGPT 的"自定义指令",但更强大:
- ✅ 可以预授权工具权限(无需每次确认)
- ✅ 支持参数传递(
/feature-dev 实现登录功能) - ✅ 可以调用其他 Agent
- ✅ 支持
$ARGUMENTS和索引参数$0,$1等变量替换
8.2 Command 文件格式
所有 Command 都是 Markdown + YAML Frontmatter 格式:
markdown
---
description: 创建 Git 提交并推送到远程分支
argument-hint: 可选的提交信息
allowed-tools: [Bash(*), Read, TodoWrite]
---
# Commit Push PR 工作流
你是一个 Git 工作流专家。用户想要提交代码并创建 PR。
## 执行步骤
1. 运行 `git status` 查看变更文件
2. 运行 `git diff` 查看具体改动
3. 根据改动生成符合 Conventional Commits 规范的提交信息
4. 执行 `git add .` 和 `git commit -m "..."`
5. 推送到远程:`git push`
6. 使用 `gh pr create` 创建 Pull Request
## 注意事项
- 提交信息必须包含 `Co-Authored-By:` 行(模型名称根据实际使用的模型动态生成,见 `src/utils/commitAttribution.ts`)
- 不要提交 `.env`、`credentials.json` 等敏感文件
8.3 Command 调用流程
8.4 核心代码逆向还原
typescript
// [伪代码] Command 解析器
class CommandParser {
// 解析 Markdown 文件
parse(filePath: string): CommandDefinition {
const content = fs.readFileSync(filePath, 'utf-8');
const { attributes, body } = parseFrontmatter(content);
return {
name: path.basename(filePath, '.md'),
description: attributes.description,
argumentHint: attributes['argument-hint'],
allowedTools: attributes['allowed-tools'] || [],
prompt: body, // Markdown 正文作为 Prompt
};
}
// 生成最终 System Prompt
buildSystemPrompt(command: CommandDefinition, userArgs: string): string {
// 替换 $ARGUMENTS 变量
let prompt = command.prompt.replace(/\$ARGUMENTS/g, userArgs);
// 添加工具权限说明
if (command.allowedTools.length > 0) {
prompt += `\n\n## 可用工具\n${command.allowedTools.join(', ')}`;
}
return prompt;
}
}
// 调用示例
const parser = new CommandParser();
const commitCommand = parser.parse('plugins/commit-commands/commands/commit.md');
const systemPrompt = parser.buildSystemPrompt(commitCommand, '修复登录bug');
// 发送到 LLM...
9. 核心模块二:Agents(智能代理)
9.1 什么是 Agent?
Agent 是一个自主执行的 AI 实体,拥有独立的:
- 🎯 目标(Goal)
- 🧰 工具集(Tools)
- 🎨 人格(Model + Color)
- 🔒 隔离上下文(不污染主对话)
Agent 与 Command/Skill 的区别:
| 特性 | Command/Skill | Agent |
|---|---|---|
| 触发方式 | 用户 /command 调用或 LLM 调用 SkillTool |
LLM 调用 AgentTool 派生 |
| 执行模式 | 在主上下文运行 | 在隔离的子上下文运行 |
| 工具权限 | 需要在 frontmatter 声明 | 同样需要声明 |
| 返回结果 | 对话式输出 | 返回结果摘要到主上下文 |
| 并行能力 | 无 | 支持多 Agent 并行(同一消息多个 AgentTool 调用) |
| 实际工具名 | SkillTool | AgentTool (src/tools/AgentTool/) |
9.2 Agent 文件格式
markdown
---
name: code-explorer
description: 深度分析现有代码库功能,追踪执行路径和架构层次
tools: [Glob, Grep, Read, TodoWrite, WebFetch]
model: sonnet
color: yellow
---
你是一个代码分析专家,专注于追踪和理解功能实现。
## 核心任务
提供完整的功能理解,从入口点到数据存储,贯穿所有抽象层。
## 分析方法
**1. 功能发现**
- 找到入口点(API、UI 组件、CLI 命令)
- 定位核心实现文件
- 绘制功能边界和配置
**2. 代码流程追踪**
- 跟随调用链从输入到输出
- 追踪每一步的数据转换
- 识别所有依赖和集成
**3. 架构分析**
- 绘制抽象层(展示层 → 业务逻辑 → 数据层)
- 识别设计模式和架构决策
- 记录组件间的接口
## 输出要求
提供包含以下内容的全面分析:
- 入口点(文件:行号)
- 逐步执行流程和数据转换
- 关键组件及其职责
- 架构洞察:模式、分层、设计决策
- **必须包含:最关键的 5-10 个文件列表**
9.3 Agent 派生与调度
src/tools/AgentTool/] AgentTool -->|"createSubagentContext()"| SubContext1[Sub-Agent 1
code-explorer] AgentTool -->|"createSubagentContext()"| SubContext2[Sub-Agent 2
code-architect] AgentTool -->|"createSubagentContext()"| SubContext3[Sub-Agent 3
code-reviewer] SubContext1 -->|"独立执行"| Result1[分析报告 1] SubContext2 -->|"独立执行"| Result2[设计方案 2] SubContext3 -->|"独立执行"| Result3[审查报告 3] Result1 --> Merge[合并结果] Result2 --> Merge Result3 --> Merge Merge -->|"返回主上下文"| MainContext style TaskTool fill:#4ecdc4 style Merge fill:#ffd93d
9.4 核心代码:Agent 调度器
typescript
// [伪代码] Agent 调度器
class AgentScheduler {
// 派生子 Agent
async spawnAgent(
agentName: string,
task: string,
options: {
fork?: boolean, // 是否隔离上下文
model?: 'sonnet' | 'opus' | 'haiku',
maxTurns?: number, // 最大对话轮数
}
): Promise<AgentResult> {
// 1. 从注册表加载 Agent 定义
const agentDef = this.registry.getAgent(agentName);
if (!agentDef) throw new Error(`Agent not found: ${agentName}`);
// 2. 构建子上下文
const subContext = options.fork
? this.createIsolatedContext() // 隔离上下文(不继承主对话)
: this.cloneContext(); // 克隆上下文(继承历史)
// 3. 注入 Agent 的 System Prompt
subContext.addSystemMessage(agentDef.prompt);
subContext.addUserMessage(task);
// 4. 设置工具权限
subContext.setAllowedTools(agentDef.tools);
// 5. 执行 Agent Loop(类似主循环)
let turns = 0;
while (turns < (options.maxTurns || 20)) {
// 注意:实际源码中 temperature 固定为 1(API 要求开启思考时必须为 1)
const response = await this.llm.chat(subContext, {
model: options.model || agentDef.model || 'sonnet',
temperature: 1,
});
// 如果完成任务,返回结果
if (response.stopReason === 'end_turn') {
return {
agentName,
transcript: subContext.messages,
summary: response.content,
};
}
// 执行工具调用
if (response.toolCalls) {
const results = await this.toolEngine.execute(response.toolCalls);
subContext.addToolResults(results);
}
turns++;
}
// 超时返回
return { agentName, error: 'Max turns exceeded' };
}
// 并行执行多个 Agent
async spawnParallel(tasks: Array<{agent: string, task: string}>): Promise<AgentResult[]> {
return Promise.all(
tasks.map(t => this.spawnAgent(t.agent, t.task, { fork: true }))
);
}
}
9.5 实际应用:Feature-Dev 的 7 阶段工作流
feature-dev 插件通过多 Agent 协作实现复杂的功能开发流程:
理解需求] Phase1 --> Phase2[Phase 2: Codebase Exploration
派生 3 个 code-explorer Agents] Phase2 --> ReadFiles[读取 Agents 推荐的关键文件] ReadFiles --> Phase3[Phase 3: Clarifying Questions
询问未明确的细节] Phase3 --> Phase4[Phase 4: Architecture Design
派生 3 个 code-architect Agents] Phase4 --> UserApproval{用户批准方案?} UserApproval -->|否| Phase4 UserApproval -->|是| Phase5[Phase 5: Implementation
编写代码] Phase5 --> Phase6[Phase 6: Quality Review
派生 3 个 code-reviewer Agents] Phase6 --> FixIssues{需要修复?} FixIssues -->|是| Phase5 FixIssues -->|否| Phase7[Phase 7: Summary
总结完成] style Phase2 fill:#ffcccb style Phase4 fill:#add8e6 style Phase6 fill:#90ee90
10. 核心模块三:Skills(技能系统)
10.1 什么是 Skill?
Skill 是一种可被 LLM 自主调用的 SOP(标准操作流程) 。Skill 的元数据(name、description)始终在 System Prompt 中,LLM 根据用户意图判断是否通过 SkillTool 调用某个 Skill。
重要纠正:原文描述 Skill 是"通过触发短语自动激活"的隐式注入。实际源码中,Skill 的触发方式有两种:
- LLM 主动调用 :Skill 元数据列在 System Prompt 中,LLM 判断相关时调用 SkillTool(
src/tools/SkillTool/)- 用户显式调用 :用户输入
/skill-name直接调用并不存在基于关键词的自动匹配引擎。
类比:
- 旧版 Command = 用户
/commit显式调用 - Skill = LLM 看到元数据后自主决策是否调用(半隐式);也可由用户
/skill-name显式调用
10.2 Skill 文件格式
markdown
---
name: Frontend Design
description: 当用户提到 "design", "UI", "frontend", "用户界面" 时触发。提供高质量前端实现指导。
version: 0.1.0
---
# 前端设计技能
## 触发场景
当检测到以下关键词时自动激活:
- "设计登录页面"
- "优化 UI 性能"
- "实现响应式布局"
## 设计原则
### 1. 组件化思维
- 单一职责原则
- Props 接口清晰
- 避免 Prop Drilling
### 2. 性能优化
- 使用 React.memo 避免不必要渲染
- 代码分割(React.lazy + Suspense)
- 图片懒加载
### 3. 可访问性(a11y)
- 语义化 HTML
- ARIA 标签
- 键盘导航支持
## 代码规范
```tsx
// ✅ 好的实践
function LoginButton({ onClick, disabled, children }: ButtonProps) {
return (
<button
onClick={onClick}
disabled={disabled}
aria-label="登录"
className="btn btn-primary"
>
{children}
</button>
);
}
// ❌ 避免的做法
function Button(props) { // 缺少类型定义
return <div onClick={props.click}>click me</div>; // 非语义化标签
}
审查清单
- 组件是否可复用?
- 是否有 TypeScript 类型定义?
- 是否处理了加载和错误状态?
- 是否支持深色模式?
- 是否通过了 a11y 测试?
less
### 10.3 Skill 渐进式加载
Skill 采用**三层加载策略**,平衡 Token 消耗与知识可用性:
```mermaid
graph BT
subgraph Level3["Level 3: References (磁盘)"]
Refs["详细文档<br/>代码示例<br/>API 参考"]
note3["超高 Token 成本<br/>仅在需要时 Read"]
end
subgraph Level2["Level 2: SOP Body (上下文)"]
Body["设计原则<br/>代码规范<br/>审查清单"]
note2["中等 Token 成本<br/>触发时注入"]
end
subgraph Level1["Level 1: Metadata (内存)"]
Meta["Name<br/>Description<br/>触发短语"]
note1["极低 Token 成本<br/>常驻内存"]
end
Meta -->|"关键词命中"| Body
Body -->|"需要细节"| Refs
style Meta fill:#90ee90
style Body fill:#add8e6
style Refs fill:#ffcccb
10.4 Skill 注入逻辑
typescript
// 实际源码逻辑(src/skills/loadSkillsDir.ts + src/tools/SkillTool/)
// 1. 启动时:加载所有 Skill 的 frontmatter 元数据
async function loadSkillsFromDir(dir: string): Promise<Command[]> {
const skillDirs = await readdir(dir);
const skills: Command[] = [];
for (const skillName of skillDirs) {
const skillPath = join(dir, skillName, 'SKILL.md');
if (!await pathExists(skillPath)) continue;
const content = await readFile(skillPath, 'utf-8');
const { attributes, body } = parseFrontmatter(content);
skills.push({
type: 'prompt',
name: attributes.name || skillName,
description: coerceDescriptionToString(attributes.description),
// 完整内容懒加载 --- 调用时才读取 body
getContent: () => body,
allowedTools: parseSlashCommandToolsFromFrontmatter(attributes),
model: parseUserSpecifiedModel(attributes.model),
});
}
return skills;
}
// 2. System Prompt 中列出所有 Skill 元数据,供 LLM 决策
// (在 src/constants/prompts.ts 的 getSystemPrompt 中)
// 3. LLM 决定调用时 → SkillTool.call() 读取完整内容
// ⚠️ 注意:没有关键词匹配引擎,是 LLM 自主决策
// 实际的 Skill 调用流程:
// 用户: "帮我设计一个登录页面"
// LLM 看到 System Prompt 中有: "- Frontend Design: 提供高质量前端实现指导"
// LLM 决定调用: SkillTool({ skill: "Frontend Design", args: "登录页面" })
// SkillTool.call() → 读取 SKILL.md 完整内容 → 替换 $ARGUMENTS
// → 返回 Skill SOP 作为用户消息注入后续对话
// LLM 后续回答遵循 Skill 中的设计原则
10.5 Skill vs Command vs Agent:三大能力对比
核心区别 :这三者代表了 Claude Code 中不同的知识传递模式。
路由引擎"] end subgraph Capabilities["🧩 能力执行层"] direction LR subgraph CommandFlow["⚡ Command 流程
显式调用"] C1["用户输入:
/feature-dev 登录功能"] C2["🎯 精确匹配命令"] C3["📋 执行固定流程
7阶段 SOP"] C4["✅ 完成任务"] C1 --> C2 --> C3 --> C4 end subgraph SkillFlow["📚 Skill 流程
隐式注入"] S1["用户输入:
设计登录页面"] S2["🔎 关键词匹配
design/UI/frontend"] S3["💉 注入 Skill SOP
前端设计最佳实践"] S4["🧠 AI自主执行
遵循设计原则"] S1 --> S2 --> S3 --> S4 end subgraph AgentFlow["🤖 Agent 流程
自主决策"] A1["Command调用:
/feature-dev"] A2["🚀 启动 Agent
code-explorer"] A3["🔄 自主规划
搜索→分析→总结"] A4["📊 返回报告"] A1 --> A2 --> A3 --> A4 end end Intent --> Router Router -.检测Command.-> CommandFlow Router -.检测关键词.-> SkillFlow Router -.调用Agent.-> AgentFlow
对比表格
| 维度 | 🎯 Skill (用户调用型) | 📚 Skill (LLM 调用型) | 🤖 Agent |
|---|---|---|---|
| 触发方式 | /skill-name 用户显式调用 |
LLM 通过 SkillTool 自主调用 | LLM 通过 AgentTool 调用 |
| 执行主体 | 主线程 Core Engine | 主线程 Core Engine | 独立子上下文 AI 实例 |
| Token 成本 | 中等(SOP注入) | 低(元数据常驻 + 按需加载正文) | 高(独立上下文) |
| 适用场景 | 固定流程任务 | 通用质量保证、知识注入 | 复杂自主任务 |
| 用户感知 | ✅ 明确知道调用 | ⚠️ 半感知(会显示 Skill 工具调用) | ✅ 明确知道调用 |
| 工具权限 | allowed-tools 预定义 |
allowed-tools 预定义(可选) |
tools 预定义 |
| 典型例子 | /commit 提交代码 |
前端设计最佳实践 | code-explorer 分析 |
纠正 :原文将 Command 和 Skill 描述为完全不同的概念。实际源码中,Command 已被 Skill 统一(
commands_DEPRECATED)。Skill 本质上就是更强大的 Command,支持用户显式调用和 LLM 隐式调用两种模式。
10.6 Skill 完整生命周期
(内存) participant FS as 💾 File System participant LLM as 🧠 Claude API Note over Engine,Index: ═══ Phase 1: 启动时索引构建 ═══ Engine->>+Router: 初始化 Skill 系统 Router->>+FS: 扫描 plugins/*/skills/*/SKILL.md FS-->>-Router: 返回所有 Skill 文件路径 loop 每个 Skill 文件 Router->>+FS: 读取 SKILL.md 的 frontmatter FS-->>-Router: 返回 { name, description } Router->>Router: 从 description 提取触发短语 Router->>Index: 存储到内存索引 end Router-->>-Engine: Skill 索引构建完成 Note over User,LLM: ═══ Phase 2: 运行时触发与注入 ═══ User->>+Engine: 输入:帮我设计一个登录界面 Engine->>+Router: 检测触发的 Skills Router->>Index: 遍历所有 Skill metadata Index-->>Router: 匹配到: frontend-design
(关键词: 设计, 界面) Router->>+FS: 读取 frontend-design/SKILL.md 完整内容 FS-->>-Router: 返回 SOP 内容 Router->>Engine: 返回触发的 Skill 列表 Engine->>Engine: 将 Skill SOP 注入 System Prompt Note over Engine: System Prompt 组成:
① Core System Prompt
② 用户偏好 (L3)
③ 项目规范 (L2)
④ Skill SOP (frontend-design) Engine->>+LLM: 发送请求 (携带注入后的上下文) LLM-->>-Engine: AI响应(遵循 Skill 中的设计原则) Engine-->>-User: 输出高质量前端代码 Note over User,LLM: ═══ Phase 3: Skill 持续生效 ═══ User->>+Engine: 后续消息: 加一个密码强度提示 Note over Engine: Skill SOP 仍在上下文中
无需重新注入 Engine->>+LLM: 发送请求 LLM-->>-Engine: 继续遵循前端设计原则 Engine-->>-User: 输出符合 a11y 标准的实现
10.7 Skill 设计哲学:渐进式披露
Claude Code 的 Skill 系统采用**渐进式披露(Progressive Disclosure)**设计模式,这是一个经典的 UX 设计原则,应用在了 AI 系统中。
🎯 核心理念
按需加载,恰到好处
不要一次性把所有知识塞给 AI,而是:
- Level 1(元数据):启动时加载,极低成本,用于快速匹配
- Level 2(SOP 主体):触发时注入,中等成本,提供核心知识
- Level 3(详细文档):需要时 Read,高成本,提供深度参考
📊 Token 成本对比
假设某个 Skill 的完整知识库包含:
- Metadata: 100 tokens(name, description, triggers)
- SOP Body: 2000 tokens(设计原则、代码规范)
- References: 10000 tokens(详细 API 文档、示例代码)
传统方式(全量加载):
- 启动时加载所有 10 个 Skill =
10 × (100 + 2000 + 10000) = 121,000 tokens - 每次对话都携带这些 tokens
- 即使用户根本不需要某些 Skill
渐进式方式(Claude Code 实现):
- 启动时加载元数据 =
10 × 100 = 1,000 tokens - 触发 1 个 Skill 时注入 SOP =
1 × 2000 = 2,000 tokens - 需要详细文档时再 Read =
0-10,000 tokens(按需)
节省比例 :(121,000 - 3,000) / 121,000 ≈ 97.5% 🎉
10.8 实战案例:Skill 如何改变 AI 行为
场景:用户要求实现一个前端表单
❌ 无 Skill 加持的输出
tsx
// 用户输入:帮我实现一个登录表单
function LoginForm() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = () => {
// 直接发送请求,没有验证
fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ username, password })
});
};
return (
<div>
<input value={username} onChange={e => setUsername(e.target.value)} />
<input value={password} onChange={e => setPassword(e.target.value)} />
<button onClick={handleSubmit}>登录</button>
</div>
);
}
问题:
- ❌ 没有类型定义
- ❌ input 缺少 label(不符合 a11y)
- ❌ 密码框没有设置 type="password"
- ❌ 没有错误处理
- ❌ 没有加载状态
- ❌ 非语义化标签(应该用 form)
✅ 有 Skill 加持的输出 (自动触发 frontend-design Skill)
tsx
// 用户输入:帮我实现一个登录表单
// [Skill Injected: frontend-design]
interface LoginFormProps {
onSuccess?: () => void;
onError?: (error: Error) => void;
}
interface FormData {
username: string;
password: string;
}
interface FormErrors {
username?: string;
password?: string;
}
function LoginForm({ onSuccess, onError }: LoginFormProps) {
const [formData, setFormData] = useState<FormData>({
username: '',
password: ''
});
const [errors, setErrors] = useState<FormErrors>({});
const [isLoading, setIsLoading] = useState(false);
const validateForm = (): boolean => {
const newErrors: FormErrors = {};
if (!formData.username.trim()) {
newErrors.username = '请输入用户名';
}
if (formData.password.length < 6) {
newErrors.password = '密码至少6位';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!validateForm()) return;
setIsLoading(true);
try {
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
});
if (!response.ok) throw new Error('登录失败');
onSuccess?.();
} catch (error) {
const err = error as Error;
onError?.(err);
} finally {
setIsLoading(false);
}
};
return (
<form onSubmit={handleSubmit} aria-label="登录表单">
<div className="form-group">
<label htmlFor="username">
用户名
<span className="required" aria-label="必填">*</span>
</label>
<input
id="username"
type="text"
value={formData.username}
onChange={e => setFormData({ ...formData, username: e.target.value })}
aria-invalid={!!errors.username}
aria-describedby={errors.username ? "username-error" : undefined}
disabled={isLoading}
/>
{errors.username && (
<span id="username-error" role="alert" className="error">
{errors.username}
</span>
)}
</div>
<div className="form-group">
<label htmlFor="password">
密码
<span className="required" aria-label="必填">*</span>
</label>
<input
id="password"
type="password"
value={formData.password}
onChange={e => setFormData({ ...formData, password: e.target.value })}
aria-invalid={!!errors.password}
aria-describedby={errors.password ? "password-error" : undefined}
disabled={isLoading}
/>
{errors.password && (
<span id="password-error" role="alert" className="error">
{errors.password}
</span>
)}
</div>
<button
type="submit"
disabled={isLoading}
aria-busy={isLoading}
>
{isLoading ? '登录中...' : '登录'}
</button>
</form>
);
}
export default LoginForm;
改进点:
- ✅ 完整的 TypeScript 类型定义
- ✅ 表单验证(前端验证)
- ✅ 错误处理和状态管理
- ✅ 加载状态(防止重复提交)
- ✅ 完整的 ARIA 标签(a11y)
- ✅ 语义化 HTML(form, label)
- ✅ Props 接口设计(回调函数)
- ✅ 错误提示与用户体验
可视化对比
缺少最佳实践"] style W3 fill:#dc2626,stroke:#fca5a5,color:#fff end subgraph With["✅ 有 Skill"] S1["用户输入"] --> S2["AI 基础知识"] S2 --> S3["+ Skill SOP"] S3 --> S4["高质量输出
遵循最佳实践"] style S3 fill:#7c3aed,stroke:#c4b5fd,color:#fff style S4 fill:#16a34a,stroke:#86efac,color:#fff end
10.9 Skill 的核心价值
Skill 系统解决了 AI 辅助编程中的一个根本性问题:
如何让 AI 在不明确指示的情况下,自动遵循项目最佳实践?
传统方案:
- ❌ 每次都在 prompt 中重复:"请使用 TypeScript,注意 a11y,处理错误..."
- ❌ 依赖 AI 的"通用知识",质量不稳定
- ❌ 无法针对特定项目定制规范
Skill 方案:
- ✅ 一次定义,自动应用
- ✅ 团队统一标准,质量可预测
- ✅ 针对项目特点定制 SOP
- ✅ 新成员无需培训,AI 自动遵循
类比 :Skill 就像团队里的高级工程师在旁边 Code Review,在你写代码时自动提醒最佳实践,而不需要你每次都问。
11. 核心模块四:Hooks(钩子与治理)
11.1 什么是 Hook?
Hook 是一个拦截器系统,在关键时刻介入 AI 的执行流程:
- 🛡️ 安全防护 :阻止危险命令(如
rm -rf /) - 📊 审计日志:记录所有工具调用
- 🎯 行为定制:根据项目规则修改 AI 行为
- ⚠️ 警告提示:在敏感操作前提醒用户
11.2 Hook 类型与事件
工具执行前] E2[PostToolUse
工具执行后] E2b[PostToolUseFailure
工具执行失败后] E3[UserPromptSubmit
用户输入提交前] E4[Stop
对话结束前] E4b[StopFailure
结束检查失败] E5[SessionStart
会话开始] E6[SessionEnd
会话结束] E7a[SubagentStart
子 Agent 启动] E7b[SubagentStop
子 Agent 结束] E8[PreCompact
上下文压缩前] E8b[PostCompact
上下文压缩后] E9[Notification
通知事件] E10[PermissionRequest
权限请求] E11[PermissionDenied
权限拒绝] end E1 -.->|"可以阻止"| Decision1{允许执行?} E2 -.->|"可以修改"| Decision2{修改结果?} E3 -.->|"可以修改"| Decision3{修改输入?} E4 -.->|"可以阻止"| Decision4{允许退出?} style E1 fill:#ff6b6b style E2 fill:#4ecdc4 style E3 fill:#ffe66d style E4 fill:#a8dadc
源码出处 :完整的 Hook 事件列表定义在
src/entrypoints/sdk/coreTypes.ts的HOOK_EVENTS常量中。
11.3 Hook 配置格式
实际支持四种 Hook 类型 (command、prompt、agent、http),以及 if 条件匹配:
json
{
"description": "Security Guidance Hook - 拦截危险操作",
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/security_reminder_hook.py",
"timeout": 10
}
],
"matcher": "Edit|Write|MultiEdit"
},
{
"hooks": [
{
"type": "prompt",
"prompt": "检查这个 Bash 命令是否安全:$ARGUMENTS",
"if": "Bash(rm *)"
}
],
"matcher": "Bash"
},
{
"hooks": [
{
"type": "agent",
"prompt": "验证此代码变更不会引入安全漏洞",
"timeout": 30
}
],
"matcher": "Edit|Write"
},
{
"hooks": [
{
"type": "http",
"url": "https://security-api.example.com/check",
"timeout": 15
}
]
}
],
"PostToolUse": [
{
"hooks": [
{
"type": "command",
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/posttooluse.py",
"timeout": 10
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/stop.py",
"timeout": 10
}
]
}
]
}
}
四种 Hook 类型说明 (源码:
src/utils/hooks/hooksSettings.ts):
command:启动子进程执行脚本,通过 stdin 传入 JSON,退出码 0=放行、2=阻止prompt:将 prompt 文本直接注入当前对话作为系统消息agent:启动子 Agent(使用 Haiku 模型),通过 SyntheticOutputTool 返回{ok, reason}结构化结果http:发送 HTTP 请求到指定 URL,请求体为工具调用信息的 JSON
python
### 11.4 实战案例:Security Guidance Hook
这是一个真实的安全拦截器,检测 XSS、命令注入等漏洞:
```python
#!/usr/bin/env python3
"""
Security Reminder Hook for Claude Code
检查文件编辑中的安全模式并发出警告
"""
import json
import sys
from datetime import datetime
# 安全模式配置
SECURITY_PATTERNS = [
{
"ruleName": "github_actions_workflow",
"path_check": lambda path: ".github/workflows/" in path
and (path.endswith(".yml") or path.endswith(".yaml")),
"reminder": """⚠️ 你正在编辑 GitHub Actions 工作流。注意以下安全风险:
1. **命令注入**:不要直接使用 ${{ github.event.issue.title }}
2. **使用环境变量**:通过 env: 传递用户输入
3. **参考指南**:https://github.blog/security/...
❌ 不安全模式:
run: echo "${{ github.event.issue.title }}"
✅ 安全模式:
env:
TITLE: ${{ github.event.issue.title }}
run: echo "$TITLE"
"""
},
{
"ruleName": "eval_injection",
"substrings": ["eval("],
"reminder": "⚠️ eval() 会执行任意代码,存在重大安全风险。考虑使用 JSON.parse() 或其他安全方案。"
},
{
"ruleName": "react_dangerously_set_html",
"substrings": ["dangerouslySetInnerHTML"],
"reminder": "⚠️ dangerouslySetInnerHTML 可能导致 XSS 漏洞。确保内容经过 DOMPurify 等库的清理。"
},
{
"ruleName": "innerHTML_xss",
"substrings": [".innerHTML =", ".innerHTML="],
"reminder": "⚠️ 直接设置 innerHTML 可能导致 XSS。对于纯文本使用 textContent,HTML 使用 DOMPurify。"
}
]
def check_patterns(file_path: str, content: str):
"""检查文件路径或内容是否匹配安全模式"""
normalized_path = file_path.lstrip("/")
for pattern in SECURITY_PATTERNS:
# 检查路径模式
if "path_check" in pattern and pattern["path_check"](normalized_path):
return pattern["ruleName"], pattern["reminder"]
# 检查内容模式
if "substrings" in pattern and content:
for substring in pattern["substrings"]:
if substring in content:
return pattern["ruleName"], pattern["reminder"]
return None, None
def main():
# 读取 Hook 输入(JSON 格式)
try:
input_data = json.loads(sys.stdin.read())
except json.JSONDecodeError:
sys.exit(0) # 解析失败,放行
tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
# 只检查文件编辑工具
if tool_name not in ["Edit", "Write", "MultiEdit"]:
sys.exit(0)
# 提取文件路径和内容
file_path = tool_input.get("file_path", "")
content = tool_input.get("content") or tool_input.get("new_string", "")
# 检查安全模式
rule_name, reminder = check_patterns(file_path, content)
if rule_name and reminder:
# 输出警告到 stderr
print(reminder, file=sys.stderr)
# 退出码 2 = 阻止执行
sys.exit(2)
# 放行
sys.exit(0)
if __name__ == "__main__":
main()
11.5 Hookify:用户自定义规则引擎
hookify 插件提供了一个可视化的规则编辑器,让用户无需写代码就能定义拦截规则:
yaml
# .hookify.rules.md (用户配置文件)
## 规则 1:禁止删除 node_modules
- **名称**:prevent-delete-node-modules
- **启用**:是
- **事件**:bash
- **条件**:
- 字段:command
- 操作符:regex_match
- 模式:`rm.*node_modules`
- **动作**:block
- **消息**:🚫 不要删除 node_modules!请使用 npm clean-install 重新安装。
## 规则 2:Git 提交前提醒
- **名称**:commit-reminder
- **启用**:是
- **事件**:bash
- **条件**:
- 字段:command
- 操作符:contains
- 模式:`git commit`
- **动作**:warn
- **消息**:⚠️ 提交前确认:是否已运行测试?是否更新了文档?
Hookify 架构:
Markdown 配置] -->|"解析"| Loader[Config Loader
YAML to Python] Loader --> Rules[Rule Objects
数据结构] Input[Hook 输入
JSON] --> Engine[Rule Engine
规则引擎] Rules --> Engine Engine --> Matcher{匹配规则?} Matcher -->|"否"| Allow[允许执行] Matcher -->|"是"| Action{动作类型?} Action -->|"block"| Block[阻止 + 显示消息] Action -->|"warn"| Warn[警告 + 继续执行] style Config fill:#ffe66d style Engine fill:#4ecdc4 style Block fill:#ff6b6b style Warn fill:#ffa500
12. MCP 协议:连接外部世界
12.1 什么是 MCP?
MCP (Model Context Protocol) 是 Anthropic 推出的标准化的 AI-服务连接协议。它类似于:
- 🔌 USB 协议:统一的接口标准
- 🌐 GraphQL:声明式的能力描述
- 🐳 Docker:封装复杂服务为简单工具
通过 MCP,Claude Code 可以连接:
- 🗄️ 数据库(PostgreSQL, MongoDB)
- 📁 文件系统(本地、S3、Google Drive)
- 🐙 GitHub API(Issues, PRs, Code Search)
- 📊 Asana, Notion(项目管理)
- 🔍 搜索引擎(Google, Brave Search)
12.2 MCP 服务器类型
本地进程] T2[SSE
服务器推送] T3[HTTP
REST API] T4[WebSocket
双向实时] end subgraph "Use Cases" U1[本地工具
文件系统, Git] U2[云服务
GitHub, Asana] U3[API 后端
自定义服务] U4[实时数据
股票行情] end T1 --> U1 T2 --> U2 T3 --> U3 T4 --> U4
12.3 MCP 配置示例
方式 1:独立 .mcp.json 文件
json
{
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"],
"env": {
"LOG_LEVEL": "info"
}
},
"github": {
"type": "sse",
"url": "https://mcp.github.com/sse"
},
"database": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/db-server",
"args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"],
"env": {
"DB_URL": "${DATABASE_URL}"
}
}
}
方式 2:内嵌在 plugin.json
json
{
"name": "my-plugin",
"version": "1.0.0",
"mcpServers": {
"api-service": {
"type": "http",
"url": "https://api.example.com/mcp",
"headers": {
"Authorization": "Bearer ${API_TOKEN}"
}
}
}
}
12.4 MCP 工具命名规范
MCP 提供的工具会自动加上前缀:
markdown
mcp__plugin_<插件名>_<服务器名>__<工具名>
示例:
- mcp__plugin_asana_asana__asana_create_task
- mcp__plugin_github_github__github_search_issues
- mcp__plugin_db_database__execute_query
在 Command 中使用:
markdown
---
description: 创建 Asana 任务
allowed-tools: [
"mcp__plugin_asana_asana__asana_create_task",
"mcp__plugin_asana_asana__asana_search_tasks"
]
---
# 任务管理
使用 Asana API 创建和管理任务。
步骤:
1. 询问用户任务标题和描述
2. 调用 mcp__plugin_asana_asana__asana_create_task
3. 确认创建成功
12.5 MCP 生命周期
13. 工具系统:执行引擎
13.1 内置工具清单
Claude Code 提供了 30+ 内置工具 (源码 src/tools/ 目录下每个子目录对应一个工具),覆盖常见开发场景:
| 类别 | 工具名称 | 源码位置 | 功能描述 |
|---|---|---|---|
| 文件操作 | Read | FileReadTool/ | 读取文件内容(支持行号范围、PDF、图片) |
| Write | FileWriteTool/ | 创建或覆盖文件 | |
| Edit | FileEditTool/ | 精确字符串替换编辑 | |
| NotebookEdit | NotebookEditTool/ | 编辑 Jupyter Notebook | |
| Glob | GlobTool/ | 文件模式匹配查找 | |
| Grep | GrepTool/ | 正则搜索文件内容(基于 ripgrep) | |
| Shell 操作 | Bash | BashTool/ | 执行 Shell 命令(支持后台、超时、沙箱) |
| PowerShell | PowerShellTool/ | Windows PowerShell 执行 | |
| 代理管理 | Agent | AgentTool/ | 派生子 Agent(隔离上下文) |
| SendMessage | SendMessageTool/ | 向已有 Agent 发送消息 | |
| TaskCreate | TaskCreateTool/ | 创建后台任务 | |
| TaskGet | TaskGetTool/ | 获取任务状态 | |
| TaskList | TaskListTool/ | 列出所有任务 | |
| TaskOutput | TaskOutputTool/ | 获取任务输出 | |
| TaskStop | TaskStopTool/ | 停止任务 | |
| TaskUpdate | TaskUpdateTool/ | 更新任务 | |
| TodoWrite | TodoWriteTool/ | 管理待办事项列表 | |
| 模式切换 | EnterPlanMode | EnterPlanModeTool/ | 进入计划模式(只读) |
| ExitPlanMode | ExitPlanModeTool/ | 退出计划模式 | |
| EnterWorktree | EnterWorktreeTool/ | 进入 Git Worktree 隔离环境 | |
| ExitWorktree | ExitWorktreeTool/ | 退出 Worktree | |
| 用户交互 | AskUserQuestion | AskUserQuestionTool/ | 询问用户选择 |
| Skill | SkillTool/ | 调用 Skill | |
| ToolSearch | ToolSearchTool/ | 搜索延迟加载的工具定义 | |
| 网络请求 | WebFetch | WebFetchTool/ | 获取网页内容 |
| WebSearch | WebSearchTool/ | 执行网络搜索 | |
| 定时调度 | RemoteTrigger | RemoteTriggerTool/ | 远程触发代理 |
| ScheduleCron | ScheduleCronTool/ | 创建定时任务 | |
| MCP 工具 | mcp__* | MCPTool/ | MCP 服务器提供的动态工具 |
| 实验性 | Sleep | SleepTool/ | 等待指定时间 |
| REPL | REPLTool/ | 交互式代码执行 |
纠正:原文列出 "MultiEdit"、"KillShell"、"Task" 等工具名,这些在实际源码中不存在。正确名称分别是 Edit(支持 replace_all)、TaskStop、Agent。
13.2 工具执行流程
连续只读工具 → 并行批次
写入工具 → 串行批次 loop 遍历每个批次 alt 只读批次(Read, Grep 等) par 并行执行 Router->>Hooks: 3a. PreToolUse Hook Hooks-->>Router: 放行 Router->>Executor: 4a. Read 执行 Router->>Executor: 4b. Grep 执行 end else 写入批次(Bash, Edit 等) Router->>Hooks: 3b. PreToolUse Hook alt Hook 阻止 Hooks-->>LLM: 拦截并返回错误消息 else Hook 放行 Router->>Executor: 4c. 串行执行 alt 内置工具 Executor->>OS: 5a. 调用系统 API OS-->>Executor: 返回结果 else MCP 工具 Executor->>MCP: 5b. JSON-RPC 调用 MCP Server MCP-->>Executor: 返回结果 end end end Executor->>Hooks: 6. PostToolUse Hook(可修改结果) Executor-->>Router: 7. 返回工具结果 end Router-->>LLM: 8. 汇总所有结果,继续对话循环
13.3 工具权限控制
每个 Command 和 Agent 都必须声明允许使用的工具:
markdown
---
# 明确列出工具
allowed-tools: [Read, Glob, Grep, TodoWrite]
# 使用通配符 --- 允许所有参数的 Bash 调用
allowed-tools: [Bash(*), Edit, Write]
# 使用参数匹配 --- 仅允许 git 开头的 Bash 命令
allowed-tools: ["Bash(git *)"]
# 允许特定 MCP 工具
allowed-tools: [
"mcp__plugin_github_github__github_search_code",
"mcp__plugin_github_github__github_create_issue"
]
---
补充 :
allowed-tools中的通配符语法Bash(git *)由src/tools/BashTool/bashPermissions.ts中的matchWildcardPattern函数实现,支持 glob 风格匹配。
权限检查逻辑:
typescript
// [伪代码] 工具权限检查器
class ToolPermissionChecker {
// 检查工具调用是否被允许
isAllowed(toolName: string, allowedTools: string[]): boolean {
// 1. 精确匹配
if (allowedTools.includes(toolName)) {
return true;
}
// 2. 通配符匹配(如 "Bash(*)" 允许所有 Bash 调用)
for (const pattern of allowedTools) {
if (pattern.endsWith('(*)')) {
const baseTool = pattern.replace('(*)', '');
if (toolName === baseTool) {
return true;
}
}
// 3. MCP 工具通配符(如 "mcp__plugin_x_y__*")
if (pattern.endsWith('*')) {
const prefix = pattern.slice(0, -1);
if (toolName.startsWith(prefix)) {
return true;
}
}
}
return false;
}
// 拦截未授权的工具调用
async checkAndExecute(toolCall: ToolCall, context: Context): Promise<ToolResult> {
const allowedTools = context.getAllowedTools();
if (!this.isAllowed(toolCall.name, allowedTools)) {
return {
error: `工具 ${toolCall.name} 未被授权。允许的工具:${allowedTools.join(', ')}`
};
}
// 执行工具
return await this.toolExecutor.execute(toolCall);
}
}
14. 实战案例:Feature-Dev 插件剖析
14.1 插件文件结构
bash
plugins/feature-dev/
├── .claude-plugin/
│ └── plugin.json # 插件元数据
├── commands/
│ └── feature-dev.md # /feature-dev 命令
├── agents/
│ ├── code-explorer.md # 代码探索 Agent
│ ├── code-architect.md # 架构设计 Agent
│ └── code-reviewer.md # 代码审查 Agent
└── README.md # 使用文档
14.2 命令定义(feature-dev.md 节选)
markdown
---
description: 引导式功能开发,包含代码库理解和架构聚焦
argument-hint: 可选的功能描述
---
# Feature Development
你正在帮助开发者实现新功能。遵循系统化方法:深入理解代码库,识别并询问所有未明确的细节,设计优雅的架构,然后实现。
## 核心原则
- **提出澄清性问题**:识别所有歧义、边界情况和未明确的行为。提出具体、实际的问题而非假设。在实现前等待用户回答。在理解代码库后、设计架构前尽早提问。
- **先理解再行动**:首先阅读和理解现有代码模式
- **阅读 Agent 识别的文件**:启动 Agent 时,要求它们返回最重要文件的列表。Agent 完成后,阅读这些文件以建立详细上下文再继续。
- **简单优雅**:优先考虑可读性、可维护性、架构合理性
- **使用 TodoWrite**:全程跟踪所有进度
---
## Phase 1: Discovery
**目标**:理解需要构建什么
初始请求:$ARGUMENTS
**行动**:
1. 创建包含所有阶段的待办列表
2. 如果功能不清楚,询问用户:
- 他们要解决什么问题?
- 功能应该做什么?
- 有哪些约束或需求?
3. 总结理解并与用户确认
---
## Phase 2: Codebase Exploration
**目标**:在高层和低层理解相关的现有代码和模式
**行动**:
1. 并行启动 2-3 个 code-explorer Agent。每个 Agent 应该:
- 全面追踪代码,专注于全面理解抽象、架构和控制流
- 针对代码库的不同方面(如类似功能、高层理解、架构理解、用户体验等)
- 包含 5-10 个关键文件的列表
**Agent Prompt 示例**:
- "找到类似 [功能] 的特性并全面追踪其实现"
- "绘制 [功能区域] 的架构和抽象,全面追踪代码"
- "分析 [现有功能/区域] 的当前实现,全面追踪代码"
- "识别与 [功能] 相关的 UI 模式、测试方法或扩展点"
2. Agent 返回后,请阅读 Agent 识别的所有文件以建立深入理解
3. 展示全面的发现总结和发现的模式
---
## Phase 3: Clarifying Questions
**目标**:在设计前填补空白并解决所有歧义
**关键**:这是最重要的阶段之一。不要跳过。
**行动**:
1. 审查代码库发现和原始功能请求
2. 识别未明确的方面:边界情况、错误处理、集成点、范围边界、设计偏好、向后兼容性、性能需求
3. **以清晰、有组织的列表向用户展示所有问题**
4. **在进入架构设计前等待答案**
如果用户说"你认为最好的方式",提供你的建议并获得明确确认。
---
## Phase 4: Architecture Design
**目标**:设计具有不同权衡的多种实现方法
**行动**:
1. 并行启动 2-3 个 code-architect Agent,具有不同的关注点:最小变更(最小改动,最大复用)、清晰架构(可维护性,优雅抽象)或务实平衡(速度 + 质量)
2. 审查所有方法并形成你对哪个最适合此特定任务的看法(考虑:小修复 vs 大功能,紧急性,复杂性,团队背景)
3. 向用户展示:每种方法的简要总结、权衡比较、**你的建议及理由**、具体实现差异
4. **询问用户更喜欢哪种方法**
---
## Phase 5: Implementation
**目标**:构建功能
**未获用户批准不要开始**
**行动**:
1. 等待明确的用户批准
2. 阅读前面阶段识别的所有相关文件
3. 按照选定的架构实现
4. 严格遵循代码库约定
5. 编写清晰、文档良好的代码
6. 在进展时更新待办事项
---
## Phase 6: Quality Review
**目标**:确保代码简单、DRY、优雅、易读且功能正确
**行动**:
1. 并行启动 3 个 code-reviewer Agent,具有不同关注点:简单性/DRY/优雅、错误/功能正确性、项目约定/抽象
2. 整合发现并识别你建议修复的最高严重性问题
3. **向用户展示发现并询问他们想做什么**(现在修复、稍后修复或按原样继续)
4. 根据用户决定解决问题
---
## Phase 7: Summary
**目标**:记录完成的工作
**行动**:
1. 标记所有待办事项完成
2. 总结:
- 构建了什么
- 做出的关键决策
- 修改的文件
- 建议的后续步骤
14.3 Agent 定义示例(code-explorer.md)
markdown
---
name: code-explorer
description: 通过追踪执行路径、绘制架构层、理解模式和抽象、记录依赖关系来深度分析现有代码库功能
tools: [Glob, Grep, Read, TodoWrite, WebFetch]
model: sonnet
color: yellow
---
你是一个代码分析专家,专注于追踪和理解功能实现。
## 核心任务
从入口点到数据存储,贯穿所有抽象层,提供功能的完整理解。
## 分析方法
**1. 功能发现**
- 找到入口点(API、UI 组件、CLI 命令)
- 定位核心实现文件
- 绘制功能边界和配置
**2. 代码流程追踪**
- 跟随从输入到输出的调用链
- 追踪每一步的数据转换
- 识别所有依赖和集成
- 记录状态变化和副作用
**3. 架构分析**
- 绘制抽象层(展示 → 业务逻辑 → 数据)
- 识别设计模式和架构决策
- 记录组件间的接口
- 注意横切关注点(认证、日志、缓存)
**4. 实现细节**
- 关键算法和数据结构
- 错误处理和边界情况
- 性能考虑
- 技术债务或改进领域
## 输出指导
提供全面的分析,帮助开发者深入理解功能,足以修改或扩展它。包括:
- 带文件:行号引用的入口点
- 带数据转换的逐步执行流程
- 关键组件及其职责
- 架构洞察:模式、分层、设计决策
- 依赖关系(外部和内部)
- 关于优势、问题或机会的观察
- **你认为绝对必要的文件列表,以理解所讨论的主题**
以最大的清晰度和实用性组织你的响应。始终包含具体的文件路径和行号。
14.4 工作流演示
- 密码加密方式?
- Token 存储位置?
- 支持第三方登录吗? User->>Main: 回答问题 Main->>Main: Phase 4: 设计架构 par 并行设计 Main->>Architect: "最小变更方案" Main->>Architect: "清晰架构方案" Main->>Architect: "务实平衡方案" end Architect-->>Main: 返回 3 种设计方案 Main->>User: 展示方案 + 推荐 User->>Main: 批准"务实平衡方案" Main->>Main: Phase 5: 实现功能
(编写代码) Main->>Main: Phase 6: 质量审查 par 并行审查 Main->>Reviewer: "检查简单性/DRY" Main->>Reviewer: "检查功能正确性" Main->>Reviewer: "检查项目约定" end Reviewer-->>Main: 返回审查报告 Main->>User: 展示问题列表 User->>Main: 修复高优先级问题 Main->>Main: Phase 7: 总结完成 Main-->>User: ✅ 功能完成
15. CLI 使用方式与最佳实践
15.1 核心命令清单
| 命令 | 功能 | 使用场景 |
|---|---|---|
claude |
启动交互式会话 | 日常开发对话 |
claude "快速任务" |
单次执行 | CI/CD 脚本、自动化 |
claude --debug |
调试模式 | 排查插件问题、查看 MCP 连接 |
/help |
查看帮助 | 了解可用命令 |
/init |
初始化项目 | 首次使用,生成 CLAUDE.md |
/commit |
智能提交 | 自动生成提交信息 |
/review |
代码审查 | 提交前质量检查 |
/compact |
压缩上下文 | 感觉 AI 反应慢时 |
/clear |
清空会话 | 切换任务时 |
/cost |
查看成本 | 监控 Token 消耗 |
/mcp |
查看 MCP 服务器 | 调试外部服务连接 |
15.2 项目配置:CLAUDE.md
这是 Claude Code 的"项目宪法",定义 AI 的行为准则:
markdown
# 项目规范:MyApp
## 代码风格
- **语言**:TypeScript(严格模式)
- **格式化**:Prettier + ESLint
- **命名**:
- 组件:PascalCase (`UserProfile.tsx`)
- 函数:camelCase (`getUserById`)
- 常量:UPPER_SNAKE_CASE (`MAX_RETRY_COUNT`)
## 架构原则
- **组件化**:每个组件单一职责
- **类型安全**:所有函数必须有类型定义
- **错误处理**:使用 Result 类型而非异常
- **测试**:核心逻辑覆盖率 > 80%
## 禁止操作
- ❌ 不要使用 `any` 类型
- ❌ 不要直接修改 `package.json`(使用 npm install)
- ❌ 不要提交 `.env` 文件
## Git 规范
遵循 Conventional Commits:
feat: 新功能 fix: Bug 修复 docs: 文档更新 refactor: 重构 test: 测试 chore: 构建/工具变更
bash
## 测试命令
```bash
npm test # 运行所有测试
npm run test:watch # 监视模式
npm run test:e2e # E2E 测试
部署流程
- 运行
npm run build - 确保所有测试通过
- 创建 PR 到
main分支 - 等待 CI 通过
- 合并后自动部署到 staging
ini
### 15.3 最佳实践
#### 1. 使用 TodoWrite 跟踪任务
```markdown
# 用户
实现用户注册功能
# Claude
我会使用 TodoWrite 来跟踪这个任务:
1. [pending] 设计数据库 schema
2. [pending] 实现 API 端点
3. [pending] 编写单元测试
4. [pending] 添加前端表单
5. [pending] 集成验证码
现在开始第一步...
2. 善用 Plan Mode(Shift+Tab)
Plan Mode 会禁用所有写操作,只允许读取和分析。适合:
- 🔍 探索不熟悉的代码库
- 📋 制定实现计划
- 🤔 架构设计讨论
3. 自定义 Hookify 规则
yaml
# .hookify.rules.md
## 规则:生产环境保护
- **启用**:是
- **事件**:bash
- **条件**:
- 字段:command
- 操作符:regex_match
- 模式:`kubectl.*delete|helm.*uninstall`
- **动作**:block
- **消息**:🚫 生产环境操作已被阻止!请联系 DevOps 团队。
## 规则:大文件警告
- **启用**:是
- **事件**:file
- **条件**:
- 字段:file_path
- 操作符:regex_match
- 模式:`\.png$|\.jpg$|\.mp4$`
- **动作**:warn
- **消息**:⚠️ 你正在提交二进制文件。考虑使用 Git LFS 或 CDN。
16. 总结:Markdown 驱动的 AI 应用新范式
16.1 核心设计哲学
Claude Code 的插件生态系统证明了一个重要理念:
用 Markdown 定义能力,用 LLM 执行逻辑,用 Hook 保障安全。
这种范式的优势:
| 传统代码 | Claude Code 插件 |
|---|---|
| 用 Python/JS 编写逻辑 | 用 Markdown 描述意图 |
| 硬编码的 if-else | LLM 动态推理 |
| 需要编译/部署 | 热加载(无需重启) |
| 学习曲线陡峭 | 接近自然语言 |
| 难以维护 | 易于修改和理解 |
16.2 技术架构精髓
插件生态)) 分层设计 微内核 插件扩展 能力注册 声明式能力 Commands Agents Skills 治理机制 Hooks 权限控制 安全拦截 外部连接 MCP 协议 stdio/SSE/HTTP 多服务集成 开发者体验 Markdown 驱动 热加载 调试友好
16.3 适用场景与限制
适用场景:
- ✅ 自动化开发工作流(commit, review, PR)
- ✅ 代码库探索和文档生成
- ✅ 定制化开发助手(企业内部规范)
- ✅ 连接外部服务(数据库、API、CI/CD)
当前限制:
- ⚠️ 核心引擎闭源(无法深度定制)
- ⚠️ 依赖网络(需要 Claude API)
- ⚠️ Token 成本(大型项目可能昂贵)
- ⚠️ Hook 调试较困难(需要 --debug 模式)
16.4 未来展望
基于当前架构,我们可以预见:
- 更多官方插件:数据库管理、DevOps、测试生成
- 插件市场:类似 VS Code Extensions
- 本地模型支持:降低成本,提高隐私
- 可视化编辑器:拖拽式创建 Command/Agent
- 企业版:SSO、审计日志、合规性控制
附录:快速参考
A. 文件格式速查
Command 格式:
markdown
---
description: 描述
argument-hint: 参数提示
allowed-tools: [工具列表]
---
# Prompt 内容
$ARGUMENTS 会被替换为用户输入
Agent 格式:
markdown
---
name: agent-name
description: 描述
tools: [工具列表]
model: sonnet|opus|haiku
color: yellow|blue|green
---
# Agent 指令
详细的执行逻辑...
Skill 格式(新版统一格式,替代旧版 Command):
markdown
---
name: Skill Name
description: 功能描述(LLM 根据此判断何时调用)
version: 1.0.0
model: sonnet # 可选:指定模型
allowed-tools: [Read, Glob, Grep] # 可选:预授权工具
argument-hint: 可选的参数提示 # 可选
---
# SOP 内容
标准操作流程...
$ARGUMENTS 会被替换为用户输入
也支持索引参数:$0, $1, $ARGUMENTS[0]
Hook 格式:
json
{
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "python3 script.py",
"timeout": 10
}
],
"matcher": "Edit|Write"
}
]
}
}
B. 环境变量
${CLAUDE_PLUGIN_ROOT}- 插件根目录(必须使用)${API_KEY}- 自定义 API 密钥${DATABASE_URL}- 数据库连接字符串ENABLE_SECURITY_REMINDER- 启用/禁用安全提示(0/1)
C. 调试技巧
bash
# 启用调试日志
claude --debug
# 查看 MCP 服务器状态
/mcp
# 查看插件列表
/help
# 强制压缩上下文
/compact
# 查看 Token 使用
/cost
# 清空会话重新开始
/clear
D. Bun 适配层(源码运行必备)
Claude Code 核心引擎使用 Bun 编译,依赖 bun:bundle 和 bun:ffi 两个 Bun-only 模块。通过 extracted/ 中的 shim 层可在 Node.js 下运行:
less
extracted/
├── loader.mjs # ESM Loader Hook --- 拦截 bun:bundle/bun:ffi 导入
├── shims/
│ ├── register.ts # 入口:注册 MACRO 全局常量
│ ├── macro.ts # MACRO.VERSION 等构建时常量
│ ├── bun-bundle.ts # feature() 函数 shim --- 所有特性开关默认 false
│ └── bun-ffi.ts # FFI 桩 --- dlopen/ptr 空实现
└── stubs/ # Anthropic 内部包的空壳 (@ant/*, @anthropic-ai/mcpb)
feature() 函数 是核心适配点 --- Bun 编译期将 feature('FLAG') 替换为字面量实现 Dead Code Elimination(DCE),Node 运行时通过 shim 返回 false:
typescript
// shims/bun-bundle.ts
const FEATURE_FLAGS: Record<string, boolean> = {};
export function feature(flag: string): boolean {
return FEATURE_FLAGS[flag] ?? false; // 默认全部关闭
}
E. 源码校正勘误表
| 原文内容 | 纠正 | 依据源码位置 |
|---|---|---|
| "Sonnet 4.5/Opus 4.5" | 当前版本为 Sonnet 4.6/Opus 4.6 | src/constants/prompts.ts:118-123 |
| "CapabilityRegistry 类" | 不存在该类,组件分散合并 | src/hooks/useMergedTools.ts |
| "Intent Router" | 不存在该模块 | 直接由 processUserInput() 处理 |
| "Skill 通过关键词自动激活" | LLM 通过 SkillTool 自主调用 | src/tools/SkillTool/ |
| "commands/ 目录" | 已标记为 commands_DEPRECATED |
src/skills/loadSkillsDir.ts:68 |
| "MultiEdit 工具" | 不存在,Edit 支持 replace_all | src/tools/FileEditTool/ |
| "KillShell 工具" | 不存在,使用 TaskStop | src/tools/TaskStopTool/ |
| "Task 工具" | 实际名为 Agent (AgentTool) | src/tools/AgentTool/ |
| "使用 ink npm 包" | 自建 Ink 引擎 (40+ 文件) | src/ink/ |
| "temperature: 0.7" | 固定为 1(思考模式要求) | src/services/api/claude.ts:1693 |
| "config.json 存偏好" | 全局偏好在 ~/.claude/CLAUDE.md |
src/memdir/memdir.ts |
| Hook 事件仅 9 种 | 实际 15 种(含 PermissionDenied 等) | src/entrypoints/sdk/coreTypes.ts |
| Hook 仅 command 类型 | 支持 command/prompt/agent/http 四种 | src/utils/hooks/hooksSettings.ts |
17. 三足鼎立:Claude Code vs Codex vs Gemini CLI
基于 Claude Code v2.1.88、OpenAI Codex(开源版)、Gemini CLI v0.21.0 的源码对比分析。
17.1 基础画像
| 维度 | Claude Code | OpenAI Codex | Gemini CLI |
|---|---|---|---|
| 开发商 | Anthropic | OpenAI | |
| 核心语言 | TypeScript (Bun 编译) | Rust + TypeScript | TypeScript |
| 运行时 | Bun(发布)/ Node(兼容) | Rust 原生二进制 | Node.js 20+ |
| UI 框架 | 自建 Ink 引擎 (react-reconciler) | Rust TUI (ratatui) | Ink (npm 包) |
| 代码规模 | ~800 文件,闭源核心 + 开源插件 | 45+ Rust 模块,完全开源 | ~200 文件,完全开源 |
| 后端模型 | Claude Sonnet/Opus 4.6 | GPT-4 系列 | Gemini 2.5 Pro/Flash |
| 许可证 | 核心闭源,插件 MIT | Apache 2.0 | Apache 2.0 |
17.2 架构哲学对比
三者看似功能相同,但架构哲学截然不同:
objectivec
Claude Code: Markdown 驱动 + 微内核插件
"用文档定义能力,让 LLM 执行逻辑"
Codex: Rust 系统级 + 沙箱隔离优先
"安全第一,性能极致,系统级隔离"
Gemini CLI: TypeScript 全栈 + 最简设计
"清晰分层,标准 React 模式,易于理解"
Claude Code --- 微内核 + 插件生态
scss
┌──────────────────────────────────────────┐
│ Markdown 插件生态层 │
│ Skills(*.md) │ Agents(*.md) │ Hooks │
├──────────────────────────────────────────┤
│ 微内核引擎(闭源 Bun 编译) │
│ query() 主循环 │ 30+ 内置工具 │ MCP │
├──────────────────────────────────────────┤
│ 自建 Ink 渲染引擎 │
│ react-reconciler + Yoga Layout │
└──────────────────────────────────────────┘
核心理念:业务逻辑全部外化到 Markdown 文件
Codex --- Rust 系统级安全优先
┌──────────────────────────────────────────┐
│ TypeScript SDK 层 │
│ 开发者 API │ 嵌入式集成 │
├──────────────────────────────────────────┤
│ Rust 核心引擎 │
│ SQ/EQ 异步队列 │ 工具注册表 │ MCP │
├──────────────────────────────────────────┤
│ 多平台沙箱隔离层 │
│ macOS Seatbelt │ Linux Landlock+Seccomp │
│ Windows RestrictedToken │
└──────────────────────────────────────────┘
核心理念:系统级沙箱隔离,Rust 内存安全保障
Gemini CLI --- TypeScript 全栈最简
scss
┌──────────────────────────────────────────┐
│ CLI UI 层 (Ink + React 19) │
│ Composer │ MessageDisplay │ Themes │
├──────────────────────────────────────────┤
│ Core 业务逻辑层 │
│ GeminiClient │ ToolScheduler │ Hooks │
├──────────────────────────────────────────┤
│ Gemini API + MCP │
│ REST + SSE │ Stdio/HTTP 传输 │
└──────────────────────────────────────────┘
核心理念:清晰的两包分层(cli + core),标准 React 模式
17.3 核心机制深度对比
工具系统
| 特性 | Claude Code | Codex | Gemini CLI |
|---|---|---|---|
| 工具数量 | 30+ 内置 | 8 内置 | 10 内置 |
| 工具定义 | Zod Schema + prompt() 函数 | Rust trait ToolHandler | 类继承 BaseDeclarativeTool |
| 并行执行 | 只读工具并行,写入串行 | 顺序执行 | 顺序执行 |
| 权限控制 | Hook + canUseTool 多层 | Starlark 策略引擎 | shouldConfirmExecute() |
| 沙箱 | 可选沙箱(特定命令) | 系统级强制沙箱 | 无沙箱 |
| 独有工具 | Agent(子代理)、Skill、PlanMode、Worktree | apply_patch(diff 补丁) | memory(AI 自动写入记忆) |
typescript
// Claude Code --- buildTool 工厂 + isReadOnly 影响并行策略
export const BashTool = buildTool({
name: 'Bash',
inputSchema: z.object({ command: z.string(), timeout: z.number().optional() }),
isReadOnly(input) { return isReadOnlyCommand(input.command); },
async call(input, ctx) { return await exec(input.command); },
});
rust
// Codex --- Rust trait 实现,编译期类型安全
pub trait ToolHandler: Send + Sync {
async fn handle(&self, invocation: ToolInvocation) -> Result<ToolOutput, ToolError>;
}
typescript
// Gemini CLI --- 类继承 + 声明式 schema
class ReadFileTool extends BaseDeclarativeTool {
readonly kind = 'Read';
readonly requiresConfirmation = false;
async execute(signal: AbortSignal): Promise<ToolResult> { ... }
}
记忆系统
| 特性 | Claude Code | Codex | Gemini CLI |
|---|---|---|---|
| 全局记忆 | ~/.claude/CLAUDE.md |
~/.codex/instructions.md |
~/.gemini/GEMINI.md |
| 项目记忆 | ./CLAUDE.md(多级向上查找) |
./AGENTS.md |
./GEMINI.md(多级 + @import) |
| AI 自动记忆 | 无(只读) | 无 | 有(MemoryTool 自动写入) |
| 注入方式 | Attachment 消息 | System Prompt | System Prompt |
| 会话持久化 | session storage | ~/.codex/sessions/ |
支持 --resume |
关键差异 :Gemini CLI 是唯一支持 AI 自动写入记忆 的工具 --- LLM 可以调用 MemoryTool 将事实保存到 GEMINI.md 的
## Gemini Added Memories部分。Claude Code 和 Codex 的记忆文件都是用户手动维护的。
上下文压缩
| 特性 | Claude Code | Codex | Gemini CLI |
|---|---|---|---|
| 触发阈值 | 90% 上下文窗口 | 接近上下文限制 | 50% 上下文窗口 |
| 保留策略 | 保留最近 N 轮 | 保留头尾,删除中间 | 保留最近 30% |
| 快照格式 | Summary + Snapshot | 摘要 + 环境差异 | XML 结构化(含文件操作记录) |
| 手动触发 | /compact 命令 |
无 | 无 |
xml
Gemini CLI 压缩最激进 --- 50% 就触发,但快照最结构化:
<state_snapshot>
<user_goal>实现用户认证</user_goal>
<file_operations>READ: login.ts, MODIFIED: jwt.ts</file_operations>
<progress>1. [DONE] JWT 生成 2. [IN PROGRESS] 修复测试</progress>
</state_snapshot>
Claude Code 最保守 --- 90% 才触发,但支持手动 /compact。
Codex 独有环境差异策略 --- 只发送 <environment_context_diff>。
Hook / 安全系统
| 特性 | Claude Code | Codex | Gemini CLI |
|---|---|---|---|
| Hook 事件 | 15 种 | 无 Hook 系统 | 11 种 |
| Hook 类型 | command / prompt / agent / http | --- | command(shell 脚本) |
| 安全核心 | Hook → 权限 → 可选沙箱 | 策略引擎 + 强制沙箱 | 工具确认 + Hook |
| 策略语言 | JSON | Starlark (.codexpolicy) | JSON |
| AI 验证 | agent 类型 Hook | 无 | 无 |
| 独有事件 | PermissionDenied, SubagentStart | --- | BeforeModel, AfterModel |
Claude Code 的 Hook 最丰富(15 种事件 + 4 种执行方式);Codex 没有 Hook 但有最强系统级沙箱;Gemini CLI 独有 AI 模型调用生命周期钩子(BeforeModel/AfterModel)。
插件/扩展系统
| 特性 | Claude Code | Codex | Gemini CLI |
|---|---|---|---|
| 插件系统 | 完整插件生态(Marketplace) | 无 | 无 |
| 扩展方式 | Skills/Agents/Hooks + MCP | MCP + AGENTS.md | MCP + GEMINI.md + Hooks |
| 技能注入 | Skill 渐进式加载 | 无 | 无 |
| 子代理 | AgentTool(隔离上下文,可并行) | 无 | 无 |
这是 Claude Code 最大的差异化优势 --- 唯一拥有完整插件生态的工具。
17.4 通信与异步模型
| 特性 | Claude Code | Codex | Gemini CLI |
|---|---|---|---|
| API 通信 | Anthropic SDK(流式) | OpenAI Responses API(流式) | Google GenAI SDK (REST+SSE) |
| 异步模型 | AsyncGenerator (query 主循环) | SQ/EQ 队列 (Rust channels) | AsyncGenerator (Turn) |
| 后台任务 | TaskCreate/TaskStop | 无 | 无 |
| 并发工具 | 最多 10 个只读工具并行 | 顺序 | 顺序 |
17.5 性能与安全权衡
css
安全性 Codex ████████████ > Claude Code ████████ > Gemini CLI █████
系统级沙箱 多层 Hook 工具确认
扩展性 Claude Code ████████████ > Gemini CLI ████████ > Codex █████
插件+Skill+Agent+Hook MCP+Hook+记忆 MCP only
性能 Codex ████████████ > Claude Code ████████ > Gemini CLI ██████
Rust 原生 Bun 编译 Node.js
易读性 Gemini CLI ████████████ > Claude Code ████████ > Codex ██████
纯 TS,清晰分层 TS 但闭源编译 Rust 高门槛
开放性 Codex ████████████ = Gemini CLI ████████████ > Claude Code ████
Apache 2.0 全开源 Apache 2.0 全开源 核心闭源
17.6 谁适合谁?
| 场景 | 推荐 | 原因 |
|---|---|---|
| 企业级团队协作 | Claude Code | 插件生态 + Skill SOP 统一团队标准 |
| 安全敏感环境 | Codex | 系统级沙箱 + Starlark 策略引擎 |
| 快速上手/学习 | Gemini CLI | 代码最清晰,纯 TS,Google 免费额度 |
| CI/CD 自动化 | Codex | Rust 性能 + codex exec 非交互模式 |
| 自定义 AI 行为 | Claude Code | Markdown 驱动的 Skill + Agent 扩展 |
| 源码学习/二开 | Gemini CLI / Codex | 完全开源,社区活跃 |
17.7 本质差异总结
三个工具解决同一个问题 --- 让 LLM 在终端里执行编程任务 --- 但各自的"灵魂"完全不同:
- Claude Code 本质上是一个知识管理系统 --- Skills 渐进式加载用最少 Token 给 AI 最多知识,子 Agent 并行让多个 AI 实例分工协作
- Codex 本质上是一个安全执行环境 --- 跨平台沙箱(Seatbelt/Landlock/Seccomp)确保 AI 操作不会伤害系统
- Gemini CLI 本质上是一个极简 Agent 框架 --- 200 文件覆盖全功能,AI 能主动学习用户偏好,适合学习和快速定制
参考资料:
- Claude Code 官方文档
- OpenAI Codex 源码
- Gemini CLI 源码
- Model Context Protocol 规范
- Claude API 文档
extracted/src/--- 逆向提取的 v2.1.88 核心源码
致谢 :本文基于 claude-code 官方仓库和逆向提取的核心引擎源码分析。v2.0 版本基于实际源码校正了多处不准确描述,并新增了与 Codex/Gemini CLI 的三方对比。
