Appearance
1.3 配置树:组合包、profile 与 patch 层
本章概览:继 0.3 之后深入配置树的"数据结构"——
cordis.yml条目的结构、patch 的定位与替换算法、profile manifest,以及按会话组合的 agent preset。理解本章才能准确回答"某个插件是怎么被挂进运行时的"。
cordis.yml:配置项列表
一份 cordis.yml(或组合包的 cordis.patch.yml)本质上是一组 Cordis 配置项的列表(entry list)。每个条目描述一个要挂载的插件:
yaml
- id: bash-tool # 可选:条目 id,patch 按它定位
name: '@deepseek-ai/dsh-tool-bash' # 模块指定符:包名或相对路径
inject: [...] # 可选:声明所需服务
disabled: false # 可选:可含 !!js 表达式
config: {...} # 插件的配置对象Loader 的 entryListSchema 与 applyEntryPatches 是这一数据结构的正式定义——配置转储(--dump-config)与启动挂载共用同一套解析与 patch 算法,因此组合结果不会漂移。
出处:
packages/boot/app-boot/README.md(deepseek-harness-src/packages/boot/app-boot/README.md)
patch 算法:按 id 替换整个 config
patch 层(如 profile 的 cordis.patch.yml、home 级、--patch overlay)是一组 PatchOptions 条目:
- 按 id 定位:
- id: <target>指向要覆盖的条目; - 替换整个 config:patch 会整体替换目标条目的
config——没有深层合并。dsh-baseREADME 明确提醒:profile 覆盖一个条目时,必须重述该条目保留的所有字段; - 插入新条目:也可用
insert列表新增条目。
IMPORTANT
"一条 patch 替换一个条目的整个 config"这一语义,解释了为什么模式专属的值放在模式组合包里(如 dsh-web-app),而不是 base 里:任何模式无关的字段都可能被上层 patch 覆盖掉。
出处:
packages/bundle/base/README.md(deepseek-harness-src/packages/bundle/base/README.md)
profile manifest:dsh.profile
profile 目录的 package.json 中,dsh 字段声明 manifest:
jsonc
{
"dependencies": { /* 树外插件依赖 */ },
"dsh": {
"profile": {
"bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app"]
// bundles 顺序 = 叠加顺序
}
}
}组合包侧则声明:
jsonc
{
"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
}loadProfile 按两个锚点解析 bundle:先 dsh 安装目录,再 profile 目录;列出的包若没有 bundle 声明则响亮失败。composeEntries 通过 include 自身的 applyEntryPatches 把各层 patch 应用到空条目列表上。
出处:
packages/boot/app-boot/README.md#profiles(deepseek-harness-src/packages/boot/app-boot/README.md)
应用参数:dsh-cmdline
配置树中还藏着"命令行参数解析"这一能力:dsh-cmdline 把启动器之后的所有 token 解析为共享的不可变快照注入 ctx.cmdlineArgs。任意应用插件都可以消费这份快照。模式组合包通过"startup provider"(如 web-startup、headless-startup)解析自己的参数并提供 webStartup / headlessStartup 服务;flag 配置的行只读 lazy config,因此 dsh --profile web --help 不会启动任何服务器。
出处:
packages/boot/cmdline/README.md与packages/bundle/web-app/README.md
agent preset:按会话组合
组合包把插件挂进进程级配置树;而 agent preset 把插件挂进每个 agent 会话的作用域。一个 preset 是存放一份 agent.cordis.yml 的目录;roster 在进程内以"standing scope"挂载一次,每个选择该 preset 的会话通过 dsh-scope 的父链加入(解析顺序 agent → preset → global,最近者遮蔽最远者)。
要点:
- 发现即读盘:
list()/resolve()每次重读根目录,运行期新建的 preset 立即可见; - 健康检查:组合缺失或不可加载的目录以
broken原因列出,而非静默跳过; - 切换:
recompose()仅在 agent 尚未产生任何内容时有效,切换会卸载旧子树、挂载新子树(两个组合不能共存,因为会在同一层注册同名工具); - 子代理继承:subagent 通过
composeFrom()绑定父代理的 standing composition——因为所有模型可见行都在 agent 平面上,子代理若不绑定,将带着空工具注册表到达模型。
出处:
packages/preset/agent-presets/README.md(deepseek-harness-src/packages/preset/agent-presets/README.md)
配置目录:可配置字段的权威来源
每个可加载包 config: 块的逐字声明(含 JSDoc)由脚本生成在 docs/config-catalog.md,并校验运行时 schemastery schema 与声明的类型完全对应——schema 校验接受的每个键都能在声明类型上找到,因此声明无法隐藏 loader 接受的字段。查找"某个插件能配什么"以该文件为准。
小结
配置树的三层结构——进程级(profile + 组合包 + patch)、应用参数级(cmdline)、会话级(agent preset)——是 DSH "一切皆插件" 的组合载体。下一章 1.4 能力缝 讲解插件如何组织成"可替换能力"。
参考资料
- packages/boot/app-boot/README.md — 启动与组合机制(
deepseek-harness-src/packages/boot/app-boot/README.md) - packages/bundle/base/README.md — base 组合包与 patch 语义(
deepseek-harness-src/packages/bundle/base/README.md) - packages/preset/agent-presets/README.md — agent preset(
deepseek-harness-src/packages/preset/agent-presets/README.md) - docs/config-catalog.md — 插件配置目录(生成)(
deepseek-harness-src/docs/config-catalog.md)