当前位置: 首页 > article >正文

claw-code 源码分析:从「清单」到「运行时」——Harness 为什么必须先做 inventory 再做 I/O?

说明本文分析对象为开源仓库claw-codeREADME 中Rewriting Project Claw Code的 Python/Rust 移植工作区。1. 问题在问什么Inventory清单在 Harness 里指「系统承认存在的命令名、工具名及其元数据」的有穷集合——谁算内置、谁算插件、谁可被模型调用、各自职责与来源提示是什么。I/O输入输出指真正对外部世界产生副作用的行为——读盘、起进程、调网络 API、改用户仓库等。核心论点是在智能体系统里若没有一个稳定、可枚举、可过滤的清单就直接开放 I/O会把「命名空间」「路由」「权限」「审计」全部绑死在即兴逻辑上后期每一次加工具/加命令都会变成全库手术。claw-code 的 Python 移植层用快照 JSON → 内存元组 → 路由/注册表 →再模拟执行的链条把这一顺序写进了代码结构本身。2. 源码中的「清单层」长什么样2.1 数据源头reference_data快照命令与工具的权威枚举来自版本库内的 JSON而不是运行时再扫描磁盘猜名字src/reference_data/commands_snapshot.jsonsrc/reference_data/tools_snapshot.jsoncommands.py/tools.py在模块加载时读取 JSON解析为不可变元组PORTED_COMMANDS、PORTED_TOOLS并缓存lru_cache(maxsize1) def load_command_snapshot() - tuple[PortingModule, ...]: raw_entries json.loads(SNAPSHOT_PATH.read_text()) return tuple( PortingModule( nameentry[name], responsibilityentry[responsibility], source_hintentry[source_hint], statusmirrored, ) for entry in raw_entries ) PORTED_COMMANDS load_command_snapshot()lru_cache(maxsize1) def load_tool_snapshot() - tuple[PortingModule, ...]: raw_entries json.loads(SNAPSHOT_PATH.read_text()) return tuple( PortingModule( nameentry[name], responsibilityentry[responsibility], source_hintentry[source_hint], statusmirrored, ) for entry in raw_entries ) PORTED_TOOLS load_tool_snapshot()学习点清单与代码解耦——JSON 可 diff、可审计、可随 parity 演进Python 侧只消费「已镜像」条目避免运行时动态发现带来的不可重复性。2.2 在清单之上做「视图」过滤、简单模式、权限get_tools()不重新发明清单而是在PORTED_TOOLS上叠加策略simple mode、是否包含 MCP、权限上下文def get_tools( simple_mode: bool False, include_mcp: bool True, permission_context: ToolPermissionContext | None None, ) - tuple[PortingModule, ...]: tools list(PORTED_TOOLS) if simple_mode: tools [module for module in tools if module.name in {BashTool, FileReadTool, FileEditTool}] if not include_mcp: tools [module for module in tools if mcp not in module.name.lower() and mcp not in module.source_hint.lower()] return filter_tools_by_permission_context(tuple(tools), permission_context)tool_pool.py的assemble_tool_pool只是把上述「当前允许的子集」包装成报告对象——先有全集inventory再有池policy 下的视图def assemble_tool_pool( simple_mode: bool False, include_mcp: bool True, permission_context: ToolPermissionContext | None None, ) - ToolPool: return ToolPool( toolsget_tools(simple_modesimple_mode, include_mcpinclude_mcp, permission_contextpermission_context), simple_modesimple_mode, include_mcpinclude_mcp, )学习点权限与产品模式是清单上的过滤器不是散落在每个 I/O 调用点里的 if-else没有 inventory过滤器无处附着。2.3 命令「图」仍是清单的划分command_graph.py根据source_hint把同一批PORTED_COMMANDS分成 builtin / plugin-like / skill-like——拓扑来自元数据字段而不是执行时行为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(builtinsbuiltins, plugin_likeplugin_like, skill_likeskill_like)3. 「I/O 层」在本仓库里如何被刻意推迟3.1 执行入口execute_*首先是名字校验 描述性消息真正的危险 I/O 并未接在execute_tool上当前实现是mirrored shim只在清单里找到名字时返回「将会如何处理」的字符串def execute_tool(name: str, payload: str ) - ToolExecution: module get_tool(name) if module is None: return ToolExecution(namename, source_hint, payloadpayload, handledFalse, messagefUnknown mirrored tool: {name}) action fMirrored tool {module.name} from {module.source_hint} would handle payload {payload!r}. return ToolExecution(namemodule.name, source_hintmodule.source_hint, payloadpayload, handledTrue, messageaction)命令同理execute_command。学习点Harness 演进的标准节奏是——先让「调用约定」在清单内跑通名字、payload、返回结构再接真实后端若颠倒顺序调试时无法区分「路由错了」还是「I/O 错了」。3.2 注册表ExecutionRegistry完全由清单构造build_execution_registry()遍历PORTED_COMMANDS/PORTED_TOOLS生成可查找对象注册表容量 清单条目数def build_execution_registry() - ExecutionRegistry: return ExecutionRegistry( commandstuple(MirroredCommand(module.name, module.source_hint) for module in PORTED_COMMANDS), toolstuple(MirroredTool(module.name, module.source_hint) for module in PORTED_TOOLS), )运行时拿路由结果去 registry 里取执行器——没有 inventoryregistry 无法构建路由结果也无法落到稳定 handler。4.PortRuntime路由与清单的硬依赖PortRuntime.route_prompt的输入是用户prompt但匹配对象只能是PORTED_COMMANDS与PORTED_TOOLS中的模块它用 token 与name/source_hint/responsibility做打分产出有限条RoutedMatchclass PortRuntime: 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), } selected: list[RoutedMatch] [] for kind in (command, tool): if by_kind[kind]: selected.append(by_kind[kind].pop(0)) leftovers sorted( [match for matches in by_kind.values() for match in matches], keylambda item: (-item.score, item.kind, item.name), ) selected.extend(leftovers[: max(0, limit - len(selected))]) return selected[:limit]bootstrap_session的流程顺序非常清晰构建上下文与 setup环境自省QueryEnginePort.from_workspace()再拉 manifest / summary 相关状态history 记下commands{len(PORTED_COMMANDS)}, tools{len(PORTED_TOOLS)}——显式把清单规模当作会话元数据route_prompt→build_execution_registry()→ 仅对匹配到的名字执行 shim再把matched_commands/matched_tools/ 推断的denials交给QueryEnginePort的submit_message/stream_submit_messagedef bootstrap_session(self, prompt: str, limit: int 5) - RuntimeSession: context build_port_context() setup_report run_setup(trustedTrue) setup setup_report.setup history HistoryLog() engine QueryEnginePort.from_workspace() history.add(context, fpython_files{context.python_file_count}, archive_available{context.archive_available}) history.add(registry, fcommands{len(PORTED_COMMANDS)}, tools{len(PORTED_TOOLS)}) matches self.route_prompt(prompt, limitlimit) 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( prompt, matched_commandstuple(match.name for match in matches if match.kind command), matched_toolstuple(match.name for match in matches if match.kind tool), denied_toolsdenials, )) turn_result engine.submit_message( prompt, matched_commandstuple(match.name for match in matches if match.kind command), matched_toolstuple(match.name for match in matches if match.kind tool), denied_toolsdenials, )学习点路由routing是定义在有穷 inventory 上的搜索问题I/O 只应作用于路由后的已解析符号。若先写 I/O常见反模式是「字符串里猜路径」「正则提取 shell 片段」——不可枚举、不可审计。权限拒绝示例_infer_permission_denials同样建立在已匹配的工具名上例如 bash 类工具说明deny-list / gate 需要名字语义而名字来自清单。5.QueryEnginePort会话与预算——仍以「匹配集合」为输入submit_message并不自己去「发现」工具它接收调用方已经算好的matched_commands、matched_tools与denied_tools再写入摘要、用量、转写与压缩策略summary_lines [ fPrompt: {prompt}, fMatched commands: {, .join(matched_commands) if matched_commands else none}, fMatched tools: {, .join(matched_tools) if matched_tools else none}, fPermission denials: {len(denied_tools)}, ] output self._format_output(summary_lines) projected_usage self.total_usage.add_turn(prompt, output) stop_reason completed if projected_usage.input_tokens projected_usage.output_tokens self.config.max_budget_tokens: stop_reason max_budget_reached self.mutable_messages.append(prompt) self.transcript_store.append(prompt) self.permission_denials.extend(denied_tools) self.total_usage projected_usage self.compact_messages_if_needed() return TurnResult( promptprompt, outputoutput, matched_commandsmatched_commands, matched_toolsmatched_tools, permission_denialsdenied_tools, usageself.total_usage, stop_reasonstop_reason, )render_summary()再次聚合manifest command/tool backlog仍来自清单说明「给用户/维护者看的系统面」与 inventory 同源。6. Bootstrap 阶段叙事bootstrap_graph把顺序写死build_bootstrap_graph()用字符串阶段描述了整个启动链其中「setup commands/agents 并行加载」在「query engine submit loop」之前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。在更完整的产品里「agents parallel load」就是 inventory policy 的装配没有这一步query loop 没有稳定工具面可展示给模型或用户。7. Parity Audit清单是「可度量一致性」的锚parity_audit.py将归档侧与当前 Python 树的根文件、目录、命令条目、工具条目做比例统计——命令/工具覆盖率直接绑定commands_snapshot/tools_snapshot与归档dataclass(frozenTrue) class ParityAuditResult: archive_present: bool root_file_coverage: tuple[int, int] directory_coverage: tuple[int, int] total_file_ratio: tuple[int, int] command_entry_ratio: tuple[int, int] tool_entry_ratio: tuple[int, int] missing_root_targets: tuple[str, ...] missing_directory_targets: tuple[str, ...]学习点没有 inventory就没有「条目覆盖率」这种工程指标移植进度会沦为感受而不是数据。8. 结论为什么必须先 inventory 再 I/O结合本仓库维度若先做 I/O先做 inventory本仓库做法命名空间任意字符串都可能触发副作用仅PORTED_*内名字可进入执行链路由难以定义「匹配到什么算合法工具」route_prompt在固定模块集合上打分权限权限逻辑散落在具体 syscallToolPermissionContext、denial 推断附着在模块名与元数据审计/回放日志与真实能力面脱节history / TurnResult 记录「匹配了哪些已登记符号」移植无法做 parity 与 snapshot diffJSON 快照 audit 量化进度演进每加一个工具改多处增删 JSON 条目 → 注册表与路由自动继承claw-code 当前用mirrored shim把真实 I/O 推到清单与路由之后是这一原则的极端清晰演示先把「系统承认什么」钉死再谈「能对世界做什么」。9. 建议阅读顺序动手src/reference_data/commands_snapshot.json、tools_snapshot.json— 感受清单体量与字段。src/commands.py、src/tools.py— 加载、过滤、execute shim。src/execution_registry.py、src/runtime.py— 注册表与bootstrap_session顺序。src/query_engine.py—submit_message如何把「已匹配集合」纳入会话与用量。src/parity_audit.py— 清单与归档的量化对照。

