Claude Code 源码泄露的背后,到底与Codex,Gemini 有啥不一样?

9 阅读31分钟

目录

  1. 从现象出发:Claude Code 是什么?
  2. 项目结构:模块化的插件仓库
  3. 整体架构:可扩展的能力注册系统
  4. 记忆系统:三层记忆架构
  5. 上下文管理:动态压缩与快照
  6. 通信协议:流式 API 与实时交互
  7. UI 层:Ink 驱动的终端渲染
  8. 核心模块一:Commands(命令系统)
  9. 核心模块二:Agents(智能代理)
  10. 核心模块三:Skills(技能系统)
  11. 核心模块四:Hooks(钩子与治理)
  12. MCP 协议:连接外部世界
  13. 工具系统:执行引擎
  14. 实战案例:Feature-Dev 插件剖析
  15. CLI 使用方式与最佳实践
  16. 总结:Markdown 驱动的 AI 应用新范式
  17. 三足鼎立:Claude 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 CopilotClaude Code
交互模式代码补全(被动)对话式 + 自主执行(主动)
执行能力可执行 Bash、读写文件、调用 API
记忆系统无状态项目级配置(CLAUDE.md)+ 会话历史
可扩展性固定功能插件系统,用户可自定义
安全机制Hook 系统拦截 + 权限控制

1.3 应用场景

graph LR
    User[开发者] -->|"实现登录功能"| Claude[Claude Code]
    Claude -->|"1. 探索代码"| Explore[Code Explorer Agent]
    Claude -->|"2. 设计架构"| Architect[Code Architect Agent]
    Claude -->|"3. 编写代码"| Implement[实现模块]
    Claude -->|"4. 代码审查"| Review[Code Reviewer Agent]
    Claude -->|"5. 提交代码"| Git[Git 操作]

    style Claude fill:#f9f,stroke:#333,stroke-width:4px

2. 项目结构:模块化的插件仓库

2.1 目录树与功能划分

通过逆向分析 claude-code 项目,我们发现这是一个插件仓库而非核心引擎代码库。核心引擎是 Bun 编译的闭源 CLI 工具(源码可通过逆向提取到 extracted/src/),而这个仓库提供了 13+ 官方插件。核心引擎的源码包含 30+ 内置工具、插件加载器、Hook 执行引擎、MCP 客户端等完整实现。

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 插件类型分类

graph TB
    subgraph DevTools["🛠️ 开发工具插件 (4)"]
        FD[feature-dev<br/>7阶段功能开发]
        PD[plugin-dev<br/>插件脚手架]
        ASD[agent-sdk-dev<br/>SDK项目生成]
        MIG[claude-opus-4-5-migration<br/>模型迁移]
    end

    subgraph Productivity["⚡ 生产力插件 (3)"]
        CR[code-review<br/>自动PR审查]
        PRT[pr-review-toolkit<br/>6种专业审查]
        CC[commit-commands<br/>Git提交工作流]
    end

    subgraph Learning["📚 学习增强插件 (2)"]
        EO[explanatory-output-style<br/>教学模式]
        LO[learning-output-style<br/>互动学习]
    end

    subgraph Security["🔐 安全治理插件 (2)"]
        HF[hookify<br/>自定义行为规则]
        SG[security-guidance<br/>安全模式拦截]
    end

    subgraph Design["🎨 设计辅助插件 (1)"]
        FE[frontend-design<br/>UI/UX设计指导]
    end

    subgraph Other["🔮 其他插件 (1)"]
        RW[ralph-wiggum<br/>自引用迭代]
    end

    Core["🎯 Claude Code 核心引擎<br/>插件注册中心"]

    Core -.加载.-> DevTools
    Core -.加载.-> Productivity
    Core -.加载.-> Learning
    Core -.加载.-> Security
    Core -.加载.-> Design
    Core -.加载.-> Other
类别插件名称核心功能
开发工具feature-dev7 阶段功能开发工作流
plugin-dev插件开发脚手架
agent-sdk-devClaude Agent SDK 项目生成
claude-opus-4-5-migration模型迁移工具
生产力code-review自动化 PR 审查
pr-review-toolkit6 种专业审查 Agent
commit-commandsGit 提交工作流
学习增强explanatory-output-style教学模式
learning-output-style互动学习
安全治理hookify用户自定义行为规则
security-guidance安全模式拦截
设计辅助frontend-designUI/UX 设计指导
其他ralph-wiggum自引用迭代循环

3. 整体架构:可扩展的能力注册系统

3.1 架构分层

Claude Code 采用微内核 + 插件的架构模式。核心引擎负责:

  • 🧠 LLM 交互(流式请求、上下文管理)
  • 🔧 工具执行(Bash, Read, Write, Edit 等)
  • 🔌 MCP 客户端(连接外部服务)
  • 📦 插件加载器(动态发现和注册)

业务逻辑全部由插件提供。

