# Dsh Architecture

> Use when 理解/审计 DeepSeek Harness 架构、Cordis 插件机制或扩展点。

- Skill: `yyyyyhhhhh0639/dsh-architecture` (Agent Skill)
- Install (CLI): `npx skillmds@latest add yyyyyhhhhh0639/dsh-architecture`
- Raw SKILL.md: https://api.skillmd.com/api/skills/yyyyyhhhhh0639/dsh-architecture/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: yyyyyhhhhh0639 (https://skillmd.com/u/yyyyyhhhhh0639)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/yyyyyhhhhh0639/dsh-architecture

---


# 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 基类 |

**核心机制**：

1. **Context 是 Proxy**：构造时 `new Proxy(this, ReflectService.handler)`。属性读取走服务解析器；`extend()` 原型继承创建子上下文（父不变）；`isolate(name, label)` 给服务创建独立作用域（同 label 合并）；`intercept()` 注入服务级配置。
2. **5 种事件派发模式**（events.ts，模式是事件公共契约，`@mode` 标注）：
   - `emit`：同步、不 await 返回值（观察）
   - `parallel`：`Promise.allSettled` 并发，聚合错误
   - `serial`：按序 await 直到 `isBailed()`（非 null/false/undefined）（决策）
   - `bail`：同步版 serial
   - `waterfall`：**洋葱中间件**——最后一个参数是 `next`，不调 `next()` 即 veto 整条链
3. **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
4. **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 | 类型契约 |

**关键设计**：

1. **子代理是可选的 capability seam，不属于 agent loop**——多 provider 共存按名注册（in-process / fork / ACP / Codex / Claude Code / dsh-sdk）
2. **Fail loud**：provider 静态 descriptor 宣告能力（outputSchema/depthLimit/toolFilter/persona），请求缺能力 → 启动时 typed error（`UNSUPPORTED_CAPABILITY`），绝不静默降级
3. **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 销毁顺序
4. **状态从唯一事实派生**是贯穿性设计原则（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

1. **文档与源码有出入时以源码为准**：文档描述设计意图，源码是最终事实（如 subagent 的 Activation 状态派生在 continuation.ts 实现）。
2. **npm 安装版无法注册自定义 UI 节点**：ConversationNodeDefinition 需 client 插件编译进 Web bundle（cookbook 明示），运行时插件只能影响后端行为。
3. **改 bundle/源码会被升级覆盖**：优先 profile patch 层 + 本地插件（相对路径加载），不要改 `packages/bundle/` 或 node_modules。
4. **dsh 迭代快**：架构文档标注的机制可能随版本变化，重大决策前核对 `--dump-config` 实际树。

## Verification Checklist

- [ ] 能画出 Cordis 五件套职责与 Fiber 生命周期状态机
- [ ] 能解释 "Model-visible means logged" 不变式的含义与后果
- [ ] 能说明 subagent seam 与 web seam 的三角色结构与 fail-loud 哲学
- [ ] 能写出插件安装的三种 name 形式（cordis: / 相对路径 / 裸包名）及适用场景
- [ ] 需要最新行为时用 `dsh --profile web --dump-config` 核对实际插件树

