安全与参考
插件发布 V1:作者与智能体指南
本文给插件作者、开发智能体和内置 QA 智能体使用。目标是把一个插件准备成可审核的官方市场内容,让用户在支持该链路的客户端中刷新、添加或更新,无需为每个新插件重装客户端。
V1 指官方内容分发协议。插件自己的版本、客户端版本、后端 Host API 和前端 UI SDK 分别管理。本文描述代码支持的流程,不代表某个历史安装包已经具备全部能力;以目标安装包的交付记录和实际验收为准。
接到任务先确认输入
| 输入 | 要求 |
|---|---|
| 任务范围 | 区分解释文档、开发插件、准备内容 PR、正式发布。已有明确授权就继续;“准备插件”不自动包含生产发布。 |
| 插件身份 | 稳定 ID、新 SemVer、开发源码位置、要交付的运行文件。示例 ID example-echo 不是待上架商品。 |
| 用户任务 | 用户装好后在哪里、通过哪些操作完成什么工作;给出可复现验收步骤。 |
| 兼容目标 | 明确客户端安装包、平台、后端 Host API 范围;有前端时还要确认 UI SDK。 |
| 外部条件 | 实际许可证、第三方服务、配置项、网络域名、文件/进程操作与凭据使用。 |
| 发布权限 | 普通作者提交包和元数据,由有权限的维护者审核并签名发布。没有仓库权限时交付运行包和元数据,不索要生产私钥。 |
缺少输入时先列出缺口,可以继续完成不依赖它的开发和校验。不要猜兼容范围、许可证或生产发布授权。QA 智能体默认负责检索、解释与交接;实际修改和发布以当前任务授权及自身能力为准。
文件放在哪里
正式内容源由 CogineWork 仓库维护,无需另建管理应用:
official-assets/v1/
├── publication.json
└── packages/plugin/<id>/<version>/<id>/
├── plugin.json
├── plugin.py
├── LICENSE
└── dist/index.js # 可选的已构建前端入口
official-assets/presentation/v2/source.json
publication.json 管身份、安装兼容、权限和状态;当前展示源是 official-assets/presentation/v2/source.json,管分类、精选、图标和详情。正式发布从这份 v2 源生成兼容旧客户端的 presentation.json 和新版 presentation-v2.json,两个输出仍发布在 metadata/official-assets/v1/ 路径下。presentation/v1/source.json 保留给旧工具兼容,不是当前正式发布的内容输入;只改它不会更新正式展示。
官网与 QA 共用本页,客户端读取发布后的签名目录和运行包;仅把代码提交到开发仓库不会自动上架。
下文所有仓库相对路径以 CogineWork 源码根目录为起点。只有安装包、没有源码的智能体可以准备交付材料;不要假设安装目录里有 CI 配置、测试或发布器。
第一步:准备已构建的运行包
plugin.json 至少一个后端或前端入口,身份和版本必须与目录一致。下面仅演示格式,兼容区间必须换成经过验收的目标范围,不能直接把示例当作生产条目:
{
"schema_version": "official-plugin-manifest-v1",
"id": "example-echo",
"name": "Example Echo",
"version": "1.0.0",
"description": "Echo text for a plugin authoring example.",
"author": "Cogine",
"type": "tool",
"entry": { "backend": "plugin.py" },
"dependencies": [],
"coginework_version": { "min": "2.4.0-beta.5", "max": "4.0.0" },
"plugin_host_api": { "min": "1.1.0", "max": "2.0.0" },
"meta": {}
}
区间语义为 >=min,<max。清单使用协议 SemVer,例如 2.4.0-beta.5;不要直接复制 Python 包版本 2.4.0b5。示例下界不是对该历史桌面包的功能保证。
最小后端入口 plugin.py:
from coginework.plugins import PluginApi
async def example_echo(text: str) -> str:
return text
class EchoPlugin:
def register(self, api: PluginApi) -> None:
api.register_tool(
tool_name="example_echo",
tool_func=example_echo,
description="Echo the supplied text.",
)
plugin = EchoPlugin()
模块必须导出 plugin 并实现 register(api)。未声明工具治理的工具在受管模式下可能要求批准。文件、网络和进程工具应按宿主合同使用 ToolGovernance/ToolEffect;市场里的权限声明不等于运行时授权。
包准备规则:
- 后端入口是包根目录的
.py,前端入口是包内.js/.mjs,声明的文件必须存在。 - 有前端时使用仓库
console/plugin-sdk/和console/examples/frontend-plugin-template/的 README,先构建单文件 ESM 再放进运行包。不要假定 SDK 已发布到公共 npm。 - 官方 V1 运行包不允许
requirements.txt、package.json或 pip/npm 安装命令;运行依赖按下节准备。 - 放入实际
LICENSE;不放凭据、.git、虚拟环境、缓存、node_modules、符号链接或临时制品。 - 官方包由发布器生成确定性 ZIP,当前最多 50 MiB、1024 文件;单文件最多 32 MiB,解包总量最多 200 MiB。
运行依赖怎么准备
| 依赖类型 | 当前规则 |
|---|---|
plugin.json.dependencies | 声明宿主提供的依赖;当前官方发布白名单为空,填写 []。不能把任意 pip/npm 包名写进去期待安装时补齐。 |
publication.json 条目的 dependencies | 声明其他市场资产的精确 {kind,id,version},由客户端生成安装计划;不是 Python/Node 包依赖。 |
| 构建依赖与随包代码 | 作者可以在开发项目中使用构建依赖,将适合分发的运行代码打包或 vendor 到产物中,并保留相应许可证;只交付通过包校验的运行文件。 |
| MCP 运行产物 | 支持该链路的客户端可按 mcp_install 声明准备独立 MCP 产物,规则见下文;它不为普通插件提供任意依赖安装。 |
后端可依赖的稳定扩展接口以对应的 Host API 合同为准,包括 PluginApi 和工具治理类型;dependencies: [] 不表示禁止导入这些接口或合规的包内模块。
后端 Python 插件加载在 CogineWork 后端进程中。技能脚本使用的独立 Python/Node 及其预装库,不代表后端插件能直接导入同一批库,也不代表任意第三方依赖已具备。作者应对目标客户端、系统和架构验证实际依赖,写清外部软件与准备步骤,不把本机开发环境当作接收者环境。
桌面构建会为独立 Python 准备部分文档库,例如 python-docx、openpyxl、python-pptx、pypdf;实际版本和可用性应在目标安装包中检查,Node 的模块也应单独检查。LibreOffice、Poppler、pandoc、中文字体等仍是需要作者明确列出的外部条件,并非都已随客户端提供。
官方 MCP 连接器可以在 plugin.json 中声明 mcp_install(schema_version: mcp-install-v1):固定 runtime.version、制品完整性摘要 integrity、启动参数及所需解释器,并按实际支持情况声明平台制品。运行来源支持 npm、pypi、url、sidecar;宿主准备过程(provision)负责下载或复制、校验、展开该产物,不会递归运行 npm/pip 安装它的依赖。作者仍需准备能独立运行的产物或提前解决依赖;指向 npm/PyPI 包并不等于它的运行依赖已齐备。
例如仓库的 pexels-mcp 包先把 MCP 及其运行依赖构建为 runtime/pexels-mcp-server.mjs,再用 sidecar 和固定 SHA-256 声明交给宿主准备。可参考 official-assets/v1/packages/plugin/pexels-mcp/1.0.1/pexels-mcp/plugin.json;示例不代表其他 MCP 或所有平台已经验收。API Key、OAuth 等凭据由接收者配置或授权,通过声明的凭据引用使用,不放入发布包。
第二步:准备完整安装条目
以下是新增 publication.json.assets 条目的模板。两个时间占位符和许可证摘要必须替换为真实值;它不是可以原样发布的 JSON。statement、下载 URL 和制品路径由维护者的发布器生成,不手写。
{
"schema_version": "official-asset-v1",
"kind": "plugin",
"id": "example-echo",
"version": "1.0.0",
"package_profile": "plugin-bundle-v1",
"name": { "en-US": "Example Echo", "zh-CN": "回显示例" },
"description": {
"en-US": "Echo supplied text.",
"zh-CN": "返回输入的文本。"
},
"compatibility": {
"coginework": { "min": "2.4.0-beta.5", "max": "4.0.0" },
"plugin_host_api": { "min": "1.1.0", "max": "2.0.0" }
},
"status": "active",
"capabilities": ["tools"],
"permissions": ["agent.tools.register"],
"network": { "mode": "none", "domains": [] },
"dependencies": [],
"license": {
"expression": "MIT",
"path": "example-echo/LICENSE",
"sha256": "REPLACE_WITH_ACTUAL_LICENSE_SHA256"
},
"published_at": "REPLACE_WITH_UTC_TIMESTAMP",
"updated_at": "REPLACE_WITH_UTC_TIMESTAMP"
}
MIT 也是示例,必须与实际许可证一致。license.path 含包根 ID;在 macOS/Linux 可用 shasum -a 256 <LICENSE路径> 计算摘要,时间采用 YYYY-MM-DDTHH:MM:SSZ。
兼容区间与包清单保持一致;两处 dependencies 的区别见上节。网络访问要如实列出域名与 network.outbound,有前端时声明 frontend 能力和 ui.extend 权限。
第三步:准备展示条目
在 official-assets/presentation/v2/source.json 的 assets 添加下面的条目,分类必须在同一文件的 categories 中存在。更新时身份中的版本也要更新;由发布器生成 v1/v2 输出,不手工修改生成文件:
{
"kind": "plugin",
"id": "example-echo",
"version": "1.0.0",
"featured": false,
"featured_order": 0,
"category_ids": ["getting-started"],
"icon": "puzzle",
"details": {
"en-US": "## Use\nEcho supplied text.\n\n## After adding\nCheck the plugin is loaded, then invoke example_echo.",
"zh-CN": "## 适用场合\n返回输入文本。\n\n## 添加之后\n确认插件已加载,再调用 example_echo。"
}
}
featured_order 即使不精选也必须填写。不要仅写“提供强大能力”;写清使用入口、完成的任务、所需配置和数据去向。展示字段不能更改安装权限或替代签名。新增场景分类、图标等以仓库合同为准,不猜枚举值。
第四步:校验并交接
有源码访问权限时,使用仓库开发 Python 环境,从根目录执行规范化。先将示例路径替换为真实 ID/版本:
PYTHONPATH=src:. python - <<'PY'
import json
from pathlib import Path
from scripts.official_assets.contract import canonical_json_bytes, pretty_json_bytes
manifest = Path("official-assets/v1/packages/plugin/example-echo/1.0.0/example-echo/plugin.json")
manifest.write_bytes(canonical_json_bytes(json.loads(manifest.read_bytes())))
publication = Path("official-assets/v1/publication.json")
source = json.loads(publication.read_bytes())
source["assets"].sort(key=lambda item: (item["kind"], item["id"], item["version"]))
publication.write_bytes(pretty_json_bytes(source))
PY
PYTHONPATH=src:. python -m pytest \
tests/contract/official_assets/test_production_source.py \
tests/unit/official_assets/test_generate_presentation.py -q
新开发环境可按仓库贡献说明创建隔离虚拟环境并安装 .[dev,test];不要为做校验而修改用户已安装客户端。缺依赖、没有源码或测试失败时说明具体命令与错误,不宣称校验成功。
本地校验使用隔离测试密钥验证真实内容,不接触生产私钥、不上传。它不能证明生产目录代次或桌面兼容性。普通作者提交包、安装条目、展示条目与业务验收证据即可;维护者负责从生产已签名目录取 predecessor、推进 generation、审核并发布。没有生产上下文时不要猜 generation。
仓库维护者的完整操作说明是 docs/2026-09-21-plugin-publishing-handbook-v1.md,它包含环境核对、生产目录验签、首次初始化和发布读回。该路径只对有源码访问权限的维护者适用;QA 安装包或官网无需能打开它才能解释本页流程。
交接时输出这份清单:
结果:包已准备 / 内容 PR 待审 / 生产已发布(只能填写有证据的阶段)
插件:ID、版本、源码提交与运行包位置
文件:包、安装条目、展示条目
兼容:目标安装包、平台、Host API/UI SDK;已测和未测范围
校验:命令、结果、日志路径;业务任务复现步骤
权限:文件、网络域名、凭据、进程行为及必要配置
交付:PR URL 或交付目录;缺失输入与下一位负责人
更新、撤回与常见问题
新增插件要重装客户端吗? 在已验收的宿主能力范围内不需要。用户刷新市场、确认添加或更新即可;新宿主 API 或新的 UI SDK 主版本仍可能要求客户端升级。
插件改了代码怎么发? 升级插件 SemVer,新增版本目录,保留历史包和条目,更新展示版本。不能覆盖同版本字节。维护者发布新的 Catalog generation。
只改文案要升插件版本吗? 仅修改展示源中的分类、精选、图标、详情时不需要;仍须审核并运行内容发布流程。包清单或代码变化不能伪装成文案更新。
合并 PR 就上架了吗? 没有。维护者还要执行签名发布和公开读回;能下载也不等于在目标桌面完成业务验收。
发现已发布版本有问题怎么办? 提交撤回原因和受影响版本,由维护者把条目设为 revoked 并发布更高 generation。修复版本使用新的插件版本号;不要删除历史包、倒退目录或删除用户配置。撤回不等于强制卸载所有用户的现有插件。
QA 回答“文档里有,所以客户端一定支持”对吗? 不对。先确认客户端版本和实际功能,再区分文档描述、源码支持、生产上架、目标桌面验收四个事实。拿不到证据时说明缺口。