卡与插件的关系
互不嵌套
卡目录里永远只有 requires 声明,不含插件实体。 插件单独安装、按 id 匹配。
为什么不许把插件塞进卡目录:
- 两张卡都要同一个插件,就会有两份实体,升级要挨张卡改;
- 「换一张卡」与「装一个插件」是两件独立的事,绑死后哪件都做不干净;
- 卡是纯数据、免代码信任门; 一旦卡里能藏代码,这条安全边界就没了。
声明的三个层次
卡对「我需要什么」的表达,从粗到细有三层,都在 requires 段(详见requires 依赖声明):
| 层次 | 字段 | 说的是 |
|---|---|---|
| 要一类能力 | providers[].capability | 「我要 TTS」——不关心谁实现 |
| 偏好某个 provider | providers[].prefer | 「优先用这一家,别家顶上效果会不同」 |
| 指明去哪装 | providers[].plugins / plugins[] | 「装这个插件就能得到上面那个 provider」 |
这套分层让卡不锁死实现:收卡人机器上没有作者点名的那家 provider 时,系统可以按声明回落到别家(除非作者显式写 fallback: false),并且知道该引导用户装哪个插件。
一起分发:组合包
互不嵌套说的是安装后的形态,不妨碍分发时打包在一起。导出 .channekcard 时,打包器可以按 requires 把已安装的插件一并收进包里;导入时拆包,卡进卡库、插件走各自的安装与信任门,互不越界。
注意
导入向导会逐个列出包内插件的 id、版本、信任级与权限清单,要求用户逐项确认——导入一张卡可能装上代码,绝不随卡静默安装。作为卡作者,别指望「藏在包里」能跳过用户的知情同意;作为收卡人,看到确认清单再点安装。
skill 跟着所有者走
给 AI Agent 看的方法论文档(skill)同样按归属分发:
- 「某个插件怎么用」的 skill,住插件包里,跟插件走;
- 「某个频道特有的流程方法论」,住卡声明的 skill 目录里(
layout.cardAssets.libraries.skills),跟卡走。
打开频道时,应用把两处的 skill 摆到该频道的 .claude/skills/ 下,供用户自己的 AI Agent 读取。执行主体是用户的 Agent,应用本身不执行 skill。 同名时卡里的优先——频道的具体打法覆盖插件的通用说明。