章节导航 第 3 章 / 共 23 章
启动流程与运行模式
从 main.tsx 加载到 REPL 渲染——四阶段初始化策略、三种运行模式分流、React + Ink 终端渲染管线
3.1 四阶段启动
Claude Code 的启动不是简单的”加载模块 → 开始执行”。它采用分层初始化策略,把启动过程拆分为四个严格有序的阶段:
阶段 1:早期配置加载
└── 解析命令行参数、加载用户配置
└── eagerLoadSettings()
阶段 2:入口点判断
└── 确定运行模式(CLI / MCP / SDK / GitHub Action)
└── initializeEntrypoint()
阶段 3:全局状态初始化
└── 遥测、权限、MCP 服务、迁移版本管理
└── init()
阶段 4:主循环启动
└── 交互式界面 或 无头执行
└── launchRepl() / runHeadless()
源码引用:启动流程分析来自源码分析知识库”应用启动流程 - 启动流程概述”和”入口点判断与配置加载 - 启动流程架构”,参考 main.tsx。
为什么要拆成四个阶段?因为每个阶段的产出是下一个阶段的前提:
- 配置不加载完,就不知道该走哪种运行模式
- 运行模式不确定,就不知道该初始化哪些服务
- 服务不初始化完,就不能启动主循环
这看起来理所当然,但很多项目在实践中并没有这么严格。它们会在启动过程中随处读取配置、随处初始化服务,导致启动顺序脆弱、难以调试。Claude Code 的四阶段设计确保了启动过程的确定性。
3.2 阶段 1:早期配置加载
main.tsx 是整个程序的入口。加载这个模块后,系统首先执行的是一系列”在做任何事之前必须做的事”:
安全防护
在解析任何命令行参数之前,Claude Code 先设置安全环境变量:
// main.tsx 中的安全防护(伪代码重构)
// 设置 PATH 为安全路径,防止路径劫持攻击
process.env.PATH = getSafePath();
// 禁止 Node.js 从不受信任的目录加载模块
process.env.NODE_PATH = '';
这一步防止的是路径劫持攻击——如果攻击者能在 PATH 中注入恶意目录,就可能替换系统命令(比如 git、grep)来窃取数据。在 CLI 工具中,这个威胁尤其真实,因为用户可能在任何目录下运行 Claude Code。
并行预取
启动性能是 CLI 工具的生命线。用户不会容忍一个启动要 5 秒的命令行工具。Claude Code 的做法是在配置加载阶段就并行启动几个耗时操作:
| 预取项 | 目的 | 节省时间 |
|---|---|---|
| MDM 进程预启动 | 移动设备管理(Ant 内部) | ~100ms |
| 钥匙串预取 | 预加载认证凭据 | ~100ms |
| 模块懒加载标记 | 标记哪些模块需要延迟加载 | 减少初始加载量 |
源码引用:并行预取策略参见 main.tsx 启动优化 和 startupProfiler.ts。
性能检查点
Claude Code 在启动过程的关键节点打了性能检查点(main_tsx_entry、init_start、repl_start 等),支持两种性能分析模式:
- 详细模式(
CLAUDE_CODE_PROFILE_STARTUP=1):生成完整的启动耗时报告 - 采样模式:Ant 用户 100% 采样,外部用户 0.5% 采样
这不是调试时的临时代码,而是生产级的性能可观测性基础设施。它说明 Anthropic 在持续监控和优化启动性能。
3.3 阶段 2:入口点判断
配置加载完成后,系统通过 initializeEntrypoint() 判断运行模式。判断依据是命令行参数和环境变量的组合:
// 入口点判断逻辑(简化表达)
if (args.includes('--mcp')) {
// MCP Server 模式
return startMcpServer(config);
}
if (process.env.CLAUDE_CODE_SDK || args.includes('--sdk')) {
// SDK 模式
return startSdkSession(config);
}
if (args.includes('--print') || !process.stdin.isTTY) {
// Headless 模式(非交互式)
return runHeadless(config);
}
// 默认:CLI 交互式 REPL 模式
return launchRepl(config);
三种模式的定位完全不同:
| 模式 | 入口文件 | 适用场景 | 交互方式 |
|---|---|---|---|
| CLI (REPL) | entrypoints/cli.tsx | 开发者在终端交互 | React + Ink 渲染的 TUI |
| MCP Server | entrypoints/mcp.ts | 被其他 MCP 客户端调用 | stdin/stdout、SSE、HTTP、WebSocket |
| SDK | entrypoints/agentSdkTypes.ts | 程序化集成 | API 调用 |
一个关键设计:所有模式共享同一个 QueryEngine。区别主要在入口壳(怎么接收输入、怎么呈现输出),核心的 Agent Loop 逻辑是同一套代码。⚠️ 但 v2.1.302 之后,“入口壳”不再只决定输入输出——它开始影响执行语义(详见 3.6 的同名段落)。这意味着:
- Bug 修复一次,三种模式一并受益
- 新增工具一次,三种模式一并可用
- 任何核心逻辑的 Bug 也会一并波及三种模式
这里需要先拆开一个被混用的概念。 本章到 3.6 为止列出的 CLI(REPL) / MCP Server / SDK / IDE Bridge / 浏览器旁路,回答的都是交互维度的问题——怎么输入输出。还有第二个维度是能力维度:加载哪些工具、读哪几层设置、权限上限在哪。v2.1.248(2026-08-27)新增的 --restricted(或 CLAUDE_CODE_RESTRICTED=1)属于后者:
Added
--restricted(orCLAUDE_CODE_RESTRICTED=1): removes the built-in tools that run commands or code andWebFetch(unless named in--tools), keeps file tools inside the working directory, refusesbypassPermissions, and ignores user, project and local settings files
它不与上表任何一行互斥——可以在 REPL 下受限运行,也可以在 SDK 或 MCP 模式下受限运行。把它记为第四个运行维度,含义是 Claude Code 从”面向单人开发者的 CLI”向”可被平台方以最小权限嵌入”演进:调用方能预先钉死能力边界,而不必信任被嵌入方的配置。第 7 章会展开它与权限模型的交叉。
还有第三个维度:预置维度。 --bare 在 v2.1.286 被重新定义(官方 changelog 逐字):
Changed
--bareto connect only the MCP servers named on the command line, send the model no system reminders, and start no background tasks; under--bare, a shell command that reaches its timeout now stops instead of moving to the background
它与 --restricted 正交:--restricted 减的是”能做哪些事”(能力维度),--bare 减的是”启动时预置了多少东西”(预置维度)——不连多余 MCP server、不发 system reminders、不起后台任务,连超时命令都不再转后台。两者可叠加,组合出的是四种而非两种启动形态。对嵌入方来说这很重要:“最小权限”和”最小预置”是两个不同的目标,前者防agent 做坏事,后者减少不可控的隐式状态。
后端选择:运行模式之外的第二个分流维度
运行模式决定了”怎么交互”,但还有一个维度决定了”用哪个 API 后端”。init() 阶段根据环境变量选择 API 服务后端:
先修正一个前提:托管设置的优先级高于环境变量。
下面这张表按环境变量逐行列出后端,隐含”设了哪个环境变量就用哪个后端”。2026-09 的两条破坏性变更推翻了这个前提:
v2.1.261(2026-09-04):托管设置固定
forceLoginMethod: "gateway"的机器会忽略遗留的 API key 或 claude.ai 登录,并要求/login。官方原文:Changed machines whose managed settings pin
forceLoginMethod: "gateway"to ignore a leftover API key or claude.ai login and ask for/login; Bedrock, Vertex AI, and Foundry sessions are unaffectedv2.1.265(2026-09-08):托管设置带
forceLoginGatewayUrl的机器从启动起即为 Claude apps gateway 会话(与forceLoginMethod: "gateway"同效),遗留的 claude.ai 登录或 API key 不再被使用。排障提示:企业用户遇到”明明设了
ANTHROPIC_API_KEY却被要求登录”时,先查托管设置(managed-settings.json)而不是环境变量。Bedrock / Vertex AI / Foundry 会话不受这两条影响。
“托管设置能钉死什么”——2026-09 ~ 10 的六次出现,值得合并看。 上面两条只是这条原则的前两例。同一个季度里它又出现了四次,而且钉死的对象从”怎么登录”扩展到了”用哪家 provider、用哪个模型、多高 effort”:
| 托管设置 | 版本 | 钉死的是什么 | 覆盖范围 |
|---|---|---|---|
forceLoginMethod: "gateway" | v2.1.261 | 忽略遗留 API key / claude.ai 登录,强制 /login | Bedrock / Vertex / Foundry 不受影响 |
forceLoginGatewayUrl | v2.1.265 | 从启动起即为 Claude apps gateway 会话(与 forceLoginMethod: "gateway" 同效) | 同上 |
maxEffortLevel | v2.1.267 | effort 等级天花板(top-level 或 modelSettings 下按模型设);用户仍可选更低等级,但不能越过天花板 | 含 Bedrock / Vertex / Foundry 在内的所有 provider |
availableModelsMatch: "exact" | v2.1.283 | availableModels 条目只允许它点名的那个模型版本 | 全部 |
deniedModels | v2.1.283 | 即使 availableModels 允许,也可单独封禁特定模型 | 全部 |
allowedProviders | v2.1.285 | 能用哪家 API provider(官方 changelog 枚举八项:Anthropic API、custom endpoint、Bedrock、Mantle、Vertex AI、Foundry、Claude Platform on AWS、Cloud gateway) | 全部 |
⚠️ 最后两行有一个反直觉后果:开启 availableModelsMatch: "exact" 后,“升级到最新版就会用上最新模型”这个直觉在企业环境里不成立——新模型发布默认是被阻断的,直到管理员把它显式列进 availableModels。
把六行连起来读,本节的结论就比”托管设置优先级更高”更具体了:从认证方式 → 用哪家 provider → 哪个模型 → 哪个模型版本 → 多高 effort,整条链现在每一环都可以被平台方钉死,而且后四条(v2.1.267 / 283 / 285)的覆盖范围都是全部 provider,不再给 Bedrock / Vertex / Foundry 留例外。
📌 allowedProviders(v2.1.285)是这条链的最上游,这一点决定了它的权重:provider 决定可选模型集合,模型决定 effort 的可选项。钉在链的上游,等于一次性收窄了下游所有可选项——这也是为什么它值得单独记,而不只是”多了一个可钉死的键”。
⚠️ 同族还有一个本章此前没有的键:v2.1.284 起 Claude apps gateway 的启动告警引入了 enforceAvailableModels(官方 changelog 逐字:当托管策略的 availableModels 为空、或漏掉了 Claude Code 启动时用的模型且未设置 model 或 enforceAvailableModels 时发出告警)。它与 availableModelsMatch: "exact" 是两个不同的键——后者的定义见 v2.1.283,前者本轮只在告警语境里见到,未找到其独立定义条目,不得与 availableModelsMatch 混为一谈(详见本节末尾”待回源”)。
| 环境变量 | 后端 | 默认模型 | Auto 模式 | 说明 |
|---|---|---|---|---|
ANTHROPIC_API_KEY | Anthropic Direct | Claude Sonnet 5(v2.1.197+);Claude Opus 5.5(claude-opus-5-5,v2.1.280+,1M 上下文,$4/$20 per Mtok,cache reads $0.20/Mtok,Fast mode $8/$40);Claude Opus 5(v2.1.219+,上一代);Claude Fable 5.1(v2.1.257+,默认 Fable 模型,1M 上下文) | 默认开启(可 /effort 调整);v2.1.278 起 Claude API / Enterprise 及 Bedrock / Vertex / Foundry / gateway 默认走服务端分类器,且不计 classifier 开销;后四者可用 CLAUDE_CODE_AUTO_MODE_SERVER=0 退出;/status 新增 “Auto mode server” 行 | 直连 Anthropic API;Fast mode 现覆盖 Opus 5.5($8/$40,最高 2.5×)与 Opus 4.8,Opus 4.7 已退出 Fast mode;v2.1.271 起 Claude Code Remote 会话(cloud 与 self-hosted runners)也支持 fast mode,由宿主机的 fast-mode 设置或会话内 /fast 决定,需组织允许 |
AWS_PROFILE / CLAUDE_CODE_USE_BEDROCK=1 | Amazon Bedrock | Claude Opus 4.8(v2.1.207+) | v2.1.207+ 默认开启(可通过 disableAutoMode 关闭) | |
CLAUDE_CODE_USE_VERTEX=1 | Google Vertex AI | Claude Opus 4.8(v2.1.207+) | v2.1.207+ 默认开启 | |
CLAUDE_CODE_USE_MANTLE=1 | Amazon Bedrock (Mantle) | Claude Opus 4.8(v2.1.207+);v2.1.287 起 Opus 4.7+ 与 Fable 在这些后端默认 1M 且无 [1m] 后缀 | 待确认 | v2.1.94 新增,Bedrock 的简化接入路径 |
| 企业配置 | Azure / Foundry | 企业配置决定 | 待确认 | 企业部署场景 |
⚠️ Opus 4.1 已于 2026-08-05 退役(请求报错而非警告)——该日期已过,此为既成事实而非预告(快照 2026-09-27)。
后端选择不影响 Agent Loop 的行为(模型调用仍然走统一的 API 服务层),但影响初始化路径——不同后端的认证流程、Token 计费方式、可用模型列表各不相同——且”可用模型列表”在 v2.1.283 之后本身也由托管设置决定,“可用 provider”在 v2.1.285 之后同样由托管设置决定(allowedProviders,八个取值;见 3.3 的六次出现表)。这种”入口层隔离后端差异”的设计确保了核心逻辑的后端无关性——⚠️ 但”后端无关”指的是 Agent Loop 代码路径无关,默认模型与默认上下文窗口这两样是后端相关的,见下。
v2.1.287 把”默认上下文窗口”也变成了后端相关量。 官方 changelog 逐字:
Changed Opus 4.7+ and Fable to use a 1M context window by default on Bedrock, Vertex, Foundry and the Claude apps gateway, with no
[1m]suffix (CLAUDE_CODE_DISABLE_1M_CONTEXT=1keeps 200K)
⚠️ 官方只说了 Opus 4.7+ 与 Fable,不含 Sonnet——不要写成”所有模型在这些后端默认 1M”。这条同时说明 [1m] 这个后缀此前是选择 1M 的标记,现在 1M 成了默认,后缀随之消失;CLAUDE_CODE_DISABLE_1M_CONTEXT=1 可退回 200K(v2.1.223 起该变量通过 auto-compaction 把所有原生 1M 模型压到 200K,而非只针对固定列表)。
Anthropic Direct 的默认模型线在 2026-09 ~ 10 推进了两代:Sonnet 5.5(claude-sonnet-5-5,v2.1.284+,1M,$2/$10,cache reads 公告 $0.20、v2.1.296 起计价 $0.10)取代 Sonnet 5 成为默认;Haiku 5.5(claude-haiku-5-5,v2.1.293+,1M,$0.10/$0.50,prompts over 100K 为 $0.50/$2.50)成为默认 Haiku 线——后者是全书第一个按提示长度分段计价的默认模型。
⚡ 行为变更(v2.1.94+):对于 API Key / Bedrock / Vertex / Foundry / Team / Enterprise 用户,默认 effort 等级从
medium调整至high(Pro/Max 用户不受影响,之前已为 high)。可通过/effort low/medium/high/xhigh手动控制。背景:社区反馈 medium 下 Claude 表现被认为”敷衍”(GitHub issue #30726)。⚠️ “可自由选到 xhigh”这个前提在 v2.1.267 之后不再无条件成立:新增
maxEffortLevel设置(top-level,或在modelSettings下按模型设),为 effort 等级设天花板,覆盖包括 Bedrock、Vertex、Foundry 在内的所有 provider;用户仍可选更低等级,但不能越过天花板。官方原文:caps the effort level on every provider, including Bedrock, Vertex and Foundry; users can still pick a lower level。
effort 之外,还有一层此前没人记的:判定”要不要批准”的那个分类器,自己也有模型策略。 auto mode 分类器本身就是一次模型调用,它用哪个模型现在是独立可配的:
- v2.1.302 新增
CLAUDE_CODE_AUTO_MODE_MODEL,指定客户端 auto mode 分类器使用的模型(官方 changelog 逐字:“it does not change the model for server-side auto mode”)。 - v2.1.288 客户端分类器会主动降级:官方 changelog 逐字 “Changed the client-side auto mode classifier to ignore an
ANTHROPIC_DEFAULT_SONNET_MODELpin that names Claude Sonnet 5.5 or Opus 5.5 and use Claude Sonnet 5 instead”——即你 pin 了 Sonnet 5.5,分类器仍会退回 Sonnet 5。
合起来的含义:分类器有自己的模型策略,不跟随会话模型。本章”effort 可被封顶”那条成立之后,还要加一句——连判定要不要批准的那个模型也是可配的、且会自己降级。⚠️ 这与 v2.1.278「auto mode 分类器默认走服务端且不计费 classifier 开销」(见 Ch01 第 11 条)是两条不同的线:v2.1.302 的这条明确只作用于客户端分类器。
3.4 阶段 3:全局状态初始化
init() 函数是启动流程中最重的一步。它负责建立整个运行时环境:
// init() 的主要职责(简化)
async function init() {
// 1. 创建全局 STATE 对象
STATE.projectPath = resolveProjectPath(cwd);
STATE.telemetry = initTelemetry();
// 2. 版本迁移(确保数据结构向后兼容)
await runMigrations(CURRENT_MIGRATION_VERSION);
// 3. 初始化权限系统
await loadPermissionRules();
// 4. 初始化 MCP 客户端
// ⚠️ v2.1.274 起,非交互模式下该等待由
// CLAUDE_CODE_MCP_STARTUP_WAIT_MS 设上界(0 = 完全不等)
await initMcpClients(config.mcpServers);
// 5. 加载工具池
const tools = await assembleToolPool();
// 6. 启动遥测
startTelemetryReporting();
}
其中版本迁移是一个有趣的设计。Claude Code 在本地维护了一个迁移版本号(CURRENT_MIGRATION_VERSION),每次启动时检查用户本地的数据结构版本,如果落后就自动执行迁移脚本。这和数据库迁移的思路完全一样,但应用在了一个 CLI 工具上——说明 Claude Code 的本地状态足够复杂,需要结构化的迁移策略。
子代理模型的解析链与一次三段式语义翻转:init() 阶段还要确定子代理用哪个模型,这条链路在 2026-08 至 09 之间翻转过一次,是理解第 8 章多 Agent 的前提:
| 阶段 | 版本 | CLAUDE_CODE_SUBAGENT_MODEL 的语义 |
|---|---|---|
| 强覆盖 | v2.1.251 之前 | 覆盖一切子代理模型选择 |
| 默认值 | v2.1.251(2026-08-28,破坏性变更) | 仅设默认子代理模型;代理定义的 model: 与每次派生的显式模型优先于它 |
| 显式强制 | v2.1.257(2026-09-01) | 新增 CLAUDE_CODE_SUBAGENT_MODEL_FORCE,把 CLAUDE_CODE_SUBAGENT_MODEL(或主模型)应用到每个子代理,忽略派生与定义的覆盖 |
v2.1.251 的官方原文:
Changed
CLAUDE_CODE_SUBAGENT_MODELto set the default subagent model rather than override everything: an agent definition’smodel:and an explicit per-spawn model now take precedence over it
这次翻转的实际影响是:同一个环境变量在升级前后会产生完全不同的子代理模型分配结果。把”用环境变量统一钉死所有子代理”当生产约束的团队,需要迁移到 _FORCE 变体,否则 v2.1.251 之后该约束会静默失效——代理定义里的 model: 会重新生效。
后台 agent 的可靠性挑战:v2.1.200(2026-07-03)修复了一个 OS 级别的边缘 case——当后台 agent daemon 崩溃后,残留的 daemon.lock 文件中记录的旧 PID 可能被 OS 随机复用给其他进程,导致新 daemon 误判为’已有实例在运行’而拒绝启动。修复方案:增加进程特征深度双重审计,不再仅依赖 PID 匹配。这揭示了 long-running agent 系统的一个底层挑战:CLI 工具不仅要处理自己的状态,还要防御 OS 的资源竞争(PID 复用、休眠唤醒、信号处理)。
3.5 阶段 4:REPL 启动与渲染
如果运行模式是 CLI(最常见的情况),系统进入 REPL 启动阶段。这里 Claude Code 做了一件不寻常的事——用 React 渲染终端 UI。
React + Ink:终端里的 React
Ink 是一个将 React 组件渲染到终端的框架。它的原理是:
- 开发者用 JSX 编写终端 UI 组件
- Ink 把 React 的虚拟 DOM 渲染为 ANSI 转义序列
- 终端解释这些转义序列,显示格式化的文本
// Ink 组件示例(概念性)
const StatusBar = () => {
const [model, setModel] = useState('claude-sonnet');
const [tokens, setTokens] = useState(0);
return (
<Box borderStyle="round">
<Text color="cyan">Model: {model}</Text>
<Text color="green"> | Tokens: {tokens}</Text>
</Box>
);
};
但 Claude Code 并没有简单地使用 Ink。src/ink/ 目录有 96 个文件、近 2 万行代码——这是对 Ink 框架的大量内部改造。社区逆向分析揭示了几项关键改造:
- 双缓冲渲染:先在内存中完成全部更新,再一次性输出到终端,避免逐行刷新导致的闪烁
- NO_FLICKER 模式(v2.1.89+):进一步优化高频更新场景的渲染稳定性
- Focus View(v2.1.97+):通过
Ctrl+O切换,提供 prompt / tool summary with diffstats / 最终响应三视图,适配 no_flicker 模式 - 帧率控制:在工具密集调用期间自动降低渲染频率,避免终端 I/O 成为瓶颈
- 自定义 Yoga 布局:针对终端场景调整 Yoga 布局引擎参数(代码高亮、diff 展示、表格)
- 输入处理:vim 模式、快捷键绑定
- 响应式布局:适配不同终端宽度
REPL.tsx:5,980 行的主界面
screens/REPL.tsx 是交互式主界面的入口组件。它不只是一个”输入框 + 输出区”,而是集成了:
- 会话管理:历史消息、会话恢复、上下文压缩
- 权限控制:工具调用前的权限确认、Trust Dialog
- 远程连接:Bridge 模式下与 IDE 的通信
- 输入处理:多行输入、文件拖拽、粘贴检测
- 状态展示:Token 用量、模型信息、速率限制
这个组件的复杂度解释了为什么 Claude Code 选择了 React 而不是传统的终端 UI 方案——当 UI 状态足够复杂时,声明式渲染和组件化的优势开始显现。readline 能做一个交互式提示符,但做不了这种级别的复杂 UI。
3.6 MCP Server 模式与 SDK/Bridge
除了 CLI REPL,Claude Code 还支持两种非交互模式:
MCP Server 模式:Claude Code 作为标准的 MCP 服务器运行,将 42+ 内置工具暴露为 MCP 工具。任何 MCP 客户端都可以调用它们——这意味着你可以把 Claude Code 作为”工具服务器”集成到其他 AI 系统中。支持 6 种传输方式(stdio、SSE、HTTP、WebSocket 等),完整分析见第 10 章。
SDK 模式:面向程序化集成,外部程序可以创建会话、发送消息、控制工具审批、获取结构化结果。
IDE Bridge:通过 JWT 认证的双向通信,让 VS Code / JetBrains 扩展与 Claude Code REPL 交互。src/bridge/ 目录(31 个文件,12,613 行)实现了完整的 Bridge 服务。
三种模式的关键共性:它们都共享同一个 QueryEngine。区别主要在入口壳(怎么接收输入、怎么呈现输出),核心的 Agent Loop 逻辑是同一套代码。
🔴 2026-10-17 限定:v2.1.302 之后,入口壳的差异第一次渗进了执行语义。 原论断(“区别只在入口壳”)在 v2.1.302 之前成立,此后需要加一句”但入口壳不再只决定输入输出”:
- 默认权限模式按入口 + provider + 遥测状态分叉。 官方 changelog 逐字:“Changed
claude -pand Agent SDK sessions with no permission mode to start indefaultmode on third-party providers, with telemetry off or on a fresh install;--permission-mode autokeeps auto.” 即同一个未指定权限模式的参数,在终端与在-p/ SDK 下会得到不同的默认值。⚠️ 触发条件的结构是”(入口 =claude -p或 Agent SDK)∧(未指定权限模式)∧(第三方 provider)∧(遥测关闭 ∨ 全新安装)“——四项合取,只有最后一项内部是析取。 - 子代理的执行位置按入口分叉。 官方 changelog 逐字:“Changed fork subagents (
subagent_type: "fork") to be on by default inclaude -p, the Agent SDK, the desktop app and VS Code, as they already are in the terminal;CLAUDE_CODE_FORK_SUBAGENT=0turns them off, andclaude mcp servenever offers them.” 桌面与 VS Code 的主会话子代理改为强制后台运行(不再由 Claude 选),而子代理自己的Agent调用在-p/ SDK / 桌面 / VS Code 中默认前台。⚠️claude mcp serve永不提供 fork subagent 是官方陈述的事实,官方未给理由,本书不推测。
对本轮论断的修正写法:入口壳决定”怎么输入输出”以及”默认权限模式”与”子代理跑在前台还是后台”。共享 QueryEngine 依然成立,但共享的是循环,不是策略。
沙箱内建浏览器(v2.1.202+,Week 28 GA):桌面端 Claude Code 新增了一种特殊的交互旁路——它不改变运行模式,但在 CLI REPL 会话中提供了一个并行信息通道。浏览器运行在隔离的沙箱 profile 中(与用户个人凭据和历史记录隔离),安全性由分类器审查外部操作。与 MCP 工具不同,浏览器是 first-party 集成——不经过工具注册、不经 partitionToolCalls 调度。从架构视角,它更像是 REPL UI 层的一个新的输入/输出源(类似附件上传、图片粘贴),而非独立的运行模式。Cmd+Shift+B 快捷键打开。支持网站登录(含 Google OAuth 弹窗)使 Claude 可测试需要认证的 web 应用。
Chrome DevTools MCP:第二条浏览器接入路径:与 Claude in Chrome 的 first-party 集成形成架构对立的,是 Google 官方提供的 Chrome DevTools MCP——走标准 MCP 工具注册路径(claude mcp add chrome-devtools npx chrome-devtools-mcp@latest),提供 26 个工具(控制台调试、网络检查、性能分析含 Core Web Vitals、DOM 快照和截图、设备模拟),免费、所有 Claude Code 用户可用。两种路径互补:Claude in Chrome 适合认证工作流和快速可视化验证,Chrome DevTools MCP 适合深度调试和性能分析。这一架构对立——first-party UI 层集成 vs 标准 MCP 工具管线——体现了 Claude Code 在浏览器能力上的”双轨”策略。
⚡ MCP 2026-07-28 正式发布:无状态核心与扩展框架
MCP 2026-07-28 正式发布(2026-07-28):涵盖 21+ SEP,五大支柱:
- Stateless core(SEP-2575/SEP-2567):移除 initialize 握手和
Mcp-Session-Id,协议版本/client info/capabilities 在_meta中随请求传递 - Operability layer(SEP-2243/SEP-2549/SEP-414):强制
Mcp-Method/Mcp-Name头(网关可在头级别路由),ttlMs/cacheScope缓存控制,W3C Trace Context 传播 - Extensions framework:MCP Apps(SEP-1865,server-rendered UI)、Tasks 扩展
- Auth hardening:6 SEPs 对齐 OAuth 2.1 和 OpenID Connect
- Deprecation policy(SEP-2596):至少 12 个月迁移窗口,Roots/Sampling/Logging 被标记 deprecated
对 Claude Code 的影响:
- 本地 STDIO 用户:基本不受影响,本地通信不依赖 session 概念
- MCP Server 模式的远程连接:连接管理已从”有状态会话”转为”无状态请求”,远程 MCP 客户端需适配新的头字段和缓存语义
- MCP Tunnels(研究预览):提供到私有网络 MCP 服务器的安全加密连接,避免公网暴露
- Self-hosted Sandboxes(公开 beta):允许工具执行在用户自有基础设施中
- JSON Schema 2020-12 强制要求:工具 Schema 验证更严格,需 Zod→JSON Schema 双向转换
- Enterprise Managed Authorization (EMA):Okta/Entra 等企业 IdP 作为统一门禁,Claude 等产品实现 zero-touch 连接器配置
- 12 个月弃用政策:首次写入规范(SEP-2596),Roots/Sampling/Logging 被标记 deprecated
2026-09 的三条后续落地(发布两个月后补进来的能力,都不在 2026-07-28 的七条影响里):
- URL-mode elicitation(v2.1.281):在 2026-07-28 协议连接上,MCP server 可以反向要求 Claude Code 打开一个基于浏览器的流程(OAuth 等);若 server 无法确认完成,屏幕上不会留下等待对话框。这条值得单独记一笔:无状态核心(上面第 1 条)去掉了握手,但 server 侧反而获得了一个反向交互通道——“无状态”不等于”单向”。
claude plugin validate新增 MCP 检查(v2.1.281):会报出加载时会被静默丢弃的.mcp.json条目、未声明的${user_config.*}引用、以及不安全的 URL。“静默丢弃”这四个字与本章第 208 行”约束静默失效”是同一个失败模式:你以为生效的配置,其实从没被读进去——只是这次有了官方的检查器。- MCP 工具描述与 server 指令的长度配额(v2.1.280):默认 2,048 字符/server,
CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH可改,会话级对所有 server 生效(第 2 章 2.5 节的”体积三面”里,这一面属于上下文体积)。
MCP 2026-07-28 的正式发布标志着协议从”实验性标准”升级为”生产级协议”。无状态核心使 MCP Server 可部署在 Serverless/Edge 平台——从架构上消除了 sticky sessions 的运维负担。Tier 1 SDK(TypeScript/Python/Go/C#)正式版同步发布,SDK 月下载近 5 亿次。Google Cloud、Cloudflare、Netlify 宣布 Day Zero 支持,Figma/Intuit/Netlify/PostHog/Xero/Zoom 公开背书。
2026-06-29:Python v2 / TypeScript v2 / Go / C# 四个 Tier 1 SDK beta 发布——支持 stateless core + MRTR + JSON Schema 2020-12 测试。这是 7 月 28 日正式发布前最后一个重大里程碑。如果您正在评估 MCP 迁移影响,现在可以对照 beta SDK 测试实际工作负载。
Dynamic Workflows:运行时内的第四种执行维度
2026 年 5 月与 Opus 4.8 同日上线的 Dynamic Workflows 不是一种独立的入口模式,而是在 CLI REPL 模式内触发的脚本编排执行路径。它的触发条件是 prompt 中包含”workflow”关键词,或使用 /effort ultracode 模式。
CLI REPL 模式(主入口)
└── prompt 包含 "workflow" 或 ultracode 模式
└── Claude 生成 JavaScript 编排脚本
├── 脚本调度数十至数百个并行子Agent(总数;并发峰值另受下文的并发上限约束)
├── 子Agent 在 acceptEdits 模式下运行
├── 编排逻辑在对话上下文外(脚本变量)
└── 主会话保持响应,中间结果不回填上下文
这是”同入口、不同执行策略”的运行时分叉——主循环仍是 QueryEngine 的 while 循环,但编排逻辑移入了脚本运行时,与主循环完全解耦。约束:默认 16 个并发 Agent(v2.1.269 起可通过 CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS 在 1–256 区间上调,官方定位为 inference-bound fan-outs)、1000 个总 Agent 上限;脚本自身不能访问文件系统或 Shell,只能通过子Agent 间接执行。
2026-07-02 GA 更新:Dynamic Workflows 正式 GA 并下放至 Pro 计划($20/月)。GA 明确了三个核心原语:pipeline()(顺序流水线,前一个的输出作为后一个的输入)、parallel()(并发扇出,默认 16 个并发 Agent,同上可调)、agent()(单任务子 Agent)+ phase()(分阶段进度追踪)。标杆案例为 Bun JavaScript 运行时从 Zig 到 Rust 的移植——96 万行代码、6 天完成、现有测试套件通过率 99.8%——验证了 Dynamic Workflows 在极端规模的代码迁移场景下的工程可行性。
📌 阅读提醒:本章写死的编排常量,请一律按”当前默认值 + 可调区间 + 调整所需版本”三要素来读。 本章已经出现过两次同一个故事——第 208 行的 CLAUDE_CODE_SUBAGENT_MODEL 从”强覆盖”翻转成”默认值”,把”用环境变量统一钉死所有子代理”当生产约束的团队会遇到约束静默失效;这里的”16 个并发”是第二次:一个曾经可以当生产约束的常量变成了一个可调参数。两者的教训一致——不要把本章的快照当成契约,尤其是那些看起来像硬上限的数字。反过来,第 164 行的 maxEffortLevel 与上面托管设置表里的 availableModelsMatch 说明趋势是双向的:常量在变成参数,可被平台方钉死的东西也在变多。
3.7 启动性能优化策略总结
把所有的启动优化手段汇总:
| 策略 | 实现方式 | 效果 |
|---|---|---|
| 并行预取 | MDM、钥匙串与模块加载并行 | 节省 ~200ms |
| 动态模块加载 | Feature Flag 控制条件导入 | 减少初始加载量 |
| 工具延迟加载 | shouldDefer 标记 + ToolSearch 激活 | 按需加载非核心工具 |
| 单例模式 | REPL 原始工具采用单例 | 避免重复实例化 |
| 性能检查点 | 关键节点插桩 + 采样上报 | 持续监控优化 |
| 渐进式 UI | 先渲染骨架再填充数据 | 感知速度提升 |
| Native 安装 | claude install 生成原生可执行文件(v2.1.90+) | 规避 Node.js 冷启动开销 |
| 关键路径外移 | 沙箱与 MCP bring-up 不再阻塞首帧,裸启动跳过子命令注册,workflow 发现、设置与 trust-store 开销降低(v2.1.243+) | 首帧渲染不等沙箱/MCP 就绪 |
| 外部依赖提前取回 | Team/Enterprise 组织的策略与托管设置更早拉取,停滞请求 3 秒后重试(v2.1.293+) | 外部依赖不再在启动后变成新的等待点 |
新增的第九行需要和前三行区分开。并行预取是在同一段时间里做更多事,延迟加载是把工作推迟到真正用到时,关键路径外移则是把工作移出”用户在等的那个点”——它并没有消失,只是允许在首帧出现之后继续跑。外部依赖提前取回是第四类,方向与”关键路径外移”相反:关键路径外移是把工作移出等待点,这条是把原本可能迟到的外部依赖提前取回,避免它之后变成阻塞点。四类的判别问题是——并行预取:同一段时间里做更多事?延迟加载:推到用到时?关键路径外移:移出等待点?提前取回:防止它后来成为等待点。(“第四类”的归类是本书记述,非官方分类。)
另有三个可引用的小数据点:headless/SDK 会话在 MCP 服务器完成连接后不再无谓等待,首轮开始时间最多提前 50 ms(v2.1.259);v2.1.274 把这段等待变成了一个你能定的量——CLAUDE_CODE_MCP_STARTUP_WAIT_MS 为首个非交互轮次等待 MCP 连接的时长设上界,0 表示完全不等。v2.1.259 是把等待变短,v2.1.274 是把等待变成可调参数,headless/SDK 场景可以换来确定性的首轮时间;--worktree 在大仓库上的启动改为新 worktree 并行 checkout,需要 git 2.32+(v2.1.265)。
两条运维向的补充:v2.1.273 起,MCP server 中途断开且自动重连最终放弃时,会收到通知并指向 /mcp(此前是静默失败);v2.1.274 修了一个协议适配坑——配置为 http 但实际只支持 legacy HTTP+SSE 的服务器,在首个请求返回 422 时会连接失败。
一个 CLI 工具在启动性能上投入这么多工程努力,足以说明 Anthropic 对用户体验的重视程度。毕竟,如果每次敲 claude 都要等 3 秒才能开始输入,再强大的功能也会被弃用。
⚡ Mid-conversation System Messages:不破坏 Prompt Cache 的系统指令插入
Opus 4.8 支持在 user turn 之后发送 role: "system" 消息(遵循放置规则),保持 prompt cache 命中。无需 beta header。这对 Claude Code 的 System Prompt 动态构建系统有直接影响——除了”静态部分 + 动态部分”的边界分离(SYSTEM_PROMPT_DYNAMIC_BOUNDARY 标记)之外,现在有了第三种动态调整系统指令的路径:在长会话中动态插入系统指令而不需要重建整个 prompt cache。此能力仅限 Opus 4.8+,且需遵循 Anthropic 规定的放置规则。
Sonnet 5 例外(v2.1.201,2026-07-03):v2.1.201 在 Claude Sonnet 5 会话中移除了 mid-conversation system role 的 harness 提醒。原因是 Sonnet 5 的指令遵循能力足以在标准 user/assistant 消息中完成上下文调整,system role 注入反而引入了不必要的推理干扰。这并不意味着 mid-conversation system message 能力本身被废弃(Opus 4.8 仍支持),但说明 Anthropic 在实践中发现:对于足够强的模型,‘第三种动态调整路径’的收益低于其带来的 prompt 复杂度。
反向开关:--system-prompt-snapshot off(v2.1.267,2026-09-09)。前面所有能力都在想办法保住 prompt cache——静态/动态边界分离、SYSTEM_PROMPT_DYNAMIC_BOUNDARY 标记、mid-conversation system message 的放置规则,目的都是别让缓存失效。这个开关反着来:官方原文 render the system prompt fresh on every request instead of reusing the conversation's recorded prompt (for iterating on prompt text)——每次请求都重新渲染系统提示,不再复用会话已记录的提示。代价是丢掉 cache 命中,收益是改提示文本时不用重开会话。
这是本章”缓存 vs 灵活性”张力最直白的一次产品化:Anthropic 没有把”必须复用”写成唯一正确解,而是把选择权做成一个开关。判断依据也很清楚——迭代提示文本时,重开会话的成本高于丢缓存的成本;正常使用时则相反。
至此,全局视角的三章完成。我们知道了 Claude Code 是什么(第 1 章)、由什么组成(第 2 章)、如何启动(第 3 章)。接下来进入核心引擎——从 Agent Loop 开始,理解这个系统的”思考方式”。