claw-code 源码详细分析:Hooks + Plugins + Skills——扩展三角里,哪一层该稳定、哪一层该开放?

涉及源码 :Python 占位包 src/hooks/、src/plugins/、src/skills/ 与 src/reference_data/subsystems/*.json;Rust 侧 rust/crates/plugins(manifest/permission/hooks runner)。


1. "扩展三角"是什么

把可扩展系统拆成三角形,有一个很实用的工程直觉:

  • Hooks(钩子):把扩展挂到"生命周期/事件点"上(例如工具调用前/后)。
  • Plugins(插件) :把扩展作为一个可安装、可启停、可权限化的分发单元(manifest + registry)。
  • Skills(技能):把扩展包装成"可被发现、可被路由/调用的能力块"(面向用户或面向 agent 的可复用能力)。

三者常常都会"能做同样的事",但成熟产品会刻意分工:一层稳定做约束,一层开放做生态,一层面向体验做组合。


2. 先看本仓库的现实:Python 侧多为占位,Rust 侧更像产品骨架

2.1 Python:占位包 = 元数据锚点(对照归档)

Python 的 hooks/、plugins/、skills/ 当前都是统一模板:读取 reference_data/subsystems/*.json,暴露 MODULE_COUNT 与 SAMPLE_FILES,用于 parity 对照与目录地图(见 result/12.md)。例如:

python 复制代码
# 1:16:src/hooks/__init__.py
\"\"\"Python package placeholder for the archived `hooks` subsystem.\"\"\"
...
MODULE_COUNT = _SNAPSHOT['module_count']
SAMPLE_FILES = tuple(_SNAPSHOT['sample_files'])

快照显示:

  • hooks 在归档中体量大(module_count: 104),且包含 toolPermission/*、通知类 hook 等(说明 hooks 往往是"横切层")。
  • plugins 在归档中体量很小(module_count: 2),更像"注册/捆绑索引"。
  • skills 中等体量(module_count: 20),多为 bundled skills 与加载目录逻辑。

这正好符合常见产品分工:hooks 多且细、plugins 少而硬、skills 处在体验与可发现层。

2.2 Rust:插件与钩子的"可执行语义"已经长出来

Rust crates/plugins 提供了较完整的插件 manifest、权限与 hooks runner:

  • PluginManifest:含 permissions、hooks、lifecycle、tools、commands。
  • PluginPermission:Read/Write/Execute。
  • PluginToolPermission:read-only / workspace-write / danger-full-access(更贴近工具安全分级)。
  • HookRunner:支持 PreToolUse / PostToolUse,能运行外部 shell 命令并用 exit code 表示 allow/deny/warn。

例如 hooks runner:

rust 复制代码
// 65:93:rust/crates/plugins/src/hooks.rs
pub fn run_pre_tool_use(&self, tool_name: &str, tool_input: &str) -> HookRunResult {
    self.run_commands(
        HookEvent::PreToolUse,
        &self.hooks.pre_tool_use,
        tool_name,
        tool_input,
        None,
        false,
    )
}

pub fn run_post_tool_use(...)

以及"拒绝语义":exit code 2 → deny(并且立刻停止后续 hook):

rust 复制代码
// 174:186:rust/crates/plugins/src/hooks.rs
match output.status.code() {
    Some(0) => HookCommandOutcome::Allow { message },
    Some(2) => HookCommandOutcome::Deny { message },
    Some(code) => HookCommandOutcome::Warn { ... },
    None => HookCommandOutcome::Warn { ... },
}

这与 Python 文档 result/05.md 里谈的"拒绝要变成一等语义"高度一致:Rust 侧已经把 deny/allow/warn 变成 HookRunner 的稳定接口面。


3. 哪一层该稳定?(建议稳定面)

稳定层的核心是:一旦第三方依赖,就要尽量少破坏。在扩展三角里,建议优先稳定的是:

3.1 Hooks:稳定事件名 + 稳定 payload 形状

原因:hook 是"把系统切开一刀插针"的位置,生态会围绕 event 名与字段写脚本/插件。 \nRust 侧已经把事件名固定为 PreToolUse / PostToolUse,并构造 JSON payload:

  • hook_event_name
  • tool_name
  • tool_input(解析后的 JSON 或 raw)
  • tool_input_json
  • tool_output(post)
  • tool_result_is_error

这些字段一旦变动,外部脚本会大量断裂。因此:event 名与字段名应稳定,字段只做 additive 扩展。

3.2 Plugins:稳定 manifest schema + 权限模型

原因:插件分发与安装/启停需要可预测性。Rust 的 PluginManifest 与 permission 枚举就是典型"应稳定"的内容:\n\n- manifest 路径规范(.claw-plugin/plugin.json)\n- defaultEnabled 等开关\n- 权限枚举(以及工具权限分级)

一旦变动,安装器、市场、配置系统都要联动,成本极高。\n\n### 3.3 Skills:稳定"发现协议"和"调用契约",而不是稳定内部实现

skills 作为可发现能力,稳定的重点是:\n\n- skills 如何被索引(bundled/目录扫描/manifest)\n- skills 对外暴露的名称、描述、输入输出约定\n\nskills 内部实现可以更开放、更快迭代(因为它更贴近"内容层/体验层")。


4. 哪一层该开放?(建议开放面)

开放层的核心是:允许第三方创新与快速迭代,同时不破坏稳定层。

4.1 Skills 应该最开放(生态与体验的承载层)

skills 天生适合承载:prompt 模板、工作流脚本、领域知识封装、对工具链的组合调用。 \n只要调用契约稳定,skills 的数量和内容可以高速增长,且不会迫使核心 runtime 频繁发布破坏性版本。

4.2 Plugins 的"内容部分"开放,但"框架部分"稳定

插件里可以开放:\n\n- 自定义工具定义(tool spec + input schema + command)\n- 自定义命令(command spec)\n- hook 命令链(脚本)

但插件框架要稳定:manifest/registry/permissions/安装位置/启停语义。

4.3 Hooks 本身不宜太开放(事件点数量要克制)

hook 点越多越"自由",但也越难维护:\n\n- 每多一个 hook 事件名,都是一个稳定 API 面。\n- hook 点过细会导致行为难以推理("为什么工具没执行?哦是某个 hook deny 了")。

因此 hooks 最佳实践是:事件点少而关键 (如 pre/post tool use、session start/stop),并配合强审计(见 result/06.md)。


5. 三角如何协作(推荐职责边界)

可以把三角的"职责边界"写成一句话:

  • Hooks 负责"什么时候/在什么事件点"(稳定)
  • Plugins 负责"谁能装、装了能做什么、权限是什么"(稳定+部分开放)
  • Skills 负责"怎么把能力组合成可复用体验"(开放)

一个成熟的工具调用链常见流程(抽象):\n\n1. 模型请求 tool_call\n2. Plugin registry 决定该 tool 是否存在/是否启用/权限等级\n3. HookRunner 在 PreToolUse 执行策略脚本 → allow/deny\n4. 真实工具执行\n5. HookRunner PostToolUse 记录或改写输出\n6. 运行史落盘(审计/回放)

claw-code 目前 Python 侧只把占位与审计位摆出来;Rust 侧已经具备 (2)(3) 的大量骨架。\n\n---

6. 与仓库现状的对齐建议(避免"开放把自己玩坏")

结合本仓库现状,比较稳的演进顺序是:\n\n1. 先稳定 hooks/插件的最小公共面 (事件名、payload、manifest、权限枚举)。\n2. 用 skills 承载快速迭代 (bundled skills、目录加载、模板化工作流)。\n3. 把拒绝与审计贯穿 :hook deny、plugin permission deny 都应进入统一的 PermissionDenial / event log(Python 文档已指出持久化缺口)。\n\n如果反过来(先让 hooks 事件点无限增长、先让插件 schema 频繁破坏性变更),就会在生态早期把自己拖进"兼容地狱"。


7. 小结

  • 该稳定的:hooks 的事件名与 payload、plugins 的 manifest/registry/权限模型、skills 的发现/调用契约。
  • 该开放的:skills 内容与组合方式;plugins 内的具体工具/命令实现;hook 命令脚本(在稳定 payload 上)。
  • 该克制的:hook 事件点数量(每个都是长久维护承诺)。

相关推荐
外收内放16 小时前
ENSP学习记录(2)
网络·智能路由器
m0_7381207216 小时前
JWT 安全从入门到实战:六种典型攻击场景解析
前端·网络·python·安全·网络安全
zdd5678916 小时前
tcpdump测试
网络
xbzb16 小时前
OpenStack 网络管理(实操):建网络、连路由、浮动 IP 与安全组
网络·安全·openstack·ip·安全组·浮动
用户2986985301416 小时前
Python 实现 HTML 转纯文本:两种场景下的文档模型方案
python·html·api
叼烟扛炮16 小时前
Linux 学习笔记(四十七):TCP 状态机与 tcpdump 抓包排雷实战
linux·网络·笔记·学习·tcp/ip·tcpdump
车载中间件通信17 小时前
[TC8测试]TCP_FLAGS_INVALID_13_Flag SYN,ACK
网络·网络协议·tcp/ip
爱和冰阔落17 小时前
【Linux网络】UDP 聊天室怎么实现?从在线用户管理、消息广播到双线程收发与线程池
linux·运维·网络·udp
VIP_CQCRE17 小时前
Claude Code 如何接入 Ace Data Cloud?终端与 VS Code 配置指南
api·ai编程·vs code·claude code·ace data cloud
小小张说故事17 小时前
Python 的赋值为什么不会复制对象?拆开引用、浅拷贝与深拷贝
后端·python