相关文章:

claw-code 源码分析:从「清单」到「运行时」——Harness 为什么必须先做 inventory 再做 I/O?

说明:本文分析对象为开源仓库 claw-code(README 中 Rewriting Project Claw Code 的 Python/Rust 移植工作区)。1. 问题在问什么 Inventory(清单):在 Harness 里,指「系统承认存在的命令名、工具…...

Windows HEIC缩略图扩展:让苹果照片在PC上清晰呈现

Windows HEIC缩略图扩展:让苹果照片在PC上清晰呈现 【免费下载链接】windows-heic-thumbnails Enable Windows Explorer to display thumbnails for HEIC/HEIF files 项目地址: https://gitcode.com/gh_mirrors/wi/windows-heic-thumbnails 问题场景&#xf…...

5步打造专业虚拟摄像头:OBS插件从部署到精通

5步打造专业虚拟摄像头:OBS插件从部署到精通 【免费下载链接】obs-virtual-cam obs-studio plugin to simulate a directshow webcam 项目地址: https://gitcode.com/gh_mirrors/ob/obs-virtual-cam OBS虚拟摄像头插件是一款能够将OBS Studio的专业直播画面转…...

复旦微FM33单片机GPIO的“高级”玩法:用FL库实现软件PWM、按键扫描和LED流水灯

