涉及源码 :
src/runtime.py、src/tool_pool.py、src/command_graph.py、src/bootstrap_graph.py、src/main.py,辅读src/setup.py、src/context.py、src/query_engine.py。
1. 「可执行面」指什么
在 Harness 语境里,可执行面 不是单指「调了哪个 API」,而是 在某一信任级别与策略下,系统承认可以接线的命令名、工具名及其执行入口 的集合,再加上 把自然语言提示词(prompt)落到该集合上的映射结果。
claw-code 把这件事拆成几层 互不替代 的能力:
| 层次 | 代表 API / CLI | 是否依赖用户 prompt | 回答的问题 |
|---|---|---|---|
| 静态能力面(工具池) | assemble_tool_pool / tool-pool |
否 | 当前策略下 最多 能给模型/用户暴露哪些工具? |
| 静态能力面(命令图) | build_command_graph / command-graph |
否 | 命令清单在 builtin / plugin-like / skill-like 上如何分段? |
| 启动叙事(引导图) | build_bootstrap_graph / bootstrap-graph |
否 | 与上游对齐时,运行时阶段 在文档上如何排序? |
| 提示词条件映射 | route_prompt / route |
是 | 这句 prompt 像 在点名哪些命令/工具条目? |
| 会话级编排 | bootstrap_session / bootstrap |
是 | 在 真实上下文 + setup + 路由 + shim + 引擎 + 落盘 下,一整轮 可观测地 长什么样? |
下面按 从静到动 说明实现,并标出 分层策略 的用意与边界。
2. Tool-Pool:策略约束下的「工具可执行面」
python
# 28:37:src/tool_pool.py
def assemble_tool_pool(
simple_mode: bool = False,
include_mcp: bool = True,
permission_context: ToolPermissionContext | None = None,
) -> ToolPool:
return ToolPool(
tools=get_tools(simple_mode=simple_mode, include_mcp=include_mcp, permission_context=permission_context),
simple_mode=simple_mode,
include_mcp=include_mcp,
)
python
# 16:25:src/tool_pool.py
def as_markdown(self) -> str:
lines = [
'# Tool Pool',
'',
f'Simple mode: {self.simple_mode}',
f'Include MCP: {self.include_mcp}',
f'Tool count: {len(self.tools)}',
]
lines.extend(f'- {tool.name} --- {tool.source_hint}' for tool in self.tools[:15])
return '\n'.join(lines)
策略输入 :simple_mode(只保留 BashTool/FileReadTool/FileEditTool)、include_mcp、permission_context(deny_tool / deny_prefix)。
输出 :当前 允许出现在「池」里 的 PortingModule 子集 + Markdown 报告(默认只列前 15 条)。
分层含义 :这是 产品/安全策略下的「能力上限」 ------回答「系统打算 让 agent 看见多少工具」,不读用户这句 prompt 。CLI 里 tools 子命令可走同一套 get_tools 过滤;tool-pool 则是 固定默认参数 的报表入口:
python
# 113:115:src/main.py
if args.command == 'tool-pool':
print(assemble_tool_pool().as_markdown())
return 0
3. Command-Graph:命令侧的「分段可执行面」
python
# 29:34:src/command_graph.py
def build_command_graph() -> CommandGraph:
commands = get_commands()
builtins = tuple(module for module in commands if 'plugin' not in module.source_hint.lower() and 'skills' not in module.source_hint.lower())
plugin_like = tuple(module for module in commands if 'plugin' in module.source_hint.lower())
skill_like = tuple(module for module in commands if 'skills' in module.source_hint.lower())
return CommandGraph(builtins=builtins, plugin_like=plugin_like, skill_like=skill_like)
策略输入 :get_commands 的 include_plugin_commands / include_skill_commands(CLI commands 可关插件/技能)。
输出 :三段计数 + 可 flattened() 拼回列表。
分层含义 :与 Tool-Pool 对称------命令宇宙 在 来源维度 (builtin vs 插件 vs 技能)上长什么样,同样 与当前 prompt 无关,用于架构评审与 parity 对照。
4. Bootstrap-Graph:阶段叙事,不是 bootstrap_session 的逐行调用栈
python
# 16:27:src/bootstrap_graph.py
def build_bootstrap_graph() -> BootstrapGraph:
return BootstrapGraph(
stages=(
'top-level prefetch side effects',
'warning handler and environment guards',
'CLI parser and pre-action trust gate',
'setup() + commands/agents parallel load',
'deferred init after trust',
'mode routing: local / remote / ssh / teleport / direct-connect / deep-link',
'query engine submit loop',
)
)
性质 :文档化/对齐用 的阶段列表,描述完整产品里从预取到 submit loop 的 意图顺序 ;不等于 Python bootstrap_session 里函数调用顺序的 1:1 映射。
价值 :评审时把 Tool-Pool / Route / QueryEngine 放在同一幅「运行时故事」里,避免只见树木不见森林。
5. Route:唯一「prompt → 候选符号」层
python
# 90:107:src/runtime.py
def route_prompt(self, prompt: str, limit: int = 5) -> list[RoutedMatch]:
tokens = {token.lower() for token in prompt.replace('/', ' ').replace('-', ' ').split() if token}
by_kind = {
'command': self._collect_matches(tokens, PORTED_COMMANDS, 'command'),
'tool': self._collect_matches(tokens, PORTED_TOOLS, 'tool'),
}
...
return selected[:limit]
输入 :用户字符串 + limit。
输出 :带 kind / name / source_hint / score 的 有序候选列表。
关键分层点 (与 result/08.md 一致):路由扫的是 全量 PORTED_COMMANDS / PORTED_TOOLS,不 应用 Tool-Pool 的 simple_mode、MCP 开关或 permission_context。因此:
- Tool-Pool 描述的是 策略收缩后的能力面;
- Route 描述的是 在完整镜像面上,这句 prompt 的文本相关性;
两者 故意解耦 :移植期可同时观察「若全开镜像会路由到哪」与「若收紧池子模型本该看见什么」,产品期则需在更上层 用同一 policy 过滤路由结果 或 只把池内名字喂给模型 以对齐。
6. Bootstrap(bootstrap_session):把各层粘成「一轮可观测会话」
bootstrap_session 是 动态层的总编排 :在 已有 prompt 的前提下,依次叠 环境上下文、setup、路由、shim、权限推断、QueryEngine、持久化。
python
# 109:152:src/runtime.py
def bootstrap_session(self, prompt: str, limit: int = 5) -> RuntimeSession:
context = build_port_context()
setup_report = run_setup(trusted=True)
setup = setup_report.setup
history = HistoryLog()
engine = QueryEnginePort.from_workspace()
history.add('context', f'python_files={context.python_file_count}, archive_available={context.archive_available}')
history.add('registry', f'commands={len(PORTED_COMMANDS)}, tools={len(PORTED_TOOLS)}')
matches = self.route_prompt(prompt, limit=limit)
registry = build_execution_registry()
command_execs = tuple(registry.command(match.name).execute(prompt) for match in matches if match.kind == 'command' and registry.command(match.name))
tool_execs = tuple(registry.tool(match.name).execute(prompt) for match in matches if match.kind == 'tool' and registry.tool(match.name))
denials = tuple(self._infer_permission_denials(matches))
stream_events = tuple(engine.stream_submit_message(...))
turn_result = engine.submit_message(...)
persisted_session_path = engine.persist_session()
...
return RuntimeSession(...)
分层在代码里的体现:
- 环境层 :
build_port_context()------ 源码树、测试、资源、归档是否在盘(context.py)。 - 启动层 :
run_setup(trusted=True)------ Python/平台、预取、延迟初始化(setup.py);WorkspaceSetup.startup_steps()明文列出 加载镜像 command/tool 快照 等步骤。 - 清单规模层 :history 记录
PORTED_*数量(全宇宙大小,与 Tool-Pool 子集对照)。 - 路由层 :
route_prompt→matches。 - 可执行 shim 层 :
ExecutionRegistry对 匹配到的名字 执行(仍不读 Tool-Pool 过滤)。 - 策略/审计层 :
_infer_permission_denials。 - 会话语义层 :
QueryEnginePort流式 +submit_message→TurnResult。 - 持久化层 :
persist_session。
RuntimeSession.as_markdown() 把上述块 按章节输出,便于人类做一次「分层验收」:
python
# 39:85:src/runtime.py
def as_markdown(self) -> str:
lines = [
'# Runtime Session',
...
'## Context',
render_context(self.context),
...
'## Routed Matches',
...
'## Command Execution',
...
'## Tool Execution',
...
'## Stream Events',
...
'## Turn Result',
self.turn_result.output,
...
self.history.as_markdown(),
]
7. 分层关系示意图
提示词驱动
静态能力面(无 prompt)
策略子集
builtin/plugin/skill
全量 PORTED_* 打分
未自动接入
command-graph
tool-pool
bootstrap-graph 叙事
route_prompt
bootstrap_session
当前允许的工具集合
命令分段
RoutedMatch 列表
QueryEnginePort + persist
虚线表示:本仓库尚未 把 Tool-Pool 的过滤结果自动喂给 route_prompt,这是阅读与演进时最需要注意的接缝。
8. CLI 上的「策略组合」速查
| 命令 | 分层角色 |
|---|---|
command-graph |
静态命令分段 |
tool-pool |
默认策略下的工具池报告 |
tools --simple-mode --no-mcp --deny-prefix ... |
自定义策略下的池(与 tool-pool 默认不同) |
route <prompt> |
仅路由,无 setup/shim/引擎 |
bootstrap <prompt> |
全栈编排 + Markdown 报告 |
bootstrap-graph |
阶段叙事(对照用) |
9. 小结:分层策略在工程上的收益
- Tool-Pool / Command-Graph :把 策略与分段 从 prompt 中剥离,便于 配置 diff、安全评审、与模型 context 对齐。
- Route :把 自然语言 → 符号候选 隔离成单一函数,便于 换算法(embedding、学习排序)而不动 setup。
- Bootstrap :把 「这一轮故事里每一层长什么样」 固化为
RuntimeSession+ Markdown,便于 移植回归与 PR 审查。 - 有意识的不连接 :路由用全量镜像、池用过滤子集,迫使贡献者显式决定 产品最终用哪一面驱动模型 ------这是 避免隐式魔法 的一种粗糙但诚实的设计。