一、什么是能力缝Capability Seam
能力缝(seam)= 可替换能力的标准切口。seam 本义是衣服上的缝:沿缝拆开就能换掉一只袖子,不用重做整件衣服。一条完整的缝由三个角色构成:
Service Definition声明接口
"这个能力长什么样"
←
Service Provider提供实现
"具体我来干"
→
Consumer使用能力
"通常是一个
模型可调的工具"
| 角色 | 职责 | 通俗理解 |
| Service Definition(服务定义) | 声明 Cordis 服务 + 请求/结果类型 | 合同模板:规定接口的形状 |
| Service Provider(服务提供者) | 实现接口 | 施工队:可以换,合同不变 |
| Consumer(消费者) | 使用能力(常是模型工具) | 住户:只认合同,不认施工队 |
铁律:三角色齐全才构成缝;依赖方向固定——Provider 和 Consumer 都只依赖 Definition,彼此互不依赖,这就是"换施工队,住户无感"。
二、真实例子:Bash 执行能力The Bash Seam
| 角色 | 包 | 它做什么 |
| Definition | dsh-shell | 定义 shell 服务和 Bash 请求/结果类型 |
| Provider | dsh-bash-local | 在你本机执行命令 |
| Consumer | dsh-tool-bash | 把能力包成模型可调用的 bash 工具 |
想换掉"在本机执行",把 dsh-bash-local 那行换成任何同样实现 shell 服务的包(如远程沙箱),Definition 和 Consumer 一个字不用改:
# cordis.yml —— 换 Provider 就是换一行配置
- name: '@deepseek-ai/dsh-bash-local' # 本地执行
# 换成另一个提供 shell 服务的包即可,其余不动
三、为什么这招威力巨大Why It Matters
文件系统和子进程共享一个执行环境:把它们的 Provider 一起指向远程沙箱后,Bash、持久终端(PTY)、LSP 全部无感跟随——这些 Consumer 只是插在缝上的住户,施工队搬走了它们跟着搬,没有任何工具需要改代码。像整栋楼换物业:住户不换门牌、不动装修,水电气已全部切到新供应商——一处替换、全局跟随。
类似的缝有一整排:shell、fs、web(搜索/抓取)、subagent(提供者从"进程内新生"到"另一个产品"都有)、sandbox(Landlock / bwrap / Seatbelt)、compaction、persistence(JSONL / SQLite)……完整清单见 docs/capability-seams.md。
四、使用守则Rules of Use
- 扩展插件依赖 Definition,永不依赖具体 Provider——依赖了具体实现,替换能力就对你失效。
- 不要过早拆三角色:简单工具一个包就够,只有实现确实需要独立演化/替换时才拆(官方原话:不要 preemptively 拆分)。
- Request/Result 类型归 Definition 所有——合同条款跟合同走,不散落在施工队手里。
钩子:L16 会带你把一个工具拆成三角色包;L18"读插件五步法"第一步就是判断插件站在哪个角色——看到社区插件先问"它是 Definition、Provider 还是 Consumer?"
seam 能力缝
可替换能力的标准切口:三角色齐全才构成。
Definition
合同模板:服务接口 + 请求/结果类型。
Provider
施工队:接口的具体实现,可整体替换。
Consumer
住户:使用能力的插件,常见形态是模型工具。
✏️ 动手练习
- 打开
docs/capability-seams.zh.md,数一数仓库里有多少条完整的能力缝。
- 对照
packages/subagent/:找出三角色各是什么包,Provider 有几种(spawn-in-process / fork / acp / codex / claude-code / dsh-sdk)。
- 自问:公司的"内部工单系统"想接进 dsh,该站在哪个角色?(答案不止一个,想想为什么。)
📝 自测(点击展开答案)
1. 一条能力缝的三个角色是什么?依赖方向如何?
Definition(接口声明)、Provider(实现)、Consumer(使用,常为工具)。Provider 和 Consumer 都只依赖 Definition,彼此互不依赖。
2. 为什么换掉 fs 和 subprocess 的 Provider 后,Bash/PTY/LSP 工具会"自动跟着走"?
这些 Consumer 都只依赖 fs/subprocess 的 Definition、共享同一执行世界;Provider 换了地址,插在缝上的住户整体迁移,无需改任何 Consumer 代码。
3. "单独一个角色不构成缝"是什么意思?
只有接口声明、只有实现或只有使用者,都不构成可替换能力的完整闭环;三角色齐全是逻辑要求,与是否拆包无关。
4. 什么时候应该把三个角色拆成三个包?
只有当角色需要独立演化或替换时(如多 Provider 并存);简单工具不要过早拆分,拆分是手段不是目的。