claw-code runtime 核心 crate 深度解析:模块地图、四大不变量与工程约定
claw(claw-code 项目)的核心 crate runtime 承载了会话持久化、权限控制、提示词组装、MCP 管道、工具侧文件操作和对话循环等全部核心职责。它以 47 个扁平模块(约 330 个 pub 符号,其中约 170 个从 lib.rs 平铺再导出)构成整个 CLI 的执行底座。读完本文,你将掌握该 crate 的完整模块导航地图、四条不可破坏的不变量(invariants)、严格的依赖与命名约定,以及每条约束背后对应的源码证据与回归测试,从而安全地在其中定位代码、阅读实现并遵循规范进行维护。
1. crate 定位:它负责什么
runtime 位于 rust/crates/runtime 目录,是 claw 工作区 11 个 crate 中唯一的“核心库”:
rusty-claude-cli (bin `claw`) → tools / commands / runtime / api / plugins
claw-analog → api + runtime
即:会话、权限、MCP 和对话循环的全部状态机都在 runtime 里,而 CLI 二进制只负责呈现。其依赖声明见 Cargo.toml——这是理解其工程风格的关键一页:
[dependencies]
sha2 = "0.10"
glob = "0.3"
plugins = { path = "../plugins" }
regex = "1"
serde = { version = "1", features = ["derive"] }
serde_json.workspace = true
telemetry = { path = "../telemetry" }
tokio = { version = "1", features = ["io-std", "io-util", "macros", "process",
"rt", "rt-multi-thread", "time"] }
walkdir = "2"
[dev-dependencies]
tempfile = "3"
依赖清单刻意保持最小:只有 serde、tokio、glob、regex、sha2、walkdir 加上内部 plugins/telemetry 两个 crate。没有 reqwest,没有 async-trait——远程调用与 SSE 解析由 remote.rs 和 sse.rs 手工实现。这意味着阅读网络相关代码时不用追踪第三方 HTTP 栈,SSE 帧解析逻辑就在 rust/crates/runtime/src/sse.rs 内部。
2. 模块导航地图:47 个文件按职能分组
源码全部平铺在 src/ 下(无子目录),文档给出的分组地图如下(已对照实际文件与行数核实):
| 职能分组 | 文件 | 关键入口 |
|---|---|---|
| 会话/对话 | session.rs, session_control.rs, conversation.rs, compact.rs, summary_compression.rs, usage.rs |
Session、SessionStore、ConversationRuntime、ApiClient/ToolExecutor trait |
| 配置 | config.rs, config_validate.rs, bootstrap.rs |
ConfigLoader;MCP 服务器配置枚举也在此定义 |
| MCP(6 文件拆分) | mcp.rs, mcp_client.rs, mcp_stdio.rs, mcp_server.rs, mcp_tool_bridge.rs, mcp_lifecycle_hardened.rs |
McpServerManager(mcp_stdio.rs),JSON-RPC 进程启动 |
| 钩子/插件 | hooks.rs, plugin_lifecycle.rs |
HookRunner(hooks.rs)、中止信号、健康检查、降级模式 |
| 权限/安全 | permissions.rs, permission_enforcer.rs, policy_engine.rs, approval_tokens.rs, sandbox.rs, bash_validation.rs, trust_resolver.rs |
PermissionEnforcer(permission_enforcer.rs)、GreenLevel、lane 决策 |
| 工具/执行 | bash.rs, file_ops.rs, lsp_client.rs |
execute_bash、*_in_workspace 系列文件操作 |
| 通道/工作者 | lane_events.rs, worker_boot.rs, task_packet.rs, task_registry.rs, team_cron_registry.rs, branch_lock.rs, stale_base.rs, stale_branch.rs |
LaneEvent 去重/溯源、LaneBoard |
| 提示词 | prompt.rs |
SystemPromptBuilder、ContextFile、动态边界标记 |
| git/远程/认证 | git_context.rs, remote.rs, oauth.rs |
上游代理、PKCE 流程 |
| 杂项 | json.rs, sse.rs, g004_conformance.rs, green_contract.rs, recovery_recipes.rs, report_schema.rs, trident.rs |
Report v1 与脱敏(redaction) |
行数最大的文件为:config.rs(3894 行)、mcp_stdio.rs(2969 行)、lane_events.rs(2561 行)、worker_boot.rs(2441 行)、session.rs(1961 行)、conversation.rs(1878 行)——与实际 wc -l 结果完全一致。
几个值得展开的入口点:
Session 与 ConversationRuntime。session.rs 中的 Session 结构体携带 session_id、messages: Vec<ConversationMessage>、compaction: Option<SessionCompaction>、fork: Option<SessionFork> 以及 workspace_root: Option<PathBuf> 等字段。源码注释解释了 workspace_root 的必要性:全局会话存储跨所有服务实例共享,没有显式 workspace 绑定时,并行 lane 可能竞态并报告“假成功”。conversation.rs 的 ConversationRuntime<C, T> 则以泛型同时约束 C: ApiClient(conversation.rs 定义)和 T: ToolExecutor(#L62),协调模型循环、工具执行、钩子和会话更新,并内置 max_iterations、usage_tracker、auto_compaction_input_tokens_threshold 与 hook_abort_signal 字段。
ConfigLoader。config.rs 中定义为“发现配置文件并合并为 RuntimeConfig 的加载器”,字段为 cwd: PathBuf 与 config_home: PathBuf。3894 行的 config.rs 是全 crate 类型导出最重的文件,MCP 服务器配置的枚举类型同样定义在这里——改配置项时先来这里找类型定义。
McpServerManager。mcp_stdio.rs 中的管理器持有 servers: BTreeMap<String, ManagedMcpServer>、unsupported_servers、tool_index: BTreeMap<String, ToolRoute> 与 next_request_id,并提供了 from_runtime_config 与 from_servers 两个构造入口。MCP 被拆成 6 个文件(协议、客户端、stdio 启动、服务器、工具桥、生命周期加固)正是为了把最大的单文件复杂度摊开。
3. 约定(CONVENTIONS):扁平布局与测试纪律
文档列出六条约定,逐条对照源码均成立:
- 一个文件一个模块,扁平布局,无子目录。
src/下恰好 47 个.rs文件,没有子目录。 - 多数模块是私有
mod x+ 选择性pub use。lib.rs 中有 22 个pub mod(bash_validation、branch_lock、config_validate、g004_conformance、green_contract、lsp_client、mcp_lifecycle_hardened、mcp_server、mcp_tool_bridge、permission_enforcer、plugin_lifecycle、recovery_recipes、sandbox、session_control、trident、stale_base、stale_branch、summary_compression、task_packet、task_registry、team_cron_registry、worker_boot),其余模块只通过再导出暴露。消费方因此既可以用再导出路径,也可以用限定路径。 - 依赖最小化(见第 1 节,无 reqwest / async-trait)。
- 每个文件内联
#[cfg(test)]测试,其中 session.rs 含两个测试模块。 test_env_lock()。lib.rs 提供了一个pub(crate)的静态互斥锁(OnceLock<Mutex<()>>),用于串行化所有修改环境变量的测试——凡触碰 env 的测试必须持有该锁。trust_resolver.rs是“测试门控的公开 API”。整个实现位于#[cfg(test)]门控下,却以 pub 符号被使用,属于仅供测试的 API 表面;阅读时不要把它当作运行时逻辑的一部分。
4. 四大不变量:绝不能破坏的约束
文档的 INVARIANTS 一节列出了四条硬约束,每条都有对应的源码位置与回归测试:
4.1 压缩不得拆散工具调用对
compact.rs 在任何情况下都不得在 assistant 消息的 ToolUse 块与对应的 ToolResult 之间下刀。compact.rs 的注释明确说明了边界判定:若某条消息是 ToolResult,则其前一条必须是指派(assistant)且携带匹配 ToolUse 的助手消息,否则视为孤儿。回归测试 compaction_does_not_split_tool_use_tool_result_pair(compact.rs)正是为此而写,断言压缩结果中不存在“有 ToolResult 却没有前序 ToolUse”的消息。
4.2 构造无副作用
SessionStore 的构造不得创建 .claw 目录。session_control.rs 的测试 session_store_from_cwd_is_side_effect_free_until_save 直接验证了这一点:SessionStore::from_cwd(&workspace) 之后,workspace 下不得出现 .claw,sessions_dir() 必须懒创建,直到第一次 save 才落盘。
4.3 工作区包含性
file_ops.rs 的 workspace 文件操作不得逃逸出 workspace 根目录。源码中提供了成对的受检/非受检实现:read_file_in_workspace、write_file_in_workspace、edit_file_in_workspace、glob_search_in_workspace、grep_search_in_workspace(见 file_ops.rs 一带)。约定同时规定:在 workspace 上下文中不得绕过 *_in_workspace 变体去调未受检版本——未受检版本仅为 bootstrap 与 workspace 外场景保留。
4.4 权限判定的顺序陷阱
前导只读权限令牌不得为尾随的破坏性命令“洗白”。permission_enforcer.rs 附近的硬编码回归测试 read_only_rejects_command_rejects_command_chaining 覆盖了典型攻击面:
assert!(!is_read_only_command("cat foo; rm -rf bar"));
assert!(!is_read_only_command("cat foo && rm -rf bar"));
assert!(!is_read_only_command("ls || rm bar"));
assert!(!is_read_only_command("cat foo | sh"));
assert!(!is_read_only_command("echo `rm bar`"));
assert!(!is_read_only_command("echo $(rm bar)"));
判定函数 is_read_only_command(permission_enforcer.rs)还额外拒绝了解释器与构建驱动(如 python3 -c ...),因为这类命令可执行任意代码,不再算只读。PermissionEnforcer::check 本身在 Prompt 模式下会把决策交给调用方的交互询问流程(enforcer 自身没有 prompter)。
5. 反模式清单:什么是不被允许的
文档 ANTI-PATTERNS 一节给出的五条禁令,全部可用源码现状验证:
- 不要扩展整文件
#![allow(...)]块。以下 8 个文件第 1 行就带有遗留容忍块:worker_boot.rs、mcp_tool_bridge.rs、lsp_client.rs(clippy::should_implement_trait, clippy::must_use_candidate)、stale_branch.rs、stale_base.rs、recovery_recipes.rs(cast_possible_truncation, uninlined_format_args)、mcp_lifecycle_hardened.rs、session_control.rs(dead_code)。这是遗留容忍,新增不可接受。 - 不得添加 reqwest 或 async-trait 依赖。远程调用必须走
remote.rs与sse.rs的手工 SSE/代理层。 - 不得在
src/下创建子目录。扁平模块布局是有意为之。 - 不得在 workspace 上下文中绕过
*_in_workspace文件操作变体(见 4.3)。 - 不得无理由地新增
pub mod导出。优先“私有 mod + 从 lib.rs 选择性pub use”。
6. 阅读与维护建议
结合上述结构,进入这个 crate 的推荐路径是:
- 先读 lib.rs 的再导出表,确认目标符号走的是限定路径还是再导出;
- 再按第 2 节的分组地图定位文件,行数最大的六个文件(config / mcp_stdio / lane_events / worker_boot / session / conversation)是主战场,建议带着具体类型名(如
RuntimeConfig、McpServerManager、LaneEvent)进入; - 动手前先找到对应的内联
#[cfg(test)]测试——每个文件自带测试模块,第 4 节的四条不变量均有回归测试锚点;涉及环境变量的改动记得test_env_lock(); - 提交前遵循工作区级检查。按 rust/AGENTS.md 的规定,从
rust/目录执行:
# 格式化检查(不要直接在仓库根跑 cargo fmt)
../scripts/fmt.sh --check
# 严格 lint(比 CI 门禁更严)
cargo clippy --workspace --all-targets -- -D warnings
# 全量测试
cargo test --workspace
工作区另有硬性 lint:unsafe_code = forbid(不是 deny,无法 #[allow]),以及“格式化函数只接受 &mut impl Write、绝不直写 stdout”的 TUI 规则(该规则约束 TUI 层,但维护共享代码时同样适用)。
7. 小结
runtime crate 是一份“约束先于代码”的工程范本:47 个扁平模块、最小依赖、内联测试、四条带回归测试的不变量,以及一份明确到“哪个文件第 1 行有遗留 allow 块”的反模式清单。它的全部设计意图都写在 rust/crates/runtime/AGENTS.md 里,并与 Cargo.toml、lib.rs 及各模块源码一一对应。理解并遵守这套地图与约束,是安全修改该 crate 的前提。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00