每个插件包的根目录都有一个 plugin.json,即插件清单(Manifest)。宿主在安装时按 v3 JSON Schema 校验它,再做跨字段检查(权限组合、文件哈希、图标等)。清单中未定义的字段一律拒绝。
顶层字段
| 字段 | 必填 | 类型与约束 | 说明 |
|---|---|---|---|
schema_version | 是 | 常量 3 | 清单协议版本。 |
plugin_id | 是 | ^[a-z][a-z0-9.-]{2,63}$ | 全局唯一且不可变的插件标识,建议用反向域名,如 com.example.my-notes。 |
name | 是 | 字符串,1–80 | 插件名称。 |
display_name | 否 | 字符串,1–80 | 界面展示名;未提供时使用 name。 |
description | 否 | 字符串,1–200 | 一句话简介,显示在插件列表和安装预览中。 |
plugin_type | 否 | workspace | knowledge | skill | integration | utility | 插件分类:工作区、知识源、技能、集成、工具。 |
icon | 见说明 | { "resource_id" } | 指向 contributions.resources 中的一项 PNG 资源。新打包的插件必须提供,见图标。 |
i18n | 否 | 对象 | 插件自带的多语言信息,见多语言。 |
version | 是 | 语义化版本,如 1.2.0、1.2.0-beta.1 | 插件版本。 |
minimum_app_version | 是 | 字符串,5–32 | 要求的最低桌面端版本,低于此版本时拒绝安装。 |
contributions | 是 | 对象 | 插件提供的界面、技能和资源,见贡献。 |
workers | 是 | 数组,≤16 | 后台 Worker 进程,没有时写 []。 |
triggers | 否 | 数组,≤32 | 定时或生命周期触发器。 |
event_channels | 否 | 数组,≤16 | 长连接事件通道。 |
credentials | 否 | 数组,≤16 | 由宿主保管的凭据。 |
requested_permissions | 是 | 数组,≤64 | 申请的权限,见权限。 |
required_services | 是 | 数组,≤32 | 依赖的服务,没有时写 []。 |
ai_runtime | 否 | 对象 | 宿主托管的 AI 运行时,必须与 runtime.ai 权限同时出现,仅对官方来源开放。 |
platforms | 是 | 至少一项:windows-x86_64 | macos-aarch64 | macos-x86_64 | 支持的平台,当前平台不在列表中时拒绝安装。 |
files | 是 | 对象:路径 → 64 位小写十六进制 | 包内每个文件的 SHA-256,构成封闭文件集。 |
publisher | 是 | 字符串,1–120 | 发布者名称。 |
publisher_key_id | 否 | ^[A-Za-z0-9._-]{3,128}$ | 签名公钥标识,与 signature 成对出现。 |
signature | 否 | 字符串,40–4096 | 清单签名,与 publisher_key_id 成对出现。由打包工具生成,不要手写。 |
本地标识
清单内各项的 id(workspace、worker、skill、resource、trigger 等)都遵循同一规则:^[a-z][a-z0-9_-]{1,47}$,即小写字母开头、2–48 位。同类贡献的 id 在清单内不能重复。
图标
- 在
contributions.resources中声明一项media_type为image/png的资源,再用icon.resource_id引用它。 - 图片必须恰好是 200×200 像素的 PNG,文件不超过 500 KiB,并出现在
files中。 - 打包时缺图标、不是 PNG、尺寸不对或没有进入
files,会直接拒绝出包(PLUGIN_MANIFEST_INVALID);安装时图标资源不合法报PLUGIN_ICON_INVALID。 - 已经发布的旧包没有图标仍然可以安装,但重新打包前必须补上 200×200 的图标。
- 工作区和顶部栏页面里用到的图片、字体等素材直接放在
payload/ui/下,不需要通过resources声明。
多语言
i18n 让插件自带名称、简介和界面文案的多语言版本,不需要也不允许向桌面端的语言包写入内容。
| 字段 | 必填 | 约束 | 说明 |
|---|---|---|---|
default_locale | 是 | ^[a-z]{2}(-[A-Z]{2})?$ | 默认语言,如 zh-CN。 |
languages | 是 | 数组,1–32 | 每种语言一项。 |
languages[].locale | 是 | 同上 | 语言标签。 |
languages[].label | 是 | 1–40 | 语言名称,如「简体中文」。 |
languages[].display_name | 是 | 1–80 | 该语言下的插件展示名。 |
languages[].description | 否 | 1–200 | 该语言下的简介。 |
languages[].workspaces | 否 | 对象:workspace id → { "title" } | 该语言下的工作区标题。 |
languages[].ui_catalog | 否 | payload/i18n/*.json | 界面文案字典,界面中用 i18n.t() 读取。 |
至少一项贡献
清单必须在 contributions 中提供 knowledge_providers、workspaces、skills、resources 中的至少一项。由于新插件必须通过 resources 声明图标,只有顶部栏项、没有工作区的插件同样合法。
贡献(contributions)
所有入口、资源和技能文件都必须位于 payload/ 下,并出现在 files 中。
workspaces:工作区界面
数量上限 16 项。每项是一个在沙箱 iframe 中运行的 HTML 页面,API 见 Workspace 与 Bridge API。
| 字段 | 必填 | 约束 | 说明 |
|---|---|---|---|
id | 是 | 本地标识 | 工作区标识。 |
title | 是 | 1–80 | 工作区标题。 |
entrypoint | 是 | payload/ui/*.html | 入口页面。 |
bridge_version | 是 | 常量 "1.0" | Workspace Bridge 版本。 |
allowed_placements | 是 | 至少一项:replace_files | replace_editor | replace_both | 允许的摆放位置:替换文件区、替换编辑区、两者都替换。 |
default_placement | 是 | 同上,单个值 | 默认摆放位置。 |
worker | 否 | 引用 workers[].id | 界面通过 worker.invoke 调用的 Worker。 |
drops | 否 | 对象 | 接收文件拖放,需要 storage.blob。宿主把文件存进插件 Blob 存储后再通知界面,插件拿不到系统路径。 |
drops.extensions | 是* | 1–16 项,^[a-z0-9]{1,16}$ | 接受的扩展名,不带点。 |
drops.max_files | 是* | 1–16 | 单次最多文件数。 |
drops.max_bytes | 是* | 1–1073741824 | 单次总字节数上限。 |
capture_providers | 否 | ≤8 项 | 向 Agent 提供界面截图,需要 agent.capture 和 storage.blob。 |
capture_providers[].id | 是* | 本地标识 | 截图提供者标识。 |
capture_providers[].description | 是* | 1–160 | 告诉 Agent 这张截图展示什么。 |
capture_providers[].max_long_edge | 是* | 256–4096 | 截图长边像素上限。 |
connect | 否 | ≤64 个 http(s) origin | 见网络声明。 |
标 * 的字段在其父对象出现时必填。
topbar_items:顶部栏项
数量上限 16 项,显示在工作区插件专用的顶部栏。side 为 full 的项独占整行,同一分区的插件不能同时启用。
| 字段 | 必填 | 约束 | 说明 |
|---|---|---|---|
id | 是 | 本地标识 | 顶部栏项标识。 |
side | 是 | left | center | right | full | 所在分区。 |
label | 是 | 1–32 | 显示文字。 |
tooltip | 否 | 1–160 | 悬停提示。 |
priority | 否 | -100–100,默认 0 | 同分区内的排序优先级。 |
workspace | 否 | 引用 workspace id | 点击后打开的工作区。 |
worker | 否 | 引用 worker id | 提供数据的 Worker,与 method 同时出现。 |
method | 否 | ^topbar\. 开头 | 宿主定期调用的 Worker 方法。 |
entrypoint | 否 | payload/ui/*.html | 嵌入式小页面,与 bridge_version 同时出现。 |
bridge_version | 否 | 常量 "1.0" | 嵌入页面使用的 Bridge 版本。 |
min_width | 否 | 48–600,默认 48 | 最小宽度(像素)。 |
max_width | 否 | 48–600,默认 280 | 最大宽度(像素)。 |
refresh_seconds | 否 | 1–300,默认 15 | 调用 method 的刷新间隔。 |
connect | 否 | ≤64 个 http(s) origin | 见网络声明。 |
每个顶部栏项必须是以下三种形态之一:
- 静态:只有
label等展示字段,不带worker、method、entrypoint、bridge_version。 - Worker 驱动:同时提供
worker和method,不带entrypoint。 - 嵌入页面:同时提供
entrypoint和bridge_version,不带method。
skills:技能
只接受 1 项,超过 1 项时安装报 PLUGIN_MANIFEST_INVALID。该项为 { "id", "entrypoint" },entrypoint 为 payload/agent/*.md。技能文件告诉 Agent 如何读取插件发布的上下文、可以发送哪些动作。技能文件同样参与哈希和签名校验,但不会因此获得额外的工具权限。
payload/agent/ 下只放这一个文件。resources:资源
最多 64 项,三个字段都必填:id(本地标识)、path(payload/resources/ 下的文件)、media_type(type/subtype 形式,3–127 字符)。资源是给宿主读取的文件,目前用于根级 icon 和 ai_runtime。
knowledge_providers:知识源
数量上限 16 项,每项 { "id", "worker" },worker 引用 workers[].id。
网络声明(connect)
工作区和顶部栏项可以用 connect 列出会访问的 origin(只能是 http:// 或 https:// 加主机和可选端口,不带路径),用于在安装页展示。声明 connect 时必须同时申请 worker 为 host 的 net.fetch,否则拒绝安装。地址由用户自行配置时可以省略 connect。
"connect": ["https://api.example.com"]
workers:Worker
数量上限 16 项。Worker 的运行方式和协议见 Worker。
| 字段 | 必填 | 约束 | 说明 |
|---|---|---|---|
id | 是 | 本地标识 | Worker 标识,供权限、工作区、触发器引用。 |
entrypoint | 是 | payload/worker/* | 入口脚本。 |
protocol_version | 是 | 常量 "2.0" | Worker 协议版本。 |
isolation | 是 | sandboxed_plugin | dev_unrestricted | 隔离级别。dev_unrestricted 需要用户授予本电脑模式后才会以不受限方式运行。 |
activation | 是 | on_demand | on_startup | 按需启动,或随应用启动。on_startup 只拉起进程,不会自动执行业务。 |
resource_limits.memory_mb | 是 | 64–2048 | 内存上限(MB)。 |
resource_limits.cpu_percent | 是 | 1–100 | CPU 占用上限(%)。 |
resource_limits.max_inflight | 是 | 1–64 | 同时处理的请求数上限。 |
execution_policy | 否 | sandbox | trusted,默认 sandbox | trusted 需要用户在安装时勾选确认,仍在沙箱内运行,不能启动子进程。 |
资源上限按实际需要设置,不要为规避问题盲目放大。
required_services:依赖的服务
| 字段 | 必填 | 约束 | 说明 |
|---|---|---|---|
service_id | 是 | ^[a-z][a-z0-9.-]{2,127}$ | 服务标识,如 com.stabledge.ocr。 |
version | 是 | 1–64 | 语义化版本范围,如 ^1.0.0。 |
worker | 是 | 本地标识 | 调用该服务的 Worker,该 Worker 必须同时申请 service.invoke。 |
optional | 否 | 布尔,默认 false | 为 true 时服务缺失不阻止安装,插件需自行降级。 |
后台任务、事件与凭据
插件需要在不打开界面、没有 Agent 消息时运行(定时同步、启动或唤醒后补一次、持续监听推送)时,使用下面三类声明。后台运行一律由宿主调度:到点或来事件时,宿主调用你声明的 Worker operation。不要在 Worker 里自己 setInterval 或自己维持 socket。
triggers:触发器
| 字段 | 必填 | 约束 | 说明 |
|---|---|---|---|
id | 是 | 本地标识 | 触发器标识。 |
kind | 是 | interval | startup | resume | 按间隔、应用启动后、系统唤醒后。 |
worker | 是 | 本地标识 | 执行的 Worker。 |
operation | 是 | ^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$ | 调用的 operation,必须出现在 Worker 握手返回的 methods 中。 |
minimum_interval_seconds | 见说明 | 60–604800 | kind 为 interval 时必填,其他类型不得填写。 |
default_enabled | 否 | 布尔,默认 false | 为 false 时需要用户在插件详情页「后台任务」中手动启用。 |
catch_up | 是 | skip | once | 错过多个周期后,不补或最多补一次。 |
"triggers": [
{
"id": "sync",
"kind": "interval",
"worker": "main",
"operation": "sync.incremental",
"minimum_interval_seconds": 900,
"default_enabled": false,
"catch_up": "once"
}
]
event_channels:事件通道
长连接由宿主维持(建连、心跳、断线重连),每收到一条事件就调用一次声明的 operation。对应 Worker 必须申请 events.connect。
| 字段 | 必填 | 约束 | 说明 |
|---|---|---|---|
id | 是 | 本地标识 | 通道标识。 |
kind | 是 | sse | websocket | webhook | webhook 指云端 Webhook 中转:由你的云服务接收第三方 Webhook,再通过 wss:// 推给宿主。 |
worker | 是 | 本地标识 | 处理事件的 Worker。 |
operation | 是 | 同触发器 | 处理事件的 operation。 |
url | 是 | URI,≤2048 | sse 要求 https://,另外两种要求 wss://。本地开发时允许 http:// / ws:// 指向 127.0.0.1、localhost 或 [::1]。 |
credential_refs | 否 | ≤8 项 | 建连时注入的凭据 id。 |
protocols | 否 | ≤8 项 | WebSocket 子协议。 |
default_enabled | 否 | 布尔,默认 false | 目前没有单独开关事件通道的界面,是否连接由该字段决定。 |
投递语义为至少一次:operation 成功返回即确认,抛错或超时则在重连后重放。请按事件 id 做幂等处理。
credentials:凭据
凭据由用户在插件详情页填写或完成授权,保存在系统钥匙串中。Worker、Agent 和界面都读不到明文,只能按引用让宿主注入请求。声明凭据的 Worker 必须申请 net.fetch 或 events.connect。
| 字段 | 必填 | 约束 | 说明 |
|---|---|---|---|
id | 是 | 本地标识 | 凭据标识。 |
label | 是 | 1–80 | 显示给用户的名称。 |
kind | 否 | static | oauth2,默认 static | 静态密钥或 OAuth2。为 oauth2 时必须提供 oauth2 对象。 |
worker | 是 | 本地标识 | 使用该凭据的 Worker。 |
allowed_origins | 是 | 1–32 个 https:// origin | 只有请求目标在列表中时才注入。 |
injection.location | 是 | header | query | 注入位置。 |
injection.name | 是 | ^[A-Za-z][A-Za-z0-9_-]{0,63}$ | 请求头名或查询参数名。 |
injection.prefix | 否 | ≤64,默认空 | 值前缀,如 Bearer 。 |
oauth2 凭据
宿主负责 PKCE、令牌刷新和轮换;遇到 401 会强制刷新并重试一次。
| 字段 | 必填 | 约束 | 说明 |
|---|---|---|---|
authorization_endpoint | 是 | https://,不带查询和片段 | 授权地址。 |
token_endpoint | 是 | 同上 | 换取令牌的地址。 |
revoke_endpoint | 否 | 同上 | 撤销令牌的地址。 |
client_id | 是 | 1–512 | 客户端标识。 |
scopes | 否 | ≤64 项 | 申请的授权范围。 |
callback_mode | 是 | custom_scheme | loopback | 回调方式:自定义协议或本机回环地址。 |
client_auth | 否 | none | client_secret_post | client_secret_basic,默认 none | 客户端认证方式。 |
token_request_encoding | 否 | form | json,默认 form | 令牌请求体编码。token_method 为 get 时不能用 json。 |
token_method | 否 | get | post,默认 post | 令牌请求方法。 |
response | 否 | 对象,值为 JSON Pointer | 非标准响应时,指出 access_token、refresh_token、expires_in、token_type、error、error_description 和 metadata 所在位置。 |
authorization_params | 否 | ≤32 个键值 | 授权请求的附加参数。 |
token_params | 否 | ≤32 个键值 | 令牌请求的附加参数。 |
input、cursor、日志或 Worker 内存的长期缓存中。ai_runtime
ai_runtime 让宿主拉取源码、建立 Python 环境并托管一个模型运行时,必须与 runtime.ai 权限同时出现。它只对官方来源开放,第三方发布者的包一律拒绝安装。第三方插件需要模型或重型计算时,请使用全局 Worker 服务,或让用户自行运行本机 HTTP 服务。
files:封闭文件集
- 键是以
/分隔、以payload/开头的相对路径;值是原始文件字节的 SHA-256(64 位小写十六进制)。 - 不能漏列文件、多列文件,不能出现绝对路径、
..、反斜杠和符号链接。 - 每次修改
payload/后都要重新打包;旧的哈希和签名会立即失效。不要手改files。
v1 / v2 清单
桌面端仍能安装 v1 和 v2 清单,但只用于兼容旧插件和迁移,新插件一律使用 v3。
| 版本 | 特点 |
|---|---|
| v1 | 只支持知识源插件;顶层有 entrypoint 和 capabilities;必须签名。 |
| v2 | 加入 workspaces 和 agent_integration,capabilities 扩展了工作区和 Agent 事件能力;signature 必填。 |
| v3 | 以 contributions、workers、requested_permissions 取代 capabilities;支持顶部栏、后台任务、凭据、服务依赖;允许未签名的开发者包。 |