第 3 章 第一部分:全局视角

启动流程与运行模式

从 main.tsx 加载到 REPL 渲染——四阶段初始化策略、三种运行模式分流、React + Ink 终端渲染管线

Claude Code 启动流程 REPL MCP SDK 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 Serverentrypoints/mcp.ts被其他 MCP 客户端调用stdin/stdout、SSE、HTTP、WebSocket
SDKentrypoints/agentSdkTypes.ts程序化集成API 调用

源码引用:运行模式说明来自源码分析知识库”项目概述 - 运行模式说明”,引用 cli.tsx、mcp.ts。

一个关键设计:所有模式共享同一个 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 (or CLAUDE_CODE_RESTRICTED=1): removes the built-in tools that run commands or code and WebFetch (unless named in --tools), keeps file tools inside the working directory, refuses bypassPermissions, and ignores user, project and local settings files

它不与上表任何一行互斥——可以在 REPL 下受限运行,也可以在 SDK 或 MCP 模式下受限运行。把它记为第四个运行维度,含义是 Claude Code 从”面向单人开发者的 CLI”向”可被平台方以最小权限嵌入”演进:调用方能预先钉死能力边界,而不必信任被嵌入方的配置。第 7 章会展开它与权限模型的交叉。

还有第三个维度:预置维度。 --bare 在 v2.1.286 被重新定义(官方 changelog 逐字):

Changed --bare to 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 unaffected

  • v2.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 登录,强制 /loginBedrock / Vertex / Foundry 不受影响
forceLoginGatewayUrlv2.1.265从启动起即为 Claude apps gateway 会话(与 forceLoginMethod: "gateway" 同效)同上
maxEffortLevelv2.1.267effort 等级天花板(top-level 或 modelSettings 下按模型设);用户仍可选更低等级,但不能越过天花板含 Bedrock / Vertex / Foundry 在内的所有 provider
availableModelsMatch: "exact"v2.1.283availableModels 条目只允许它点名的那个模型版本全部
deniedModelsv2.1.283即使 availableModels 允许,也可单独封禁特定模型全部
allowedProvidersv2.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_KEYAnthropic DirectClaude 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=1Amazon BedrockClaude Opus 4.8(v2.1.207+)v2.1.207+ 默认开启(可通过 disableAutoMode 关闭)
CLAUDE_CODE_USE_VERTEX=1Google Vertex AIClaude Opus 4.8(v2.1.207+)v2.1.207+ 默认开启
CLAUDE_CODE_USE_MANTLE=1Amazon 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=1 keeps 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_MODEL pin 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_MODEL to set the default subagent model rather than override everything: an agent definition’s model: 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 组件渲染到终端的框架。它的原理是:

  1. 开发者用 JSX 编写终端 UI 组件
  2. Ink 把 React 的虚拟 DOM 渲染为 ANSI 转义序列
  3. 终端解释这些转义序列,显示格式化的文本
// 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 之前成立,此后需要加一句”但入口壳不再只决定输入输出”:

  1. 默认权限模式按入口 + provider + 遥测状态分叉。 官方 changelog 逐字:“Changed claude -p and Agent SDK sessions with no permission mode to start in default mode on third-party providers, with telemetry off or on a fresh install; --permission-mode auto keeps auto.” 即同一个未指定权限模式的参数,在终端与在 -p / SDK 下会得到不同的默认值。⚠️ 触发条件的结构是”(入口 = claude -p 或 Agent SDK)∧(未指定权限模式)∧(第三方 provider)∧(遥测关闭 ∨ 全新安装)“——四项合取,只有最后一项内部是析取。
  2. 子代理的执行位置按入口分叉。 官方 changelog 逐字:“Changed fork subagents (subagent_type: "fork") to be on by default in claude -p, the Agent SDK, the desktop app and VS Code, as they already are in the terminal; CLAUDE_CODE_FORK_SUBAGENT=0 turns them off, and claude mcp serve never 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,五大支柱:

  1. Stateless core(SEP-2575/SEP-2567):移除 initialize 握手和 Mcp-Session-Id,协议版本/client info/capabilities 在 _meta 中随请求传递
  2. Operability layer(SEP-2243/SEP-2549/SEP-414):强制 Mcp-Method/Mcp-Name 头(网关可在头级别路由),ttlMs/cacheScope 缓存控制,W3C Trace Context 传播
  3. Extensions framework:MCP Apps(SEP-1865,server-rendered UI)、Tasks 扩展
  4. Auth hardening:6 SEPs 对齐 OAuth 2.1 和 OpenID Connect
  5. 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 的七条影响里):

  1. URL-mode elicitation(v2.1.281):在 2026-07-28 协议连接上,MCP server 可以反向要求 Claude Code 打开一个基于浏览器的流程(OAuth 等);若 server 无法确认完成,屏幕上不会留下等待对话框。这条值得单独记一笔:无状态核心(上面第 1 条)去掉了握手,但 server 侧反而获得了一个反向交互通道——“无状态”不等于”单向”。
  2. claude plugin validate 新增 MCP 检查(v2.1.281):会报出加载时会被静默丢弃的 .mcp.json 条目、未声明的 ${user_config.*} 引用、以及不安全的 URL。“静默丢弃”这四个字与本章第 208 行”约束静默失效”是同一个失败模式:你以为生效的配置,其实从没被读进去——只是这次有了官方的检查器。
  3. 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 开始,理解这个系统的”思考方式”。