File contents DeepSeek Harness 架构(源码级审计)
Overview
DeepSeek Harness(dsh)是 DeepSeek AI 的开源 agent harness(@deepseek-ai/dsh,MIT,developer preview,版本迭代快、有破坏性变更)。核心信条:"Everything is a plugin" ——没有特权核心,包括 agent loop 本身都是插件。底层是 vendored 的 Cordis 插件框架(设计论文《A Programming Paradigm for Spatiotemporal Composability》)。
本技能记录源码审计结论(基于仓库 master 源码),用于理解 dsh 行为、评估插件、与 Hermes 对照。
When to Use
理解 dsh 的架构决策(为什么这样设计)
评估/编写 dsh 插件(事件、service、seam 选择)
排查 dsh 行为异常(会话日志、子代理、工具调用)
与 Hermes 架构对照(身份系统 vs 插件哲学)
仓库布局
vendor/ # Cordis 及周边 vendored 包(插件框架本体)
packages/core/ # session / system-prompt / tools / agent / agent-loop / scope
packages/web/ # web seam(web / tool-web / web-search-* / web-fetch-http)
packages/subagent/ # subagent seam(subagent + 6 个 provider 包)
packages/bundle/ # 分发格式(base / web-app / headless)
packages/boot/ # 启动装配(app-boot)
packages/client/ # Web UI(浏览器端)
docs/ # 官方文档(architecture.md 等,质量高)
Cordis 插件框架(vendor/cordis/src,9 文件 2693 行)
五件套(源码逐行确认):
文件
行数
职责
context.ts
146
Context 代理 + 作用域
events.ts
352
事件总线(5 种派发模式)
fiber.ts
754
插件生命周期核心
registry.ts
337
插件注册表 + DI
service.ts
115
Service 基类
核心机制 :
Context 是 Proxy :构造时 new Proxy(this, ReflectService.handler)。属性读取走服务解析器;extend() 原型继承创建子上下文(父不变);isolate(name, label) 给服务创建独立作用域(同 label 合并);intercept() 注入服务级配置。
5 种事件派发模式 (events.ts,模式是事件公共契约,@mode 标注):
emit:同步、不 await 返回值(观察)
parallel:Promise.allSettled 并发,聚合错误
serial:按序 await 直到 isBailed()(非 null/false/undefined)(决策)
bail:同步版 serial
waterfall:洋葱中间件 ——最后一个参数是 next,不调 next() 即 veto 整条链
Fiber 生命周期 (fiber.ts):PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED
↑_________________↓
(依赖变化触发 _reload/_unload)
每个插件实例 = 一个 Fiber,持有 _disposables
依赖即状态 :_refresh() 把 inject 服务的 fiber uid 拼成 epoch 字符串;epoch 变化即重载/卸载——加载顺序由服务依赖声明驱动,无手动 boot 顺序
effect() 注册可逆副作用:disposer 按逆注册序 执行;支持 generator/async iterable
update() 走 internal/update waterfall,HMR 插件可 veto
DI :ctx.inject(['agents'], cb) = 服务可用时运行,变化自动重跑;@Inject 装饰器(类/方法级);插件形态统一 function/class/{apply} 三种,registry.resolve() 提取 callback 作为运行时身份键。
会话模型:Session Log 是唯一事实源
packages/core/session/src/index.ts(1157 行):
"Model-visible means logged" :任何到达模型请求的东西必须能从日志重建(运行时不变式断言);新增模型可见输入必须扩展 SessionEventMap(declaration merging 可扩展)
Session = append-only SessionEvent[] 日志,seq = log.length 连续性契约
deriveMessages() 从日志派生 LLM 历史(带缓存:surface 节点每节点投影一次,compaction 失效重建;返回对象共享且 deep-frozen)
firstLiveSeq 区分构造种子(replay/fork/resume)与进程内新事件;session/end-seed 标记持久化边界
种子验证严格:JSON 无损序列化 + envelope + seq 从 0 连续 + surface 转换合法("坏 seed 不会晚到后端才爆")
invariant.ts:session-invariant 插件用 trace 状态机验证事件序列(如 tool/call 配对)
Subagent Seam(多代理)
packages/subagent/subagent/src/(4531 行)核心文件:
文件
行数
职责
continuation.ts
1483
可续接子代理管理器
index.ts
499
Service Definition(ctx.subagents)
list-children.ts
452
子代理/后代发现
types.ts
324
类型契约
关键设计 :
子代理是可选的 capability seam,不属于 agent loop ——多 provider 共存按名注册(in-process / fork / ACP / Codex / Claude Code / dsh-sdk)
Fail loud :provider 静态 descriptor 宣告能力(outputSchema/depthLimit/toolFilter/persona),请求缺能力 → 启动时 typed error(UNSUPPORTED_CAPABILITY),绝不静默降级
Continuable children :持久化 Session → 至多一个 live Activation → 一个 AgentHandle
→ Agent inbox 唯一 turn FIFO → 零或多个 owned child Activations
Activation 状态(running/waiting/settled)从 Agent quiescence + owned-child 集合派生 ,不维护第二状态机
followup() 路由:running 入队 / waiting 唤醒 / 无 Activation 冷恢复(重放持久化事件)
每个 continuation 消息 = 一个 FIFO turn;child-first 销毁顺序
状态从唯一事实派生 是贯穿性设计原则(Activation 不另建状态机)
Web Seam(搜索/抓取)
packages/web/web/src/:
单选无回退 :resolveProvider() 配置 id 或唯一可用;多可用无配置 → WEB_PROVIDER_AMBIGUOUS;无 fallback/retry (fail-loud 哲学)
三角色:Service Definition(ctx.web)/ Service Provider(各搜索后端)/ Consumer(tool-web 的 web_search/web_fetch)
WebSearchProvider 接口:{ id, available(), search(request, signal) }(极简)
provider 注册 = 能力注册,工具可见性独立于 backend 可用性(执行时才解析,错误结构化:WEB_PROVIDER_CONFIGURED_MISSING 等)
工具卡片呈现链路:result.content → searchMetaFromValue → meta.answer → presentSearchResult card:'web' → client WebBlock(answer 显示在引用列表上方)
插件加载与配置(loader)
vendor/loader/ + packages/boot/app-boot/:
Profile = 命名组合(web/headless 模板),Bundle = 分发格式;层级:bundle 序 → profile 的 cordis.patch.yml → home 级 → --patch overlay
ctx.baseUrl = profile 目录(pathToFileURL(dirname(configPath)).href + '/')
loader import(name, baseUrl):支持 cordis: 内建 / 相对路径(. 开头按 baseUrl)/ 裸包名——本地插件无需 pnpm ,patch 写相对路径即可
patch 语义:按 id 替换整行 config;插入新行用 - insert: 数组 (直接写 id 会 entry not found)
dsh --profile web --dump-config 查看实际启动的插件树
与 Hermes 对照(推断,dsh 侧以源码为准)
维度
dsh
Hermes
扩展机制
全插件化(无特权核心,注册即 effect)
插件/技能/工具集 + 配置
会话事实源
追加式事件日志 + 派生(严格不变式)
session DB(SQLite)
子代理
Subagent seam 多 provider 共存、可续接 + 冷恢复
delegate_task 子代理
身份系统
persona 是 per-child 可选能力(模板插值)
SOUL/USER/MEMORY 三层身份文档
治理哲学
生成目录 + verify 脚本(doc/config/module 全可校验)
技能生态 + 记忆治理流程
反差点:dsh 把"persona"做成可插拔能力;Hermes 把身份系统作为第一公民——两种身份架构哲学。
Common Pitfalls
文档与源码有出入时以源码为准 :文档描述设计意图,源码是最终事实(如 subagent 的 Activation 状态派生在 continuation.ts 实现)。
npm 安装版无法注册自定义 UI 节点 :ConversationNodeDefinition 需 client 插件编译进 Web bundle(cookbook 明示),运行时插件只能影响后端行为。
改 bundle/源码会被升级覆盖 :优先 profile patch 层 + 本地插件(相对路径加载),不要改 packages/bundle/ 或 node_modules。
dsh 迭代快 :架构文档标注的机制可能随版本变化,重大决策前核对 --dump-config 实际树。
Verification Checklist
1 --- 2 name: dsh-architecture 3 description: Use when 理解/审计 DeepSeek Harness 架构、Cordis 插件机制或扩展点。 4 license: MIT 5 --- 6 7 # DeepSeek Harness 架构(源码级审计) 8 9 ## Overview 10 11 DeepSeek Harness(dsh)是 DeepSeek AI 的开源 agent harness(`@deepseek-ai/dsh`,MIT,developer preview,版本迭代快、有破坏性变更)。核心信条:**"Everything is a plugin"**——没有特权核心,包括 agent loop 本身都是插件。底层是 vendored 的 **Cordis** 插件框架(设计论文《A Programming Paradigm for Spatiotemporal Composability》)。 12 13 本技能记录源码审计结论(基于仓库 master 源码),用于理解 dsh 行为、评估插件、与 Hermes 对照。 14 15 ## When to Use 16 17 - 理解 dsh 的架构决策(为什么这样设计) 18 - 评估/编写 dsh 插件(事件、service、seam 选择) 19 - 排查 dsh 行为异常(会话日志、子代理、工具调用) 20 - 与 Hermes 架构对照(身份系统 vs 插件哲学) 21 22 ## 仓库布局 23 24 ``` 25 vendor/ # Cordis 及周边 vendored 包(插件框架本体) 26 packages/core/ # session / system-prompt / tools / agent / agent-loop / scope 27 packages/web/ # web seam(web / tool-web / web-search-* / web-fetch-http) 28 packages/subagent/ # subagent seam(subagent + 6 个 provider 包) 29 packages/bundle/ # 分发格式(base / web-app / headless) 30 packages/boot/ # 启动装配(app-boot) 31 packages/client/ # Web UI(浏览器端) 32 docs/ # 官方文档(architecture.md 等,质量高) 33 ``` 34 35 ## Cordis 插件框架(vendor/cordis/src,9 文件 2693 行) 36 37 五件套(源码逐行确认): 38 39 | 文件 | 行数 | 职责 | 40 |---|---|---| 41 | context.ts | 146 | Context 代理 + 作用域 | 42 | events.ts | 352 | 事件总线(5 种派发模式) | 43 | fiber.ts | 754 | **插件生命周期核心** | 44 | registry.ts | 337 | 插件注册表 + DI | 45 | service.ts | 115 | Service 基类 | 46 47 **核心机制**: 48 49 1. **Context 是 Proxy**:构造时 `new Proxy(this, ReflectService.handler)`。属性读取走服务解析器;`extend()` 原型继承创建子上下文(父不变);`isolate(name, label)` 给服务创建独立作用域(同 label 合并);`intercept()` 注入服务级配置。 50 2. **5 种事件派发模式**(events.ts,模式是事件公共契约,`@mode` 标注): 51 - `emit`:同步、不 await 返回值(观察) 52 - `parallel`:`Promise.allSettled` 并发,聚合错误 53 - `serial`:按序 await 直到 `isBailed()`(非 null/false/undefined)(决策) 54 - `bail`:同步版 serial 55 - `waterfall`:**洋葱中间件**——最后一个参数是 `next`,不调 `next()` 即 veto 整条链 56 3. **Fiber 生命周期**(fiber.ts): 57 ``` 58 PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED 59 ↑_________________↓ 60 (依赖变化触发 _reload/_unload) 61 ``` 62 - 每个插件实例 = 一个 Fiber,持有 `_disposables` 63 - **依赖即状态**:`_refresh()` 把 inject 服务的 fiber uid 拼成 epoch 字符串;epoch 变化即重载/卸载——**加载顺序由服务依赖声明驱动,无手动 boot 顺序** 64 - `effect()` 注册可逆副作用:disposer 按**逆注册序**执行;支持 generator/async iterable 65 - `update()` 走 `internal/update` waterfall,HMR 插件可 veto 66 4. **DI**:`ctx.inject(['agents'], cb)` = 服务可用时运行,变化自动重跑;`@Inject` 装饰器(类/方法级);插件形态统一 function/class/`{apply}` 三种,`registry.resolve()` 提取 callback 作为运行时身份键。 67 68 ## 会话模型:Session Log 是唯一事实源 69 70 `packages/core/session/src/index.ts`(1157 行): 71 72 - **"Model-visible means logged"**:任何到达模型请求的东西必须能从日志重建(运行时不变式断言);新增模型可见输入必须扩展 `SessionEventMap`(declaration merging 可扩展) 73 - Session = append-only `SessionEvent[]` 日志,`seq = log.length` 连续性契约 74 - `deriveMessages()` 从日志派生 LLM 历史(带缓存:surface 节点每节点投影一次,compaction 失效重建;返回对象共享且 deep-frozen) 75 - `firstLiveSeq` 区分构造种子(replay/fork/resume)与进程内新事件;`session/end-seed` 标记持久化边界 76 - 种子验证严格:JSON 无损序列化 + envelope + seq 从 0 连续 + surface 转换合法("坏 seed 不会晚到后端才爆") 77 - `invariant.ts`:`session-invariant` 插件用 trace 状态机验证事件序列(如 tool/call 配对) 78 79 ## Subagent Seam(多代理) 80 81 `packages/subagent/subagent/src/`(4531 行)核心文件: 82 83 | 文件 | 行数 | 职责 | 84 |---|---|---| 85 | continuation.ts | 1483 | **可续接子代理管理器** | 86 | index.ts | 499 | Service Definition(`ctx.subagents`) | 87 | list-children.ts | 452 | 子代理/后代发现 | 88 | types.ts | 324 | 类型契约 | 89 90 **关键设计**: 91 92 1. **子代理是可选的 capability seam,不属于 agent loop**——多 provider 共存按名注册(in-process / fork / ACP / Codex / Claude Code / dsh-sdk) 93 2. **Fail loud**:provider 静态 descriptor 宣告能力(outputSchema/depthLimit/toolFilter/persona),请求缺能力 → 启动时 typed error(`UNSUPPORTED_CAPABILITY`),绝不静默降级 94 3. **Continuable children**: 95 ``` 96 持久化 Session → 至多一个 live Activation → 一个 AgentHandle 97 → Agent inbox 唯一 turn FIFO → 零或多个 owned child Activations 98 ``` 99 - Activation 状态(running/waiting/settled)**从 Agent quiescence + owned-child 集合派生**,不维护第二状态机 100 - `followup()` 路由:running 入队 / waiting 唤醒 / 无 Activation 冷恢复(重放持久化事件) 101 - 每个 continuation 消息 = 一个 FIFO turn;child-first 销毁顺序 102 4. **状态从唯一事实派生**是贯穿性设计原则(Activation 不另建状态机) 103 104 ## Web Seam(搜索/抓取) 105 106 `packages/web/web/src/`: 107 108 - **单选无回退**:`resolveProvider()` 配置 id 或唯一可用;多可用无配置 → `WEB_PROVIDER_AMBIGUOUS`;**无 fallback/retry**(fail-loud 哲学) 109 - 三角色:Service Definition(ctx.web)/ Service Provider(各搜索后端)/ Consumer(tool-web 的 `web_search`/`web_fetch`) 110 - `WebSearchProvider` 接口:`{ id, available(), search(request, signal) }`(极简) 111 - provider 注册 = 能力注册,工具可见性独立于 backend 可用性(执行时才解析,错误结构化:`WEB_PROVIDER_CONFIGURED_MISSING` 等) 112 - 工具卡片呈现链路:`result.content → searchMetaFromValue → meta.answer → presentSearchResult card:'web' → client WebBlock`(answer 显示在引用列表上方) 113 114 ## 插件加载与配置(loader) 115 116 `vendor/loader/` + `packages/boot/app-boot/`: 117 118 - **Profile** = 命名组合(web/headless 模板),**Bundle** = 分发格式;层级:bundle 序 → profile 的 `cordis.patch.yml` → home 级 → `--patch` overlay 119 - `ctx.baseUrl` = profile 目录(`pathToFileURL(dirname(configPath)).href + '/'`) 120 - loader `import(name, baseUrl)`:支持 `cordis:` 内建 / 相对路径(`.` 开头按 baseUrl)/ 裸包名——**本地插件无需 pnpm**,patch 写相对路径即可 121 - patch 语义:按 id 替换整行 config;**插入新行用 `- insert:` 数组**(直接写 id 会 `entry not found`) 122 - `dsh --profile web --dump-config` 查看实际启动的插件树 123 124 ## 与 Hermes 对照(推断,dsh 侧以源码为准) 125 126 | 维度 | dsh | Hermes | 127 |---|---|---| 128 | 扩展机制 | 全插件化(无特权核心,注册即 effect) | 插件/技能/工具集 + 配置 | 129 | 会话事实源 | 追加式事件日志 + 派生(严格不变式) | session DB(SQLite) | 130 | 子代理 | Subagent seam 多 provider 共存、可续接 + 冷恢复 | delegate_task 子代理 | 131 | 身份系统 | persona 是 per-child 可选能力(模板插值) | SOUL/USER/MEMORY 三层身份文档 | 132 | 治理哲学 | 生成目录 + verify 脚本(doc/config/module 全可校验) | 技能生态 + 记忆治理流程 | 133 134 反差点:dsh 把"persona"做成可插拔能力;Hermes 把身份系统作为第一公民——两种身份架构哲学。 135 136 ## Common Pitfalls 137 138 1. **文档与源码有出入时以源码为准**:文档描述设计意图,源码是最终事实(如 subagent 的 Activation 状态派生在 continuation.ts 实现)。 139 2. **npm 安装版无法注册自定义 UI 节点**:ConversationNodeDefinition 需 client 插件编译进 Web bundle(cookbook 明示),运行时插件只能影响后端行为。 140 3. **改 bundle/源码会被升级覆盖**:优先 profile patch 层 + 本地插件(相对路径加载),不要改 `packages/bundle/` 或 node_modules。 141 4. **dsh 迭代快**:架构文档标注的机制可能随版本变化,重大决策前核对 `--dump-config` 实际树。 142 143 ## Verification Checklist 144 145 - [ ] 能画出 Cordis 五件套职责与 Fiber 生命周期状态机 146 - [ ] 能解释 "Model-visible means logged" 不变式的含义与后果 147 - [ ] 能说明 subagent seam 与 web seam 的三角色结构与 fail-loud 哲学 148 - [ ] 能写出插件安装的三种 name 形式(cordis: / 相对路径 / 裸包名)及适用场景 149 - [ ] 需要最新行为时用 `dsh --profile web --dump-config` 核对实际插件树
yyyyyhhhhh0639/agent-skills/tree/main/skills/deepseek-harness/dsh-architecture commit b020c0e905
Frequently asked questions How do I install the Dsh Architecture skill? Run npx skillmds@latest add yyyyyhhhhh0639/dsh-architecture in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
What does the Dsh Architecture skill do? Use when 理解/审计 DeepSeek Harness 架构、Cordis 插件机制或扩展点。 It is listed under Coding & Dev Tools on SkillMD.
Is Dsh Architecture safe to use? This skill has not completed SkillMD's automated safety review yet. Capability flags: makes network calls. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
Which AI agents work with Dsh Architecture? This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Is Dsh Architecture free to use? Yes. Installing skills from SkillMD is free. This skill is licensed under MIT.
Who published Dsh Architecture? yyyyyhhhhh0639 (@yyyyyhhhhh0639) published this skill. Their other Agent Skills are listed on their SkillMD profile.