1906 字
10 分钟
- 次浏览
本地助手的插件系统,我先做成能力包
读前导览

codex-windows-bot 第一版插件管理只做 action bundle 的开关、分类、健康检查和能力目录过滤,不急着动态加载代码。

正文
1906 字
阅读
10 分钟
结构
9 节
来源线索

windows-bot-memory/plugin-manager

windows-bot-memory:plugin-manager windows-bot-memory:capabilities windows-bot-memory:windows-plugins-registry

一提到插件系统,很容易想到动态加载代码:放一个插件目录,扫描入口文件,按名称 import,然后让插件自己注册命令。

这对很多桌面软件是自然设计,但对一个能从聊天入口触发本机动作的本地助手来说,第一版插件系统最好别这么做。

codex-windows-bot 的插件管理后来走了一个更保守的方向:插件不是新的执行器,也不加载任意代码。插件只是覆盖在 action registry 上的一层 action bundle。

也就是说,插件负责分组、开关、展示和健康检查;执行动作的还是原来的动作注册表、风险模型、确认门和固定 handler。

插件先做能力包,不做代码包#

一个插件可以长这样:

{
"id": "projects",
"name": "Project Registry",
"category": "projects",
"enabled": true,
"description": "registered project context and safe checks",
"actions": [
"projects.list",
"projects.brief",
"projects.run_check"
],
"friendly_commands": ["/project", "/check"],
"parameters": {
"default_mode": "quick"
}
}

这里最重要的一点是:actions 只能引用已经在动作注册表里存在的 action id。

插件自己不提供 handler,不带脚本路径,不接收任意命令,也不能改写风险等级。它只是说:“这些已登记动作属于同一个能力包,可以一起展示,也可以一起关闭。”

这样一来,第一版插件系统更接近能力治理层,暂时不碰扩展运行时。

开关要真的拦住执行#

如果插件只是 UI 分类,那它的价值有限。

更有用的做法是:执行动作前,除了检查 action 自己是否启用,还要检查它所属插件是否启用。

执行路径可以简化成:

收到动作请求
-> 读取动作注册表
-> 校验私聊和调用边界
-> 查动作风险、确认、参数、handler
-> 查插件归属
-> 插件关闭则拒绝执行
-> 调用固定 handler

这样就能把一组能力作为整体收起来。比如某天不想让自然语言任务代理继续接收新任务,可以关掉 task-agent 插件;底层动作仍在注册表里,但执行入口会被插件层挡住。

这比逐个改几十个 action 的 enabled 更稳,也更容易回滚。

core 不能被随手关掉#

插件系统里通常需要一个基础能力包。

它应该包含健康检查、能力目录、插件目录、路由状态之类的基础动作。这个包不能像普通插件一样被随手关闭,否则系统会出现一个很尴尬的状态:能力被关掉了,但你连“现在关了什么”都查不到。

所以本地维护命令应该拒绝关闭 core。

这个限制主要是为了保住诊断通道。外层能力怎么开关,至少还得看得到健康状态、能力目录和插件状态。

参数包只能放非敏感默认设置#

插件参数很容易失控。

一开始只是想放 default_limitretention_daysdefault_mode,后来就有人想把 API key、聊天 id、脚本路径、环境变量名、URL、glob 或命令也塞进去。

这些都不该进插件参数。

插件参数适合放的是:

  • 默认显示条数。
  • 默认模式。
  • 保留天数。
  • 枚举型策略。
  • 友好命令提示。

不适合放的是:

  • 凭据类内容。
  • 用户或群聊标识。
  • 任意路径。
  • 任意 URL。
  • shell 命令。
  • handler 名称。
  • 风险等级覆盖。
  • 确认门绕过选项。

插件层如果能改 handler、改风险、改确认,就不再是覆盖层,而是在偷偷变成第二套动作系统。

聊天侧先只读#

插件管理最诱人的功能,是从聊天里开关插件。

但第一版最好别做。

更稳的顺序是:

plugins.list
plugins.describe
plugins.status
plugins.health

也就是聊天侧只能看插件列表、描述、状态和健康结果。真正的 enable/disable 留在本机维护命令里,而且默认 dry-run,必须显式 apply 才写入配置。

这样做少了些“远程管理”的爽感,但避免了一类高风险误操作:一句聊天消息把整组本地能力打开,或把诊断能力关掉。

等插件注册表稳定一段时间后,再考虑确认门控的远程开关动作也不迟。

能力目录要能按插件过滤#

插件层还有一个很实际的用途:让能力目录变得可读。

动作多了以后,一个平铺的 action list 很难看。用户更关心的是:

  • 现在 task-agent 能做什么。
  • memory 插件是不是只读。
  • desktop-observe 有没有暴露点击或输入。
  • apps 插件是否允许启动应用。
  • reports 插件到底会不会读取正文。

所以 capabilities.list 应该支持按 plugin 过滤。它返回的是被脱敏过的能力目录:action id、分类、风险、是否启用、是否需要确认、属于哪个插件、简短说明。

它不该返回 handler、真实路径、内部策略、输出目录、确认码、配置细节或敏感匹配规则。

能力目录面向聊天入口,用来确认“我当前能安全调用什么”;维护者要看的完整内部状态不该从这里吐出来。

health 要检查引用关系#

插件注册表有一个常见坏法:引用不存在的 action。

如果插件里写了一个已经删掉或改名的 action id,展示层可能还以为能力存在,执行时才发现坏掉。更糟的是,如果某个 action 没有插件归属,能力目录和开关行为就会变得不可预测。

所以插件 health 至少要检查:

  • 每个插件 id 格式稳定。
  • core 存在且启用。
  • 每个插件只引用已注册 action。
  • 同一个 action 不被多个插件重复声明,除非明确支持多归属。
  • 插件参数不含敏感字段、路径、命令或 URL。
  • 插件开关会影响 action 执行。
  • 插件状态输出不暴露内部路径和敏感规则。

这类检查不会让系统更炫,但能让插件层长期不变形。

插件层别绕过原来的风险模型#

最重要的原则是:插件层不提升权限。

如果一个 action 原本是只读,插件不能让它变成写入。如果一个 action 原本需要确认,插件不能因为自己启用了就绕过确认。如果一个 action 原本被禁用,插件也不能直接把它变成可执行。

插件层只做额外限制,不做额外授权。

这句话很简单,但能挡住很多后续设计漂移。

现在我的判断#

本地助手的插件系统不一定要从动态加载开始。

第一版更值得做的是:

  • 把已登记动作按能力包分组。
  • 用插件开关控制一组动作是否可执行。
  • 用只读插件视图给聊天侧展示能力状态。
  • 用本地 dry-run/apply 管住配置写入。
  • 用 health 检查插件和 action 的引用关系。
  • 禁止插件参数携带凭据、路径、命令、URL 和权限覆盖。

这套设计看起来没有“插件市场”刺激,但更适合远程触发本机动作的场景。

我现在更关心的是,每项能力能不能说清楚:属于哪个包、风险是什么、要不要确认、为什么此刻能执行、关掉后会影响哪些动作。

这些问题能稳定回答,插件层才算真的帮助手变得可维护。

本地助手的插件系统,我先做成能力包
https://blog.sunmmyapi.xyz/posts/windows-plugin-bundles-not-runtime-code/
作者
Sun
发布于
2026-05-29
许可协议
CC BY-NC-SA 4.0

继续读

相关内容