简介:Claude Code开源项目源码包,面向想深入理解AI编程工具内部实现的开发者、研究者,以及需要 TypeScript 工程范本的中高级学习者。zip压缩包内完整保留1903个文件、约9.43MB,其中以1332个ts文件承载核心逻辑与数据处理,552个tsx文件对应组件化界面,另有js脚本和md文档辅助构建与项目说明。整体采用模块化和面向对象设计,将复杂功能拆分为高内聚小模块,工具类与辅助函数的高复用设计明显降低了维护成本;项目附带大量注释、测试用例、开发者指南、API文档和用户手册,既能学习源代码的设计思路,也能参照其工程规范进行二次开发与扩展。源码管理遵循Git协作方式,目录结构清晰,便于跟踪变更与排查问题;已有279人学习/下载,适合作为前端或全栈方向开发者的源码分析范本。 最近我频繁在群里看到同一类问题:"Claude Code 源码哪里能看?"、"npm 装完之后到底哪一个是入口文件?"、"claude code 和 opencode 架构源码有什么区别?"…… 说句实话,Claude Code 官方并不开放完整源码,npm 包里只有被打包混淆的运行产物,你想 clone 一份干净源码自己改改,在官方路径上基本做不到。但这个话题依然有解。我研究 Claude Code 半年多了,从安装、配置、Skill 到接入第三方模型,再到把它嵌进 CI 持续集成,踩过的坑足够写几屏。这篇博文我就用"源码级拆解"的思路,不带内部资料,只靠公开文档、配置行为、日志缓存,以及开源替代品的代码结构,把 Claude Code 从启动、会话、模型调用到工具执行的完整链路还原给你。无论你只是想装好它接进 VSCode,还是想基于它做二次开发,这篇都能给你一套看得懂、能落地的地图。
1. 先把"Claude Code源码"这个话题说透:你看到的其实不是源码
1.1 全网都在搜一个不存在的东西
这里要先把话说清楚。Claude Code 是 Anthropic 推出的命令行 AI 编程助手,安装方式很简单:npm install -g @anthropic-ai/claude-code。但 npm 包不等于源码,它就像去店里买了个预制菜,包装上有配料表,但没有给厨师的完整菜谱。发布到 npm 的代码是经过打包、混淆的 JavaScript 产物,变量名都被处理过,和真正意义上的可读源码完全是两回事。Anthropic 没有开放它的核心仓库,GitHub 上能找到的anthropics/claude-code主要是一些 issue 跟踪和文档,不是全部实现。
这背后的原因也不难理解:Claude Code 的核心竞争力就是那套 Agent 编排逻辑——怎么组装上下文、怎么决定调哪个工具、怎么处理工具结果,这些思考过程属于商业护城河,开源了等于把自己的底牌亮出来。但矛盾点在于,生态需要开发者参与,所以它又必须开放配置、Hooks、MCP 这类扩展接口。于是你就看到"源码没有,但扩展点一堆"的局面。这不是缺陷,而是商业闭源产品的典型形态。
1.2 没有源码,源码级拆解照样成立
既然官方源拿不到,我们怎么研究?我一般用两条线并行。第一条线叫行为侧写:开一个测试项目,盯着 Claude Code 的输入输出、debug 日志、~/.claude/下的缓存文件,观察它先执行什么命令、后执行什么命令、报错时读取了什么配置。这些东西虽然是运行时表象,但能非常准确地反推出内部模块划分和调用顺序。第二条线是开源替代品对照:目前社区里最有代表性的是 opencode,一个 TypeScript 写的开源版本,源码完整放在 GitHub,工具注册、权限校验、模型 Provider 抽象这些核心模块都能看到。两条线合起来,你大脑里就能建立起一个"逻辑源码"——不是逐行抄的代码,而是对系统行为的精确建模。
我在实际研究里的体会是:大多数搜"Claude Code源码"的人,内心真正想要的不是某一堆代码文件,而是"当它执行某件事时,内部到底发生了什么"这个答案。只要把行为模型建立起来,闭源和开源对你来说差别不大。
2. 从命令行输入到模型返回:还原主循环里的几个关键模块
2.1 入口、会话与上下文管理
敲下claude命令后发生的事情,我会拆成四层来看。第一层是 CLI 入口,解析--model、--continue、--output-format、-p这类参数,决定你是进入交互式 REPL 还是只跑一条一次性指令。第二层是会话管理,读取~/.claude/projects/下的历史会话记录,把之前的多轮对话、当前工作目录、git 分支状态恢复出来。第三层是上下文采集,Claude Code 会先扫一遍项目结构,读.gitignore、找.claude/目录、执行一组只读命令,把项目当前状态打包成上下文。第四层才是模型调用,把组装好的 system prompt、tools 定义、历史消息一起发给模型 API。
很多新手第一次用 Claude Code 都会问:"它怎么这么懂我的项目?" 其实就是因为第三层做足了文章。你可以用claude --debug跑一次简单对话,日志里能看到它自动执行了ls、git diff --stat、find之类命令,顺手把相关文件读进上下文。这个过程非常像新手程序员接手老项目时先看目录结构、再看 git 历史、再读核心文件,只是它把这几步做成了可重复的流水线。
2.2 模型路由与请求组装
Claude Code 默认走 Anthropic 的 Messages API,但在代码结构上它一定有一个"模型路由"模块,专门决定这次请求发给谁、用什么模型名、带什么参数。路由的输入来源按优先级排列:CLI 参数、环境变量、项目配置、用户配置。最后解析出来的模型名会填进请求体的model字段。请求体不是只有 messages 那么简单,还要附带完整的工具 schema、system prompt、max_tokens、temperature,以及各种控制参数。
这里就有一个经典翻车点。很多人想给 Claude Code 接 DeepSeek,于是设置ANTHROPIC_BASE_URL指向兼容网关,再把ANTHROPIC_MODEL改成deepseek-chat,结果启动直接报错:deepseek-v4-pro is not a model this version of claude code recognizes。这个错误说实话很有迷惑性,因为它看起来像是"版本不支持这个模型",但本质是模型路由模块在启动时拿模型名做了一次白名单校验,发现你给的名字不在它认识的枚举列表里。Claude Code 根本不打算支持任意模型名,它只认自己家的那几种模型 ID 和别名。想让网关生效,正确思路不是教 Claude Code 认识新模型,而是在网关层做模型名映射:Claude Code 请求时仍然说自己要调用sonnet,网关收到后再把这个请求转发给 DeepSeek 或者本地模型,返回时再转成 Anthropic 的格式。这种方案才是社区里真正能落地的"接入 DeepSeek"姿势。具体配置冲突排查,我在第 4 节会展开。
2.3 工具执行与响应收敛
模型流式返回有两种内容块:text和tool_use。如果是纯文本,直接输出给用户;如果出现tool_use,主循环会进入工具执行阶段。关键点是:它不是拿到工具调用就立刻执行,而是要过一个权限闸门。默认情况下,只读命令直接放行,写操作或危险命令会弹确认框。用户确认后,工具真正执行,再把结果包装成tool_result塞回 messages,带着新内容重新发起模型请求。这个"请求-工具-反馈-再请求"的循环会一直转,直到模型不再要求调用工具。
这里有一个特别容易踩的暗坑:工具结果太长会被截断或摘要。比如你让 Bash 工具执行cat huge-file.log,如果这个文件几万行,Claude Code 不会把全部 10 万 token 塞回上下文,而是做截断处理,只保留头尾或者中间采样一部分。很多"文件里明明有答案但 Claude Code 却看不到"的诡异情况,基本都是这个原因。知道了这点,你喂给它的文件最好提前用grep过滤,或者直接把关键行读出来,而不是让它自己去 cat 大文件。
3. 工具系统才是 Claude Code 的灵魂:Schema、权限、执行器三件套
3.1 内置工具清单与职责边界
Claude Code 内置工具大致有这些:Bash、Read、Write、Edit、Glob、Grep、WebFetch、WebSearch、TodoWrite、Task。每个工具放进模型请求之前,都会先被序列化成 JSON Schema,描述工具叫什么、参数有哪些、参数类型是什么。模型看到这堆 schema 后,就知道自己可以使用哪些"手脚"。
如果用源码思维去抽象,一个工具就是三段式结构:Schema 负责描述,Execute 负责执行,Permission 负责管控。三个模块彼此独立,这也是为什么你可以很轻松地加自定义工具。官方通过 MCP 协议开放了工具注册能力,你不需要改 Claude Code 的代码,只需要提供一个 MCP server,它就会在启动时动态把 MCP 工具列表并入已有工具集。这种设计很像浏览器插件机制,核心进程不开源,但扩展位全部开放。
3.2 权限模型:哪些操作会弹确认框
权限模型是工具系统里最需要认真理解的部分。Claude Code 默认运行在"逐步确认"模式,但我实测发现,它并不是每个工具都问,而是有一套内置的风险分级。
- 只读类命令,比如
ls、cat、grep、git diff,一般直接执行; - 文件写入类工具,比如 Write、Edit,会有确认提示;
- 危险 Bash 命令,比如
rm -rf、mv、sudo,一定弹框; - 网络请求类工具,比如 WebFetch,也会在第一次请求时确认。
如果你想在 CI 或脚本里无人值守地跑,一定要在启动参数里规划好--allowedTools和--disallowedTools。我在真实项目里踩过一次坑:写了个自动化脚本,忘了配 allowedTools,结果 Claude Code 执行到要改文件的那一步,权限闸门卡住,进程一直等确认,CI 超时直接飘红。后来我修改了策略,用--allowedTools "Bash(cat*) Bash(git*) Edit Write"这样的粒度,既不会把所有命令都放行,又保证自动化流程能往下走。这里多提一句:--dangerouslySkipPermissions这个参数我建议只在一次性容器里用,平时别碰。
3.3 用 MCP 和 Skill 扩展工具面
MCP 配置大概长这样:项目根目录放一个.mcp.json,声明一个本地 server 用npx启动,或者远程 server 填 URL。Claude Code 启动时会去读这个文件,把 server 往返过来的工具列表并入主工具表。这些 MCP 工具同样走权限闸门,可以被 allow/disallow 规则约束。你完全可以把自己团队里的数据库查询接口、构建系统、工单平台都做成 MCP server,让 Claude Code 在对话里直接调用。
除 MCP 外,Skills 是另一个被低估的扩展点。Skill 本质是一个目录,里面放SKILL.md和若干辅助文件。SKILL.md用 Markdown 写清楚这个技能什么时候触发、怎么执行、需要调用哪些工具。比如我写了一个"代码审查"技能,规定当用户在对话中触发/review时,先执行git diff获取改动,再读取项目根目录的规范文档,最后按模板输出审查意见。Skill 相比普通 Prompt 的优势是它把工具调用流程也写进了技能文档里,模型会按文档步骤走,而不是自由发挥。
4. 配置文件里的"源码级"秘密:模型白名单和 Hooks
4.1 从报错 deepseek-v4-pro 说起:模型名校验逻辑
前面提到的deepseek-v4-pro is not a model this version of claude code recognizes是最近热词里出现频率很高的报错。很多人收到这个报错后第一反应是升级 Claude Code,但升级几轮后依然存在。结合我前面对模型路由的分析,这个报错的根源在配置校验层。Claude Code 的模型名解析逻辑会维护一个已知模型集合,集合里包含常见的 Claude 模型 ID,比如claude-sonnet-4-20250514,以及opus、sonnet、haiku这类别名。如果你设置的环境变量或配置项里的模型名不在集合里,启动阶段就会直接抛错。
要绕过这个限制,正经做法是网关映射。我在本地实验用的方案是:在本地起一个兼容服务,监听某个端口,环境变量里写ANTHROPIC_BASE_URL=http://localhost:9000,ANTHROPIC_MODEL=sonnet。Claude Code 发请求时,会带着model=sonnet发给本地服务;本地服务收到后,把请求转发给 DeepSeek 的 API,同时把模型名改成 DeepSeek 认的名字;DeepSeek 返回后,再按 Anthropic 的消息格式转回给 Claude Code。从 Claude Code 视角看,它的确是在和一个"官方的 sonnet"通话,只是那个"官方"恰好是你的网关。这个方案不涉及任何逆向或破解,只是利用配置层面的规范化转换。
4.2 settings.json、环境变量和 CLI 参数的优先级
Claude Code 的配置体系特别像 git 的层级:默认值在最底层,往上是用户级配置,再往上是项目级配置,然后是环境变量,最高层是 CLI 参数。我用一张表来总结:
| 配置来源 | 示例 | 优先级 |
|---|---|---|
| CLI 参数 | claude --model sonnet | 最高 |
| 环境变量 | ANTHROPIC_MODEL=sonnet | 高 |
| 项目配置 | .claude/settings.json | 中 |
| 用户配置 | ~/.claude/settings.json | 低 |
| 内置默认值 | 官方默认模型和参数 | 最低 |
这个优先级顺序会坑到很多人。我在帮一个朋友排查问题时发现,项目.claude/settings.json里明明设置了model: "opus",但实际跑起来一直用的是 haiku,查了很久才发现是 shell 的.zshrc里残留了一行export ANTHROPIC_MODEL=haiku。环境变量优先级比项目配置高,所以项目配置压根没生效。遇到这种问题,最快的方式是跑claude --debug,启动日志会打印最终生效的配置项。不要靠猜,看日志最直接。
4.3 Hooks 机制:在工具调用前后插入你的代码
Hooks 是 Claude Code 里最像"源码级扩展"的官方特性。它允许你在工具调用的前后、会话停止时、子代理结束时等生命周期节点上执行外部脚本。配置位置在settings.json的hooks字段,每个事件可以配置一个或多个命令。
PreToolUse是最常用的事件。脚本会收到一个 JSON 参数,里面包含tool_name、tool_input、session_id、prompt等。如果脚本往 stdout 输出{"decision": "block"},工具就不会执行;如果输出{"decision": "allow"},就直接放行。我做过一个内部安全插件:在PreToolUse里拦截所有 Bash 命令,检查命令字符串是否包含rm -rf,如果包含就把命令原文、工作目录、会话 ID 发到审计系统,并选择 block。效果相当于在闭源工具外面包了一层自己的安全审批层。这个特性特别适合企业环境,你在不碰 Claude Code 内部代码的情况下,也能实现相当强的管控。
5. 自己动手写一个极简 Claude Code:看开源项目怎么落地
5.1 开源替代品 opencode 的架构借鉴
如果你实在想看源码,我建议直接从开源替代品入手。opencode 是我目前见过和 Claude Code 设计最接近的开源实现,TypeScript 编写,仓库结构很清晰:cli/管入口参数,session/管会话持久化,tool/内置各类工具,provider/抽象模型接口,permission/实现权限引擎。你按照这个目录读一遍,再回头用 Claude Code,很多之前看不懂的配置项瞬间就通了。
它和 Claude Code 的核心差异在于:opencode 为了兼容多种模型,把 Provider 层做得更厚,所以你在它源码里看到的"模型路由"会比 Claude Code 的复杂得多。但这反而方便学习——你直接看一套完整实现,比对着闭源黑盒猜要高效得多。
5.2 极简主循环代码骨架
我把自己写的极简版主循环贴出来,这个骨架对标的就是 Claude Code 的核心闭环,去掉了大量边缘逻辑,只剩最重要的链路:
async function agentLoop({ provider, tools, messages, permission }) { for (let turn = 0; turn < maxTurns; turn++) { const res = await provider.chat({ messages, tools }); const text = extractText(res); const toolUses = extractToolUses(res); if (text) process.stdout.write(text); if (toolUses.length === 0) break; for (const toolUse of toolUses) { const tool = tools.find((t) => t.name === toolUse.name); if (!tool) continue; const verdict = await permission.check(toolUse); if (!verdict.allowed) { messages.push(toolBlockedResult(toolUse)); continue; } const output = await tool.execute(toolUse.input); messages.push(toolResultMessage(toolUse, output)); } } }这段代码看着简单,但它已经把三个关键机制都体现了:循环轮次控制、工具结果回填、权限闸门。你基于这个骨架做二次开发时,可以把permission.check换成内部审批接口,把tool.execute换成执行你的私有工具链,模型层换成任意兼容 OpenAI 或 Anthropic 格式的服务。我实际把这个骨架跑在了本地服务上,发现只要模型输出格式稳定,整个链路就能撑住日常对话式任务。
5.3 本地部署时的权限安全和模型兼容性
最后说说落地时最容易翻车的几个点。权限安全是第一位的,Bash 工具绝不能默认全放行。我的建议是默认"无 Bash 权限",只有通过白名单才允许执行特定前缀命令。模型兼容性上,建议做一个 Provider 适配层,内部统一消息格式,对外对接不同模型厂商;这样换模型只需改一份配置,不用动主循环代码。上下文管理上,一定要对长工具结果做截断或摘要,否则本地模型稍有上下文限制,跑几十轮后就开始"失忆"。会话持久化也很重要,把每次消息记录到 JSONL 文件,断点续跑和问题复盘都靠它。
我本地部署踩得最狠的坑就是上下文溢出。当时没做工具结果截断,一个find命令返回了一万多行文件路径,直接塞进 messages,下一轮模型就开始答非所问。后来在工具执行结果进入 messages 之前加了个压缩函数:超过 3000 字的部分用head和tail各取一段,中间标注"内容过长已省略",既保留关键信息又控制 token 消耗。加了这层之后,长时间会话稳定多了。
写到这里,我个人的体会是:与其纠结于拿不到 Claude Code 的完整源码,不如把它当作一个黑盒来侧写,再用开源项目对照验证。你真正需要的不是那几万行代码,而是对 Agent 主循环、工具系统、权限模型的理解。这套心智模型换到任何 AI 编码工具上都成立。最后再分享一个小技巧:每次 Claude Code 跑出奇怪结果时,先别急着抱怨,去~/.claude/和项目.claude/下翻一翻配置、日志和缓存会话记录,绝大多数问题在配置层和上下文层就能解释,根本不用看到源码。
本文还有配套的精品资源,点击获取