编写 Skill Bundle
技能包是一种插件类型,完全不包含任何 WebAssembly。它是一个 markdown 技能目录,通过插件机制进行打包和分发:相同的清单、相同的发现方式、相同的签名策略、相同的 zeroclaw plugin install。当你要添加的能力是说明、提示和工作流,而不是代码,并且你希望使用插件分发语义(签名、注册表安装、版本管理),而不是 skills 目录中的松散文件时,就使用它。
先检查你的二进制文件。 技能包依赖插件机制。64 位桌面和服务器目标平台的发布归档包含插件宿主;两个 32 位 ARM 归档、实验性 Android 归档,以及使用 Cargo 默认设置的源码构建(
cargo install zeroclaw、install.sh --source)都不包含插件宿主。在这些版本中,zeroclaw plugin ...是无法识别的子命令,插件附带的技能也无法加载。每次发布都会从携带插件宿主的每个归档中执行一个插件,完整列表见按产物划分的插件支持表。如果二进制文件不包含插件宿主,可以从源码构建并启用插件执行后端,例如cargo build --release --features plugins-wasm-cranelift;也可以改用技能中介绍的原生技能包:zeroclaw skills bundle add <alias>用于创建技能包,zeroclaw skills install <source> --bundle <alias>用于将技能安装到该包中。这样得到的技能与插件分发的技能相同,且不涉及插件分发机制。
本指南已根据 crates/zeroclaw-plugins/src/host.rs 中的校验路径(validate_skill_bundle、validate_skill_md_frontmatter)以及 crates/zeroclaw-runtime/src/skills/mod.rs 中的加载器进行检查。
关于技能本身是什么以及代理如何使用它们,请先阅读Skills。本页仅介绍 bundle 打包。
布局
仅技能插件会省略 wasm_path,并包含符合 agentskills.io 格式的 skills/ 目录:
my-toolkit/
manifest.toml # capabilities = skill only, no wasm_path
README.md # optional bundle-level overview
skills/
design-review/
SKILL.md
scripts/ # optional
references/ # optional
code-review/
SKILL.md
data-analysis/
SKILL.md
references/
验证:是什么发现机制强制执行
主机会在发现和安装时验证 bundle 的形状,并在首次失败时拒绝整个插件(host.rs 中的 validate_skill_bundle)。具体规则:
skills/必须存在且是一个目录。- 它必须至少包含一个子目录。空的
skills/是无效的清单,而不是一个空的 bundle。 - 每个子目录都必须包含一个
SKILL.md。 - 每个
SKILL.md必须以 YAML frontmatter 开头(第一行是---分隔符,并以关闭的---结束),且该 frontmatter 必须声明非空的name和description键。
frontmatter 检查有意在发现时运行:当技能缺少 name 或 description 时,bundle 会在插件加载时失败,而不是在代理首次在对话中调用该技能时才失败。
有效的技能头部:
---
name: design-review
description: Structured design review workflow for architecture proposals.
---
# Design Review
...instructions...
命名空间化
已加载的 bundle 技能会以插件限定的 ID 注册:plugin:<plugin-name>/<skill-name>,例如 plugin:my-toolkit/design-review(namespace_plugin_skill 在 skills/mod.rs 中)。每个技能还会接收一个 plugin:<plugin-name> 标签。这可以防止与用户编写的技能以及不同 bundle 之间发生冲突:两个 bundle 都可以提供 code-review 技能并共存。
命名空间与技能优先级相互作用:在代理的有效技能解析中,来自不同来源的同名技能会按优先级去重,失败者会被记录为被遮蔽。除非同一捆绑名称的另一个副本也在参与,否则 plugin 限定符会让你的 bundle 完全避开这场争夺。
脚本
一个技能可以携带一个 scripts/ 目录。是否加载带脚本的技能由操作者的 skills.allow_scripts 设置决定,插件技能加载器会原样传递该设置(skills/mod.rs 中的 discover_plugin_skills):带脚本的捆绑包技能与工作区技能完全受相同的审核并丢弃规则约束。不要仅仅因为捆绑包已安装就假定你的脚本会运行。
清单
manifest 是插件目录中名为 manifest.toml 的文件。其字段是 crates/zeroclaw-plugins/src/lib.rs 中 PluginManifest 的 serde 表面,这是唯一的事实来源:
| 字段 | 必填 | 含义 |
|---|---|---|
name | 是 | 唯一的规范包 slug,也是每个派生实例配置键中的包组件。它本身不是操作符配置键。使用 1–128 个小写 ASCII 字符;以 [a-z0-9] 开头和结尾,中间只能包含 [a-z0-9._-]。发现过程会拒绝无效或重复的名称。 |
version | 是 | 版本字符串,例如 0.1.0。 |
description | 不 | 由 zeroclaw plugin list 显示的人类可读描述。 |
author | 不 | 作者姓名或组织。 |
wasm_path | 用于 WASM 能力 | 组件文件名,相对于插件目录。除非唯一的 capability 是 skill,否则为必填。如果指定的文件不存在,发现过程会跳过该插件。 |
wasm_sha256 | 在 WASM 能力的严格模式下 | 十六进制的 SHA-256 值,对应组件的精确字节内容。若存在该值,则始终强制校验;严格签名策略要求必须提供该值,以便已签名的清单能够绑定被准入的可执行文件。 |
capabilities | 是,非空 | 插件类型:tool、channel、memory、observer、skill 中的任意一个(PluginCapability,序列化为 snake_case)。 |
provides | 不 | 面向内置通道的 channel 插件(drop-in):它所镜像的蛇形命名配置 ID,例如 telegram、gmail_push。宿主会为每个已配置、已启用,且被已启用 agent 路由到的 [channels.<id>.<alias>] 准入一个逻辑实例,因此规范的通道配置仍是这些设置的唯一归属。需要 config_read。plugin 系列为保留项,会被拒绝;本构建未定义的 ID 会被拒绝;两个已安装包声明同一 ID 时,两者都会被拒绝。未设置(默认)时,表示从 [channels.plugin.<alias>] 配置的新通道。镜像已准入但尚未构建,参见 crates/zeroclaw-runtime/src/plugin_runtime.rs 中的激活计划。 |
permissions | 不 | 宿主服务(代码可能访问的服务):http_client、config_read、state_read、state_write、file_read、file_write、memory_read、memory_write(PluginPermission)。HTTP、配置和精确实例状态权限仅对工具/通道适配器强制执行;文件系统和内存权限目前不生效。声明 config_read 时必须同时声明 config_schema。 |
config_schema | 恰好使用 config_read | 为此插件的私有配置起草一份 Draft 2020-12 JSON Schema。它包含在规范清单字节中,因此清单签名时会一并覆盖。根对象必须是带有 properties 映射且 additionalProperties = false 的对象。每个顶层属性必须直接或通过本地 JSON Pointer 明确指定一种受支持的类型:string、boolean、integer、number、array 或 object。工具和通道的使用方可以直接在顶层 string 属性上设置 x-secret = true,使其从公共配置中移除,并通过限定作用域的 secrets.get 宿主导入提供。secret 属性名是 1–128 字节的可移植 ASCII 名称,只能包含字母、数字、_、- 或 .。工具通过 __config 接收公共配置,并可在 execute 期间读取 secret。通道在 configure 和运行时操作调用期间,通过 config.get 读取当前公共对象,并通过 secrets.get 读取 secret;这两个导入在实例化和静态元数据发现期间均不可用。嵌套的、值为 false 或非布尔值的 secret 标记,以及非字符串的 secret 属性都会被拒绝。没有 config_read 的 schema,或没有 schema 的 config_read,都会被拒绝。 |
signature | 不 | 对规范化清单字节进行的 Base64url Ed25519 签名。用于发布签名时设置。 |
publisher_key | 不 | 签名者的十六进制编码 Ed25519 公钥。 |
egress | 不 | 可选的 [egress] 表,包含一个 hosts 列表:声明该插件所需访问的目标地址,可以是精确主机名(api.example.com)或显式的后缀模式(*.example.com,匹配子域名但不匹配顶级域名本身)。该表属于规范化的清单字节内容,因此在清单签名时会被一并覆盖,修改它需要重新签名。无效语法会在发现和安装阶段导致整个清单被拒绝。缺失、为空以及“未声明任何内容“三种状态视为相同。 |
只声明代码实际使用的权限。未声明的权限是组件无法触达的宿主表面;不必要声明的权限则是你主动增加的攻击面,也是审查你的插件的人需要承担的审核负担。
[egress] 是一项声明,而非授权。清单文件本身不赋予任何网络访问权限:主机强制执行的白名单是运维人员在该实例自身的 zpi1_… 记录上设置的 plugins.entries[].egress_hosts,因此即使未签名的组件自行写入了 [egress] 表,也无法访问任何地址。声明的作用在于安装流程:zeroclaw plugin install 会将其写入它新建的记录中,并打印已授予的内容;对于已存在的记录,它从不会扩大其权限。参见 Declaring and granting egress。
操作方提供的值在 plugins.entries 中仍保持为字符串,并会在持久化时加密,以一个由宿主拥有的包、能力和绑定标识派生的版本化 zpi1_… 字符串作为键(安装过程会打印并初始化默认工具绑定的完整实例密钥):字符串按原样存储,布尔值和数字使用 JSON 标量文本,数组和对象使用 JSON 文本。在任何来宾代码运行之前,宿主会将这些字符串物化为包模式规定的类型,并针对工具和频道适配器验证完整对象。非机密工具属性构成 __config;频道通过 config.get 获取非机密对象。标记为 x-secret = true 的属性会从两个公共接口中省略,仅可在授权的服务帧中通过 secrets.get("property") 获取。频道在一次调用中的公共和机密读取共享同一个规范修订版本,调用结束时宿主会丢弃该物化视图。符合要求的频道插件 必须 在每个使用点都解析这两类值,并且不得在来宾的热状态中保留配置或凭据值;将明文返回给来宾意味着宿主无法针对恶意代码强制实施不保留策略。如果请求了 config_read 但未实际获授予,宿主会验证一个空对象;因此,包含必需属性的模式会拒绝启动,而不会在缺少必需配置的情况下启动。如果空对象有效,工具会省略空的 __config,而频道的配置/机密导入会返回 access-denied;在授权帧之外的调用、解析失败以及宿主调用预算耗尽会返回 unavailable。
对于一个技能包:capabilities 仅包含 skill,不包含 wasm_path,并且通常根本没有 permissions;该包是数据,而权限集用于控制 Markdown 从不调用的宿主函数。
混合能力插件(例如 tool + skill)是合法的:此时它必须为工具世界携带一个有效的 wasm_path,并且还要有一个有效的 skills/ bundle,而且两项校验都会运行。
安装并验证
这些命令需要一个编译了插件宿主的二进制文件。 64 位桌面和服务器目标的发布归档包(x86_64 和 aarch64 的 Linux,包括 glibc 和 musl 版本,Apple silicon 与 Intel 的 macOS,以及 Windows x86_64)都包含该宿主,并且每次发布前都会从这些归档中各执行一个插件,然后才会正式发布。两个 32 位 ARM 归档和实验性的 Android 归档不包含该宿主,使用 Cargo 默认配置的源码构建也不包含(
cargo install zeroclaw、install.sh --source或不带特性的cargo build):在这些情况下,zeroclaw plugin ...会被识别为未知子命令,已安装的插件也永远不会被发现。对于这些情况,请使用插件执行后端从源码构建,例如cargo build --release --features plugins-wasm-cranelift。协议页面列出了每个构件的插件支持情况。
每个插件都位于 plugins 目录的各自子目录中(默认 ~/.zeroclaw/plugins/,通过 plugins.plugins_dir 解析),其中包含清单以及与清单的 wasm_path 匹配的组件:
~/.zeroclaw/plugins/
└── my-plugin/
├── manifest.toml
└── my-plugin.wasm
从本地目录安装(这会在复制任何内容之前验证清单形状并运行签名策略):
zeroclaw plugin install ./my-plugin/
启用插件系统并确认发现:
zeroclaw config set plugins.enabled true
zeroclaw plugin list
zeroclaw plugin info my-plugin
zeroclaw plugin list 和 zeroclaw plugin info 可确认软件包已安装且可被发现,但发现并不等于激活。plugins.enabled = true 会开启插件主机;只有同时将 plugins.auto_discover = true 设为 true 时,自动发现的工具和技能功能才会在运行时加载,而该标志默认为 false(故障关闭):
zeroclaw config set plugins.auto_discover true
因此,仅设置 plugins.enabled = true 时,会启用你在 [channels.plugin.<alias>] 下声明的通道,而不会启用任何插件工具或技能:工具或技能包可能会出现在 zeroclaw plugin list 中,但在运行时不会产生任何作用。显式通道绑定由操作员命名,而不是自动发现,因此不需要 auto_discover;该标志仅控制自动发现的工具和技能。
zeroclaw plugin list 中缺失的插件在发现时已被跳过:请检查启动日志中的跳过警告(清单格式错误、缺少 wasm_path 文件,或签名策略拒绝)。
在发现之后,这些技能会在技能界面(技能列表、仪表板)中以 plugin:<your-bundle>/<skill> 的命名空间形式显示。请让代理使用其中一个,以确认端到端流程。
下一个
- 发布插件:技能包是最简单的发布形式,其签名流程与 WASM 插件完全相同。