At a glance
What it does
Guidance for developing, distributing, and verifying DeepSeek Harness plugins.
Before you choose it
Guidance for developing, distributing, and verifying DeepSeek Harness plugins.
Best for
Users whose task matches this skill trigger.
Common tasks
- Guidance for developing, distributing, and verifying DeepSeek Harness plugins.
Permissions and data
The skill guides a local workflow; external behavior was not independently audited.
Permissions- Uses the declared plugin or skill workflow.
- Data handling was not independently audited.
- External services follow the supplied project documentation.
- Credential requirements were not independently tested.
Limitations
- The supplied record does not establish runtime compatibility.
What DSHub checked
- The pinned source and supplied artifact evidence were captured.
What DSHub did not check
- Installation and runtime behavior were not tested.
Pinned install
Primary action
This standalone skill does not have a DSH Plugin install action. Use its source documentation for the delivery method.
Maintainer source
Skill instructions
name: dsh-plugin-development description: 开发、维护、分发和验证 DeepSeek Harness (DSH) 插件的执行型 Skill。覆盖 host/client 形态判断、bundle/profile 契约、Service 与函数插件、工具、HTTP、持久化、slot、Conversation Node、客户端构建、HMR、GitHub 安装和真实组合验证。 metadata: version: "3.1.0" date: "2026-08-13" reference: "https://github.com/NanmiCoder/dsh-agent-teams"
DSH 插件开发
这是正式版导向的执行清单。先判断运行面,再选择官方模板,实现后必须从真实组合和用户安装路径验证。不要把某个项目的偶然实现当成框架契约。
1. 开始前
- 用
pwd、git rev-parse --show-toplevel、git status --short --branch确认项目与用户改动。 - 读取
package.json、cordis.patch.yml、tsconfig*.json、构建配置、相关src/和测试。 - 不覆盖用户改动,不操作用户明确排除的 profile、端口或实例。
- 判断最小运行面:
- 工具、system prompt、HTTP、持久化、provider:host。
- slot、Conversation Node、浏览器状态和浮层:client。
- host 能力且需要 Web 可视化:host + client。
- 没有 Web 需求:不要声明
dsh.client,也不要构建 client bundle。
- 写下插件唯一职责、依赖的 service、贡献的配置行、持久化 owner 和用户可见验证面,再开始编码。
2. 证据与官方参考
2.1 取证顺序
行为不确定时按顺序取证,不猜:
- 当前项目及已安装
node_modules/@deepseek-ai/*的package.json、exports、types、README。 - 环境明确提供的 DeepSeek Harness checkout;只读分析,不修改。
- 克隆官方仓库取证(见 §2.3)。
- 信息仍不足时,以当前正式版 exports/types 为边界,选择可安全失败的最小实现并标注假设。
不要写死本机绝对路径,也不要访问或转述未授权的私有仓库内容。
2.2 官方模板选择
若提供了 Harness checkout(环境提供或按 §2.3 克隆),优先按插件形态阅读这些模板;路径以 checkout 根目录为基准:
| 目标 | 主参考 | 学习重点 |
|---|---|---|
| Host Service / HTTP | packages/host/webserver |
Service、static Config、Service.init、route disposer、连接清理 |
| 最小 client 插件 | packages/client/ui-message-feedback |
inject、apply、locale、per-session controller、slot 注册与清理 |
| Slot / Conversation Node | packages/client/ui-conversation + packages/client/ui-slots |
SlotMap、slot kind/scope、children 认领、keyed node renderer |
| Bundle 分层 | packages/bundle/base + packages/bundle/web-app |
顶层 patch 数组、行 id 覆盖、整段 config 替换、加载顺序 |
| 简单持久化 backend | packages/storage/storage-json |
register → disposer → close、显式 root、并发打开门禁 |
| 崩溃安全日志 | packages/session/session-persistence-jsonl |
原子发布、fsync、并发 no-clobber、torn-tail 处理 |
| 工具插件 | packages/fs/tool-fs |
defineTool、schema、render、可选能力挂载 |
| Client 测试 | packages/test-support/client-runtime |
jsdom、SlotTestRuntime、mount/dispose、fake service |
复杂插件只用于补证据,不作为起步模板。若要委派只读调研,提示词必须要求给出文件、行区间、契约与最小建议。
2.3 官方仓库兜底层
官方仓库 https://github.com/deepseek-ai/deepseek-harness 是公开、MIT 许可的可引用证据源(默认分支 master;开发者预览阶段无 release tag,不 pin 版本)。需要兜底取证时:
选临时目录:用用户或环境提供的目录,例如
SCRATCH="$(mktemp -d)";不要写死本机绝对路径。复用已有 checkout:若
$SCRATCH/dsh-official已存在,且git remote -v指向官方、根目录含AGENTS.md与LICENSE,直接复用;需要更新时git -C "$SCRATCH/dsh-official" fetch --depth 1 origin master && git -C "$SCRATCH/dsh-official" reset --hard origin/master(或删除后重克隆)。同一任务只维护这一个目录,避免反复克隆。浅克隆(只读取证,无需
pnpm install):git clone --depth 1 https://github.com/deepseek-ai/deepseek-harness.git "$SCRATCH/dsh-official"只克隆官方
deepseek-ai/deepseek-harness;不要访问或转述未授权的私有仓库内容。对克隆内容同样只读分析,不修改。
进入后定位:
- 先读根
AGENTS.md(CLAUDE.md是它的符号链接):仓库布局、命令与约定一次讲清,是官方给 agent 的入口。 - 再用
packages/README.md的 group 表确认目标包位于哪个packages/<group>/<pkg>。 - 按 §2.2 模板表读对应包的
README.md与src/;取证结论给出文件与行区间。
演进兜底:官方仓库处于开发者预览、迭代极快、无兼容承诺、无 release tag,§2.2 的模板路径只是索引,一切以当前 checkout 的实际代码为准;路径或名称漂移时,用 packages/README.md 定位新位置并回报修正,不要凭旧文档猜。需要复现一致证据时记录 git rev-parse HEAD。
3. Bundle、Profile 与 package 契约
3.1 两个概念
- Bundle 是作者分发的包:
package.json.dsh.bundle.patch指向配置层。 - Profile 是用户运行的组合:
$DSH_HOME/profiles/<name>/package.json.dsh.profile.bundles保存有序 bundle 列表。 - 插件作者写 bundle;
dsh plugin创建和维护 profile。不要手写用户 profile manifest。
3.2 最小双面 package
{
"name": "dsh-my-plugin",
"type": "module",
"main": "lib/index.js",
"types": "lib/types/index.d.ts",
"exports": {
".": { "types": "./lib/types/index.d.ts", "default": "./lib/index.js" },
"./client": { "types": "./lib/types/client/index.d.ts", "default": "./lib/client.js" },
"./cordis.patch.yml": "./cordis.patch.yml",
"./package.json": "./package.json"
},
"files": ["lib", "cordis.patch.yml", "README.md"], // 目录或显式清单均可;官方仓库常用显式文件清单
"dsh": {
"bundle": { "patch": "./cordis.patch.yml" },
"client": {
"platform": "web",
"inject": ["@deepseek-ai/dsh-client-runtime"]
}
}
}
规则:
- Host-only 包删除
./client与dsh.client。 - Client 包必须同时有
dsh.client.platform: "web"和真实存在的exports["./client"]。 dsh.client.inject是随图下发的信息性元数据(预检展示 / HMR diff 用),不决定 client fiber 的激活顺序;预取由dsh.client.immediately驱动,真正的依赖等待来自 client bundle 导出的export const inject(§5.1),两者互不替代。dsh.client.immediately是仅供启动关键入口使用的可选预取标记;普通第三方插件不要默认开启。- 当前权威字段是
dsh.client;历史兼容字段只有在目标正式部署仍明确读取时才添加。 - exports、
files和 Git/发布产物必须一致;任何入口都不能指向不存在的文件。 - DSH、Cordis、React 等共享运行时优先声明为 peer,避免复制 runtime identity;版本范围从目标正式版 package metadata 取证。
3.3 Patch 层
cordis.patch.yml 必须是顶层数组:
- insert:
- id: my-plugin
name: dsh-my-plugin
config: {}
注意:
id是配置树中稳定的行身份;name是 Node 可解析的包名或导出路径。- 后层按
id覆盖前层;目标行的config是整段替换,不是深合并,因此覆盖时要重述所需键。 - 生效顺序是 profile bundles → profile
cordis.patch.yml→$DSH_HOME/cordis.patch.yml→ 命令行--patch;后者获胜。 - 包没有
dsh.bundle时只会成为普通依赖,不会自动成为 profile 层。
4. Host 面实现
4.1 函数插件
普通插件通常导出:
export const name = 'my-plugin'
export const inject = ['tools']
export interface Config { enabled: boolean }
export const Config = z.object({ enabled: z.boolean().default(true) })
export function apply(ctx: Context, config: Config): void {}
z从@deepseek-ai/schemastery导入(不是 zod);static Config = Config引用导出的 schema,与官方内联的static Config: z<Config> = z.object({...})等价。inject是必需 service;未满足时 fiber 保持 pending,框架会在服务就绪后激活,不要用轮询模拟依赖注入。- Config 默认值放 schema;任何部署可能需要改变的值都应成为配置,而不是源码常量。
- 可选 service 用
ctx.get()判断或ctx.inject([...], childCtx => ...)惰性挂载;不要在apply()中抢跑兄弟 provider。
4.2 Service 插件
当插件提供稳定 service 时,参考 host/webserver:
export class MyService extends Service {
static Config = Config
constructor(ctx: Context, config: Config) {
super(ctx, 'myService')
}
async [Service.init](): Promise<void> {}
}
- 构造器声明 service key;异步启动放在
Service.init。 - 初始化失败应让 fiber 失败并由启动方报告,不要吞掉组合错误。
- 注册方法返回 disposer;拥有资源的一方负责关闭资源。
4.3 Effect 所有权
所有长生命周期资源必须归当前 fiber:
- route、listener、watcher、timer、React root、DOM、socket、临时 service 都必须可清理。
- 用
ctx.on()或ctx.effect(() => disposer, label)。 - disposer 顺序通常是:停止外部入口/注销 registry → 等待或取消在途工作 → 关闭资源。
- 需要服务后绑定时,用“立即尝试 + service 事件/
ctx.inject重试 + 幂等 guard”,不要重复注册。
4.4 工具
使用 ctx.tools.register(defineTool(...)):
description写清何时调用、必要前置条件、失败语义和副作用。parameters与output.schema都用@deepseek-ai/dsh-tools的 value-schema DSL(编译后是受支持的 JSON Schema 子集):parameters是隐式开放对象根、必填用属性内联required: true;output.schema声明 canonical 返回值并在注册时被assertSupportedJsonSchema强制校验。二者是同一 DSL 的两个面,不是两套语言。output.render给模型稳定、紧凑、可判定的文本。- 从
exec.agent获取当前会话、工作区和 owner,不从全局进程状态猜。 - 异步工作观察或转发
exec.signal;写操作要有幂等、锁或冲突策略。
4.5 HTTP
- 注入当前正式版 Web server service,并用结构化最小接口降低耦合。
- 路由通过
ctx.effect(() => ctx.webServer.register({ kind: 'exact' | 'prefix', path, handler }))注册;重复 (kind, path) 会抛错。 - 状态接口显式设置缓存策略:敏感或实时快照优先
Cache-Control: no-store,可重验证资源使用no-cache;静态资源使用明确白名单和正确 content type。 - path decode、请求体解析和 handler rejection 都要转成明确 4xx/5xx,不能成为未处理 rejection。
- exact route、最长 prefix、fallback 的所有权不能冲突;未知插件资源返回 404,不落入 SPA fallback。
- 涉及权限或本机能力时采用最小暴露、回环/信任边界和方法白名单。
4.6 持久化与并发
先判断应复用正式版 storage/session persistence service,还是插件拥有独立介质。无论哪种:
- 路径配置显式指定;不要用
process.cwd()默认值散落用户数据。 - 状态按 workspace、session、owner 或业务 id 建立清晰隔离维度。
- 同一资源的读改写串行化;并发创建采用 no-clobber 语义。
- 人可读 JSON 要用同目录临时文件 + fsync + 原子发布;追加日志要处理 torn tail。并发创建用
link()+unlink()的 no-clobber 协议,勿用rename()静默覆盖。 - Registry backend 的清理顺序是 unregister 再 close。
- 恢复与 HMR 不能假设创建事件会重放;需要时显式扫描和回填已有对象。
5. Client 面实现
5.1 最小入口
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'
import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
export const inject = ['slots']
export function apply(ctx: ClientContext): void {}
- 类型贡献使用 type-only import 拉入 Context/SlotMap merge。
- client 注册、controller、listener、style 和 DOM 都必须随 client fiber dispose。
- per-session 状态按
SessionId分桶;连接重置时只重同步已经读过的对象。
5.2 Slot 四步契约
- 声明:从提供 slot 的官方包拉入类型;自定义 owner 才通过 module augmentation 扩展
SlotMap。 - 认领:父 entry 的
children表声明子 slot;声明即占有渲染权,不要争抢别人的 seat。 - 注册:owner 与贡献者的激活顺序不保证,使用
ctx.slots.inject(key, () => ctx.slots.register({ name, children?, store?, locale?, inject?, ...kind 参数 }, Component))等待声明;children同时是子 slot 的认领表(认领即占有渲染权)。kind 参数:keyed 必填key、list 必填id(可加order/label)、chain 必填select;single/keyed/list 可加priority做 cell 隐藏(同 cell 同 priority 会抛错)。向未声明 slot 直接 register 会抛错。 - 渲染:owner 使用
renderSlot/renderSlotChain;贡献者不 import owner 的实现组件。
选择接缝时先检查当前正式版类型。常见会话 UI 接缝包括:conversation.session.header.actions/.utilities、conversation.view、conversation.chat.node、conversation.chat.commandview、conversation.chat.assistant-actions、conversation.chat.turnTail、conversation.input.dock、conversation.composer.dock、conversation.composer.bar、conversation.input.left/conversation.input.right/conversation.input.plan/conversation.input.model。全局浮层用 shell.overlay(list/root),不要碰 root 单槽。不要仅凭旧文档写 slot 名,以当前正式版 ui-conversation/src/client/contract/slots.ts 的 SlotMap 为准。
5.3 Conversation Node
Conversation Node 是“事件折叠 + keyed slot renderer”的组合:
- 定义共享事件类型,并 merge 到 session event map。
conversationEvents.register(definition):match选择事件;start创建节点状态;update按 seq 确定性折叠;buildViewNode生成稳定的 view node。
- merge
ChatNodeDataMap/节点 kind 类型。 - 向
conversation.chat.node注册相同 key 的 renderer。
红线:
- 重放同一事件序列必须得到同一节点,不读时间、随机数或当前磁盘状态。
match返回稳定业务 id 和start|update角色;节点引擎在当前会话内使用conversationContextKey(kind, businessId)去重。跨会话持久化缓存另行把 owner session 纳入 key,不能混成引擎契约。- 事件写入业务 owner 会话;共享 host/client 事件文件保持 type-only、最好零运行时 import,避免双 tsconfig 的 Context augmentation 相互污染。
- 磁盘/服务端快照可作为实时 UI 真相;事件流用于对话投影、审计和确定性历史,两者职责不要混淆。
5.4 Portal 兜底
能用语义正确的 slot 就不用 fixed portal。全应用浮层优先注册 shell.overlay(list/root,click-through 直到你的 entry 主动开启 pointer events);确无全局角落 slot 时才 body portal:
- React root、host DOM、window listener、全局 attribute 都有 disposer。
- 跟随 session list,按当前 owner 过滤;导航时立即收起。
- 宽屏可让主列礼让,窄屏退回 overlay;只依赖稳定
data-*,不要耦合哈希 class。 - 首屏恢复的已有活动只显示徽标,避免首次请求返回后自动展开造成大幅布局位移;稳定后出现的新活动再自动展开。
- 面板限制为容器/视口的一部分高度,内容区内部滚动;窄屏单独设上限。
- 轮询使用
no-store、in-flight guard、响应形状校验和 unmount 防护;失败保留最后成功快照。 - 支持键盘、
:focus-visible、aria-*、Escape、reduced motion;hover/focus 只预览,click 才固定状态。
6. TypeScript 与 Client 构建
6.1 双 tsc program
Host 和 client 使用两个 program;文件名可按项目布局选择,官方仓库用 tsconfig.host.json 与 tsconfig.client.json 两个聚合 program 分别做 host/client 检查:host 排除 packages/client/*/src/** 与 *.client.* 测试;client 聚合含各 client 包的 CSS module 声明、client 测试与构建脚本,共享 leaf 经 project references 进入,每个 packages/client/* 包还各自维护一个 composite tsconfig 做包内类型检查。JSX 使用 .tsx 和 react-jsx;相对 TS import 必须能正确重写为 emitted JS。
这样避免 host session 与 browser runtime 对同名 Context service 的 declaration merge 冲突。
6.2 Client bundle
优先复用当前正式版 Harness 的 client tsdown helper或已验证模板,不手写 loader 协议。产物应由构建自动包装为:
window.__ModuleLoader__.load({ id, factory: (require) => { /* bundle */ } })
构建必须保留:
- host/client 两半产物并存(client build 不清空 host 输出);
- sourcemap;
- CSS Modules 编译与
style[data-plugin]注入; - 从 emitted
lib/找回src/资源的路径回退; - client bundle purity gate。
6.3 Client import 纯度
浏览器模块表只回答正式版平台 seed 模块和明确豁免。规则:
- 平台模块以正式版
packages/client/web/src/platform.ts和官方 client 构建配置为准;React、Cordis、slots、web-react、primitives、attachment、schema-form 等由模块表提供。 @deepseek-ai/dsh-client-runtime/client是官方构建配置中明确标注的临时豁免,不是普通平台模块;不要把它泛化为可任意导入 runtime 值的许可。- 纯类型 import 会被擦除,可以跨包拉入类型贡献。
- wire types、生成 remote codec 或明确 vendored 的纯库只有在官方模板允许时才 inline。
- 其他跨插件值 import 禁止;协作必须走 Cordis service/remote/slot。否则构建期纯度门或运行时 require 都会失败。
7. 分发、安装与生效边界
7.1 安装
dsh plugin --profile <name> <args...> 是 profile 目录里的 pnpm 转发层,成功后按安装状态和 dsh.bundle 对账 bundle 列表。因此支持 npm、路径、tarball 和 Git:
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:<owner>/<repo>
GitHub 分发不要求发布 npm,但必须选择一种构建策略(Git 获取的是源码,不是构建产物):
- 官方主推:提供自包含
prepare(官方 turtle-ui 模式);pnpm ≥10 默认拦截 Git 依赖的构建脚本,用户需在 profile 的pnpm-workspace.yaml显式allowBuilds后重跑add。这会执行第三方代码,应固定 commit 并只信任已审查仓库。 - 备选(无交互安装):把 exports 指向的完整、最新
lib/提交进 Git;用户无需执行依赖脚本,但非官方推荐路径。
README 只给经过全新 profile 验证的推荐命令。安装后重启目标 profile。
7.2 HMR 与重启
- client HMR 需要
tsdown --watch等构建 watcher 持续重写lib/client.js;host HMR 只负责 stat 检测文件变化,再通过 rev/SSE 触发 browser fiber 的 dispose/reload。 - 只有 bundle 内容变化可以 client HMR;package manifest、exports、插件集合、profile bundles 和 host 代码变化需要重启。
- 普通 build 后没有 watcher 时,刷新现有 DSH 页面。
- 不启动独立 Vite server 替代 DSH GUI;Web shell 依赖 host 注入的
window.__DSH_BOOT__。
8. 验证矩阵
8.1 基线
pnpm typecheck
pnpm build
pnpm test # package.json 声明时运行
pnpm verify # package.json 声明时运行
git diff --check
先读取 package.json.scripts,不要假设所有仓库都有同名聚合脚本:官方 Harness 使用 check:ci/check:all 与多个 verify-* gate;第三方插件可自定义 verify。项目级 verify/check 至少覆盖:
- 纯业务规则和状态迁移;
- 临时目录中的文件往返、锁、归档/恢复;
- client 可独立测试的投影/折叠纯函数;
- canonical Skill 与镜像一致性(若项目提供镜像)。
8.2 Host 与真实组合
- 单元测试覆盖 schema、service、失败和 disposer。
- 有 registry/backend 接口时使用共享 contract suite。
- 不只手搓
ctx.plugin():至少一个测试通过真实 Loader/patch 组合启动,断言用户可见表面。 - 先用
dsh plugin --profile <scratch> add <pkg>创建非内置 scratch profile,再执行dsh --profile <scratch> --dump-config,确认 bundle 层、行 id、name、config 和注入顺序;内置web/headlessprofile 可由 launcher 初始化。另有--dump-default-config:只打印 bundle 层、跳过用户层与--patch,可作坏cordis.patch.yml时的恢复诊断。 - 真实任务使用
dsh --profile headless "一个小而可判定的任务";不要发明dsh run子命令。
8.3 Client
- client 测试使用 jsdom lane;通过 SlotTestRuntime 或最小 fake services mount 插件。
- 断言 slot 注册、渲染、session 隔离、connection reset、dispose 后 registry/DOM/style/controller 均清理。
- 每个 registry 贡献至少有一个 HMR/dispose 安全测试。
- GUI 使用独立 web profile 和真实浏览器,验证名册、路由、交互、刷新、宽窄屏、滚动、焦点和 reduced motion。
8.4 从零安装与 Git 分发
- 使用全新临时
DSH_HOME/profile。 - 按 README 的精确命令安装。
- 断言 profile dependency 与
dsh.profile.bundles。 - 断言所有 exports、host/client bundle、patch 和静态资源存在。
--dump-config必须出现插件层。- 启动后检查 host route、client roster 和真实 UI。
仓库仍私有时,可把待发布内容复制到临时 Git repo 并提交,再通过 git+file://... 安装;这能验证“Git 获取的内容”而不是当前 checkout 的未提交文件。前提:git 在 PATH、目录是已提交的真实 Git 仓库;若包声明了 prepare,还需在 profile 的 pnpm-workspace.yaml 加 allowBuilds(与 §7.1 相同门禁)。只删除本任务创建的精确临时目录。
9. 完成标准
完成前逐项确认:
- 运行面最小,manifest、exports、patch 与产物一致。
- 必需 inject 和可选 service 边界清楚;pending/failed 状态可诊断。
- route、registry、timer、watcher、DOM、React root 和存储均可清理。
- Conversation Node 可确定性重放,owner 与去重维度正确。
- client import 未越过模块表,host/client 类型隔离。
- 持久化有并发与崩溃语义,不依赖偶然 cwd。
- typecheck、build、verify、真实组合、从零安装和需要的 GUI 验证通过。
- README 安装命令与实际分发形态一致。
- 未执行未经授权的 commit、push、发布或 visibility 变更。
Operate deliberately
Install and manage
Prerequisites and target Profile
Target: No native DSH Profile target.
Delivery: Skill Files — https://github.com/nanmicoder/dsh-agent-teams。
Compatibility and access
Requires_host_review: Not established by supplied evidence。
Review compatibility evidence ↗
Risk facts
Review instructions before use.
Evidence ↗Evidence and editorial reviewManifest, Bundle patch, distribution and freshness
Immutable evidence
Review status and source activity
Approved for publication after reviewing the source-linked content and immutable release record. AI assisted with the draft; the publication decision was human.
Human reviewed Aug 30, 2026, 10:07 AM UTC。GitHub facts last checked Aug 30, 2026, 9:19 AM UTC。
No material source change has been recorded since this evidence baseline.