启动与运行时
从真实启动入口到模型主循环:main.tsx 的总调度、init 的安全与遥测边界、setup 的会话准备、context 的上下文装配、query 的可恢复状态机。
1. 启动入口:src/main.tsx#
src/main.tsx 是启动入口。文件开头特意安排了一组必须最先执行的 side effect:
profileCheckpoint('main_tsx_entry'):在重模块加载前记录启动 profiler 点。startMdmRawRead():提前并行触发 MDM 配置读取。startKeychainPrefetch():提前并行读取 macOS keychain 中的 OAuth 与 legacy API key。
这些操作说明启动路径已经被认真优化:慢 I/O 被尽量提前、并行化,并从真正渲染路径里挪走。
main.tsx 后面承担的是“总调度器”职责,而不是单纯渲染 UI。它要处理:
- Commander 参数定义与早期 argv 预处理;
-p/--print、--sdk-url、interactive、assistant、bridge、remote、resume、teleport、worktree 等模式分流;- 顶层 CLI 还有
gateway、import、sandbox、project、prune、agents,以及 bg-spare 后台进程; init()、setup()、插件/技能初始化、MCP 预取、commands/agents 加载;- trust/onboarding/OAuth/setup/resume 等启动弹窗;
- REPL 挂载或 headless
QueryEngine路径; - remote control / CCR bridge 的初始化。
argv 先分流再动态 import:daemon、bg-spare、bridge、Chrome/Computer Use MCP 这些路径不进默认图。
2. 早期初始化:src/entrypoints/init.ts#
init() 是 memoized 的全局一次性初始化。它的核心顺序是:
enableConfigs():启用配置系统。applySafeConfigEnvironmentVariables():trust 之前只应用安全环境变量。assertScrubSandboxAvailable()。applyExtraCACertsFromConfig():在首次 TLS 前注入额外 CA,因为 Bun/BoringSSL 会缓存证书状态。setupGracefulShutdown():安装退出清理。- 动态导入 1P event logging 和 GrowthBook,避免启动时同步吞下 OpenTelemetry 依赖。
populateOAuthAccountInfoIfNeeded()、JetBrains detection、repository detection。- 初始化 remote managed settings / policy limits 的加载 promise,避免后续系统等待时死锁。
configureGlobalMTLS()与configureGlobalAgents():mTLS 与 proxy 全局配置。preconnectAnthropicApi():在合适条件下预连 Anthropic API。- remote 环境下可初始化 agent proxy。
- Windows:既没 Git Bash、PowerShell 工具又关着,直接退出;需要 Git for Windows 或 PowerShell 7(或设
CLAUDE_CODE_GIT_BASH_PATH)。 - LSP cleanup、team cleanup、scratchpad 目录。
这个文件有一个很清楚的安全边界:trust 之前只做“安全配置”,trust 之后再调用 initializeTelemetryAfterTrust()。对 remote-settings-eligible 用户,它会等待远程设置加载并重新应用环境变量,再初始化遥测。也就是说,trust dialog 在这里是真正的运行时门槛,不只是 UI 提示。
3. 会话准备:src/setup.ts#
setup() 把“进程已经启动”变成“当前会话可运行”。它做的事比名字重很多:
- 检查 Node.js 22+(不是 18)。低于 22 直接退出。
- 如传入
customSessionId,切换 session。 - 先清掉
$CLAUDE_CODE_MESSAGING_SOCKET/TOKEN。UDS inbox 要过跨会话 messaging 门:gate 关、remote thin client、bare 会跳过;CLAUDE_BG_BACKEND=daemon时另起 rendezvous。 - 装 observer spawner。
- 交互模式下恢复中断过的 iTerm2 / Terminal.app 设置备份。
setCwd(cwd),然后捕获 hooks 配置快照。- 非 remote 时初始化 FileChanged hook watcher。
- 处理
--worktree:git worktree,或WorktreeCreatehook 让非 git VCS 接入;可选创建 tmux session。 - worktree 创建后切 cwd、清缓存、重读 hooks/settings。
- 非 bare 时拉后台任务、plugin hooks、session file access、ultrareview post-commit hook;trust 且非 remote 时
startMemoryWatcher。 - 可预热 auto-memory / org-memory 的 recall 索引。
- 打
tengu_started。 bypassPermissions/--dangerously-skip-permissions:root/sudo 且不在IS_SANDBOX/CLAUDE_CODE_BUBBLEWRAP里会拒绝。
这里有两个细节很有代表性:
- hook snapshot 必须在
setCwd()之后,因为 hooks 来自当前项目目录;worktree 切换后还要重新 snapshot。 --bare跳过 UDS、部分后台任务和 prefetch,但危险权限校验和tengu_started仍会执行。
4. 上下文装配:src/context.ts#
context.ts 负责把会话环境变成模型可消费的上下文,主要有两块。
system context
getSystemContext() 会按需加入 git 快照:当前分支、main/default、git status --short(最多 2000 字符)、git log --oneline -n 5、git config user.name。remote 或关掉 git instructions 时跳过。CLAUDE_CODE_PERFORCE_MODE 会改成 Perforce 工作区说明。
user context
getUserContext() 主要负责 CLAUDE.md:
CLAUDE_CODE_DISABLE_CLAUDE_MDS会硬关闭;--bare会跳过自动发现,但仍尊重显式--add-dir;- 读取 memory files 后拼成
claudeMd,并缓存给 auto-mode classifier; - 注入当前日期;
- 有登录邮箱时注入
The user's email address is …; - 可附带 attached project 块。
5. 交互 UI 启动路径#
交互模式大致是:
main.tsx
→ interactiveHelpers.tsx
→ replLauncher.tsx
→ components/App.tsx
→ REPL
interactiveHelpers.tsx 维护进入 UI 前的“仪式”:trust dialog、setup screens、MCP approval、外部 CLAUDE.md include 审批、环境变量应用、telemetry-after-trust、GrowthBook 重置等。
replLauncher.tsx 职责更纯:动态导入 <App> 和 <REPL>,再用 renderAndRun() 挂载。动态导入可以避免 main.tsx 过早拉入 React/Ink 组件树。
dialogLaunchers.tsx 则把 resume chooser、snapshot update、teleport mismatch、invalid settings 等一次性 UI 从主入口拆出去,让 main.tsx 不至于更膨胀。
6. Headless / SDK 路径:src/QueryEngine.ts#
交互 REPL 会走 React 组件和 hooks;--print、SDK、remote session 子进程等非交互场景则主要依赖 QueryEngine。
QueryEngine 是对 query() 的会话化包装:
- 一个
QueryEngine对应一个 conversation; submitMessage()处理用户输入、slash command、attachments、系统 prompt、工具上下文;- 维护
mutableMessages、read file cache、permission denials、usage、loaded nested memory、discovered skills; - 写 transcript,使 kill-mid-request 后仍可 resume;
- 将内部
Message转成 SDK 事件,如assistant、user replay、system init、api_retry、compact_boundary、tool_use_summary、result; - 支持
maxTurns、maxBudgetUsd、structured output retry limit、partial stream events、MCP URL elicitation; - compact boundary 后主动裁剪 pre-boundary messages,降低长 headless 会话内存。
可以把 QueryEngine 理解为“非交互模式的 REPL store + query loop adapter”。
7. 主查询循环:src/query.ts#
query.ts 是整个系统的运行时核心。它不是“发一次请求”,而是一个可恢复、可压缩、可执行工具、可继续多轮的状态机。
每次循环大致做这些事:
- 建立 query chain tracking,用于嵌套查询/子代理的 analytics。
- 截取 compact boundary 之后的消息。
- 对 tool results 应用总预算,必要时把大结果替换为持久化文件引用。
- 可选 microcompact;中间轮可 fold 排队命令。history snip / context collapse drain 在 2.1.233 字面量里看不到,不当默认步骤。
- 自动 compact:可先吃预计算的 compact(
tengu_sepia_moth+precomputeCompactionEnabled),再跑阈值 compact。窗口解析见 压缩专题。 - 拼接完整 system prompt 与 user context。
- 计算当前模型;plan 模式下可根据 200k token 情况切模型。
- 调用
deps.callModel()流式请求模型。 - 流式过程中发现 tool_use 时,可用
StreamingToolExecutor提前开始执行工具。 - 对可恢复错误做 withheld:prompt-too-long、media-size、max-output-tokens 等先不立刻暴露给 SDK/UI。
- 流结束后处理 fallback、reactive compact、max output tokens recovery。
- 若没有 tool_use,执行 stop hooks、token budget continuation、返回完成。
- 若有 tool_use,执行剩余工具,收集 tool results、attachments、memory prefetch、skill discovery、queued commands。
- 刷新工具集合,使新连接的 MCP server 可在下一轮暴露给模型。
- 检查
maxTurns,否则组装下一轮 messages 继续循环。
query.ts 里几个重要恢复策略:
- streaming fallback tombstone:如果流式过程中触发模型 fallback,会 tombstone 已 yield 的孤儿 assistant messages,避免 thinking signature 或 tool_use 残块污染 transcript。
- prompt-too-long recovery:先 withhold 413,再
tryReactiveCompact(remote 还要过tengu_reactive_compact_remote)。 - max_output_tokens recovery:meta user message 让模型从中断点继续。2.1.88 那条 8k→64k 升级门不在 2.1.233 制品里。
- thinking-only retry、Stop hook 阻断上限(默认 8)、rapid-refill breaker(compact 后 3 轮内把窗口填满,连续 3 次就停)。
- tool result budget:大 tool result 可被替换/落盘,避免上下文被工具输出撑爆。
- pending tool use summary:上一轮工具摘要用小模型异步生成,在下一轮流式期间等待,减少主路径阻塞。
8. 工具执行在 query 中的位置#
query.ts 自身不直接执行工具细节,而是委托:
services/tools/toolOrchestration.ts:按并发安全性分批,read-only/concurrency-safe 批并行,写操作串行。services/tools/toolExecution.ts:单个 tool use 的 schema、权限、hook、progress、结果映射、错误处理。StreamingToolExecutor:模型还在流式输出时就启动已完整到达的 tool use。2.1.233 不再走tengu_streaming_tool_execution2门,当作默认开。
这层拆分使主循环可以专注“轮次状态机”,而工具层专注“执行一个 tool use 是否安全、如何展示、如何转换结果”。
9. API 客户端:src/services/api/client.ts#
API client 把不同模型提供方统一到 Anthropic SDK 风格接口下。可以直接看到几条分支:
- 直连 Anthropic:API key 或 Claude.ai OAuth token。
- Bedrock:AWS region、small fast model region override、AWS bearer token、AWS credential refresh。
- Foundry:Azure Foundry API key 或 Azure AD token provider。
- Vertex:GCP credential refresh、GoogleAuth、按模型选择 region。
它还统一加默认 headers:x-app、User-Agent、session id、container/session metadata、SDK client app 等。对 first-party API,会通过 fetch wrapper 注入 x-client-request-id,方便 timeout 这类无 server request id 的问题排查。
10. 这一层的阅读建议#
如果目标是理解“一次输入后发生什么”,推荐顺序:
main.tsx:看模式分流和启动顺序。entrypoints/init.ts:看全局安全与遥测边界。setup.ts:看会话准备、hooks、worktree、permission 安全校验。context.ts:看系统上下文和用户上下文来源。QueryEngine.ts:看 headless/SDK 怎么包query()。query.ts:看模型循环、compact、工具执行和恢复策略。services/api/client.ts:看 provider 和认证分支。