Paperclip 插件规范怎么读:哪些能力现在能用,哪些还只是设计稿
想给 Paperclip 写个插件,翻开仓库会看到两份文档:doc/plugins/PLUGIN_SPEC.md 和 doc/plugins/PLUGIN_AUTHORING_GUIDE.md。照着第一份写,你会得到一个跑不起来的插件;照着第二份写,你会觉得功能少得可怜,回头又忍不住去翻第一份。
问题出在两份文档身份不一样,而文档自己写得很清楚,只是容易被略过。规范开头第一行就标着 Status: proposed complete spec for the post-V1 plugin system,并且明确说「这不是 doc/SPEC-implementation.md 里 V1 实现契约的一部分」。开发指南则在开头写明:它「有意比 PLUGIN_SPEC.md 窄」,规范里包含未来构想,而指南只覆盖当下存在的 alpha 面。
所以正确的读法是:开发指南定义你今天能写什么,规范定义这套东西将来长成什么样。
规范自己列出的「当前实现注意事项」
规范并没有假装自己已经实现了。它在 Scope 之前专门有一节 Current implementation caveats,讲清了仓库里那套早期插件运行时和管理界面的实际边界。这一节比后面 30 个章节都更值得先看:
| 规范写明的当前限制 | 对写插件的实际影响 |
|---|---|
| 插件 UI 包目前作为同源 JavaScript 跑在主应用里 | 把插件 UI 当作可信代码,不要把它当成前端能力边界 |
| manifest 里的 capabilities 只拦 worker 侧的宿主 RPC | 它不阻止插件 UI 代码直接调普通的 Paperclip HTTP API |
| 运行期安装假设本地文件系统可写 | 插件包目录和插件数据目录都要落盘 |
运行期 npm 安装假设环境里有 npm 且能连到配置的 registry | 离线或锁死出网的部署要提前想清楚 |
| 动态安装尚未适配云端 | 没有共享制品库、安装协调、跨节点分发层 |
仓库 packages/plugins/examples/ 下的示例插件是开发便利 | 它们从源码检出可用,不能假定通用发布版里存在 |
| 当前运行时不支持插件资源(asset)上传/读取 | 插件 asset API 属于未来构想,不是当前承诺 |
开发指南里还有一句更直接的补刀:ctx.assets 在当前运行时不被支持。而规范第 14 节的「必需 SDK 客户端」列表里明明写着 ctx.assets。规范列的是目标清单,指南列的是可用清单,决定你代码能不能跑的是后者。
规范给的结论也很坦白:当前实现适合本地开发和自托管的持久化部署,还不适合多实例的云端插件分发。
先分清平台模块和插件,别选错扩展类
Paperclip 有两类扩展,选错方向会白写一大圈。
**平台模块(Platform Module)**是可信的、进程内的、宿主集成的低层扩展,走显式注册表而不是插件 worker 协议。它的注册面是四个函数:registerAgentAdapter()、registerStorageProvider()、registerSecretProvider()、registerRunLogStore()。新的 Agent 适配器包、新的存储后端、新的密钥后端属于这一类。如果你的目标是接一个新的执行端,那要走的是适配器那条路,不是插件那条路(参见自己写一个 Paperclip 适配器)。
**插件(Plugin)**是按实例全局安装的、通过插件运行时加载的、加法式的、受能力门控的扩展,通过稳定 SDK 和宿主协议与核心隔离。分四个 category:connector、workspace、automation、ui,一个插件可以声明多个。
安装模型是全局的、由运维方驱动的:没有按公司维度的安装表,也没有按公司的启停开关。如果插件需要针对某个业务对象做映射,那属于插件配置或插件状态——规范举的例子是一个全局 Linear 插件安装,配置里存「公司 A 映射到 team X、公司 B 映射到 team Y」。
manifest:唯一的静态声明面
包契约要求每个插件包导出 manifest、worker 入口,UI 包可选。建议布局是 dist/manifest.js、dist/worker.js、dist/ui/,并在 package.json 里用 paperclipPlugin 键指路。
manifest 的规范形状(PaperclipPluginManifestV1)里,几个硬规则值得记住:
id必须全局唯一,通常等于 npm 包名;apiVersion必须匹配宿主支持的插件 API 版本,装的时候校验,不兼容直接拒;capabilities必须是静态的、安装时可见的;minimumHostVersion是现在推荐的字段,minimumPaperclipVersion标了@deprecated,只为向后兼容保留;ui.slots声明插件要填哪些扩展位,每个 slot 引用 UI 包里的一个exportName,宿主据此知道要挂什么,而不必提前加载整个包。
槽位类型的枚举相当长:page、settingsPage、dashboardWidget、sidebar、routeSidebar、sidebarPanel、detailTab、taskDetailView、projectSidebarItem、globalToolbarButton、toolbarButton、contextMenuItem、commentAnnotation、commentContextMenuItem、companySettingsPage。开发指南单列了一份「宿主里当前已经接线的挂载面」,和上面这份基本重合——这是少见的、规范和实现对得比较齐的一块。
UI slot ID 由宿主按插件 ID 自动加命名空间(形如 @paperclip/plugin-linear:sync-health-widget),跨插件冲突在结构上不可能发生;但单个插件自己 manifest 里出现重复 slot ID,宿主必须在安装时拒绝。
能力清单是白名单,而且有一份明确的禁区
能力是强制且静态的,宿主在 SDK 层执行,拒绝授予范围之外的调用。分类涵盖数据读、数据写、插件状态、运行时/集成、Agent 工具、UI 六块,条目相当细,光读的一侧就区分了 issues.read、issue.comments.read、issue.documents.read、issue.relations.read、issue.subtree.read。
真正要记住的是禁区。规范第 15.2 节写明宿主不得为以下事项暴露能力:
- 审批决策
- 预算超额覆盖
- 认证绕过
- issue checkout 锁覆盖
- 直接访问数据库
这跟核心假设是一条线:董事会治理、审批门、预算硬停止、核心任务不变量永远归 Paperclip 核心所有。Non-Goals 里也重申了一遍——任意插件不得覆盖核心路由或核心不变量,不得改动审批、认证、issue checkout、预算强制逻辑。
升级时若新版本增加了能力,宿主必须把插件标为 upgrade_pending,运维方显式批准新能力集合之前,新版本不会进入 ready。
有一个细节体现了这套设计的谨慎程度:ctx.issues.createComment() 默认以插件自己的 agent 身份发评论;如果要以某个人类成员的身份发,除了 issue.comments.create 还要额外的 issue.comments.create_human_attributed,并且宿主会独立校验这个 actorUserId 确实是该公司在职的人类成员。插件伪造不了归属。
worker 是独立进程,协议就那几个方法
第三方插件默认跑在进程外。Paperclip 服务端为每个已安装插件起一个 worker 进程,是 Node 进程,宿主与 worker 之间走 stdio 上的 JSON-RPC。换来的是故障隔离、更清晰的日志边界和更容易做的资源限制。
必需的 RPC 方法只有三个:initialize(input)、health()、shutdown()。可选的是 validateConfig、configChanged、onEvent、runJob、handleWebhook、getData、performAction、executeTool。
事件投递语义要留意:至少一次,插件必须幂等;跨事件类型没有全局顺序保证;重试之后连按实体的顺序也只是尽力而为。任何依赖「事件只来一次」或「事件严格有序」的实现都会出问题。
关闭流程有时限阶梯:宿主先发 shutdown(),worker 有 10 秒收尾并干净退出;超时发 SIGTERM;SIGTERM 后 5 秒仍未退出发 SIGKILL。被强杀时进行中的 job 运行会标为 cancelled 并附注说明,进行中的 getData / performAction 调用向桥返回错误。需要更长排空时间的插件,可以在插件配置里调这个截止时间。
worker 挂了的处理是隔离的:把插件状态标 error、在健康页面暴露错误、实例其余部分继续跑、按有界退避重试启动,不牵连其他插件和核心服务。
「托管资源」是当前最该照做的一条建议
开发指南和规范都反复强调同一件事:别把长期存在的工作藏在插件私有状态里。插件提供的如果是持久的 Paperclip 业务对象,就在 manifest 里声明出来,让宿主按公司创建或重新关联真实记录。
四类托管资源,各自对应一个能力:
| 声明字段 | 需要的能力 | 用在什么时候 |
|---|---|---|
agents[] | agents.managed | 插件提供一个具名的、可被调用的工作者,董事会要能看到它、给它预算、暂停它、检查它 |
projects[] | projects.managed | 插件需要一个稳定的、公司范围的项目来装它的 issue、routine 或工作区导向的 UI |
routines[] | routines.managed | 定时、webhook 或手工触发、且应该产生可见 Paperclip issue 的工作 |
skills[] | skills.managed | 可复用的、对运维方可见的能力,同步进托管 agent |
指南明确给了取舍:recurring 的业务工作优先用托管 routine,而不是插件的 jobs[];插件 job 留给不需要看板可见任务痕迹的运行时维护活。规范第 17 节也是同一口径。
托管资源按稳定的插件 key 解析,不是硬编码的数据库 id。在 worker 的 action 或 data handler 里,对当前 companyId 调 ctx.agents.managed.reconcile()、ctx.projects.managed.reconcile() 之类的方法:reconcile() 会创建缺失的资源、重新关联可恢复的绑定,或返回已有资源;reset() 则把 manifest 默认值重新应用一遍。资源之间的依赖用 ref 声明,routine 可以通过 assigneeRef 指向托管 agent、通过 projectRef 指向托管项目;引用的 agent 和 project 要先 reconcile,ref 还缺的话 routine 解析会报 missing_refs 而不是猜。
有一条授权规则是硬的:key 一旦发布就别改。改 agentKey、projectKey、routineKey、skillKey,在宿主眼里就是新建了一个托管资源。
仓库里的 LLM Wiki 插件是这套模式的参考实现:manifest 里声明托管 agent、项目、routine 和 skill,按公司 reconcile,用托管 routine 跑周期性的 wiki 维护和摄取。内容型插件被建议照抄这个结构,而不是自己跑不受管的后台循环。把可复用提示与工具指引挂成技能这条线,见给 Paperclip 写一个 skill;把周期工作交给 routine,见流水线与例行任务。
数据库、密钥、API 路由三条硬边界
数据库:插件不直接连库。可信的编排类插件可以在 manifest 里声明 database: { migrationsDir, coreReadTables },需要 database.namespace.migrate 和 database.namespace.read,运行期改数据还要 database.namespace.write。宿主派生出 ctx.db.namespace,在 worker 启动前按文件名顺序跑 SQL 文件,把校验和记进 plugin_migrations,已应用过又被改动的迁移会被拒绝。迁移 SQL 只能在自己的命名空间里建表改表,可以为外键或只读视图引用白名单内的 public 核心表,但不得修改/删除/清空 public 表,不得建扩展、触发器、非可信语言,也不得跑运行期多语句 SQL。运行期 ctx.db.query() 只允许 SELECT,ctx.db.execute() 只允许命名空间内的 INSERT、UPDATE、DELETE。
密钥:插件配置永远不落原始密钥值,只存 { type: "secret_ref", secretId, version? } 这种共享引用形状,旧的 UUID 字符串引用会被拒绝。保存时会校验引用的密钥属于所选公司。worker 只在执行时拿到解析后的密钥,且解析会写 secret_access_events,consumerType 标为 plugin_worker。密钥值绝不允许写进插件配置 JSON、活动日志、webhook 投递行、错误消息。这套引用机制的上游细节见 Paperclip 密钥管理。
API 路由:插件自有的 JSON 路由必须在 manifest 的 apiRoutes 里声明,只挂在 /api/plugins/:pluginId/api/* 下面,抢不到核心路径。声明项包括 routeKey、method、插件本地 path、auth、capability、可选的 checkout 策略和公司解析方式。分派给 worker 的 onApiRequest 之前,宿主会解析插件、确认它 ready、强制 api.routes.register、匹配方法与路径、解析公司访问权、应用 checkout 策略。只有安全的请求头会转发,认证头和 cookie 永不传给 worker。
上手实际要敲的命令
开发指南给的脚手架命令是:
paperclipai plugin init @yourscope/plugin-name --output /absolute/path/to/plugin-repos
生成的目录里有 src/manifest.ts、src/worker.ts、src/ui/index.tsx、tests/plugin.spec.ts,以及 esbuild.config.mjs 和 rollup.config.mjs。在 monorepo 内部,脚手架用 workspace:* 引 @paperclipai/plugin-sdk;在外部,它会把本地检出里的 SDK 快照成一个 .paperclip-sdk/ tarball,让你不必先发 npm 就能构建和测试,多个检出的情况用 --sdk-path 指定。
交付前的最低验证:
pnpm --filter <your-plugin-package> typecheck
pnpm --filter <your-plugin-package> test
pnpm --filter <your-plugin-package> build
改了宿主集成的话,还要跑 pnpm -r typecheck、pnpm test:run、pnpm build。
发布口径也明确:npm 包是部署制品,仓库内示例安装只当开发流程;插件 UI 尽量自包含在包里;不要依赖宿主的设计系统组件或没写进文档的应用内部结构。GitHub 仓库直装今天不是一等公民工作流——本地开发用检出的本地路径,生产环境发到 npm 或兼容 npm 的私有 registry。
什么时候不适用,以及还没解决的部分
这套插件系统现在不适合几类场景:
多实例云端部署。规范说得很直白:动态插件安装还没有 cloud-ready,没有共享制品存储、安装协调和跨节点分发层。一次成功安装只把包写到本地宿主,其他节点不会自动拿到这个插件。
把插件 UI 当安全边界。UI 包以标准 ES 模块加载,不是 iframe。规范给了隔离规则(不得从宿主内部导入、不得直接用 window.fetch 或 XMLHttpRequest 调宿主 API、要能被静态分析、不得动态 import() 包外 URL),并说宿主可以用 CSP 限制网络访问;但当前口径仍是「把插件 UI 当作可信代码」。iframe 隔离在 Phase 2,规范说到那时插件源码不用改,桥 API 保持不变。
第三方任意 schema 迁移。第一版插件系统不允许,规范把「以后若真有必要,可能加一条仅限可信模块的迁移路径」留成了未来选项。
外部对象引用提供方。指南说这块在 MVP 阶段仅限可信安装,能力只门控检测/解析和宿主 API 调用,不是给不可信市场代码用的沙箱边界。还有条渲染红线:内联 markdown 渲染归 Paperclip 自己所有,插件不得为内联引用返回 React、HTML 或 dangerouslySetInnerHTML 内容。
还有一些是规范里写成规范性要求、但你不该假定已经实现的:热生命周期(安装、卸载、升级、改配置都不重启服务端)、@paperclipai/plugin-test-harness 测试工具包、create-paperclip-plugin starter、插件日志表与健康看板、卸载后默认 30 天的数据保留宽限期、SDK 多版本共存与至少 6 个月的弃用期。这些在规范第 25 到 29 节写得很细,但它们属于「post-V1 目标架构」这一栏。想确认某条到底能不能用,办法只有一个:回到开发指南那份 alpha 支持面清单去对照。
最后提醒一句 manifest 与运行时的错位:能力门控的是 worker 侧的宿主 RPC 调用,拦不住 UI 代码直接打普通 HTTP API。做安全评估时,别把 manifest 的 capabilities 当成插件的实际权限上限——它是 worker 的上限,不是整个插件包的上限。
延伸阅读
- 从头读起:Paperclip 是什么:一个自己不跑 Agent 的控制平面,怎么管住一整家 AI 公司
- 本专题共 40 篇,完整分组目录见专题页
- Paperclip API 总览:base URL、三种令牌与七个错误码分别代表什么
- Paperclip 的 issues 与 agents 接口怎么用:字段、状态机与 409/400 的真实含义
本文依据 Paperclip 官方仓库(github.com/paperclipai/paperclip,MIT 协议)的 docs/ 用户文档
与 doc/ 下的规范、运维与连接器手册整理,核对日 2026-08-17。
我们没有部署或运行过 Paperclip,因此不涉及界面外观与操作手感;
部分规范文档描述的是目标架构而非当前实现,文中已就地标注,不构成对实际行为的保证。
请以仓库最新内容为准。