cordis.yml:把插件列表变成可修改的应用组合
理解 Cordis 配置项、稳定 id、group、isolate 与 patch 层,读懂配置文件如何定义一次运行。
核心观点:cordis.yml 不是“按顺序执行的启动脚本”,而是一棵可以被 profile 和 overlay 修改的插件配置树。
当配置文件只剩下 name 时,它像模块清单;加上 id、config、disabled 和嵌套组后,它开始描述一个可比较、可替换、可局部重载的运行时组合。
01 / 一行配置包含什么
一个常见配置项可以写成:
- id: shell
name: '@deepseek-ai/dsh-shell-local'
config:
cwd: '/workspace'
inject: ['subprocess']这些字段的责任不同:
| 字段 | 作用 | 变化时的含义 |
|---|---|---|
id | 稳定识别配置项 | Loader 可以比较“同一项”的新旧版本 |
name | 模块或包指定符 | 决定加载哪个插件入口 |
config | 传给插件的选项 | 通过插件 schema 验证后进入 apply |
inject | 声明服务依赖 | 依赖就绪后才允许挂载 |
disabled | 保留配置但跳过挂载 | 改回 false 后可以重新加载 |
列表位置不是启动顺序。插件可以并发启动,依赖关系由 inject 表达。
02 / id 是 HMR 的稳定锚点
配置文件被重新读取时,Loader 需要判断哪些项没变、哪些项被修改。显式 id 让它能把新行和旧行对应起来:只更新变化的项,保留没变化的 Fiber。
如果不写 id,Loader 会为行生成新的身份。配置文件哪怕只改了另一行,也可能让这个无 id 项被视为“先删除,再添加”,从而触发整体重挂。
这不是为了好看的 YAML,而是为了让配置 diff 有稳定的比较键。
03 / group 把一组插件变成一个单元
- id: sandbox-tools
name: '@deepseek-ai/cordis-plugin-group'
group: true
isolate:
shell: true
config:
- id: fs
name: '@deepseek-ai/dsh-fs'
- id: shell
name: '@deepseek-ai/dsh-shell-local'group 可以嵌套一组配置项,作为一个单元加载和卸载。它适合表达一项完整能力由多个插件共同组成的情况:提供服务的插件、消费者和辅助事件监听器可以一起出现、一起离开。
isolate 则针对服务作用域。两个组可以各自拥有名为 shell 的服务实例,组内消费者看到自己的提供方,不会改写父 Context 中的同名服务。
04 / patch 层让组合可以被重写
DeepSeek Harness 的 bundle 先把配置行插入空列表,随后 profile patch、用户 patch 和命令行 overlay 继续修改这棵树。patch 可以按 id 替换目标行的整个 config,也可以插入新行。配置替换不是深度合并;需要保留的字段必须在 patch 中再次写出。
可以用下面的命令查看机器实际启动的组合:
dsh --profile web --dump-config这条路径把“部署选择”从插件实现中移到组合层:同一个消费者可以在不同 profile 里使用不同 provider,而不用改自己的源码。
05 / 把配置分成三层看
- 入口层:
name和id说明挂载谁、如何识别它。 - 依赖层:
inject说明它需要哪些已注册服务。 - 行为层:
config说明这次挂载用什么选项;schema 会在apply前验证它。
!!js 是本仓库 loader 的扩展,只在 config 和条目的 disabled 字段内求值;name、id 和 inject 保持静态。环境选择应优先使用 overlay,而不是把动态表达式塞进所有元数据。
下一步
更多文章
事件:不知道谁在听,也能让插件协作
从类型化事件和五种分发模式出发,理解 Cordis 如何让服务广播事实、并发工作或交出决策。
生命周期与 effect:让 Cordis 注册可以回卷
跟随 Fiber 从 PENDING 到 DISPOSED,理解 effect、disposer 与 HMR 如何共同管理插件副作用。
动手:从 hello.ts 写出你的第一个 Cordis 插件
用一个函数插件和一份 cordis.yml,跑通 Loader、Context 与 Fiber 的最短路径。
邮件列表
加入我们的社区
订阅邮件列表,及时获取最新消息和更新