复旦微FM33单片机GPIO的“高级”玩法:用FL库实现软件PWM、按键扫描和LED流水灯 在嵌入式开发中,GPIO(通用输入输出)是最基础也是最常用的外设之一。对于复旦微FM33系列单片机来说,除了基本的电平控制,通过巧…...

WarcraftHelper:突破经典游戏限制的焕新体验工具

WarcraftHelper:突破经典游戏限制的焕新体验工具 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 当你在4K显示器上启动《魔兽争霸III》时&…...

保姆级教程:在Ubuntu 20.04上从零搭建AFL++模糊测试环境(含QEMU模式配置与常见报错解决)

从零构建AFL模糊测试环境:Ubuntu 20.04实战手册与深度排错指南 模糊测试作为现代软件安全领域的核心技术之一,正在重新定义漏洞挖掘的效率和深度。当传统人工审计难以应对日益复杂的代码规模时,AFL以其智能化的变异策略和精准的路径追踪能力&…...

VLC安卓版隐藏功能大揭秘:这些options参数让你的播放体验飞起

VLC安卓版隐藏功能大揭秘:这些options参数让你的播放体验飞起 作为安卓平台上最强大的开源播放器,VLC的潜力远不止表面看到的那些基础功能。许多用户不知道的是,通过调整options参数,可以彻底改变播放体验——解决卡顿、优化画质、…...