flowchart TB
    subgraph Layer1["🖥️ 用户交互层 - User Interface Layer"]
        direction LR
        CLI["💻 CLI 终端<br/><small>命令行交互</small>"]
        VSCode["📝 VSCode 扩展<br/><small>IDE 集成</small>"]
        GitHub["🤖 GitHub Bot<br/><small>CI/CD 自动化</small>"]
    end

    subgraph Layer2["⚙️ 核心引擎层 - Core Engine Layer <small>(闭源)</small>"]
        direction TB

        subgraph Router_Group["🎯 请求路由模块"]
            Router["Intent Router<br/><small>智能意图识别</small>"]
        end

        subgraph Context_Group["🧠 上下文管理模块"]
            Context["Context Manager<br/><small>记忆压缩·注入</small>"]
            PluginLoader["Plugin Loader<br/><small>动态插件发现</small>"]
        end

        subgraph Execution_Group["⚡ 执行引擎模块"]
            ToolEngine["Tool Execution Engine<br/><small>工具调用·沙箱隔离</small>"]
            MCPClient["MCP Client<br/><small>外部服务桥接</small>"]
        end
    end

    subgraph Layer3["🧩 插件生态层 - Plugin Ecosystem Layer <small>(开源)</small>"]
        direction TB

        Registry["📋 Capability Registry<br/><small>能力注册中心</small>"]

        subgraph Plugin_Types["插件能力矩阵"]
            direction LR
            Commands["⚡ Commands<br/><small>显式调用</small>"]
            Agents["🤖 Agents<br/><small>自主决策</small>"]
            Skills["📚 Skills<br/><small>隐式注入</small>"]
            Hooks["🪝 Hooks<br/><small>行为拦截</small>"]
        end
    end

    subgraph Layer4["🌐 外部服务层 - External Services Layer"]
        direction LR
        LLM["🧠 Claude API<br/><small>Sonnet 4.6/Opus 4.6/Haiku 4.5</small>"]
        MCP["🔌 MCP Servers<br/><small>GitHub·DB·FS</small>"]
        OS["💾 Operating System<br/><small>文件系统·Shell</small>"]
    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)分别由对应的加载器(loadPluginCommandsloadPluginAgentsloadSkillsDirloadPluginHooks)加载后,通过 React hooks(useMergedCommandsuseMergedTools)在 REPL 运行时合并到工具池和命令列表中:

sequenceDiagram
    participant Boot as 启动入口 (cli.tsx)
    participant Init as init()
    participant Loader as pluginLoader.ts
    participant FS as File System
    participant Hooks as useMergedTools/Commands

    Boot->>Init: 1. 初始化配置、认证、遥测
    Init->>Loader: 2. loadAllPlugins()
    Loader->>FS: 3. 读取 settings.json 中已安装插件列表

    loop 遍历每个已启用插件
        Loader->>FS: 4. 解析 plugin.json 清单
        Loader->>FS: 5. loadPluginCommands (commands/*.md)
        Loader->>FS: 6. loadPluginAgents (agents/*.md)
        Loader->>FS: 7. loadSkillsDir (skills/*/SKILL.md)
        Loader->>FS: 8. loadPluginHooks (hooks/hooks.json)
    end

    Loader-->>Hooks: 9. 插件组件注入到 REPL 运行时
    Hooks-->>Boot: 10. 合并到工具池 (assembleToolPool)

3.3 核心数据结构

// 实际源码中的插件元数据结构(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 三层记忆架构图

