Claude Code 源码深度研究报告(最终版)
基于当前仓库 claude-code 的实际源码结构、入口链、运行时管线和关键注册点整理而成。
分析日期:2026-04-01 清晨(北京时间)
分析方法:
- 静态源码审读
- 主入口到主循环的调用链追踪
- prompt、tool、agent、skill、plugin、hook、MCP 等关键模块交叉核对
需要先说明一个非常重要的分析前提:当前仓库是一个 reverse-engineered 的 Claude Code 工程,不是官方原始仓库;并且 src/entrypoints/cli.tsx 顶部把 feature() polyfill 成了恒为 false。这意味着很多源码中存在的实验路径,在当前仓库默认运行时并不会打开。因此本文会始终区分两层事实:
- 当前源码实现了什么。
- 当前仓库默认运行时真正启用了什么。
目录
- 研究范围与结论总览
- 源码结构全景:它为什么更像 Agent Runtime Platform
- 系统提示词总装:
prompts.ts的真实地位 - Prompt 全量提取与模块级拆解
- Agent Prompt 与 built-in agents 深挖
- Agent 调度链深挖:从
AgentTool到runAgent再到query - Skills / Plugins / Hooks / MCP 生态深挖
- 权限、Hook、工具执行链深挖
- 为什么 Claude Code 这么强:从源码看它真正的护城河
- 关键文件索引与后续可继续深挖方向
1. 研究范围与结论总览
1.1 这次到底研究了什么
这次研究不是只看某个 prompt 文件,也不是只做目录级扫视,而是沿着当前仓库的真实执行路径,对下列主线做了系统拆解:
- Claude Code 当前仓库的整体源码结构
- 默认 system prompt 如何被构造、缓存和切分
- 真正有效的 system prompt 如何被选择
query.ts如何组织模型主循环、attachments、工具执行和上下文压缩AgentTool、runAgent、built-in agents 的职责边界- Skills、Plugins、Hooks、MCP 如何接入并改变模型可见能力面
- Permission、Pre/Post hook、Tool execution 如何协同形成可治理 runtime
- 为什么 Claude Code 的体验明显强于“LLM + 一层 function calling”
1.2 关键确认事实
基于当前仓库代码,可以确认以下事实:
- 当前项目是一个多文件 reverse-engineered 工程,主运行入口是
src/entrypoints/cli.tsx,再进入src/main.tsx和src/entrypoints/init.ts。 - 当前项目不是一个单纯的 prompt 项目,真正的主会话执行器是
src/query.ts。 src/constants/prompts.ts负责默认 system prompt 的构造,但最终生效的 prompt 还受到src/utils/systemPrompt.ts和src/utils/attachments.ts影响。- 默认 system prompt 里确实存在静态 section、动态 section 和明确的 cache boundary:
SYSTEM_PROMPT_DYNAMIC_BOUNDARY。 - 当前项目的工具执行链并不是“模型决定后直接调函数”,而是经过 schema 校验、工具校验、hook、permission、post-hook、tracing 的完整执行管线。
- 当前项目的 Agent 系统不是简单“子任务转发”,而是完整的 orchestration runtime。核心文件至少包括:
src/tools/AgentTool/AgentTool.tsxsrc/tools/AgentTool/runAgent.tssrc/tools/AgentTool/prompt.ts
- Skills 在当前项目里不是普通说明文档,而是“模型可调用的 prompt-command 抽象”。
- Plugins 在当前项目里不是单一扩展点,而是能贡献 commands、skills、agents、hooks、MCP、settings、output styles 的平台级扩展单元。
- MCP 在当前项目里既是外部工具与资源接入平面,也是行为说明注入平面。
- 当前项目源码中确实存在 Explore / Plan / verification 等 built-in agent 设计,但由于
feature()在当前仓库默认恒为false,这些能力不等同于“默认 live capability”。
1.3 最重要的总判断
Claude Code 的强,不是来自某个神秘 system prompt,而是来自一个完整的软件工程系统。这个系统至少包含以下几层:
- Prompt assembly architecture
- Prompt cache and context budget management
- Tool runtime governance
- Permission model
- Hook policy layer
- Agent orchestration
- Skill packaging
- Plugin platform
- MCP integration
- Conversation lifecycle management
如果只拿走其中一层,例如只拿 system prompt 或只拿文件编辑工具,通常只能做出“能跑”的 coding agent;而 Claude Code 的优势来自这些层被统一在一个产品级 runtime 里。
一句话总结:
Claude Code 的价值,不是一段 prompt,而是一整套把 prompt、context、tool、permission、hook、agent、skill、plugin、MCP、cache 和产品体验统一起来的 Agent Runtime Platform。
2. 源码结构全景:它为什么更像 Agent Runtime Platform
2.1 顶层结构暴露出的系统复杂度
从当前仓库的顶层和 src/ 一级目录来看,Claude Code 至少包含这些关键模块:
src/entrypoints/:入口层src/main.tsx:CLI 主编排src/constants/:prompt、querySource、常量、输出样式等src/context.ts:系统上下文和用户上下文构造src/query.ts:主会话循环src/tools/:工具实现层src/services/tools/:工具执行 runtime、hook 适配、流式工具执行器src/tools/AgentTool/:subagent orchestrationsrc/skills/:skills 加载和 bundled skills 注册src/utils/plugins/与src/plugins/:plugin 与 built-in plugin 体系src/services/mcp/:MCP 配置、连接、类型、鉴权、工具抓取src/utils/attachments.ts:attachment 和system-reminder注入层src/utils/hooks.ts:广义 hook 运行框架src/services/compact/:上下文压缩系统src/tasks/与src/Task.ts:后台任务和通知体系
这已经足够说明:当前项目不是简单 CLI 包装器,而是一个由会话层、执行层、协作层、扩展层组成的完整 agent runtime。
2.2 入口层说明它是平台,而不是单一交互壳
当前仓库的入口并不只有一个 CLI 文件。关键入口包括:
src/entrypoints/cli.tsxsrc/entrypoints/init.tssrc/entrypoints/mcp.tssrc/entrypoints/sdk/*
这意味着它从设计上就考虑了多种消费方式:
- 本地 CLI
- 初始化和 trust/config bootstrap
- 作为 MCP server 对外暴露工具
- SDK / headless 场景的数据结构与运行协议
这种设计不是“一个 REPL 的附加能力”,而是一个平台化 runtime 的常见形态。
2.3 主入口链路的真实结构
当前最可信的主入口链路是:
src/entrypoints/cli.tsx
-> fast path / polyfill / mode dispatch
-> src/main.tsx
-> src/entrypoints/init.ts
-> src/commands.ts
-> src/tools.ts
-> src/context.ts
-> src/query.ts这里有两个关键事实:
cli.tsx顶部的feature()polyfill 会决定大量分支的默认关闭状态。- 真正让 Claude Code 运转起来的不是 prompt 文件,而是
main.tsx + init.ts + query.ts这一条运行时链路。
2.4 命令系统是产品控制面,而不是边角功能
src/commands.ts 不是简单的 slash command 列表,而是整个产品运行时的重要控制面。当前它至少承担:
- built-in commands 注册
- skill commands 注册
- bundled skills 合并
- plugin skills / plugin commands 合并
- dynamic skills 合并
- availability 和 enable 状态过滤
也就是说,命令系统在这里既是用户交互层,也是 skill / plugin / workflow 的生态入口。
2.5 真正的会话中枢是 query.ts
当前项目最值得强调的一点是:真正的会话执行器不是某个 prompt builder,而是 src/query.ts。
query.ts 负责:
- 组织 API request 所需的 system prompt、context 和 attachments
- 执行 auto-compact / microcompact / snip
- 调度模型流式响应
- 识别和执行 tool use
- 调度 stop hooks
- 生成 tool use summary
- 管理 turn state、token budget、继续与终止条件
所以从运行架构看,Claude Code 不是“prompt 驱动一切”,而是 “query loop 驱动一切,prompt 是其中一个关键输入”。
3. 系统提示词总装:prompts.ts 的真实地位
3.1 真正的主入口不是单文件,而是三层组合
如果只看 src/constants/prompts.ts,很容易得出“这就是 Claude Code 的主系统提示词入口”的结论。但对当前仓库来说,更准确的说法是:
src/constants/prompts.ts:默认 system prompt 构造器src/utils/systemPrompt.ts:有效 system prompt 选择器src/utils/attachments.ts:一部分动态指令和能力清单的增量注入平面
因此 Claude Code 的真实 prompt 架构并不是单层,而是三层叠加:
- 默认 prompt blocks
- effective prompt selection
- attachment-based runtime reminders
3.2 getSystemPrompt() 不是静态文本,而是 section 编排器
src/constants/prompts.ts::getSystemPrompt() 会把 prompt 拆成静态部分和动态部分,并以数组形式返回,而不是直接生成一整块未分层的长字符串。
当前静态主干包括:
getSimpleIntroSection()getSimpleSystemSection()getSimpleDoingTasksSection()getActionsSection()getUsingYourToolsSection()getSimpleToneAndStyleSection()getOutputEfficiencySection()
动态部分则通过 section registry 注入,例如:
- session-specific guidance
- memory
- ant model override
- env info
- language
- output style
- MCP instructions
- scratchpad
- function result clearing
- summarize tool results
- token budget
- brief
这说明 Claude Code 的 prompt 不是静态字符串,而是“模块化 system prompt assembly”。
3.3 systemPromptSections.ts 暴露出 prompt 的工程化缓存思路
src/constants/systemPromptSections.ts 里有一套明确的 section registry:
systemPromptSection(name, compute)DANGEROUS_uncachedSystemPromptSection(name, compute, reason)resolveSystemPromptSections(sections)
这套机制的价值在于:
- 常规 section 可缓存
- 特定 section 可显式声明“每轮重算”
/clear或/compact时能统一清理 section state
这不是普通 prompt 拼接能提供的工程收益。它把 prompt section 变成了一个可以单独管理缓存和生命周期的资源。
3.4 buildEffectiveSystemPrompt() 才决定“最终真正发给模型的 prompt”
src/utils/systemPrompt.ts::buildEffectiveSystemPrompt() 负责最后的 prompt 选择逻辑。当前优先级大致是:
overrideSystemPrompt- coordinator system prompt
- main-thread agent prompt
- custom system prompt
- default system prompt
appendSystemPrompt永远后拼
这说明 prompts.ts 虽然非常重要,但它并不是每次请求都直接决定最终 prompt;它更多是在提供“默认主 prompt 基底”。
3.5 SYSTEM_PROMPT_DYNAMIC_BOUNDARY 是缓存边界,不只是分隔符
当前源码里存在明确的动态边界标记:
SYSTEM_PROMPT_DYNAMIC_BOUNDARY
它的作用不是语义分段,而是给 prompt cache split 提供稳定边界。真正消费这个边界的是:
src/utils/api.ts::splitSysPromptPrefix()src/services/api/claude.ts::buildSystemPromptBlocks()
在当前实现里,这套逻辑至少支持三种情况:
- 有 global cache 且找到 boundary:静态部分单独作为
globalcache block,动态部分不缓存。 - 因某些条件跳过 global split:system prompt 退回 org-scope cache。
- 默认 fallback:system prompt 前缀和其余部分走 org-scope cache。
所以更精确的结论应当是:
SYSTEM_PROMPT_DYNAMIC_BOUNDARY是 Claude Code prompt cache 经济学中的关键边界标记,但它只是整体 cache strategy 的一部分,而不是全部。
3.6 当前项目里还有一个重要补充:attachment 也承担提示词职责
prompts.ts 并不是唯一的“模型行为说明书”。当前 attachments.ts 会在对话里注入大量 system-reminder,例如:
skill_listingagent_listing_deltamcp_instructions_deltacritical_system_reminderplan_moderelevant_memories
这说明 Claude Code 的提示词架构是双平面的:
- system prompt blocks 提供稳定主规则
- attachment reminders 提供可变、按需、增量的会话规则和能力通告
4. Prompt 全量提取与模块级拆解
4.1 身份与基本定位:getSimpleIntroSection()
这一段的作用不只是“介绍自己”,而是在一开始就完成三件事:
- 明确自己是一个 interactive agent。
- 明确主要任务是帮助用户做 software engineering work。
- 注入 cyber risk instruction,并禁止随意生成或猜测 URL。
这段很短,但它决定了后续行为的起点:Claude Code 不是普通聊天机器人,而是一个工具驱动的工程协作者。
4.2 基础运行现实:getSimpleSystemSection()
这一段定义了 Claude Code 所处的 runtime reality:
- 所有非工具输出都会直接给用户看到
- 工具调用运行在用户选定的 permission mode 下
- 用户拒绝某个 tool call 后,不能原样重试
- tool result 和 user message 可能带有
system-reminder等标签 - 外部结果可能包含 prompt injection
- 系统存在 hook
- 对话会自动压缩,并不严格受单次上下文窗口限制
这段的价值很高,因为它把模型从“纯语言模型视角”拉回到了“受治理 runtime 视角”。
4.3 做任务哲学:getSimpleDoingTasksSection()
这一段是 Claude Code 工程行为稳定性的核心来源之一。当前源码明确要求模型:
- 不要加用户没有要求的功能
- 不要做额外重构和无关改进
- 不要滥加 error handling / fallback / validation
- 不要为一次性操作引入抽象
- 先读代码再改代码
- 不要轻易创建新文件
- 不要给时间估计
- 失败时先诊断再换策略
- 注意安全漏洞
- 不要做无意义的兼容性垃圾
- 结果必须如实报告,不能虚构验证结果
这部分不是“措辞漂亮”,而是 Anthropic 把 coding agent 的行为制度化写进了 prompt。
4.4 风险动作规范:getActionsSection()
这一节定义了哪些事情属于需要确认的风险动作,包括:
- destructive operations
- hard-to-reverse operations
- 对外可见动作
- 修改共享状态
- 向第三方上传内容
而且它不是简单列举风险,而是把 blast radius 思维写进提示词:
- 不要用 destructive action 当捷径
- 发现陌生状态先调查
- merge conflict、lock file 等不要暴力删除
这是 Claude Code 在产品体验上“看起来更稳”的重要来源。
4.5 工具使用规范:getUsingYourToolsSection()
这一段定义了清晰的工具优先级:
- 读文件优先
Read - 改文件优先
Edit - 新建文件优先
Write - 搜文件优先
Glob - 搜内容优先
Grep Bash只留给真正必须 shell 的任务- 有任务工具时优先使用
TodoWrite/TaskCreate - 无依赖的多个 tool call 应并行
这说明 Claude Code 的稳,不只是因为“工具很多”,而是因为它有强约束的 tool usage grammar。
4.6 Session-specific guidance:会话态局部规则层
getSessionSpecificGuidanceSection() 是默认 prompt 里非常关键的一段动态 section。它会基于当前 enabled tools 和 feature gate 注入局部规则,例如:
- 如果有
AskUserQuestion,工具被拒绝后可向用户追问 - 非交互模式与交互模式的行为差异
AgentTool的使用说明- Explore / Plan agent 的使用策略
SkillTool的调用前提DiscoverSkills的使用 guidance- verification contract
这意味着 Claude Code 的 system prompt 并不是“永恒总规则”,而是“稳定主规则 + 会话局部约束”。
4.7 Tone and style:统一输出风格和产品感
getSimpleToneAndStyleSection() 对交互风格做了细粒度约束:
- 默认不要用 emoji
- 外部用户分支里要求简洁
- 引用代码位置时使用
file_path:line_number - GitHub issue / PR 用
owner/repo#123 - tool call 前不要加冒号式废话
这些小规则本身不复杂,但对产品统一感非常重要。
4.8 Output efficiency:用户体验优化,而不是模型能力本身
getOutputEfficiencySection() 明确要求:
- 先说动作或结论
- 状态更新要短而关键
- 不要过度解释
- 不要把解释塞进大表格
- 简单问题直接回答
对当前项目而言,这说明 Claude Code 不只关注“能不能做成”,还关注“做事时输出是不是像成熟产品”。
4.9 DEFAULT_AGENT_PROMPT:子 agent 的通用基础人格
当前 prompts.ts 里定义了 DEFAULT_AGENT_PROMPT,其核心意思是:
- 你是 Claude Code 的 agent
- 用工具把任务做完
- 不要半成品,也不要过度设计
- 完成后给简洁报告
这说明主线程和子 agent 在 prompt 结构上是分层的,不是把主 prompt 原样复制给所有 worker。
5. Agent Prompt 与 built-in agents 深挖
5.1 AgentTool/prompt.ts:Agent 工具的模型侧协议说明书
src/tools/AgentTool/prompt.ts 的价值很高,因为它不是简单的 tool description,而是完整的 agent 使用协议。当前它明确规定了:
- 可用 agent 列表如何呈现
- 何时该用
AgentTool - 如何写 prompt 给子 agent
- 前台与后台运行的差异
- 如何继续已经启动的 agent
- worktree / remote isolation 的含义
- 如何并行启动多个 agent
这说明 Claude Code 的多 agent 并不是暗箱,而是明确写给模型看的协议系统。
5.2 built-in agent 的真实清单与启用边界
当前源码里存在的 built-in agents 包括:
general-purposestatusline-setupclaude-code-guideExplorePlanverification
但必须明确:当前仓库默认 feature() 恒为 false,因此源码中存在,不等于当前默认已启用。结合 src/tools/AgentTool/builtInAgents.ts,当前情况更准确地说是:
general-purpose:默认存在statusline-setup:默认存在claude-code-guide:非 SDK 入口下通常存在Explore/Plan:源码存在,但默认由 gate 关闭verification:源码存在,但默认由 gate 关闭
这一点在阅读当前仓库时必须牢记。
5.3 General Purpose Agent:默认工作马
general-purpose 是默认的通用 subagent。它的特点是:
tools: ['*']- 强调代码搜索、架构分析、多步任务执行
- 要求优先研究现有代码,不主动制造文档和多余文件
它不是某个超专业角色,而是“默认通用工种”。
5.4 Explore Agent:只读搜索专家
Explore agent 的 system prompt 非常清晰:
- 严格只读
- 不能创建、修改、删除、移动文件
- 不允许用重定向或 heredoc 写文件
Bash仅限只读操作- 鼓励高效并行检索
- 目标是尽快返回搜索结果
这个设计很有价值,因为它把“探索”从“实现”里切开了,让研究型任务不污染主线程上下文,也不带来副作用。
5.5 Plan Agent:纯规划,不做编辑
Plan agent 的 prompt 同样明确:
- 只读
- 不改文件
- 先理解需求和现有架构
- 输出 step-by-step plan
- 最后必须给出
Critical Files for Implementation
Plan agent 的价值,不是“帮忙想一想”,而是把 architect / planner 角色从 executor 角色里剥离出来。
5.6 Verification Agent:对抗实现者偏差的独立验证者
verification agent 的 prompt 是当前源码里最强的一组约束之一。它的核心不是“帮忙跑一下测试”,而是:
你的工作不是确认实现看起来能用,而是尽量把它搞坏。
它明确写了两种失败模式:
- verification avoidance
- 被前 80% 的表面成功迷惑
并要求:
- 跑 build
- 跑 test suite
- 跑 linter / type-check
- 根据变更类型做专项验证
- 做至少一个 adversarial probe
- 每个 check 都必须有 command 和 output observed
- 最终必须输出
VERDICT: PASS / FAIL / PARTIAL
这套 prompt 设计非常强,因为它直接针对 LLM 常见的“看代码就当验证完成了”的偷懒倾向做反制。
需要再次提醒的是:当前仓库默认 gate 下,这个 agent 的 runtime 默认并不启用;这里讨论的是其源码设计价值。
5.7 Claude Code Guide Agent:产品知识与文档问答专职 agent
claude-code-guide 不是普通 research agent,而是面向 Claude Code、Claude Agent SDK、Claude API 文档问答的专职 agent。
它的特点包括:
- 明确分三类知识域:CLI、Agent SDK、Claude API
- 主动使用
WebFetch/WebSearch - 结合本地项目中的 custom skills、custom agents、MCP server 和 user settings 做回答
这说明 built-in agents 不只是“研发过程角色”,也包含面向产品使用场景的专职角色。
5.8 Statusline Setup Agent:高度产品化的专职 agent
statusline-setup 的 prompt 详细规定了如何:
- 读取 shell 配置文件
- 解析
PS1 - 转换 escape sequences
- 更新
~/.claude/settings.json - 在需要时生成 statusline 脚本
它体现出一种很重要的设计倾向:Claude Code 不只是让 agent “会写代码”,还让 agent 能承担具体产品工作流里的可复用服务角色。
6. Agent 调度链深挖:从 AgentTool 到 runAgent 再到 query
6.1 总体调用链长什么样
当前源码中,subagent 调度主链可以抽象成:
- 主模型决定调用
Agent工具 AgentTool.call()解析输入参数- 选择 teammate / fork / built-in / custom / background / isolation 路径
- 选择 agent definition
- 生成 prompt messages 和 system prompt
- 组装 agent 工具池和 permission mode
- 调用
runAgent() runAgent()构造 agent-specific runtimerunAgent()内部再调用query()query()执行真正的模型循环、工具调用和消息流- 最后写 transcript、metadata,并清理资源
这是一条完整的 subagent runtime pipeline,而不是单次函数跳转。
6.2 AgentTool.call():真正的 orchestration controller
src/tools/AgentTool/AgentTool.tsx 的 call() 做的事情远不止“把 prompt 转给子 agent”。它要处理:
description/prompt/subagent_type/model/run_in_background等参数解析- teammate spawn 路径
- fork 路径与 normal path 分流
- agent deny 规则过滤
- MCP requirement 校验
- agent model 选择
- background / foreground 生命周期分流
- remote / worktree isolation
- agent prompt 和 prompt messages 构造
- worktree 的创建与清理
也就是说,AgentTool 本质上是一个 agent orchestration controller。
6.3 normal path 与 fork path 的区别
当前源码里 normal path 和 fork path 是两条明显不同的设计路径。
normal path
- 明确指定
subagent_type,或在 gate 关闭时回落到general-purpose - 依据 agent definition 生成 agent 自己的 system prompt
- 用简单 user message 作为 prompt message
- 根据 agent 权限和工具限制组装独立工具池
fork path
- 只有在
FORK_SUBAGENT实验开启时才会走 - 省略
subagent_type触发 - 继承父线程的 system prompt 和完整 conversation context
- 用
buildForkedMessages()生成 placeholder tool results + directive - 尽量保持 cache-identical prefix
这里最关键的一点不是功能,而是目标:fork path 是为“上下文继承 + prompt cache 复用”专门设计的。
6.4 但要明确:fork 是源码里的实验设计,不是当前仓库默认 live path
src/tools/AgentTool/forkSubagent.ts 里的 fork 语义设计很成熟,包括:
- 避免递归 fork
- placeholder tool results 保持字节级稳定
- 强调不要窥探 fork transcript
- 不要预测 fork 结果
- fork child 的输出格式和 scope 都被强限制
但当前仓库 feature() 恒为 false,所以这条路径默认不会打开。对当前项目的正确理解应该是:
- 源码里有非常成熟的 fork 设计。
- 当前仓库默认运行时并不启用这套实验语义。
6.5 background / foreground / worktree / remote 是不同生命周期模型
AgentTool.call() 当前还处理多种生命周期和隔离模式:
- foreground sync path
- async background path
- worktree isolation
- remote isolation
- teammate spawn
其中:
- background agent 会注册 async task,独立运行,完成后通知主线程
- foreground agent 会阻塞当前流程并返回结果
- worktree isolation 会创建临时 git worktree
- remote isolation 走远程 CCR 路径
这说明 Claude Code 对 subagent 的理解不是“起个线程”,而是有正式生命周期和隔离模型的 worker system。
6.6 runAgent.ts:真正的 subagent runtime constructor
src/tools/AgentTool/runAgent.ts 是当前 agent 子系统最关键的文件之一。它负责:
- 初始化 agent-specific MCP servers
- 处理 fork context messages
- 构造 agent-specific user/system context
- 生成 agent-specific permission mode
- 解析 tool pool
- 执行
SubagentStarthooks - 注册 frontmatter hooks
- 预加载 frontmatter skills
- 合并 agent MCP tools
- 构造 subagent
ToolUseContext - 调
query()进入主循环 - 记录 transcript 与 metadata
- 清理 MCP、hooks、shell tasks 和 tracking
这里非常重要的一个事实是:真正的 agent 执行循环并不在 runAgent.ts 本身,而是在它内部再次调用的 query() 里。
所以分层关系其实很清楚:
AgentTool:模式分流与调度runAgent:上下文构造和生命周期管理query:真正的模型循环和 tool-calling 执行器
6.7 agent-specific MCP、hooks、skills 说明 agent 本身也是可配置容器
在 runAgent.ts 中,agent 不是只有一个 system prompt。它还可以带:
- agent-specific MCP servers
- frontmatter hooks
- frontmatter skills
- memory scope
- critical system reminder
这说明 agent 在当前代码里本身就是一种“可组合 runtime container”,而不是纯硬编码角色。
7. Skills / Plugins / Hooks / MCP 生态深挖
7.1 Skill:不是文档,而是“模型可调用的 prompt-command 抽象”
当前项目里,Skill 的最佳理解方式不是“一个 markdown 工作流文档”,而是:
一类模型可调用的 prompt-based command 抽象。
它的来源可以包括:
- bundled skills
.claude/skills- 旧的
/commands目录风格 prompt command - plugin skills
- 当前源码里的 MCP skill plumbing
src/tools/SkillTool/prompt.ts 明确要求:
- 用户任务匹配 skill 时,先调用 Skill tool
- 不能只提 skill 名字不执行
/<something>形式可视为 skill 调用引用- 当前 turn 已经带对应 command tag 时,不要重复调用
这说明 Skill 在 Claude Code 里不是附属功能,而是 first-class primitive。
7.2 Skill 的加载链比想象中更正式
当前 Skill 的加载主链主要经过:
src/commands.tssrc/skills/loadSkillsDir.tssrc/skills/bundledSkills.tssrc/tools/SkillTool/SkillTool.ts
Skill frontmatter 支持的能力很丰富,至少包括:
allowed-toolsargumentsargument-hintwhen_to_useversionmodeleffortdisable-model-invocationuser-invocablehookscontext: forkagentshellpaths
这意味着 Skill 不只是“文本片段”,而是带有工具许可、参数化、执行上下文和 hook 能力的一类轻量工作流包。
7.3 Skill listing 不是简单罗列,而是 budget-aware 的模型可见性控制
当前 SkillTool prompt 和 attachment 体系对 skill 的模型可见性做了明确工程化控制:
SkillTool/prompt.ts为 skill listing 设置字符预算formatCommandsWithinBudget()会在预算内裁剪描述attachments.ts用skill_listingattachment 按需注入- skill-search 开启时,还会做 bundled + MCP 子集过滤
这说明 Claude Code 对“模型知道哪些 skill”和“上下文成本是否可控”这两个问题是一起设计的。
7.4 Plugin:平台级扩展单元,而不是单一 prompt 扩展
当前项目中的 Plugin 能力面明显比普通“CLI 插件”更重。结合 src/types/plugin.ts、src/utils/plugins/schemas.ts、src/utils/plugins/pluginLoader.ts、src/utils/plugins/loadPluginCommands.ts、src/utils/plugins/loadPluginAgents.ts 可以确认,plugin 至少能贡献:
- commands
- skills
- agents
- output styles
- hooks
- MCP servers
- LSP servers
- settings
commandsMetadatauserConfig
并且支持运行时变量替换:
${CLAUDE_PLUGIN_ROOT}${CLAUDE_PLUGIN_DATA}${CLAUDE_SKILL_DIR}${CLAUDE_SESSION_ID}${user_config.KEY}
这说明 plugin 在当前架构里已经是平台级扩展单元,而不是简单的 prompt 拼接器。
7.5 Plugin 系统有明确的安全边界
一个非常重要但容易漏掉的设计点是:plugin agent 并不能在 agent frontmatter 里任意声明高权限能力。
src/utils/plugins/loadPluginAgents.ts 明确限制了 plugin agent 的这些 frontmatter 字段:
permissionModehooksmcpServers
这些字段会被忽略并警告,因为插件是第三方安装边界,不能让某个隐藏在 plugin 里的 agent 文件悄悄提权。
因此当前项目里的 plugin 系统不是“无限制扩展”,而是带有信任边界设计的扩展平台。
7.6 Hook:不只是 tool hook,而是更宽的运行治理层
如果只看 src/services/tools/toolHooks.ts,会以为 Hook 系统只有:
PreToolUsePostToolUsePostToolUseFailure
但当前项目更宽的 Hook 框架在 src/utils/hooks.ts 中,至少还包含:
UserPromptSubmitSubagentStartInstructionsLoaded- stop 相关 hook
因此更准确的理解是:
toolHooks.ts管的是工具执行链上的 hook。utils/hooks.ts管的是更大范围的运行时 hook 事件总线。
7.7 MCP:不只是工具桥,也是资源层和行为说明注入层
当前仓库里的 MCP 至少有三层价值:
- 动态工具接入:连接到 server 后获得
mcp__server__tool形式的工具。 - 资源接入:通过
ListMcpResourcesTool/ReadMcpResourceTool访问 MCP resources。 - 行为说明接入:connected server 的
instructions会注入到 prompt 或 attachment。
从 src/services/mcp/types.ts 看,它支持的 transport / config 形态也相当完整:
stdiossehttpwssdkclaudeai-proxy
这说明 MCP 在当前项目里不是“外接几个函数”的薄层桥,而是完整的连接管理与能力注入平面。
7.8 Claude Code 还能反向作为 MCP server 暴露自身工具
src/entrypoints/mcp.ts 的存在说明 Claude Code 不只是 MCP client,也能作为 MCP server 对外提供工具能力。
这让它在架构上呈现出一个很重要的特征:
- 向内,它能消费外部 MCP server。
- 向外,它也能把自己的工具集暴露为 MCP 能力。
8. 权限、Hook、工具执行链深挖
8.1 toolExecution.ts:真正的工具 runtime 主线
当前项目的工具执行绝不是“模型决定 -> 直接调用函数”。在 src/services/tools/toolExecution.ts 里,一次 tool use 至少会经历:
- 找到 tool
- schema parse
tool.validateInput- Bash speculative classifier check
runPreToolUseHooksresolveHookPermissionDecisioncanUseTool/ permission flow- 真正执行
tool.call() - tracing / telemetry / analytics
runPostToolUseHooks- 失败时走
runPostToolUseFailureHooks
这是一条标准的 runtime governance pipeline。
8.2 输入校验:先挡掉低级错误和不可信参数
工具执行前的双层校验包括:
- Zod schema parse
- 工具自己的
validateInput
如果不通过,工具不会进入执行层,而是直接返回结构化错误结果。这一步对于降低模型乱填参数带来的运行时污染非常重要。
8.3 PreToolUse hook:最关键的拦截点
runPreToolUseHooks() 允许 hook 在工具执行前输出多种结果:
- 普通 message
- hook permission result
updatedInputpreventContinuationstopReason- additional context
- stop
最重要的三个控制能力是:
updatedInput- hook 可以改写输入,而不一定做权限决策。
permissionBehavior- hook 可以直接给出
allow/ask/deny。
- hook 可以直接给出
preventContinuation- 即便不 deny,也能阻止后续流程继续。
这使得 hook 真正参与了工具执行控制流,而不是只能做旁路日志。
8.4 resolveHookPermissionDecision():权限语义的关键粘合层
这段逻辑是 Claude Code 可治理性的关键之一。它明确保证:
- hook
allow不自动绕过 settings 里的 deny / ask 规则 - 需要用户交互的工具,如果 hook 没有用
updatedInput满足交互,仍需走统一权限流 - hook
ask会作为forceDecision继续传给canUseTool - hook
deny直接生效
也就是说,Hook 可以参与权限模型,但不能跳出权限模型。
8.5 Post hooks:执行结束后依然可以治理 continuation 和输出
runPostToolUseHooks() 和 runPostToolUseFailureHooks() 说明 Claude Code 并不把 “tool.call 返回” 当成终点。执行完成后 hook 仍然可以:
- 追加 message
- 注入 additional context
- 阻止 continuation
- 对 MCP tool output 做更新
- 在失败时补充恢复信息
这就是为什么它比“裸 function calling”更可治理。
8.6 还有一个容易忽略的重要层:工具并发执行语义
Claude Code 不仅治理单个工具调用,还治理多工具并发策略。
当前相关核心包括:
src/services/tools/toolOrchestration.tssrc/services/tools/StreamingToolExecutor.ts
它们做的事情包括:
- 根据
tool.isConcurrencySafe()把工具划分为可并发和不可并发批次 - read-only / concurrency-safe 工具可并发执行
- 非并发安全工具串行执行
- 流式工具执行时保持结果回放顺序
- 某些兄弟工具出错时,及时取消同批次剩余工具
这说明 Claude Code 的工具层不仅有 permission 和 hook,还有 concurrency semantics governance。
9. 为什么 Claude Code 这么强:从源码看它真正的护城河
9.1 它不是一个 prompt,而是多控制面的统一系统
从当前仓库看,Claude Code 的行为控制不是来自某一段神秘 system prompt,而是至少来自这几层:
- 默认 system prompt blocks
- effective system prompt selection
- system/user context
- attachment reminders / deltas
- tool descriptions / agent descriptions / skill descriptions
这说明它的 prompt engineering 本质上是 runtime architecture,而不是单段文案设计。
9.2 它把“好行为”制度化了
Claude Code 最大的优势之一,不是模型天然更聪明,而是:
- 不要乱加功能
- 不要过度抽象
- 不要在用户拒绝后原样重试工具
- 不要未验证就宣称成功
- 不要轻易做高风险动作
- skill 匹配时必须调用 Skill tool
- verification 必须有命令和输出证据
这些都不是靠模型临场发挥,而是被写进 prompt、tool protocol 和 runtime 规则里。
9.3 它非常懂“上下文是稀缺资源”
当前源码里到处都能看到上下文预算意识:
- system prompt 动静边界
- section cache
- skill listing budget
- agent listing 从 tool description 挪到 attachment
- MCP instructions delta attachment
- memory surfacing
- auto-compact / microcompact / snip
- tool use summary
这说明它不是把 token 当成免费空气,而是当成 runtime 预算来设计。
9.4 它把工具执行做成了产品级 runtime,而不是 demo
当前工具执行链里有:
- schema 校验
- validateInput
- hook
- permission
- classifier
- post hook
- tracing
- structured error/result handling
- concurrency control
这类设计会直接体现在“手感”上。普通 agent demo 常常在 happy path 看起来还行,一到复杂场景就崩;Claude Code 的 runtime 治理层正是减少这种崩溃的关键。
9.5 它的生态是“模型可感知”的
很多系统也有插件,也有外部工具,也有 workflow,但模型本身并不知道:
- 当前有哪些扩展
- 什么时候应该用
- 如何调用
Claude Code 不一样。Skill、Agent、MCP 和部分 plugin 能力会通过 prompt、attachment、tool schema 或 command registry 进入模型的可见能力空间。这一点非常关键,因为只有模型感知到了扩展,生态才真正能用起来。
9.6 它不是只关心“能运行”,还关心生命周期完整性
当前仓库里大量代码都在处理:
- transcript
- metadata
- cleanup
- background task
- notification
- resume
- compaction
- progress
这说明 Claude Code 的目标不是“做一个能调工具的聊天机器人”,而是“做一个可恢复、可治理、可扩展、可产品化的 agent runtime”。
10. 关键文件索引与后续可继续深挖方向
10.1 核心 Prompt 文件
默认 system prompt 与 section 组织
src/constants/prompts.tssrc/constants/systemPromptSections.ts
有效 prompt 选择与组合
src/utils/systemPrompt.ts
attachment-based 动态提示平面
src/utils/attachments.ts
10.2 主会话循环与上下文层
src/query.tssrc/query/config.tssrc/query/deps.tssrc/context.tssrc/services/api/claude.tssrc/utils/api.ts
10.3 核心 Agent 文件
src/tools/AgentTool/AgentTool.tsxsrc/tools/AgentTool/runAgent.tssrc/tools/AgentTool/prompt.tssrc/tools/AgentTool/loadAgentsDir.tssrc/tools/AgentTool/builtInAgents.tssrc/tools/AgentTool/forkSubagent.tssrc/tools/AgentTool/resumeAgent.ts
built-in agents
src/tools/AgentTool/built-in/generalPurposeAgent.tssrc/tools/AgentTool/built-in/exploreAgent.tssrc/tools/AgentTool/built-in/planAgent.tssrc/tools/AgentTool/built-in/verificationAgent.tssrc/tools/AgentTool/built-in/claudeCodeGuideAgent.tssrc/tools/AgentTool/built-in/statuslineSetup.ts
10.4 核心 Skill / Plugin / Hook / MCP 文件
Skill
src/tools/SkillTool/SkillTool.tssrc/tools/SkillTool/prompt.tssrc/skills/loadSkillsDir.tssrc/skills/bundledSkills.tssrc/commands.ts
Plugin
src/types/plugin.tssrc/utils/plugins/schemas.tssrc/utils/plugins/pluginLoader.tssrc/utils/plugins/loadPluginCommands.tssrc/utils/plugins/loadPluginAgents.tssrc/plugins/builtinPlugins.ts
Hook
src/services/tools/toolHooks.tssrc/utils/hooks.ts
Tool execution
src/services/tools/toolExecution.tssrc/services/tools/toolOrchestration.tssrc/services/tools/StreamingToolExecutor.ts
MCP
src/services/mcp/types.tssrc/services/mcp/config.tssrc/services/mcp/client.tssrc/services/mcp/utils.tssrc/entrypoints/mcp.ts
10.5 如果继续做下一轮,优先建议这样挖
如果要进一步深挖,我建议优先级如下:
src/query.ts- 它是 Claude Code 运行真相的核心文件,应当把完整状态机、流式模型调用、工具分支和 compact 路径全部展开。
src/utils/attachments.ts- 这决定了很多动态指令和能力清单是如何进入模型上下文的。
src/services/api/claude.ts- 这里能看到 prompt cache block、tool schema、betas、provider request 的真实拼装细节。
src/utils/systemPrompt.ts- 需要把 default / custom / agent / coordinator prompt 的优先级和组合行为讲透。
src/utils/hooks.ts- 这能补齐 tool hooks 之外的更宽事件模型。
src/services/compact/*- Claude Code 的上下文治理优势,很大一部分就藏在这里。
src/utils/permissions/*- 权限体系不仅决定安全,也决定产品交互体验。
10.6 最终结论
如果只保留一句话总结这份最终版研究报告:
Claude Code 的真正秘密,不是一段 system prompt,而是一套由默认 prompt、effective prompt 选择器、attachment 提示平面、query 主循环、受治理的工具执行链、agent orchestration、skills / plugins / MCP 扩展层、上下文缓存与压缩机制共同组成的产品级 agent runtime。
如果再补一句对当前仓库的限定,那就是:
阅读当前项目时,必须始终区分“源码里存在的设计能力”和“当前仓库默认运行时实际启用的能力”。只有把这两层分开,才能真正看懂 Claude Code 的架构价值。
讨论
登录后可评论、点赞、引用回复。