15、深拷贝浅拷贝的区别?如何实现一个深拷贝?

目录 一、先说本质区别 二、从内存角度理解 三、浅拷贝是什么 常见浅拷贝方式 1. Object.assign 2. 展开运算符 ... 3. 数组方法 四、深拷贝是什么 五、常见深拷贝实现方式 1. JSON.parse(JSON.stringify(obj)) 优点 缺点 无法处理: 2. structuredClo…...

上海知名seo优化公司

为什么选择上海知名SEO优化公司 在当今数字化时代,网站的流量和排名直接关系到企业的市场竞争力。特别是在竞争激烈的上海市场,一个优秀的SEO优化公司能够帮助企业在百度搜索结果中获得更好的排名,从而吸引更多的潜在客户。为什么企业选择上…...

数据取证实战:Passware Kit Forensic 和 ElcomSoft 到底怎么选?附真实案例对比

数据取证工具深度评测:Passware Kit Forensic与ElcomSoft实战决策指南 当企业遭遇数据泄露或需要电子取证时,选对工具往往意味着调查成功与否的分水岭。Passware Kit Forensic和ElcomSoft作为行业两大标杆,常让专业人士陷入选择困境——它们都…...

STM32F429DISC开发板SDRAM(IS42S16400J)性能优化—基于STM32cubeMX HAL库的实战技巧

1. 认识STM32F429DISC开发板与SDRAM 刚拿到STM32F429DISC开发板时,我第一眼就被板载的那颗IS42S16400J SDRAM芯片吸引了。这块8MB的存储空间对于嵌入式开发来说简直是"豪华配置",但真正用起来才发现,如果不做优化,性能可…...

[具身智能-220]:“关节空间”与“操作空间”

在机器人学中,关节空间 (Joint Space) 和 操作空间 (Operational Space) 是描述机器人运动的两种基本方式,它们之间通过运动学相互关联。理解这两个概念是进行机器人轨迹规划和控制的基础。简单来说,关节空间关注机器人“内部”的关节状态&am…...

避坑指南:RcisTarget转录因子分析中常见的5个错误及解决方案(附数据库选择建议)

RcisTarget转录因子分析实战避坑指南:从参数优化到结果验证 在基因调控网络研究中,RcisTarget作为一款强大的R包,能够通过motif富集分析预测调控基因集的转录因子。然而,即使是经验丰富的研究者,在实际分析过程中也常会…...

SpeedyBee F405 V4 55A飞塔到手后,除了接线你还需要注意这3个关键设置

SpeedyBee F405 V4 55A飞塔实战配置指南:从避坑到性能调优 当你拿到这块集成了飞控与电调的SpeedyBee F405 V4 55A飞塔时,官方说明书可能已经帮你完成了硬件组装的基础部分。但真正的挑战往往始于地面站连接成功后的那一刻——那些说明书里没细说的"…...

LSTM时序预测辅助忍者像素绘卷:天界画坊生成动态像素动画

LSTM时序预测辅助忍者像素绘卷:天界画坊生成动态像素动画 1. 引言:当像素艺术遇上AI动画 想象一下这样的场景:一位独立游戏开发者正在为他的复古风格RPG游戏设计角色动画。传统方法需要手工绘制每一帧像素画,一个简单的行走动画…...

ArcMap10.4.1缓冲区分析避坑指南:解决距离单位混淆和叠加效果的常见问题

ArcMap 10.4.1缓冲区分析实战避坑手册:从原理到精准操作 第一次在ArcMap里做缓冲区分析时,我盯着屏幕上那些重叠的彩色圆圈发懵——明明设置了500米缓冲距离,为什么生成的区域看起来比隔壁城市的还大?后来才发现,我的数…...

羊四种行为检测数据集(2000张高质量标注)|YOLO目标检测训练数据集

羊四种行为检测数据集(2000张高质量标注)|YOLO目标检测训练数据集 前言 在智慧养殖与畜牧业数字化转型的背景下,基于计算机视觉的动物行为识别逐渐成为研究与工程应用的热点方向。通过对动物行为的自动检测与分析,可…...

13、探索transforms.RandomRotation()在图像增强中的灵活应用

1. 理解transforms.RandomRotation()的核心功能 当你第一次接触图像数据增强时,可能会被各种变换函数搞得晕头转向。今天我们就来深入聊聊transforms.RandomRotation()这个在PyTorch中非常实用的图像旋转工具。简单来说,它能帮你把图片随机旋转一定角度&…...

