第二层 · 整体架构

分层组合:profile / bundle / patch

一个运行中的 dsh 是一棵从有序层在启动时装配出来的插件树。本章讲清这套组合机制——它是你理解"为什么改个配置就能换掉整个能力"的钥匙。依据 docs/architecture.md

三个层次概念

概念是什么类比
profile(配置档)存在 Harness home 里的命名组合;列出它叠加的 bundle、保留的树外插件、用户自己的 cordis.patch.yml一份"装机清单"
bundle(包)Cordis 配置行 + 它们挂载的代码的分发格式;它的内容仍可被上层 patch 覆盖清单里的一项"预置套餐"
patch(补丁层)按 id 瞄准某行、整体替换其 config,或插入新行对套餐做"加料/换料"

每个 bundle 在自己的 package.jsondsh 字段里声明:dsh.profile 列出 profile 叠加的 bundle,dsh.bundle 指向该 bundle 的 patch 文件。

官方自带的 bundle

webheadless 作为模板随仓库发布。

层的应用顺序

层叠加在一个空的 entry 列表上,顺序如下:

① profile 列出的每个 bundle(按列出顺序) ▼ ② profile 的 cordis.patch.yml ▼ ③ home 级的 cordis.patch.yml ▼ ④ 任何 --patch 覆盖层

一条 patch 通过 id 瞄准某行,整体替换它的 config,或插入新行。所以你想改某项行为,不必改源码——写一条 patch 覆盖该行即可。

看你的机器实际启动了什么

# 打印当前 profile 真正装配出的整棵插件树
dsh --profile web --dump-config

它打印的每一行都能被你自己的 patch 替换。组合的完整机制在 packages/boot/app-boot/README.md;字段含义在生成的 docs/config-catalog.md

这套设计为什么重要

可逐层打补丁
bundle 之上永远有更高层可覆盖它——所以升级一个 bundle 不会抹掉用户的定制,定制放在 profile/home 的 patch 层。这正是论文"时间可组合性"在产品层的体现:换实现 = 换一行配置,且可逆。
profile 即"部署形态"
同一套基础能力,web profile 长出带 GUI 的常驻服务,headless profile 长成跑完即退的 CLI。差异只是叠加了不同 bundle——没有任何"if GUI then ..."的硬编码分支。

下一节看这棵插件树里最核心的部件:Agent 循环如何驱动一次对话。