Files
ai-agent-deep-dive/README.md
2026-04-01 05:14:25 +00:00

1101 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Claude Code Deep Dive
## Quick Links
- PDF 下载 / PDF Report: [claude-code-deep-dive-xelatex.pdf](./claude-code-deep-dive-xelatex.pdf)
- 源码目录 / Extracted Source Directory: [extracted-source/](./extracted-source/)
---
# Claude Code 源码深度研究报告(增强完整版)
> 基于 `@anthropic-ai/claude-code` npm 包的 `cli.js.map` 还原源码后完成的系统性研究。本文是单文件、长篇、研究报告版重点覆盖整体架构、系统提示词、Agent 提示词、Skills、Plugins、Hooks、MCP、权限与工具调用机制以及新增的 **全量 Prompt 提取框架分析** 与 **Agent 调度链深挖**。
---
## 目录
1. 研究范围与结论总览
2. 源码结构全景:它为什么更像 Agent Operating System
3. 系统提示词总装:`prompts.ts` 的真实地位
4. Prompt 全量提取与模块级拆解
5. Agent Prompt 与 built-in agents 深挖
6. Agent 调度链深挖:从 AgentTool 到 runAgent 再到 query
7. Skills / Plugins / Hooks / MCP 生态深挖
8. 权限、Hook、工具执行链深挖
9. 为什么 Claude Code 这么强:从源码看它真正的护城河
10. 关键文件索引与后续可继续深挖方向
---
# 1. 研究范围与结论总览
## 1.1 这次到底研究了什么
这次不是只看某一个 prompt 文件,也不是只做“目录级扫一眼”。这次研究的核心,是把 `cli.js.map` 中的 `sourcesContent` 还原成可读源码后,沿着以下主线做系统性拆解:
- Claude Code 的整体源码结构
- 主系统提示词如何动态拼装
- AgentTool / SkillTool 的模型侧协议
- built-in agents 的角色分工
- Agent 调度链路如何跑通
- Plugin / Skill / Hook / MCP 如何接入并影响运行时
- Permission / Tool execution / Hook decision 如何协同
- 它为什么在体验上比“普通 LLM + 工具调用器”强很多
## 1.2 关键确认事实
本次已经确认:
1. npm 包里的 `cli.js.map` 包含完整 `sourcesContent`
2. 已从 map 中提取出 **4756 个源码文件**
3. 主系统提示词核心文件为:
- `src/constants/prompts.ts`
4. Agent Tool Prompt 核心文件为:
- `src/tools/AgentTool/prompt.ts`
5. Skill Tool Prompt 核心文件为:
- `src/tools/SkillTool/prompt.ts`
6. Agent 调度核心文件至少包括:
- `src/tools/AgentTool/AgentTool.tsx`
- `src/tools/AgentTool/runAgent.ts`
7. 工具执行链核心文件至少包括:
- `src/services/tools/toolExecution.ts`
- `src/services/tools/toolHooks.ts`
## 1.3 先给最重要的总判断
Claude Code 的强,不是来自某个“神秘 system prompt”而是来自一个完整的软件工程系统
- Prompt 不是静态文本,而是模块化 runtime assembly
- Tool 不是直接裸调,而是走 permission / hook / analytics / MCP-aware execution pipeline
- Agent 不是一个万能 worker而是多种 built-in / fork / subagent 的分工系统
- Skill 不是说明文档,而是 prompt-native workflow package
- Plugin 不是外挂,而是 prompt + metadata + runtime constraint 的扩展机制
- MCP 不是单纯工具桥,而是同时能注入工具与行为说明的 integration plane
一句话总结:
> Claude Code 的价值,不是一段 prompt而是一整套把 prompt、tool、permission、agent、skill、plugin、hook、MCP、cache 和产品体验统一起来的 Agent Operating System。
---
# 2. 源码结构全景:它为什么更像 Agent Operating System
## 2.1 顶层结构暴露出的系统复杂度
从提取出来的 `src/` 顶层看Claude Code 至少有这些重要模块:
- `src/entrypoints/`:入口层
- `src/constants/`prompt、系统常量、风险提示、输出规范
- `src/tools/`:工具定义与具体实现
- `src/services/`:运行时服务,例如 tools、mcp、analytics
- `src/utils/`:底层共用能力
- `src/commands/`slash command 与命令系统
- `src/components/`TUI / UI 组件
- `src/coordinator/`:协调器模式
- `src/memdir/`:记忆 / memory prompt
- `src/plugins/``src/utils/plugins/`:插件生态
- `src/hooks/``src/utils/hooks.js`hook 系统
- `src/bootstrap/`:状态初始化
- `src/tasks/`:本地任务、远程任务、异步 agent 任务
这已经说明它不是简单 CLI 包装器,而是一个完整运行平台。
## 2.2 入口层说明它是平台,而不是单一界面
可见入口包括:
- `src/entrypoints/cli.tsx`
- `src/entrypoints/init.ts`
- `src/entrypoints/mcp.ts`
- `src/entrypoints/sdk/`
也就是说它从设计上就考虑了:
- 本地 CLI
- 初始化流程
- MCP 模式
- SDK 消费者
这是一种平台化思维:同一个 agent runtime可以服务多个入口和多个交互表面。
## 2.3 命令系统是整个产品的操作面板
`src/commands.ts` 暴露出非常多系统级命令,例如:
- `/mcp`
- `/memory`
- `/permissions`
- `/hooks`
- `/plugin`
- `/reload-plugins`
- `/skills`
- `/tasks`
- `/plan`
- `/review`
- `/status`
- `/model`
- `/output-style`
- `/agents`
- `/sandbox-toggle`
这说明命令系统不是“锦上添花”,而是用户与系统运行时交互的重要控制面。
更关键的是,它不仅注册 builtin commands还统一加载
- plugin commands
- skill commands
- bundled skills
- 动态 skills
- 可用性过滤后的 commands
所以 command system 本身就是生态入口。
## 2.4 Tools 层才是模型真正“能做事”的根
从 prompt 和工具名能确认的重要工具包括:
- FileRead
- FileEdit
- FileWrite
- Bash
- Glob
- Grep
- TodoWrite
- TaskCreate
- AskUserQuestion
- Skill
- Agent
- MCPTool
- Sleep
工具层的本质是把模型从“回答器”变成“执行体”。Claude Code 的强,很大程度来自这层做得正式、清晰、可治理。
---
# 3. 系统提示词总装:`prompts.ts` 的真实地位
## 3.1 真正的主入口:`src/constants/prompts.ts`
这份文件是整个系统最关键的源码之一。不是因为它写了一大段神奇文案,而是因为它承担了:
- 主系统提示词的总装配
- 环境信息注入
- 工具使用规范注入
- 安全与风险动作规范
- Session-specific guidance 注入
- language / output style 注入
- MCP instructions 注入
- memory prompt 注入
- scratchpad 说明注入
- function result clearing 提示注入
- brief / proactive / token budget 等 feature-gated section 注入
Claude Code 的 prompt 不是静态字符串,而是一个 **system prompt assembly architecture**
## 3.2 `getSystemPrompt()` 不是文本,而是编排器
`getSystemPrompt()` 里最核心的结构,是先构造静态部分,再加上动态部分。你可以把它理解成:
### 静态前缀(更适合 cache
- `getSimpleIntroSection()`
- `getSimpleSystemSection()`
- `getSimpleDoingTasksSection()`
- `getActionsSection()`
- `getUsingYourToolsSection()`
- `getSimpleToneAndStyleSection()`
- `getOutputEfficiencySection()`
### 动态后缀(按会话条件注入)
- session guidance
- memory
- ant model override
- env info
- language
- output style
- mcp instructions
- scratchpad
- function result clearing
- summarize tool results
- numeric length anchors
- token budget
- brief
这个设计非常值钱,因为它不是“把能想到的都写进 system prompt”而是把 prompt 当作可编排运行时资源来管理。
## 3.3 Prompt cache boundary基础设施级思维
源码中明确存在:
- `SYSTEM_PROMPT_DYNAMIC_BOUNDARY`
并且注释说明:
- 边界前尽量可 cache
- 边界后是用户 / 会话特定内容
- 不能乱改,否则会破坏 cache 逻辑
这点非常重要。
因为这说明 Claude Code 已经不是“会写 prompt”而是在做
> Prompt assembly with cache economics
也就是说,它连 system prompt 的 token 成本与缓存命中都做了工程化优化。
---
# 4. Prompt 全量提取与模块级拆解
这一节是本次新增重点:**不是只说 prompt 在哪,而是把主 prompt 的主要 section 和行为价值拆出来**。
## 4.1 身份与基础定位:`getSimpleIntroSection()`
这一段做的事包括:
- 定义自己是 interactive agent
- 说明是帮助用户完成软件工程任务
- 指出输出风格会受 Output Style 约束
- 注入 `CYBER_RISK_INSTRUCTION`
- 明确禁止随意生成或猜 URL
这段意义不在于“介绍自己”,而在于为后续行为定基调:
1. 它不是普通聊天机器人
2. 它是工具驱动的工程协作者
3. 风险防护从第一屏开始就被注入
## 4.2 基础系统规范:`getSimpleSystemSection()`
这段本质上在定义 runtime reality
- 所有非工具输出都直接给用户看
- 工具运行在 permission mode 下
- 用户拒绝后不能原样重试
- tool result / user message 里可能有 `<system-reminder>` 等标签
- 外部工具结果可能包含 prompt injection
- 有 hooks
- 上下文会被自动压缩,不是硬性上下文窗口
这段极其重要,因为它把模型从“语言模型幻觉世界”拉回了“受控 runtime 世界”。
## 4.3 做任务哲学:`getSimpleDoingTasksSection()`
这部分是 Claude Code 行为稳定性的核心之一。它非常明确地约束模型:
- 不要加用户没要求的功能
- 不要过度抽象
- 不要瞎重构
- 不要乱加 comments / docstrings / type annotations
- 不要做不必要的 error handling / fallback / validation
- 不要设计一堆 future-proof abstraction
- 先读代码再改代码
- 不要轻易创建新文件
- 不要给时间估计
- 方法失败时要先诊断再换策略
- 注意安全漏洞
- 删除确认没用的东西,不搞 compatibility 垃圾
- 结果要如实汇报,不能假装测试过
这块本质上不是 prompt 细节,而是:
> Anthropic 对 AI 工程师行为规范的制度化表达
很多 coding agent 不稳定,不是不会写代码,而是行为发散。这一段就是为了解决行为漂移。
## 4.4 风险动作规范:`getActionsSection()`
这部分定义了什么叫“需要确认”的风险动作:
- destructive operations
- hard-to-reverse operations
- 修改共享状态
- 对外可见动作
- 上传到第三方工具
并且还强调:
- 不要用 destructive actions 当捷径
- 发现陌生状态先调查
- merge conflict / lock file 不要粗暴删
这一段值钱的点在于:它把 blast radius 思维编码进了系统提示词。
## 4.5 工具使用规范:`getUsingYourToolsSection()`
这里面有非常清楚的工具策略:
- 读文件优先 FileRead不要 cat/head/tail/sed
- 改文件优先 FileEdit不要 sed/awk
- 新建文件优先 FileWrite不要 echo 重定向
- 搜文件优先 Glob
- 搜内容优先 Grep
- Bash 只保留给真正需要 shell 的场景
- 有任务管理工具时要用 TodoWrite / TaskCreate
- 没有依赖关系的工具调用要并行
这非常关键,因为它不只是说“你有工具”,而是说:
> 你要以正确的操作语法使用这些工具
Claude Code 的稳,和这套 tool usage grammar 有很大关系。
## 4.6 Session-specific guidance运行时可变的局部指令
`getSessionSpecificGuidanceSection()` 是个非常关键的动态 section。里面会根据当前工具集和 feature gate 拼出一些当下约束,例如:
- 如果有 AskUserQuestion被拒绝后可以问用户
- 非交互模式下的行为差异
- 是否启用 AgentTool
- Explore / Plan agents 是否可用
- slash skill 的使用规则
- DiscoverSkills 工具的调用 guidance
- Verification agent 的强制验证合同
这一段说明 Claude Code 的 system prompt 不是“总规则”,而是“总规则 + 当前会话的局部规则”。
## 4.7 Output efficiency高价值但常被忽视的 section
这一段在 ant 与外部用户上有分支,但核心目标一致:
- 用户看的是自然语言,不是日志
- 先说动作或结论,不要铺垫
- 该更新时更新,但不要废话
- 不要过度解释
- 不要塞无谓表格
- 短句直给
这说明 Claude Code 不只管“能不能完成任务”,还管“完成任务时用户体验像不像正式产品”。
## 4.8 Tone and style统一交互感受
这部分规定:
- 不要乱用 emoji
- 响应要简洁
- 引用代码位置时用 `file_path:line_number`
- GitHub issue / PR 用 `owner/repo#123`
- tool call 前不要加冒号
这类细则看起来小,但它们会显著塑造产品质感。
## 4.9 DEFAULT_AGENT_PROMPT子 Agent 的基础人格
`prompts.ts` 里还定义了:
- `DEFAULT_AGENT_PROMPT`
核心意思是:
- 你是 Claude Code 的 agent
- 用工具完成任务
- 任务要完整,不要半成品
- 完成后给简洁报告
这说明主线程与子 agent 在 prompt 结构上是有分层的。
---
# 5. Agent Prompt 与 built-in agents 深挖
## 5.1 `AgentTool/prompt.ts`Agent 协议说明书
这份文件非常值钱。它不是普通说明文,而是 AgentTool 的**模型侧协议文档**。
它主要说明:
- 如何展示 agent list
- 每个 agent 的描述格式
- 何时 fork 自己
- 何时显式指定 `subagent_type`
- fork 与 fresh agent 的区别
- 什么情况下不要用 AgentTool
- 如何写给子 agent 的 prompt
- foreground / background 的行为差异
- isolation: worktree / remote 的语义
这说明多 agent 不是暗箱,而是明确写给模型看的使用协议。
## 5.2 fork 语义为什么很强
当 fork 开启时prompt 明确告诉模型:
- omit `subagent_type` 就是 fork 自己
- fork 继承完整 conversation context
- 研究任务很适合 fork
- 实现任务如果会产生大量中间输出,也适合 fork
- fork 很便宜,因为共享 prompt cache
- 不要给 fork 单独设 model否则 cache 命中会变差
- 不要偷窥 fork 输出文件
- 不要预言 fork 结果
这个设计本质上是在解决一个大问题:
> 怎么让复杂子任务并行运行,但不污染主上下文
这是多 agent 系统里非常核心、也非常难做对的一件事。
## 5.3 “How to write the prompt” 一节非常值钱
Agent prompt 里很明确地教育模型:
- fresh agent 没有上下文,要像对新同事 briefing 一样写 prompt
- 说明目标和原因
- 说明你已经排除了什么
- 提供足够背景,让它能做判断
- 如果要短答,明确说
- 不要把理解任务的工作外包给 agent
- 不要写“基于你的发现再去修 bug”这种偷懒 prompt
- 应该给到 file path、line、具体改动要求
这其实是在限制“懒 delegation”。也是为什么 Claude Code 的 subagent 效果会更稳:主 agent 被 prompt 强制要求承担 synthesis 责任。
## 5.4 built-in agents职责分工而不是万能 worker
从源码能确认至少有这些内建 agents
- General Purpose Agent
- Explore Agent
- Plan Agent
- Verification Agent
- Claude Code Guide Agent
- Statusline Setup Agent
这说明 Anthropic 的方向不是让一个 agent 什么都做,而是:
- 探索给 Explore
- 规划给 Plan
- 验证给 Verification
- 通用任务给 General Purpose
这是典型的 specialization 思路。
## 5.5 Explore Agent纯读模式的代码探索专家
`exploreAgent.ts` 的 system prompt 很有代表性。它明确规定:
### 绝对只读
- 不能创建文件
- 不能修改文件
- 不能删除文件
- 不能移动文件
- 不能写临时文件
- 不能用重定向 / heredoc 写文件
- 不能运行任何改变系统状态的命令
### 核心能力
- 用 Glob / Grep / FileRead 快速探索代码库
- Bash 只允许读操作:`ls`, `git status`, `git log`, `git diff`, `find`, `grep`, `cat`, `head`, `tail`
- 尽量并行用工具
- 要快,尽快给结果
这说明 Explore 不是“会搜索的普通 agent”而是被故意裁成 read-only specialist。
## 5.6 Plan Agent纯规划不做编辑
`planAgent.ts` 的 system prompt 也非常清晰:
- 只读
- 不准改文件
- 需要先理解需求
- 需要探索代码库、模式、架构
- 需要输出 step-by-step implementation plan
- 最后必须列出 Critical Files for Implementation
这里最关键的是Plan Agent 被定义成 architect / planner而不是 executor。这样做的价值是降低角色混杂。
## 5.7 Verification Agent为什么它非常值钱
`verificationAgent.ts` 是本轮挖掘里非常重要的新增部分。
它的 prompt 非常强,核心方向不是“确认实现看起来没问题”,而是:
> 你的工作是 try to break it
它甚至在 prompt 开头就点出两类失败模式:
1. verification avoidance只看代码、不跑检查、写 PASS 就走
2. 被前 80% 迷惑UI 看起来还行、测试也过了,就忽略最后 20% 的问题
然后 prompt 强制要求:
- build
- test suite
- linter / type-check
- 根据变更类型做专项验证
- frontend 要跑浏览器自动化 / 页面子资源验证
- backend 要 curl/fetch 实测响应
- CLI 要看 stdout/stderr/exit code
- migration 要测 up/down 和已有数据
- refactor 也要测 public API surface
- 必须做 adversarial probes
- 每个 check 必须带 command 和 output observed
- 最后必须输出 `VERDICT: PASS / FAIL / PARTIAL`
这说明 Verification Agent 不是“再跑一次测试”,而是一个 adversarial validator。
这非常强,因为它把很多 LLM 常见的“差不多就算了”直接用 prompt 反制掉了。
---
# 6. Agent 调度链深挖:从 AgentTool 到 runAgent 再到 query
这是本次新增的第二个重点:**Agent 调度链深挖**。
## 6.1 总体调用链长什么样
`AgentTool.tsx``runAgent.ts` 看,主链路可以抽象为:
1. 主模型决定调用 `Agent` 工具
2. `AgentTool.call()` 解析输入
3. 解析是否 teammate / fork / built-in / background / worktree / remote
4. 选择 agent definition
5. 构造 prompt messages
6. 构造 / 继承 system prompt
7. 组装工具池
8. 创建 agent-specific ToolUseContext
9. 注册 hooks / skills / MCP servers
10. 调用 `runAgent()`
11. `runAgent()` 内部再调用 `query()`
12. query 产出消息流
13. runAgent 记录 transcript、处理 lifecycle、清理资源
14. AgentTool 汇总结果或走异步任务通知
这已经是一条非常完整的 subagent runtime pipeline。
## 6.2 `AgentTool.call()`:真正的调度总控
`AgentTool.call()` 的职责远比“转发到子 agent”复杂。它要处理
- 解析输入参数description、prompt、subagent_type、model、run_in_background、name、team_name、mode、isolation、cwd
- 判断是否 multi-agent teammate spawn
- 解析 team context
- 判断是否允许 background
- 区分 fork path 与 normal path
- 根据 permission rules 过滤 agent
- 检查 MCP requirements
- 计算 selectedAgent
- 处理 remote isolation
- 构造 system prompt / prompt messages
- 注册 foreground / async agent task
- 启动 worktree isolation
- 调用 `runAgent()`
也就是说AgentTool 本质上是 agent orchestration controller。
## 6.3 fork path vs normal path
源码里有非常明显的分叉:
### fork path
- `subagent_type` 省略且 fork feature 开启
- 继承主线程 system prompt
-`buildForkedMessages()` 构造 prompt messages
- 用父线程完整 context
- 工具集尽量与父线程一致,保证 prompt cache 命中
- `useExactTools = true`
### normal path
- 明确指定 built-in / custom agent type
- 基于 agentDefinition 生成新的 agent system prompt
- 只给该 agent 所需上下文
- 走该 agent 的 tool restrictions
这里最值钱的地方是fork 不是“再开一个普通 agent”而是**为了 cache 和 context 继承专门优化过的执行路径**。
## 6.4 为什么 fork 会强调 cache-identical prefix
在注释里可以看出fork path 会尽量继承父线程的 system prompt 和 tool defs以保持 API request prefix byte-identical从而提高 prompt cache 命中。
这是非常高级的设计:
- 普通人只想“子任务能跑”
- Claude Code 想的是“子任务能跑,而且尽量复用主线程 cache不白烧 token”
这就是产品级系统思维。
## 6.5 background agent 与 foreground agent 是两套生命周期
`AgentTool.call()` 会根据条件决定:
- foreground sync path
- async background path
- remote launched path
- teammate spawned path
### background path 特点
- 注册 async agent task
- 独立 abort controller
- 可以在后台运行
- 完成后通过 notification 回到主线程
- 可选自动 summarization
- 可查看 outputFile 但 prompt 里明确不鼓励偷看
### foreground path 特点
- 主线程等待结果
- 可以在执行中被 background 化
- 有 foreground task 注册与 progress tracking
这说明 Claude Code 对 agent lifecycle 的处理是产品化的,而不是“一次函数调用”。
## 6.6 `runAgent()`:真正的子 Agent runtime
`runAgent.ts` 负责的事情很多:
- 初始化 agent-specific MCP servers
- 过滤 / 克隆 context messages
- 处理 file state cache
- 获取 system/user context
- 对 read-only agent 做 claudeMd / gitStatus slimming
- 构造 agent-specific permission mode
- 组装 resolved tools
- 获取 agent system prompt
- 创建 abortController
- 执行 `SubagentStart` hooks
- 注册 frontmatter hooks
- 预加载 frontmatter skills
- 合并 agent MCP tools
- 构造 subagent ToolUseContext
- 调用 `query()` 进入主循环
- 记录 transcript
- 清理 MCP、hooks、perfetto、todo、bash tasks 等资源
这说明 runAgent 不是简单 wrapper而是子 agent 的完整 runtime constructor。
## 6.7 agent-specific MCP servers真正的 additive 能力注入
`initializeAgentMcpServers()` 很有意思。
它支持 agentDefinition 自带 `mcpServers`,并且可以:
- 从现有配置按名字引用服务器
- 在 frontmatter 里内联定义 agent-specific MCP server
- 连接 server
- 拉取 tools
- 把 agent-specific MCP tools 合并进当前 agent 的 tools
- 在 agent 结束时做 cleanup
这说明 agent 不只是消费全局 MCP它还可以带自己的外接能力。这对插件 agent / 专职 agent 很强。
## 6.8 frontmatter hooks 与 frontmatter skills
`runAgent()` 里还会:
- `registerFrontmatterHooks(...)`
- 读取 `agentDefinition.skills`
- 通过 `getSkillToolCommands()` 加载技能
- 把 skill prompt 内容预加载成 meta user messages 注入初始消息
这很关键:说明 agent 本身也是可配置的 prompt container而不是固定硬编码角色。
## 6.9 `query()` 才是最终主循环执行器
虽然这次没有把 `query.ts` 全文展开,但从 `runAgent()` 能明确看到:
- 真正的模型对话循环发生在 `query({ ... })`
- `runAgent()` 只是子 agent 的上下文准备与生命周期控制器
这就让整个分层很清楚:
- AgentTool调度与模式分流
- runAgent子 agent 上下文构造与生命周期管理
- query真正的模型消息流与 tool-calling 主循环
## 6.10 transcript / metadata / cleanup产品化 runtime 的证据
`runAgent()` 里非常多产品级细节:
- `recordSidechainTranscript()`
- `writeAgentMetadata()`
- `registerPerfettoAgent()`
- `cleanupAgentTracking()`
- `killShellTasksForAgent()`
- 清理 session hooks
- 清理 cloned file state
- 清理 todos entry
这说明 Anthropic 并不是只让 subagent “跑起来”,而是把 transcript、telemetry、cleanup、resume 都纳入正式生命周期。
---
# 7. Skills / Plugins / Hooks / MCP 生态深挖
## 7.1 Skill不是文档而是 workflow package
源码里:
- `SKILL_TOOL_NAME = 'Skill'`
`SkillTool/prompt.ts` 以及命令系统相关代码中,它明确要求:
- task 匹配 skill 时必须调用 Skill tool
- 不能只提 skill 不执行
- slash command 可以视为 skill 入口
- 如果 skill 已经通过 tag 注入,则不要重复调用
这说明 Skill 是一个 first-class primitive。
### Skill 的本质
可以把它理解成:
- markdown prompt bundle
- 带 frontmatter metadata
- 可声明 allowed-tools
- 可按需注入当前上下文
- 可把重复工作流压缩成可复用能力包
这比“在 system prompt 里塞一堆固定流程”高级很多。
## 7.2 PluginPrompt + Metadata + Runtime Constraints
关键文件:
- `src/utils/plugins/loadPluginCommands.ts`
插件能提供的能力至少包括:
- markdown commands
- `SKILL.md` skill 目录
- commandsMetadata
- userConfig
- shell frontmatter
- allowed-tools
- model / effort hints
- user-invocable
- disable-model-invocation
- runtime 变量替换
例如支持:
- `${CLAUDE_PLUGIN_ROOT}`
- `${CLAUDE_PLUGIN_DATA}`
- `${CLAUDE_SKILL_DIR}`
- `${CLAUDE_SESSION_ID}`
- `${user_config.X}`
所以 plugin 不是普通 CLI 插件,而是模型行为层面的扩展单元。
## 7.3 Hook运行时治理层
关键文件:
- `src/services/tools/toolHooks.ts`
Hook 支持:
- `PreToolUse`
- `PostToolUse`
- `PostToolUseFailure`
而且 hook 结果不仅仅能“记日志”,还能:
- 返回 message
- blockingError
- updatedInput
- permissionBehavior
- preventContinuation
- stopReason
- additionalContexts
- updatedMCPToolOutput
这意味着 Hook 是 runtime policy layer。
## 7.4 Hook 与权限的耦合方式非常成熟
`resolveHookPermissionDecision()` 说明:
- hook 可以给出 allow / ask / deny
- 但 hook 的 allow 也不自动突破 settings deny/ask rules
- 如果需要 user interaction 或 requireCanUseTool仍然要走统一 permission flow
- hook 还能通过 updatedInput 满足交互输入
这说明 Hook 强,但没有绕开核心安全模型。
## 7.5 MCP不只是工具桥还是行为说明注入通道
`prompts.ts` 可以明确看到:
- `getMcpInstructionsSection()`
- `getMcpInstructions(mcpClients)`
逻辑是:
- 如果 connected MCP server 提供 instructions
- 就把这些 instructions 拼进 system prompt
也就是说 MCP 能同时注入:
1. 新工具
2. 如何使用这些工具的说明
这让 MCP 的价值远高于简单 tool registry。
---
# 8. 权限、Hook、工具执行链深挖
## 8.1 `toolExecution.ts`:真正的工具 runtime 主线
Claude Code 的工具执行并不是“模型决定 → 直接跑函数”。实际链路大致是:
1. 找 tool
2. 解析 MCP metadata
3. 做 input schema 校验
4. 做 validateInput
5. 为 Bash 启动 speculative classifier check
6. 运行 PreToolUse hooks
7. 解析 hook permission result
8. 走 permission 决策
9. 再次根据 permission updatedInput 修正输入
10. 真正执行 tool.call()
11. 记录 analytics / tracing / OTel
12. 运行 PostToolUse hooks
13. 处理 structured output / tool_result block
14. 失败则走 PostToolUseFailure hooks
这是一条标准的 runtime pipeline而不是直连函数调用。
## 8.2 输入校验:先挡低级错误
工具执行前会先做:
- Zod schema parse
- tool-specific `validateInput`
如果失败:
- 直接生成 `tool_result` 错误消息
- 记录 `tengu_tool_use_error`
这保证模型随便乱生成参数时不会直接污染执行层。
## 8.3 PreToolUse hooks最关键的拦截点
`runPreToolUseHooks()`hook 可以产出:
- 普通 message
- hookPermissionResult
- hookUpdatedInput
- preventContinuation
- stopReason
- additionalContext
- stop
最关键的几个能力是:
### updatedInput
hook 可以改写输入,但不一定做权限决策。
### permissionBehavior
hook 可以直接说:
- allow
- ask
- deny
### preventContinuation
即使没 deny也能阻止流程继续。
这使得 Hook 能真正参与控制流。
## 8.4 `resolveHookPermissionDecision()`:权限语义的关键粘合层
这段逻辑非常值钱。它定义了:
- hook allow 不一定绕过 settings 规则
- 如果 tool 要求 user interaction而 hook 没提供 updatedInput则仍要走 canUseTool
- ask 类型 hook 会作为 forceDecision 传递下去
- deny 类型直接生效
也就是说Hook 的权限语义是被严格嵌进总权限模型里的,不是外挂旁路。
## 8.5 工具执行后也不是结束
`runPostToolUseHooks()``runPostToolUseFailureHooks()` 说明Claude Code 不把“tool 成功返回”当终点。
成功后 hook 还能:
- 追加 message
- 注入 additional context
- 阻断 continuation
- 对 MCP tool output 进行更新
失败后 hook 还能:
- 补充失败上下文
- 发阻断说明
- 给用户更多恢复线索
这就是为什么整个系统比“tool call 一把梭”可治理得多。
---
# 9. 为什么 Claude Code 这么强:从源码看它真正的护城河
## 9.1 它不是一个 prompt而是一个 operating model
很多人复刻 coding agent 时只会拿走:
- 一个 system prompt
- 一个文件编辑工具
- 一个 bash 工具
- 一个 CLI 壳
但 Claude Code 真实的护城河是:
- Prompt architecture
- Tool runtime governance
- Permission model
- Hook policy layer
- Agent specialization
- Skill workflow packaging
- Plugin integration
- MCP instruction injection
- Prompt cache optimization
- Async/background/remote lifecycle
- Transcript / telemetry / cleanup / task system
少一个都行,但会显著掉“手感”。
## 9.2 它把“好行为”制度化了
Claude Code 最大的优势之一,不是模型更聪明,而是:
> 它不把“好习惯”交给模型即兴发挥,而是写进 prompt 和 runtime 规则里。
例如:
- 不要乱加功能
- 不要过度抽象
- 不要瞎重试被拒绝的工具
- 不要未验证就说成功
- 不要随便做风险操作
- 不要让 fork 输出污染主上下文
- 匹配 skill 时必须执行 skill
- verification 不能只看代码,必须跑命令
这种制度化,会极大提高系统一致性。
## 9.3 它特别懂“上下文是稀缺资源”
源码中大量设计都在围绕上下文做优化:
- system prompt 动静边界
- prompt cache boundary
- fork path 共享 cache
- skill 按需注入
- MCP instructions 按连接状态注入
- function result clearing
- summarize tool results
- compact / transcript / resume
这说明他们不是把 token 当免费空气,而是当 runtime 预算来管理。
## 9.4 Agent specialization 是很深的设计优势
Explore / Plan / Verification 这套 built-in agents 的价值,不在于“多了三个 agent”而在于
- 研究和探索不用污染主线程
- 规划和实现分离,降低混乱
- 验证独立出来,对抗“实现者 bias”
很多系统的问题,就是一个 agent 既研究、又规划、又实现、又验收,最终哪件事都不够稳定。
Claude Code 则是明确分工。
## 9.5 它的生态不是“可安装”,而是“模型可感知”
这是 Claude Code 另一个很强的点。
很多系统也有插件,也有工具,也有外部协议,但模型本身不知道:
- 有哪些扩展
- 什么时候该用
- 怎么用
Claude Code 不一样。它通过:
- skills 列表
- agent 列表
- MCP instructions
- session-specific guidance
- command integration
让模型“知道自己的扩展能力是什么”。这才是生态真正能发挥作用的关键。
---
# 10. 关键文件索引与后续可继续深挖方向
## 10.1 核心 Prompt 文件
### 主系统提示词
- `src/constants/prompts.ts`
### Agent Tool Prompt
- `src/tools/AgentTool/prompt.ts`
### Skill Tool Prompt
- `src/tools/SkillTool/prompt.ts`
### 其他可继续挖的 tool-specific prompt
- `src/tools/FileReadTool/prompt.ts`
- `src/tools/GlobTool/prompt.ts`
- `src/tools/GrepTool/prompt.ts`
- `src/tools/BriefTool/prompt.ts`
- 以及更多 `prompt.ts`
## 10.2 核心 Agent 文件
- `src/tools/AgentTool/AgentTool.tsx`
- `src/tools/AgentTool/runAgent.ts`
- `src/tools/AgentTool/resumeAgent.ts`
- `src/tools/AgentTool/forkSubagent.ts`
- `src/tools/AgentTool/agentMemory.ts`
- `src/tools/AgentTool/agentMemorySnapshot.ts`
- `src/tools/AgentTool/builtInAgents.ts`
### built-in agents
- `src/tools/AgentTool/built-in/exploreAgent.ts`
- `src/tools/AgentTool/built-in/planAgent.ts`
- `src/tools/AgentTool/built-in/verificationAgent.ts`
- `src/tools/AgentTool/built-in/generalPurposeAgent.ts`
- `src/tools/AgentTool/built-in/claudeCodeGuideAgent.ts`
- `src/tools/AgentTool/built-in/statuslineSetup.ts`
## 10.3 核心 Skill / Plugin / Hook / MCP 文件
### Skill
- `src/tools/SkillTool/constants.ts`
- `src/tools/SkillTool/prompt.ts`
- `src/commands.ts`
### Plugin
- `src/utils/plugins/loadPluginCommands.ts`
### Hook
- `src/services/tools/toolHooks.ts`
- `src/utils/hooks.js`
### Tool execution
- `src/services/tools/toolExecution.ts`
### MCP
- `src/services/mcp/types.ts`
- `src/services/mcp/normalization.ts`
- `src/services/mcp/mcpStringUtils.ts`
- `src/services/mcp/utils.ts`
- `src/entrypoints/mcp.ts`
## 10.4 如果继续做下一轮,还能怎么挖
如果要再往下继续深挖,下一轮我建议重点看:
1. `query.ts`:主会话循环与模型交互流
2. `resumeAgent.ts`agent 恢复机制
3. `loadSkillsDir`skills 完整加载链
4. `pluginLoader`:插件加载与内建插件生态
5. `systemPromptSections.ts`prompt section registry 细节
6. `coordinator/*`:多 agent 协调器模式
7. `attachments.ts`skill / agent listing / MCP delta 的消息注入方式
8. `AgentSummary`:后台 agent 进度总结机制
## 10.5 最终结论
如果只给一句话总结这份增强版研究报告:
> Claude Code 的真正秘密,不是一段 system prompt而是一个把 prompt architecture、tool runtime、permission model、agent orchestration、skill packaging、plugin system、hooks governance、MCP integration、context hygiene 和 product engineering 全部统一起来的系统。
这就是为什么它不像一个“会调工具的聊天机器人”,而更像一个真正可扩展、可治理、可产品化的 Agent Operating System。
# Claude Code Deep Dive
Files:
- `claude-code-deep-dive-xelatex.pdf`: full PDF report
- `README.md`: single-file Markdown version of the report