算法解析 | 深入EGO Planner:无ESDF的实时避障与轨迹优化

1. EGO Planner的核心创新:告别ESDF的实时避障革命 第一次接触EGO Planner时,最让我惊讶的是它居然完全抛弃了传统路径规划中视为"标配"的ESDF(欧几里得符号距离场)。这就像看到有人不用GPS导航,仅凭直觉就能…...

Canape实战指南:XCP工程配置与调试(一)

1. 从零开始创建XCP工程 第一次打开Canape时,那个满屏英文的界面确实让我有点懵。不过别担心,跟着我的步骤走,保证你能在10分钟内搭好第一个XCP工程。先说说我的习惯 - 我会在D盘专门建个"Canape_Projects"文件夹,里面按…...

Jetson Nano 实战:源码编译 PyCUDA 的完整指南与避坑手册

1. 为什么要在Jetson Nano上源码编译PyCUDA? 在嵌入式AI开发领域,Jetson Nano凭借其小巧的体积和强大的GPU计算能力,成为众多开发者的首选设备。PyCUDA作为Python生态中调用CUDA加速的黄金搭档,能让开发者用Python语法轻松实现GP…...

别再傻傻用IP了!用Kali+SET克隆真实网站的完整避坑指南

KaliSET钓鱼网站进阶实战:从克隆到高仿的避坑指南 在网络安全测试中,钓鱼网站的真实性直接决定了测试效果。很多初学者止步于简单的IP访问和基础模板克隆,却忽略了细节打磨的重要性。本文将带你突破基础操作,实现从"一眼假&q…...

OneRec:生成式推荐模型在短视频场景下的端到端实践与优化

1. 生成式推荐模型为何成为短视频行业新宠 最近两年,生成式推荐模型正在悄悄改变短视频平台的推荐逻辑。传统推荐系统像流水线上的工人,每个环节各司其职:召回负责大海捞针,粗排快速筛选,精排细致打分,最后…...

STL分解实战:从原理到应用的时间序列分析指南

1. STL分解的基本原理与核心价值 STL分解全称为Seasonal-Trend decomposition using LOESS,这个看似复杂的名字其实蕴含着非常直观的时间序列处理逻辑。想象你正在观察一条蜿蜒的山路,STL分解就像帮你把这条路拆解成三个关键部分:山坡本身的倾…...

YOLOv11 OBB实战:手把手构建旋转目标检测数据集

1. 为什么需要旋转目标检测? 在传统的目标检测任务中,我们通常使用水平矩形框(HBB)来标注物体。这种标注方式简单直接,但对于某些特定场景下的物体检测效果并不理想。比如在遥感图像中,飞机、船只等物体往往…...

Flutter系列之Dialog宽度自定义的实战技巧与避坑指南

1. 为什么你的Dialog宽度设置总是失效? 很多Flutter新手都会遇到这样的困惑:明明给Dialog的child设置了width属性,为什么显示出来还是默认的宽度?这个问题我刚开始接触Flutter时也踩过坑。其实根本原因在于Dialog组件内部使用了Co…...

高炮广告牌哪个公司好

开篇:定下基调在当今的广告宣传领域,高炮广告牌以其显著的位置和强大的视觉冲击力,成为众多企业推广品牌和产品的重要选择。本次测评旨在为对高炮广告牌感兴趣的人群,提供一份客观、专业的参考,帮助大家了解市场上不同…...

19 多语言切换实操:一个指令,让AI适配任意编程语言

多语言切换实操:一个指令,让AI适配任意编程语言 摘要 本文为《30天掌控AI编程:从指令到落地,手把手教你指挥AI写代码》系列第十九篇,属于第三阶段多语言实战核心内容。本篇专注AI代码跨语言无缝切换这一高频痛点,针对零基础开发者、多技术栈项目人员,拆解如何通过结构…...

Redis专题(二)

1. Redis的简介Redis支持多种数据结构,有广泛的业务应用场景。数据保存在内存,读写性能高,很适合做缓存。数据可以持久化到硬盘,可以做数据库来用。官⽅对Redis的作⽤,也已经定位成了三个⽅⾯:Cache(缓存)&…...

18 指挥AI批量生成业务代码,大幅提升开发效率

指挥AI批量生成业务代码,大幅提升开发效率 摘要 本文为《30天掌控AI编程:从指令到落地,手把手教你指挥AI写代码》系列第十八篇,属于第三阶段多场景实战核心内容。本篇聚焦业务代码批量生成这一高效开发痛点,针对企业开发中大量重复、模块化的业务场景,讲解如何通过结构…...