ARTICLE · 1092632
从本地数据揭秘WorkBuddy:插件四层加载 — 安装 ≠ 启用 ≠ 加载 ≠ 实例化
"
系列第 5 期。从 ~/.workbuddy/plugins/ 的真实本地数据出发,拆解 WorkBuddy 插件系统的四层加载机制。
引子:48 个插件,只有 10 个被"启用"
打开 ~/.workbuddy/settings.json,enabledPlugins 字段赫然在列:
{
"weixinpay@workbuddy-builtin": true,
"tencent-docs-plugin@workbuddy-builtin": true,
"tencent-pptx@workbuddy-builtin": true,
"agent-browser@codebuddy-plugins-official": true,
"find-skills@codebuddy-plugins-official": true,
"sheetagent@workbuddy-builtin": true,
"tencent-docx@workbuddy-builtin": true,
"document-skills@cb_teams_marketplace": true,
"finance-data@cb_teams_marketplace": true,
"playwright-cli@codebuddy-plugins-official": true
}
10 个 true。
但打开同级的 plugins/installed_plugins.json,里面是 48 个已安装插件——28 个 skill-、4 个 interactionmode-、3 个 welcomemode-*、1 个 prompt-common,加上 12 个复合能力包。
38 个已安装但未启用的插件,难道就是"死代码"?
不是。它们中的大多数,此刻正在为你工作——只是不走"启用"这条路。
这篇文章从本地文件的真实数据出发,拆解 WorkBuddy 插件系统的四层加载机制:安装 → 启用 → 加载 → 实例化。理解这四层,才能理解一个拥有 48 个插件的 Agent 操作系统,为什么冷启动不会爆炸。
01
数据现场:四个文件,四层真相
先看数据。四个本地文件,分别对应四个加载阶段。
第一层:安装(Installation)
文件:plugins/installed_plugins.json
{
"version": 2,
"plugins": {
"find-skills@codebuddy-plugins-official": [{
"scope": "user",
"installPath": "~/.workbuddy/plugins/cache/codebuddy-plugins-official/find-skills/1.0.0",
"version": "1.0.0",
"installedAt": "2026-08-24T07:38:32.237Z",
"lastUpdated": "2026-09-13T05:31:42.328Z"
}],
"skill-ardot-slides@workbuddy-builtin": [{
"scope": "user",
"installPath": "~/.workbuddy/plugins/cache/workbuddy-builtin/skill-ardot-slides/5.5.6-...",
"version": "5.5.6-wb.38337834...",
"installedAt": "...",
"lastUpdated": "..."
}],
...
}
}
关键结构:version: 2,plugins 是一个 dict(不是数组),键是 name@source,值是版本记录数组。这意味着同一个插件可以并存多个版本。
48 个已安装插件,按类型分布:
skill-* | ||
interactionmode-* | ||
welcomemode-* | ||
prompt-common | ||
安装 = 文件落盘。插件包从市场(官方 zip、内置 directory、本地专家目录)下载到 plugins/cache/<source>/<name>/<version>/,在 installed_plugins.json 登记一条记录。到此为止,插件只是一堆躺在磁盘上的文件。
第二层:启用(Enablement)
文件:settings.json → enabledPlugins
{
"weixinpay@workbuddy-builtin": true,
"tencent-docs-plugin@workbuddy-builtin": true,
...
"playwright-cli@codebuddy-plugins-official": true
}
10 个 true。仔细看这 10 个插件,有一个共同特征:它们全是"主动能力型"。
*没有一个是 skill-、interactionmode-、welcomemode- 或 prompt-common。**
这不是巧合。enabledPlugins 闸门只管"主动能力型"插件——需要启动 MCP server、注册连接器、注入 agent 的插件。被动常驻的提示片段和按需加载的 skill 包,根本不走这个闸门。
第三层:加载(Loading)
文件:plugins/cache/<source>/<name>/<version>/.in_use/<pid>
~/.workbuddy/plugins/cache/workbuddy-builtin/
├── weixinpay/1.6.109/.in_use/
│ ├── 24239 ← 空文件,每个 agent 进程一个
│ └── 43783
├── tencent-docx/5.5.6-.../.in_use/
│ ├── 24239
│ └── 43783
├── interactionmode-craft/0.1.4/.in_use/
│ └── (当前为空——因为 craft 是默认模式,锁在活跃会话中)
├── prompt-common/0.1.2/.in_use/
│ └── (同上)
...
.in_use/<pid> 是运行时 PID 锁。每启动一个 agent 进程,框架就为当前激活的插件在该目录下创建一个以进程 PID 命名的空文件;进程退出即删。
这个机制揭示了第三层加载的真相:被动常驻片段(welcomemode / interactionmode / prompt-common)不经过 enabledPlugins 闸门,而是通过 .in_use PID 锁标记"谁在用它"。
实测数据:
.in_use | ||
|---|---|---|
*28 个 skill- 插件呢?** 它们既不在 enabledPlugins 里,也没有 .in_use 锁。因为它们走的是第四层。
第四层:实例化(Instantiation)
文件:interactionmode-craft/0.1.4/.workbuddy-plugin/ 下的 interaction.md
tools:
- Read
- Write
- Edit
- Bash
- ...
- Defer(SkillManage)
- Defer(LSP)
- Defer(ImageGen)
- Defer(VideoGen)
- Defer(TeamCreate)
- Defer(TeamDelete)
- Defer(conversation_search)
- Defer(workbuddy_cloudstudio_deploy)
8 处 Defer(...) 声明。这是延迟加载的提示层表达:这些重能力在冷启动时不加载,只有当模型在 function_call 中第一次请求该工具名时,框架才拉起对应的能力包或 MCP server。
实测证据:在全工程 74 个会话 9300 次 function_call 中,DeferExecuteTool(延迟执行工具)被调用了 26 次——这就是第四层实例化的运行时痕迹。
28 个 skill- 也走类似路径:它们通过运行时 Skill 工具按需注入。模型读 <available_skills> 列表(由 loader 扫描 skills//SKILL.md 生成),按 description 判定是否触发;命中后本地读 SKILL.md 注入上下文。匹配发生在云端 LLM 的推理层,不在本地 embedding。
02
四层串联:一张图看完整生命周期

把四层叠在一起,一个插件从安装到真正被使用,要过四道闸门:
安装(Installation)
│ installed_plugins.json 登记 48 个
│ 插件文件落盘 plugins/cache/<source>/<name>/<version>/
│
├─ 启用(Enablement)
│ │ settings.json → enabledPlugins: 仅 10 个 true
│ │ 闸门条件:是否为"主动能力型"(需起 MCP / 注册连接器 / 注入 agent)
│ │
│ ├─ 被动常驻型(welcomemode / interactionmode / prompt-common)
│ │ │ 不走 enabledPlugins 闸门
│ │ │ 靠 .in_use/<pid> PID 锁标记"谁在用"
│ │ │ 每个 agent 进程启动时自动加载
│ │ │
│ │ └─ 加载(Loading)
│ │ 片段注入 system prompt(Jinja include)
│ │ 工具白名单生效(interaction.md → function calling schema)
│ │
│ └─ 主动能力型(weixinpay / sheetagent / tencent-docx / ...)
│ │ enabledPlugins = true → 注册进运行时
│ │ MCP server 启动 / 连接器注入 / agent 注册
│ │
│ └─ 实例化(Instantiation)
│ 部分能力 defer_loading:首次 function_call 才拉起
│ DeferExecuteTool 26 次 = 延迟实例化的运行时痕迹
│
└─ 按需加载型(28 个 skill-*)
│ 不走 enabledPlugins,不走 .in_use
│ 靠 Skill 工具 + 目录约定发现 SKILL.md
│ 云端 LLM 读 <available_skills> 列表 → 按 description 触发
│
└─ 实例化
命中后读 SKILL.md 注入上下文
后续该 skill 内的工具 / 脚本 / 命令可用
核心洞察:四层加载的本质是资源消耗的逐级延迟。
如果 48 个插件全在"启用"层——冷启动要起所有 MCP server、注册所有连接器、注入所有 agent。34 个被排除在启用闸门之外,不是它们没用,而是它们不需要在冷启动时就位。
03
两种血统标记:.workbuddy-plugin vs .codebuddy-plugin
在 plugins/cache/workbuddy-builtin/ 下走一圈,会发现两种隐藏目录:
interactionmode-craft/0.1.4/.workbuddy-plugin/plugin.json ← 瘦 schema
welcomemode-code/0.1.7/.workbuddy-plugin/plugin.json ← 瘦 schema
prompt-common/0.1.2/.workbuddy-plugin/plugin.json ← 瘦 schema
skill-ardot-slides/5.5.6-.../.codebuddy-plugin/plugin.json ← 全 schema
weixinpay/1.6.109/.codebuddy-plugin/plugin.json ← 全 schema
sheetagent/5.5.6-.../.codebuddy-plugin/plugin.json ← 全 schema
两种标记对应两种插件 schema:
.workbuddy-plugin | category/description | ||
.codebuddy-plugin | skills/mcpServers/commands/hooks/workbuddy.kind |
.codebuddy-plugin 是 CodeBuddy 时代的产品血统戳。这些插件的描述里还写着"CodeBuddy"/"CodeBuddy Code"——WorkBuddy 是 CodeBuddy 的 rebrand。两个标记共存,是向后兼容的体现。
关键机制:plugin.json 的 skills/mcpServers 键是可选的。loader 同时做目录约定发现——扫 skills/*/SKILL.md、扫 .mcp.json。weixinpay 的 plugin.json 只有 6 行,却是功能最强的插件(3 skill + MCP server + 原生国密 CLI + 供应链签名),真能力在目录结构里,不在 manifest 声明里。
04
被动常驻 vs 按需加载:为什么 skill-* 不进 enabledPlugins?
这是本文最核心的问题。
28 个 skill-* 插件,覆盖了从设计(ardot 6 件套)到金融(wb-finance-skill)、从文档(tencent-docs-routing)到地图合规(geo-map-compliance-guard)的广泛能力。它们全部已安装,但全部不在 enabledPlugins 里。
为什么?
因为 skill 的本质是知识包,不是运行时服务。
如果一个 skill 在冷启动时就注入 system prompt,48 个插件的 SKILL.md 全文加起来可能吃掉数万 token 的上下文窗口——还没开始干活,窗口就满了。
WorkBuddy 的选择是:skill 不进 enabledPlugins,靠运行时 Skill 工具按需注入。模型在 <available_skills> 列表里看到 28 个 skill 的 description(一行文字),按任务需要选择触发;命中后才读完整 SKILL.md 注入上下文。
这就是为什么 38 个插件不在 enabledPlugins 里却仍然可用——它们走的是不同的加载路径,不是"未启用",而是"不需要启用"。
05
对比:其他框架怎么做?
| WorkBuddy | ||
| Hermes | ||
| OpenCode | ||
| Aider | ||
| Claude Code |
Hermes 的 skill 系统最接近"扁平加载"——~/.hermes/skills/ 下的文件直接被读取使用。简单,但当 skill 数量膨胀到 28 个以上时,冷启动的上下文消耗会成为瓶颈。
WorkBuddy 的四层加载,本质上是在回答一个问题:当你的 Agent 拥有 48 个插件时,怎么保证冷启动不爆炸?
答案是:让大部分插件在不同阶段才"醒来"。
06
深层设计:能力生命周期管理
把四层加载抽象一下,WorkBuddy 实际上在做能力的生命周期管理——和 JVM 的分代内存管理异曲同工。
JVM 不会把所有对象都放进年轻代;WorkBuddy 也不会把所有插件都放进启用层。资源是有限的,按需分配才是正道。
这种设计还有一个隐含好处:插件的升级和回滚可以独立进行。installed_plugins.json 的值是版本记录数组,同一插件可以并存多版本;lastUpdated 字段支持增量更新检查。升级一个 skill 不需要重启整个框架——下次触发时自然加载新版本。
07
工程启示:造 Agent 工具时,从第一天就分层
如果你正在造一个 Agent 工具,WorkBuddy 的四层加载机制给出了一条清晰的工程启示:
不要把"安装"和"启用"混为一谈。
◆安装 = 文件落盘(磁盘成本)
◆启用 = 运行时注册(启动成本)
◆加载 = 上下文注入(上下文成本)
◆实例化 = 实际拉起(运行时成本)
四种成本性质不同,混在一起会让冷启动时间随插件数量线性增长。分开管理,才能让 Agent 在拥有丰富能力的同时保持轻量启动。
具体建议:
01被动片段(提示词、行为协议)→ 加载层,不进启用层
02知识包(skill、领域知识)→ 实例化层,不进启用层也不进加载层
03运行时服务(MCP server、连接器)→ 启用层,冷启动注册
04重能力(图像生成、LSP、部署)→ 启用层 + defer_loading,首次触发才拉起
结语
48 个已安装,10 个启用,~10 个加载,8 个 defer + 28 个 skill 按需实例化。
WorkBuddy 的插件系统不是一个简单的"开/关"模型,而是一个四级节流阀——控制着 Agent 能力从磁盘到上下文到运行时的逐级流动。
这不是过度设计。这是当一个 Agent 操作系统拥有 48 个插件时,保持冷启动不爆炸的唯一方式。
本系列从 ~/.workbuddy/ 下的真实本地文件出发。