flowchart TB
    subgraph Disk["💾 持久化存储层 - Persistent Storage <small>(Disk)</small>"]
        direction TB

        L3["🌍 L3: Global Memory<br/><small>~/.claude/config.json</small><br/>📌 用户偏好 · API配置 · 模型设置"]

        subgraph ProjectLevel["📁 项目级存储"]
            direction LR
            L2["📜 L2-A: Project Constitution<br/><small>CLAUDE.md</small><br/>🎯 代码规范 · 架构原则"]
            L2T["✅ L2-B: Todo List<br/><small>.claude/todos.json</small><br/>📋 任务队列 · 断点续传"]
        end
    end

    subgraph RAM["⚡ 运行时内存层 - Runtime Memory <small>(RAM)</small>"]
        direction TB

        L1["🧬 L1: System Prompt<br/><small>核心身份定义</small><br/>🛠️ 工具定义 · Skill SOP · 安全策略"]

        L0["💭 L0: Session History<br/><small>对话上下文</small><br/>💬 用户消息 · AI响应 · 工具调用结果"]
    end

    subgraph Pipeline["🔄 上下文处理流水线 - Context Pipeline"]
        direction TB

        subgraph Injection["📥 注入阶段"]
            Injector["Prompt Injector<br/><small>多源上下文融合器</small>"]
        end

        subgraph Compression["📦 压缩阶段"]
            Monitor["Token Monitor<br/><small>Token 使用率监控</small><br/>⚠️ 90%阈值触发"]
            Compressor["Context Compressor<br/><small>智能压缩引擎</small><br/>📸 Summary + Snapshot"]
        end
    end

    FinalContext["🎯 Final Context<br/><small>最终上下文包</small><br/>📤 发送给 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 管理结构化配置。

// ~/.claude/settings.json 结构示例
{
  "model": "claude-sonnet-4-6",
  "permissions": {
    "allow": ["Bash(git *)"],
    "deny": []
  },
  "hooks": {
    "PreToolUse": [...]
  },
  "plugins": {
    "code-review@claude-code-marketplace": { "enabled": true }
  }
}
<!-- ~/.claude/CLAUDE.md 示例 -->
# 全局偏好
- 使用中文回复
- 代码风格:简洁
- 提交信息遵循 Conventional Commits

生命周期:永久存储。CLAUDE.md 通过 loadMemoryPrompt() 在每次 API 请求时注入 System Prompt;settings.json 通过 enableConfigs() 在启动时加载。

L2: Project Memory(项目规范)

存储位置

  • CLAUDE.md:项目规范文档
  • .claude/todos.json:待办事项队列

CLAUDE.md 示例

# 项目规范:MyApp

## 代码风格
- TypeScript 严格模式
- 使用 Prettier + ESLint
- 组件命名:PascalCase

## 架构原则
- 每个组件单一职责
- 所有函数必须有类型定义
- 错误使用 Result 类型而非异常

## 禁止操作
- ❌ 不要使用 `any` 类型
- ❌ 不要直接修改 package.json
- ❌ 不要提交 .env 文件

## Git 规范
遵循 Conventional Commits:
- feat: 新功能
- fix: Bug 修复
- docs: 文档更新

todos.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(会话记忆)

存储位置:内存中的消息数组

数据结构

// 实际源码中的消息类型(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() 函数组装完整上下文:

// 实际源码逻辑(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),看似很多,但在实际开发中:

一次完整的功能开发对话可能消耗:
- 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 压缩策略流程图

sequenceDiagram
    participant Engine as 核心引擎
    participant Monitor as Token 监控器
    participant LLM as Claude API
    participant Compressor as 压缩器

    Engine->>Monitor: 1. 每轮对话后检查 Token 使用
    Monitor->>Monitor: 2. 计算当前 Token 占用

    alt Token < 90%
        Monitor-->>Engine: 继续正常对话
    else Token >= 90%
        Monitor->>Compressor: 3. 触发压缩流程

        Compressor->>LLM: 4. 调用 LLM 生成对话摘要
        Note over Compressor,LLM: Prompt: "总结之前的对话,<br/>保留关键信息和决策"
        LLM-->>Compressor: 5. 返回摘要(Summary)

        Compressor->>Compressor: 6. 生成环境快照(Snapshot)<br/>- Git 状态<br/>- 文件树<br/>- 待办事项

        Compressor->>Compressor: 7. 丢弃旧对话历史<br/>保留最近 5 轮

        Compressor->>Engine: 8. 重构 Context:<br/>[Summary] + [Snapshot] + [Recent 5]

        Engine->>Monitor: 9. 重置 Token 计数器
        Monitor-->>Engine: 继续对话
    end

5.3 压缩器核心实现

// [伪代码] 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):

[System Prompt: 5K]
[CLAUDE.md: 2K]
[Todos: 1K]
[第1轮对话: 3K]
[第2轮对话: 4K]
...
[第30轮对话: 5K]
总计:~180K tokens

压缩后(40K tokens):

[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 命令手动触发压缩:

# 感觉 AI 反应变慢或开始产生幻觉时
/compact

这会强制执行压缩流程,让 AI"清醒"过来。


6. 通信协议:流式 API 与实时交互

6.1 为什么使用流式 API?

传统的 Request-Response 模式会让用户等待很久才看到结果,而流式 API可以边生成边显示:

传统模式:
用户提问 → [等待 10 秒] → 完整回答一次性显示

流式模式:
用户提问 → [0.5秒] → "我" → [0.5秒] → "会" → [0.5秒] → "帮" → ...

6.2 通信流程图

sequenceDiagram
    participant User as 用户输入
    participant CLI as CLI 主进程
    participant API as Claude API
    participant UI as UI 渲染器

    User->>CLI: 1. 输入问题
    CLI->>CLI: 2. 构建 Context
    CLI->>API: 3. POST /v1/messages<br/>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 调用实现

// [伪代码] 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 协议进行流式传输:

事件格式:
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 错误处理与重试

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 并非直接使用 ink npm 包,而是基于 react-reconciler 自建了一套完整的终端渲染引擎(位于 src/ink/ 目录,包含 40+ 个文件)。它借鉴了 Ink 的设计理念,但包含自定义的 Yoga 布局引擎(src/ink/layout/)、ANSI 渲染器、滚动容器、超链接支持等。用 JSX 编写 CLI 界面的概念相同:

// 传统方式
console.log('Loading...');
// 无法更新这行文本

// Ink 方式
<Text color="cyan">
  <Spinner /> Loading...
</Text>
// 可以实时更新 Spinner 动画

7.2 Ink 架构原理

graph LR
    subgraph "React Layer (src/components/)"
        JSX[JSX 组件<br/>Box, Text, ScrollBox]
        VirtualDOM[Virtual DOM]
    end

    subgraph "Custom Ink Engine (src/ink/)"
        Reconciler[react-reconciler<br/>自定义 Reconciler]
        Layout[Yoga Layout Engine<br/>src/ink/layout/]
        Renderer[render-node-to-output.ts<br/>渲染到缓冲区]
    end

    subgraph "Terminal Layer"
        ANSI[ANSI Escape Codes<br/>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 组件

// [伪代码] 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 使用乐观更新策略,在工具实际执行前就显示"正在执行"状态:

// [伪代码] 工具调用的乐观更新
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 架构,可以优先渲染重要的更新:

// 高优先级:用户输入反馈
<Text color="green">{userInput}</Text>

// 中优先级:工具执行状态
<Spinner /> Executing git status...

// 低优先级:日志输出
<Text dimColor>{debugLog}</Text>

7.6 ANSI 颜色与样式

Ink 底层使用 ANSI Escape Codes 实现终端样式:

// 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:

<Text bold color="green">✓ Success</Text>

8. 核心模块一:Commands(命令系统)

8.1 什么是 Command?

重要说明:在 v2.1.88 的源码中,commands/ 目录已被标记为 commands_DEPRECATED(见 src/skills/loadSkillsDir.ts),新的推荐方式是使用 skills/ 目录。两者的 Frontmatter 格式相同,但 Skills 提供了更丰富的元数据(whenToUsemodelversion 等)。为保持文档的历史连贯性,本章仍以 Command 术语描述。

Command(现称 Skill) 是用户通过 Slash 命令(如 /commit/review)直接调用的预定义 Prompt。它类似于 ChatGPT 的"自定义指令",但更强大:

  • ✅ 可以预授权工具权限(无需每次确认)
  • ✅ 支持参数传递(/feature-dev 实现登录功能
  • ✅ 可以调用其他 Agent
  • ✅ 支持 $ARGUMENTS 和索引参数 $0, $1 等变量替换

8.2 Command 文件格式

所有 Command 都是 Markdown + YAML Frontmatter 格式:

---
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 调用流程

sequenceDiagram
    participant User as 用户
    participant Router as Intent Router
    participant Registry as Command Registry
    participant LLM as Claude API
    participant Tools as Tool Engine

    User->>Router: 输入 "/commit 修复登录bug"
    Router->>Registry: 1. 查找 "commit" 命令
    Registry-->>Router: 2. 返回 Command 定义

    Router->>Router: 3. 读取 Markdown 内容
    Router->>Router: 4. 替换 $ARGUMENTS = "修复登录bug"

    Router->>LLM: 5. 注入 System Prompt + Command
    LLM-->>Router: 6. 返回工具调用 (Bash: git status)

    Router->>Tools: 7. 执行 git status
    Tools-->>Router: 8. 返回执行结果

    Router->>LLM: 9. 继续对话循环
    LLM-->>User: 10. 显示最终结果

8.4 核心代码逆向还原

// [伪代码] 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/SkillAgent
触发方式用户 /command 调用或 LLM 调用 SkillToolLLM 调用 AgentTool 派生
执行模式在主上下文运行隔离的子上下文运行
工具权限需要在 frontmatter 声明同样需要声明
返回结果对话式输出返回结果摘要到主上下文
并行能力支持多 Agent 并行(同一消息多个 AgentTool 调用)
实际工具名SkillToolAgentTool (src/tools/AgentTool/)

9.2 Agent 文件格式

---
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 派生与调度

graph TD
    MainContext[主上下文] -->|"LLM 调用 Agent 工具"| AgentTool[AgentTool<br/>src/tools/AgentTool/]
    AgentTool -->|"createSubagentContext()"| SubContext1[Sub-Agent 1<br/>code-explorer]
    AgentTool -->|"createSubagentContext()"| SubContext2[Sub-Agent 2<br/>code-architect]
    AgentTool -->|"createSubagentContext()"| SubContext3[Sub-Agent 3<br/>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 调度器

// [伪代码] 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 协作实现复杂的功能开发流程:

flowchart TD
    Start[用户: /feature-dev 实现登录功能] --> Phase1[Phase 1: Discovery<br/>理解需求]
    Phase1 --> Phase2[Phase 2: Codebase Exploration<br/>派生 3 个 code-explorer Agents]
    Phase2 --> ReadFiles[读取 Agents 推荐的关键文件]
    ReadFiles --> Phase3[Phase 3: Clarifying Questions<br/>询问未明确的细节]
    Phase3 --> Phase4[Phase 4: Architecture Design<br/>派生 3 个 code-architect Agents]
    Phase4 --> UserApproval{用户批准方案?}
    UserApproval -->|否| Phase4
    UserApproval -->|是| Phase5[Phase 5: Implementation<br/>编写代码]
    Phase5 --> Phase6[Phase 6: Quality Review<br/>派生 3 个 code-reviewer Agents]
    Phase6 --> FixIssues{需要修复?}
    FixIssues -->|是| Phase5
    FixIssues -->|否| Phase7[Phase 7: Summary<br/>总结完成]

    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 的触发方式有两种:

  1. LLM 主动调用:Skill 元数据列在 System Prompt 中,LLM 判断相关时调用 SkillTool(src/tools/SkillTool/
  2. 用户显式调用:用户输入 /skill-name 直接调用

并不存在基于关键词的自动匹配引擎。

类比:

  • 旧版 Command = 用户 /commit 显式调用
  • Skill = LLM 看到元数据后自主决策是否调用(半隐式);也可由用户 /skill-name 显式调用

10.2 Skill 文件格式

---
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 测试?

### 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 注入逻辑

// 实际源码逻辑(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 中不同的知识传递模式

graph TB
    subgraph User["👤 用户意图层"]
        Intent["用户输入:设计一个登录页面"]
    end

    subgraph Detection["🔍 意图识别层"]
        Router["Intent Router<br/>路由引擎"]
    end

    subgraph Capabilities["🧩 能力执行层"]
        direction LR

        subgraph CommandFlow["⚡ Command 流程<br/><small>显式调用</small>"]
            C1["用户输入:<br/>/feature-dev 登录功能"]
            C2["🎯 精确匹配命令"]
            C3["📋 执行固定流程<br/>7阶段 SOP"]
            C4["✅ 完成任务"]

            C1 --> C2 --> C3 --> C4
        end

        subgraph SkillFlow["📚 Skill 流程<br/><small>隐式注入</small>"]
            S1["用户输入:<br/>设计登录页面"]
            S2["🔎 关键词匹配<br/>design/UI/frontend"]
            S3["💉 注入 Skill SOP<br/>前端设计最佳实践"]
            S4["🧠 AI自主执行<br/>遵循设计原则"]

            S1 --> S2 --> S3 --> S4
        end

        subgraph AgentFlow["🤖 Agent 流程<br/><small>自主决策</small>"]
            A1["Command调用:<br/>/feature-dev"]
            A2["🚀 启动 Agent<br/>code-explorer"]
            A3["🔄 自主规划<br/>搜索→分析→总结"]
            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 完整生命周期

sequenceDiagram
    autonumber
    participant User as 👤 用户
    participant Engine as ⚙️ Core Engine
    participant Router as 🔍 Skill Router
    participant Index as 📇 Skill Index<br/>(内存)
    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<br/>(关键词: 设计, 界面)

    Router->>+FS: 读取 frontend-design/SKILL.md 完整内容
    FS-->>-Router: 返回 SOP 内容

    Router->>Engine: 返回触发的 Skill 列表
    Engine->>Engine: 将 Skill SOP 注入 System Prompt

    Note over Engine: System Prompt 组成:<br/>① Core System Prompt<br/>② 用户偏好 (L3)<br/>③ 项目规范 (L2)<br/>④ 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 仍在上下文中<br/>无需重新注入
    Engine->>+LLM: 发送请求
    LLM-->>-Engine: 继续遵循前端设计原则
    Engine-->>-User: 输出符合 a11y 标准的实现

10.7 Skill 设计哲学:渐进式披露

Claude Code 的 Skill 系统采用**渐进式披露(Progressive Disclosure)**设计模式,这是一个经典的 UX 设计原则,应用在了 AI 系统中。

🎯 核心理念

按需加载,恰到好处

不要一次性把所有知识塞给 AI,而是:

  1. Level 1(元数据):启动时加载,极低成本,用于快速匹配
  2. Level 2(SOP 主体):触发时注入,中等成本,提供核心知识
  3. 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 加持的输出

// 用户输入:帮我实现一个登录表单
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)

// 用户输入:帮我实现一个登录表单
// [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 接口设计(回调函数)
  • ✅ 错误提示与用户体验

可视化对比

graph LR
    subgraph Without["❌ 无 Skill"]
        W1["用户输入"] --> W2["AI 基础知识"]
        W2 --> W3["低质量输出<br/>缺少最佳实践"]

        style W3 fill:#dc2626,stroke:#fca5a5,color:#fff
    end

    subgraph With["✅ 有 Skill"]
        S1["用户输入"] --> S2["AI 基础知识"]
        S2 --> S3["+ Skill SOP"]
        S3 --> S4["高质量输出<br/>遵循最佳实践"]

        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 类型与事件

graph LR
    subgraph "Hook 事件类型(v2.1.88 完整列表)"
        E1[PreToolUse<br/>工具执行前]
        E2[PostToolUse<br/>工具执行后]
        E2b[PostToolUseFailure<br/>工具执行失败后]
        E3[UserPromptSubmit<br/>用户输入提交前]
        E4[Stop<br/>对话结束前]
        E4b[StopFailure<br/>结束检查失败]
        E5[SessionStart<br/>会话开始]
        E6[SessionEnd<br/>会话结束]
        E7a[SubagentStart<br/>子 Agent 启动]
        E7b[SubagentStop<br/>子 Agent 结束]
        E8[PreCompact<br/>上下文压缩前]
        E8b[PostCompact<br/>上下文压缩后]
        E9[Notification<br/>通知事件]
        E10[PermissionRequest<br/>权限请求]
        E11[PermissionDenied<br/>权限拒绝]
    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.tsHOOK_EVENTS 常量中。

11.3 Hook 配置格式

实际支持四种 Hook 类型commandpromptagenthttp),以及 if 条件匹配:

{
  "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

### 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 插件提供了一个可视化的规则编辑器,让用户无需写代码就能定义拦截规则:

# .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 架构

graph LR
    Config[.hookify.rules.md<br/>Markdown 配置] -->|"解析"| Loader[Config Loader<br/>YAML to Python]
    Loader --> Rules[Rule Objects<br/>数据结构]

    Input[Hook 输入<br/>JSON] --> Engine[Rule Engine<br/>规则引擎]
    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 服务器类型

graph TD
    subgraph "MCP Server Types"
        T1[stdio<br/>本地进程]
        T2[SSE<br/>服务器推送]
        T3[HTTP<br/>REST API]
        T4[WebSocket<br/>双向实时]
    end

    subgraph "Use Cases"
        U1[本地工具<br/>文件系统, Git]
        U2[云服务<br/>GitHub, Asana]
        U3[API 后端<br/>自定义服务]
        U4[实时数据<br/>股票行情]
    end

    T1 --> U1
    T2 --> U2
    T3 --> U3
    T4 --> U4

12.3 MCP 配置示例

方式 1:独立 .mcp.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

{
  "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 提供的工具会自动加上前缀:

mcp__plugin_<插件名>_<服务器名>__<工具名>

示例:
- mcp__plugin_asana_asana__asana_create_task
- mcp__plugin_github_github__github_search_issues
- mcp__plugin_db_database__execute_query

在 Command 中使用

---
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 生命周期

sequenceDiagram
    participant Plugin as 插件加载器
    participant MCP as MCP Client
    participant Server as MCP Server
    participant LLM as Claude

    Plugin->>MCP: 1. 读取 .mcp.json 配置
    MCP->>Server: 2. 启动 stdio 进程 / 建立 SSE 连接
    Server-->>MCP: 3. 返回工具清单 (tools/list)
    MCP->>MCP: 4. 注册工具到能力表

    LLM->>MCP: 5. 调用 mcp__plugin_x_y__tool
    MCP->>Server: 6. 发送 JSON-RPC 请求
    Server-->>MCP: 7. 返回执行结果
    MCP-->>LLM: 8. 格式化结果

    Note over MCP,Server: 连接保持活跃,支持多次调用

    Plugin->>MCP: 9. 会话结束
    MCP->>Server: 10. 关闭连接 / 终止进程

13. 工具系统:执行引擎

13.1 内置工具清单

Claude Code 提供了 30+ 内置工具(源码 src/tools/ 目录下每个子目录对应一个工具),覆盖常见开发场景:

类别工具名称源码位置功能描述
文件操作ReadFileReadTool/读取文件内容(支持行号范围、PDF、图片)
WriteFileWriteTool/创建或覆盖文件
EditFileEditTool/精确字符串替换编辑
NotebookEditNotebookEditTool/编辑 Jupyter Notebook
GlobGlobTool/文件模式匹配查找
GrepGrepTool/正则搜索文件内容(基于 ripgrep)
Shell 操作BashBashTool/执行 Shell 命令(支持后台、超时、沙箱)
PowerShellPowerShellTool/Windows PowerShell 执行
代理管理AgentAgentTool/派生子 Agent(隔离上下文)
SendMessageSendMessageTool/向已有 Agent 发送消息
TaskCreateTaskCreateTool/创建后台任务
TaskGetTaskGetTool/获取任务状态
TaskListTaskListTool/列出所有任务
TaskOutputTaskOutputTool/获取任务输出
TaskStopTaskStopTool/停止任务
TaskUpdateTaskUpdateTool/更新任务
TodoWriteTodoWriteTool/管理待办事项列表
模式切换EnterPlanModeEnterPlanModeTool/进入计划模式(只读)
ExitPlanModeExitPlanModeTool/退出计划模式
EnterWorktreeEnterWorktreeTool/进入 Git Worktree 隔离环境
ExitWorktreeExitWorktreeTool/退出 Worktree
用户交互AskUserQuestionAskUserQuestionTool/询问用户选择
SkillSkillTool/调用 Skill
ToolSearchToolSearchTool/搜索延迟加载的工具定义
网络请求WebFetchWebFetchTool/获取网页内容
WebSearchWebSearchTool/执行网络搜索
定时调度RemoteTriggerRemoteTriggerTool/远程触发代理
ScheduleCronScheduleCronTool/创建定时任务
MCP 工具mcp__*MCPTool/MCP 服务器提供的动态工具
实验性SleepSleepTool/等待指定时间
REPLREPLTool/交互式代码执行

纠正:原文列出 "MultiEdit"、"KillShell"、"Task" 等工具名,这些在实际源码中不存在。正确名称分别是 Edit(支持 replace_all)、TaskStop、Agent。

13.2 工具执行流程

sequenceDiagram
    participant LLM as Claude API
    participant Router as Tool Router
    participant Hooks as Hook System
    participant Executor as Tool Executor
    participant OS as Operating System

    LLM->>Router: 1. 返回 tool_calls: [Bash, Read, Grep]
    Router->>Router: 2. partitionToolCalls() 分区

    Note over Router: 智能并行策略:<br/>连续只读工具 → 并行批次<br/>写入工具 → 串行批次

    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 都必须声明允许使用的工具:

---
# 明确列出工具
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 风格匹配。

权限检查逻辑

// [伪代码] 工具权限检查器
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 插件文件结构

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 节选)

---
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)

---
name: code-explorer
description: 通过追踪执行路径、绘制架构层、理解模式和抽象、记录依赖关系来深度分析现有代码库功能
tools: [Glob, Grep, Read, TodoWrite, WebFetch]
model: sonnet
color: yellow
---

你是一个代码分析专家,专注于追踪和理解功能实现。

## 核心任务

从入口点到数据存储,贯穿所有抽象层,提供功能的完整理解。

## 分析方法

**1. 功能发现**
- 找到入口点(API、UI 组件、CLI 命令)
- 定位核心实现文件
- 绘制功能边界和配置

**2. 代码流程追踪**
- 跟随从输入到输出的调用链
- 追踪每一步的数据转换
- 识别所有依赖和集成
- 记录状态变化和副作用

**3. 架构分析**
- 绘制抽象层(展示 → 业务逻辑 → 数据)
- 识别设计模式和架构决策
- 记录组件间的接口
- 注意横切关注点(认证、日志、缓存)

**4. 实现细节**
- 关键算法和数据结构
- 错误处理和边界情况
- 性能考虑
- 技术债务或改进领域

## 输出指导

提供全面的分析,帮助开发者深入理解功能,足以修改或扩展它。包括:

- 带文件:行号引用的入口点
- 带数据转换的逐步执行流程
- 关键组件及其职责
- 架构洞察:模式、分层、设计决策
- 依赖关系(外部和内部)
- 关于优势、问题或机会的观察
- **你认为绝对必要的文件列表,以理解所讨论的主题**

以最大的清晰度和实用性组织你的响应。始终包含具体的文件路径和行号。

14.4 工作流演示

sequenceDiagram
    participant User as 用户
    participant Main as Main Context
    participant Explorer as Code Explorer Agent
    participant Architect as Code Architect Agent
    participant Reviewer as Code Reviewer Agent

    User->>Main: /feature-dev 实现用户登录
    Main->>Main: Phase 1: 理解需求
    Main->>User: 确认功能范围

    User->>Main: 确认:支持邮箱/密码登录
    Main->>Main: Phase 2: 探索代码库

    par 并行探索
        Main->>Explorer: "找到类似的认证实现"
        Main->>Explorer: "分析当前的用户系统"
        Main->>Explorer: "识别 API 路由模式"
    end

    Explorer-->>Main: 返回关键文件列表
    Main->>Main: 读取推荐文件

    Main->>User: Phase 3: 询问澄清问题<br/>- 密码加密方式?<br/>- Token 存储位置?<br/>- 支持第三方登录吗?
    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: 实现功能<br/>(编写代码)

    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 的行为准则:

# 项目规范: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
npm test              # 运行所有测试
npm run test:watch    # 监视模式
npm run test:e2e      # E2E 测试

部署流程

  1. 运行 npm run build
  2. 确保所有测试通过
  3. 创建 PR 到 main 分支
  4. 等待 CI 通过
  5. 合并后自动部署到 staging

### 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 规则

# .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-elseLLM 动态推理
需要编译/部署热加载(无需重启)
学习曲线陡峭接近自然语言
难以维护易于修改和理解

16.2 技术架构精髓

mindmap
  root((Claude Code<br/>插件生态))
    分层设计
      微内核
      插件扩展
      能力注册
    声明式能力
      Commands
      Agents
      Skills
    治理机制
      Hooks
      权限控制
      安全拦截
    外部连接
      MCP 协议
      stdio/SSE/HTTP
      多服务集成
    开发者体验
      Markdown 驱动
      热加载
      调试友好

16.3 适用场景与限制

适用场景

  • ✅ 自动化开发工作流(commit, review, PR)
  • ✅ 代码库探索和文档生成
  • ✅ 定制化开发助手(企业内部规范)
  • ✅ 连接外部服务(数据库、API、CI/CD)

当前限制

  • ⚠️ 核心引擎闭源(无法深度定制)
  • ⚠️ 依赖网络(需要 Claude API)
  • ⚠️ Token 成本(大型项目可能昂贵)
  • ⚠️ Hook 调试较困难(需要 --debug 模式)

16.4 未来展望

基于当前架构,我们可以预见:

  1. 更多官方插件:数据库管理、DevOps、测试生成
  2. 插件市场:类似 VS Code Extensions
  3. 本地模型支持:降低成本,提高隐私
  4. 可视化编辑器:拖拽式创建 Command/Agent
  5. 企业版:SSO、审计日志、合规性控制

附录:快速参考

A. 文件格式速查

Command 格式

---
description: 描述
argument-hint: 参数提示
allowed-tools: [工具列表]
---

# Prompt 内容
$ARGUMENTS 会被替换为用户输入

Agent 格式

---
name: agent-name
description: 描述
tools: [工具列表]
model: sonnet|opus|haiku
color: yellow|blue|green
---

# Agent 指令
详细的执行逻辑...

Skill 格式(新版统一格式,替代旧版 Command):

---
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 格式

{
  "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. 调试技巧

# 启用调试日志
claude --debug

# 查看 MCP 服务器状态
/mcp

# 查看插件列表
/help

# 强制压缩上下文
/compact

# 查看 Token 使用
/cost

# 清空会话重新开始
/clear

D. Bun 适配层(源码运行必备)

Claude Code 核心引擎使用 Bun 编译,依赖 bun:bundlebun:ffi 两个 Bun-only 模块。通过 extracted/ 中的 shim 层可在 Node.js 下运行:

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

// 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.6src/constants/prompts.ts:118-123
"CapabilityRegistry 类"不存在该类,组件分散合并src/hooks/useMergedTools.ts
"Intent Router"不存在该模块直接由 processUserInput() 处理
"Skill 通过关键词自动激活"LLM 通过 SkillTool 自主调用src/tools/SkillTool/
"commands/ 目录"已标记为 commands_DEPRECATEDsrc/skills/loadSkillsDir.ts:68
"MultiEdit 工具"不存在,Edit 支持 replace_allsrc/tools/FileEditTool/
"KillShell 工具"不存在,使用 TaskStopsrc/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.mdsrc/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 CodeOpenAI CodexGemini CLI
开发商AnthropicOpenAIGoogle
核心语言TypeScript (Bun 编译)Rust + TypeScriptTypeScript
运行时Bun(发布)/ Node(兼容)Rust 原生二进制Node.js 20+
UI 框架自建 Ink 引擎 (react-reconciler)Rust TUI (ratatui)Ink (npm 包)
代码规模~800 文件,闭源核心 + 开源插件45+ Rust 模块,完全开源~200 文件,完全开源
后端模型Claude Sonnet/Opus 4.6GPT-4 系列Gemini 2.5 Pro/Flash
许可证核心闭源,插件 MITApache 2.0Apache 2.0

17.2 架构哲学对比

三者看似功能相同,但架构哲学截然不同:

Claude Code:  Markdown 驱动 + 微内核插件
               "用文档定义能力,让 LLM 执行逻辑"

Codex:        Rust 系统级 + 沙箱隔离优先
               "安全第一,性能极致,系统级隔离"

Gemini CLI:   TypeScript 全栈 + 最简设计
               "清晰分层,标准 React 模式,易于理解"

Claude Code — 微内核 + 插件生态

┌──────────────────────────────────────────┐
│         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 全栈最简

┌──────────────────────────────────────────┐
│         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 CodeCodexGemini CLI
工具数量30+ 内置8 内置10 内置
工具定义Zod Schema + prompt() 函数Rust trait ToolHandler类继承 BaseDeclarativeTool
并行执行只读工具并行,写入串行顺序执行顺序执行
权限控制Hook + canUseTool 多层Starlark 策略引擎shouldConfirmExecute()
沙箱可选沙箱(特定命令)系统级强制沙箱无沙箱
独有工具Agent(子代理)、Skill、PlanMode、Worktreeapply_patch(diff 补丁)memory(AI 自动写入记忆)
// 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); },
});
// Codex — Rust trait 实现,编译期类型安全
pub trait ToolHandler: Send + Sync {
    async fn handle(&self, invocation: ToolInvocation) -> Result<ToolOutput, ToolError>;
}
// Gemini CLI — 类继承 + 声明式 schema
class ReadFileTool extends BaseDeclarativeTool {
  readonly kind = 'Read';
  readonly requiresConfirmation = false;
  async execute(signal: AbortSignal): Promise<ToolResult> { ... }
}

记忆系统

特性Claude CodeCodexGemini CLI
全局记忆~/.claude/CLAUDE.md~/.codex/instructions.md~/.gemini/GEMINI.md
项目记忆./CLAUDE.md(多级向上查找)./AGENTS.md./GEMINI.md(多级 + @import
AI 自动记忆无(只读)(MemoryTool 自动写入)
注入方式Attachment 消息System PromptSystem Prompt
会话持久化session storage~/.codex/sessions/支持 --resume

关键差异:Gemini CLI 是唯一支持 AI 自动写入记忆 的工具 — LLM 可以调用 MemoryTool 将事实保存到 GEMINI.md 的 ## Gemini Added Memories 部分。Claude Code 和 Codex 的记忆文件都是用户手动维护的。

上下文压缩

特性Claude CodeCodexGemini CLI
触发阈值90% 上下文窗口接近上下文限制50% 上下文窗口
保留策略保留最近 N 轮保留头尾,删除中间保留最近 30%
快照格式Summary + Snapshot摘要 + 环境差异XML 结构化(含文件操作记录)
手动触发/compact 命令
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 CodeCodexGemini CLI
Hook 事件15 种无 Hook 系统11 种
Hook 类型command / prompt / agent / httpcommand(shell 脚本)
安全核心Hook → 权限 → 可选沙箱策略引擎 + 强制沙箱工具确认 + Hook
策略语言JSONStarlark (.codexpolicy)JSON
AI 验证agent 类型 Hook
独有事件PermissionDenied, SubagentStartBeforeModel, AfterModel

Claude Code 的 Hook 最丰富(15 种事件 + 4 种执行方式);Codex 没有 Hook 但有最强系统级沙箱;Gemini CLI 独有 AI 模型调用生命周期钩子(BeforeModel/AfterModel)。

插件/扩展系统

特性Claude CodeCodexGemini CLI
插件系统完整插件生态(Marketplace)
扩展方式Skills/Agents/Hooks + MCPMCP + AGENTS.mdMCP + GEMINI.md + Hooks
技能注入Skill 渐进式加载
子代理AgentTool(隔离上下文,可并行)

这是 Claude Code 最大的差异化优势 — 唯一拥有完整插件生态的工具。

17.4 通信与异步模型

特性Claude CodeCodexGemini 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 性能与安全权衡

安全性    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 自动化CodexRust 性能 + codex exec 非交互模式
自定义 AI 行为Claude CodeMarkdown 驱动的 Skill + Agent 扩展
源码学习/二开Gemini CLI / Codex完全开源,社区活跃

17.7 本质差异总结

三个工具解决同一个问题 — 让 LLM 在终端里执行编程任务 — 但各自的"灵魂"完全不同:

graph LR
    subgraph Claude["Claude Code 的灵魂"]
        CC1["Markdown 驱动的知识注入"]
        CC2["用文档定义能力"]
        CC3["插件生态 + 子 Agent 并行"]
        CC1 --> CC2 --> CC3
        style CC1 fill:#7c3aed,stroke:#c4b5fd,color:#fff
        style CC2 fill:#7c3aed,stroke:#c4b5fd,color:#fff
        style CC3 fill:#7c3aed,stroke:#c4b5fd,color:#fff
    end

    subgraph Codex["Codex 的灵魂"]
        CX1["系统级安全隔离"]
        CX2["Rust 性能 + 沙箱"]
        CX3["Starlark 策略引擎"]
        CX1 --> CX2 --> CX3
        style CX1 fill:#059669,stroke:#6ee7b7,color:#fff
        style CX2 fill:#059669,stroke:#6ee7b7,color:#fff
        style CX3 fill:#059669,stroke:#6ee7b7,color:#fff
    end

    subgraph Gemini["Gemini CLI 的灵魂"]
        GM1["最小可行 AI Agent"]
        GM2["清晰分层 + 纯 TS"]
        GM3["AI 自动记忆 + 结构化压缩"]
        GM1 --> GM2 --> GM3
        style GM1 fill:#dc2626,stroke:#fca5a5,color:#fff
        style GM2 fill:#dc2626,stroke:#fca5a5,color:#fff
        style GM3 fill:#dc2626,stroke:#fca5a5,color:#fff
    end
  • Claude Code 本质上是一个知识管理系统 — Skills 渐进式加载用最少 Token 给 AI 最多知识,子 Agent 并行让多个 AI 实例分工协作
  • Codex 本质上是一个安全执行环境 — 跨平台沙箱(Seatbelt/Landlock/Seccomp)确保 AI 操作不会伤害系统
  • Gemini CLI 本质上是一个极简 Agent 框架 — 200 文件覆盖全功能,AI 能主动学习用户偏好,适合学习和快速定制

参考资料

致谢:本文基于 claude-code 官方仓库和逆向提取的核心引擎源码分析。v2.0 版本基于实际源码校正了多处不准确描述,并新增了与 Codex/Gemini CLI 的三方对比。


扫码_搜索联合传播样式-标准色版.png