工作台开发规范
版本:2026-10-08 · 以官网版本为准,DSH Desktop 内附文档副本供离线取用。
官方地址:https://dshdesktop.com/workbench/docs/development/
Markdown 原文(供 Agent 读取):https://dshdesktop.com/workbench/docs/development.md
六步速览:https://dshdesktop.com/workbench/docs/quickstart/ (Markdown 原文)。
本文是开发工作台时由 AI 直接执行的规范。只在本地开发、自己使用时,满足本文即可:按第 3 节写好包,装到本机 DSH Desktop,按第 8 节自测通过,就可以正常使用,不需要公开代码,也不需要上传到任何地方。
如果之后想把工作台上架到工作台市场,再阅读《工作台市场验收规范》:https://dshdesktop.com/workbench/docs/market-acceptance/ 。仓库公开、发布、简介、截图和收录 PR 的要求都在那一份里,本文不涉及。
工作台是一种 DSH 插件。它首先必须是一个合格的 DSH 插件包,能被 dsh plugin add 安装、被 Harness 加载;在此基础上,再向 Desktop 注册业务面板,并遵守工作台与会话、工作区的交互规则。
规则分三级:必须(不满足就不能安装或加载)、建议(强烈推荐,不满足会影响体验或以后上架)、可选。
1. 执行原则
需求确认闸门(先于写代码):先确认用户要开发的工作台的业务场景、目标用户和最小核心流程。复制 Desktop 的通用“开发指令”、打开了某个目录、目录里已有项目或依赖,均不能替代用户对本次开发目标的说明;不要仅凭目录名或现有代码替用户选定产品方向。若本次请求和用户已确认的上下文仍不足以明确这三项,用一个合并问题询问,例如:“这个工作台要服务谁、解决什么业务场景?用户从进入到完成任务的核心步骤是什么?”等待用户答复,停在需求确认阶段;此前可以只读检查目录、版本、脚本和宿主能力,不得创建或修改业务代码、界面,不得运行构建、打包、安装或提交投稿。空目录不能被当作已确认需求;代理收到通用开发指令后直接开工属于执行失误。
需求明确后,从项目读取名称、作者、版本、说明和测试命令,只询问无法查明且会影响实现的必要信息。开发请求本身不代表授权公开代码、商业数据或凭证。
开发前必须检查:
- 确认项目根目录、已有代码、未提交修改、包管理器、脚本和目标 Desktop 版本;不要覆盖别人的修改。
- 确认目标平台与架构,区分 JS/TS 包、外部程序和原生依赖。缺少宿主或工具链时明确说明,不能只凭构建通过就说能运行。
一页执行流程
- 确认需求:从用户本次请求及已确认的上下文记录业务场景、目标用户、用户完成一次任务的核心流程。通用开发指令或项目目录本身不算确认;三项不明确时执行上述闸门,等待答复。
- 检查项目:确定项目根目录,运行
pwd、git status --short(若是 Git 仓库),查看已有代码、包管理器、未提交改动和目标 Desktop 版本;保留无关改动。 - 确定最小业务流程与布局:写下入口、主要动作、完成状态及失败恢复;按第 4 节明确选择标准分栏或
customFrame、首次无会话时的入口,再决定所需宿主能力。 - 实现:按第 3 节建立插件包和注册;第 4–7 节按责任及实际使用的能力落实。
- 包校验:运行
pnpm pack,检查 tarball 内package.json、声明的入口和cordis.patch.yml,检查大小和敏感文件。 - 本机安装实测:按 3.6 探测当前 Desktop 的安装能力、安装该 tarball、完成所需重启,并按第 8 节记录真实 UI 与加载证据。在目标 DSH Desktop 内开发时,按下方“同机重启边界”交给用户手动重启。
同机重启边界:如果 Agent 正运行在需要重启的这台 DSH Desktop 会话内,安装后不要自行关闭、重启 DSH Desktop 或 Harness,也不要用 ps、pgrep 等进程探测来尝试管理这次重启。告知用户完整退出并重新打开 DSH Desktop;在用户回来确认已重开后,才继续检查插件加载、已安装列表、左侧入口和真实界面。此前将这些重启后的验收项标为待验证,不能宣称已通过。运行在目标应用之外的开发 Agent 可按正常重启流程操作。
空目录演练:若目录为空、用户只粘贴 Desktop 的“开发指令”或只说“做个工作台”,此时第 1 步尚未通过。Agent 应先提出合并问题:“这个工作台要服务谁、解决什么业务场景?用户从进入到完成任务的核心步骤是什么?”可以运行 pwd、查看目录及 Desktop 能力;在用户答复前,流程停在第 1 步,不创建 package.json、组件或业务页面,也不构建、安装或投稿。
2. 工作台是什么
一个工作台包同时是:
- 一个 npm 包:有
name、version,可以从本地目录或.tgz文件安装,上架后也可以从 npm 或 GitHub 安装。 - 一个 DSH 插件(bundle):
package.json声明dsh.bundle.patch,由cordis.patch.yml把服务端入口插入 Harness 的插件树。 - 一个 Desktop 工作台:客户端通过
desktopWorkbenches.register()注册业务面板。Desktop 从repository、安装记录和市场分发映射解析仓库身份。
同一个工作台有三个标识,职责不同,不能混用:
| 标识 | 在哪里 | 用途 |
|---|---|---|
| npm 包名 | package.json 的 name | 安装、依赖解析、cordis.patch.yml 的 name: |
| 插件条目 id | cordis.patch.yml 中 insert 行的 id | Harness 插件树中定位这一行 |
| 工作台身份 | 规范的 GitHub repository URL、市场条目 id | 小写 owner/repository;市场卡片、侧栏入口和会话归属共用 |
| 兼容用旧 ID | 老包 register({ id })、旧目录 workbenchId | 仅迁移旧数据时使用;新包和新投稿都不填写 |
Desktop 将 GitHub owner 和 repo 规范化为小写,例如 https://github.com/Owner/Repo 对应 owner/repo。仓库改名或转移会改变工作台身份,需按迁移规则处理原有会话,不能仅改 URL。旧版 wb-owner-repo 只作为兼容映射,不是新包的注册 ID。
3. 包格式
3.1 目录结构
一个包只放一个工作台。典型结构:
package.json # npm 与 DSH 插件声明
cordis.patch.yml # 把服务端入口插入插件树
dsh/index.js # 服务端入口(exports["."])
lib/client.js # 已构建的客户端入口(exports["./client"])
README.md LICENSE
3.2 package.json
| 字段 | 级别 | 要求 |
|---|---|---|
name、version | 必须 | 普通 npm 字段,version 为完整 SemVer(如 1.2.0) |
"type": "module" | 建议 | 所有官方示例都使用 ES 模块 |
main 与 exports["."] | 必须 | 指向服务端入口,cordis.patch.yml 导入的就是它 |
dsh.bundle.patch | 必须 | 例如 "dsh": { "bundle": { "patch": "./cordis.patch.yml" } },路径相对包根目录。没有它,包只会被当作普通依赖安装,不会激活任何插件层 |
dsh.client.platform | 必须 | 固定为 "web",否则客户端模块不会被加载 |
dsh.client.inject | 必须 | 字符串数组,必须包含 dsh-desktop-workbenches,保证工作台服务先于你的客户端加载;用到其他客户端包时一并列出。这里只决定加载顺序,不是 Cordis 服务注入 |
exports["./client"] | 必须 | 声明了 dsh.client 就必须导出已构建的客户端文件,否则启动时报错 |
dsh.client.external | 可选 | 客户端需要 require 共享基线以外的模块(包括子路径)时列出;不能列自己 |
exports["./package.json"]、exports["./cordis.patch.yml"] | 建议 | 与官方包保持一致 |
files | 建议 | 必须把 cordis.patch.yml、服务端入口和构建产物包含进去 |
peerDependencies | 建议 | 官方 @deepseek-ai/* 包(如 @deepseek-ai/cordis、@deepseek-ai/dsh-client-connection)写在 peerDependencies,不要写在 dependencies,避免装进第二份宿主代码。版本范围要显式包含预发布分支,例如 ">=0.1.5-rc.2 <0.2.0-0",否则预发布版的 Harness 会被排除,安装时报 ERESOLVE |
@deepseek-ai/schemastery | 建议 | 服务端 Config 使用它定义;它是运行时依赖 |
license、author、description | 建议 | 真实填写 |
不要依赖未文档化的 dsh 字段(例如 dsh.client.inline),它们会被静默忽略。
3.3 cordis.patch.yml
文件是一个 YAML 数组。工作台通常只需要一条 insert:
- insert:
- id: my-workbench # 插件条目 id
name: my-workbench-package # 必须写 npm 包名,Node 才能解析到安装的代码
config:
root: !!js dshHomePath('my-workbench') # 可选:业务数据目录
- 必须:
name写包名,不写相对路径或绝对路径。 - 空文件或只有注释的文件会导致启动失败;不需要任何行时写
[]。 !!js表达式在启动时求值,可用dshHomePath()得到 DSH 数据目录下的路径。- 覆盖已有条目时,patch 会整体替换该行的
config,不会合并,需要保留的键要全部写上。工作台不应覆盖 Desktop 或其他插件的条目。
3.4 服务端入口
import Schema from '@deepseek-ai/schemastery'
export const name = 'my-workbench'
export const inject = ['connection']
export const Config = Schema.object({ root: Schema.string().required() })
export function apply(ctx, config) {
// 注册本工作台自己的本机接口,例如 /api/my-workbench/...
}
Config必须是 Schemastery schema,不能直接导出普通对象。- 本机接口放在自己的路径前缀下(如
/api/<工作台 id>/),不能占用 Desktop 或其他插件的路径。 - 需要判断会话归属时,注入内部只读服务
desktopWorkbenchOwnership并调用await read();不要从可见面板、旧预设或私有设置推断归属。 - 业务数据写在配置的数据目录或作者文档说明的位置;卸载工作台时不得删除用户数据。
3.5 客户端入口
客户端文件必须是已构建好的单文件模块,通过模块加载器注册:
window.__ModuleLoader__.load({
id: 'my-workbench-package',
factory: (require) => {
const React = require('react')
function BusinessPanel({ service, entry }) { /* 业务面板 */ }
function apply(ctx) {
ctx.effect(() => ctx.desktopWorkbenches.register({
title: '我的工作台',
repository: 'https://github.com/owner/repository',
description: '说明它解决什么问题'
}, BusinessPanel))
}
return { apply, inject: ['desktopWorkbenches'] }
}
})
require只能拿到共享基线(React、Cordis 等)、已加载的插件和dsh.client.external中列出的模块。其他依赖要在构建时打进客户端文件。register()必须提供title、业务组件和规范的 GitHubrepositoryURL。新包不要填写register({ id });Desktop 用repository解析owner/repo,并用调用方客户端包、市场分发或安装记录交叉核对,来源冲突时不会暴露 provider。旧包的id仅用于迁移,不是新协议。workbench.json和投稿 YAML 的workbenchId不是新工作台的必填协议;运行时包名必须与window.__ModuleLoader__.load({ id })对应。- 可选注册字段:
description、panelTitle、icon、audience、requirements、layout(businessSide为left或right,businessWidth在 0.25–0.7 之间)、customFrame(布尔值,见第 4 节)、initialization。 - 注册返回的函数用于注销,要交给
ctx.effect管理。
3.6 构建与本地安装
- 客户端文件必须是构建好的单文件,Desktop 不会替你构建。
- 先探测能力,不猜版本号:记录 Desktop “关于”中的版本、平台和架构;在“工作台管理/已安装的工作台”查找本地安装入口,再核对当前版本随附的插件安装界面或
dsh plugin add --help是否接受本地.tgz。只有界面或命令明确支持该输入时才安装;不能从官网文档的发布日期推断当前安装版本支持。记录采用的入口与输出。 - 用已确认支持的入口安装
pnpm pack得到的.tgz。CLI 路径按其--help显示的语法执行;安装后按界面提示完成重启,回到“已安装的工作台”确认条目,再从左侧入口实际打开并检查业务面板。如果 Agent 正在目标 DSH Desktop 内运行,必须遵守第 1 节“同机重启边界”,由用户完整退出并重新打开应用。dsh --profile web --dump-config出现插件层只能证明配置,不能替代 UI 加载证据。 - 当前 Desktop 无本地包安装入口、CLI 不支持或安装失败时,交付已校验的
.tgz与包内容/校验记录,写明 Desktop 版本、探测结果和失败原因;将“安装、重启后加载、已安装列表、左侧入口、业务操作”逐项列为未实测,不能宣称本机验收通过。 - 需要运行安装或构建脚本时(pnpm 10 默认阻止),要明确知道每个脚本做什么,再单独授权。
4. 界面边界
工作台是一种面向具体工作场景的插件。本规范约束工作台、会话、工作区的关联关系和切换行为,不规定统一的业务面板设计。
工作台作者或用户可以定义业务面板的布局、内容、工具栏和业务操作。接入已有工作台时,优先复用原有界面和业务绑定流程,不要求加入统一顶部工具栏、会话下拉框、业务区折叠按钮或“通用聊天”按钮。
4.1 先按主任务选择布局
- 标准分栏:默认左侧是宿主原生会话,右侧是业务面板,占主内容区的 36%。可在
register()的layout中指定businessSide: 'left' | 'right'和businessWidth: 0.25–0.7;这是业务区所占比例,不保证业务组件的每一列都有足够空间。它适合状态、工具、资料等紧凑的会话伴随面板。首次没有当前会话时,宿主会在会话区域显示通用的“开始使用”引导;业务面板仍须可用,并检查两侧内容是否形成合理的首次使用流程。不要仅靠调大businessWidth把报表塞进分栏,导致另一侧引导或会话被挤压。 customFrame: true:当阅读报表、操作看板或宽表格本身是主任务时,可让工作台编排整个宿主主内容区。需要原生会话时,把宿主传入的conversation节点放到合适的位置,不自行复制聊天界面。此模式不显示标准分栏的宿主通用无会话引导;工作台需自行提供首次进入、无会话以及会话相关操作的入口,明确何时创建或恢复工作台会话。若业务主要是伴随对话的小工具,仍可选择标准分栏,不要求所有工作台改为整页。
无论选择哪种布局,都要按业务内容容器的实际宽度设计响应式布局;整窗媒体查询不能代表侧栏展开、分栏及嵌入后的可用宽度。可用容器查询或测量业务根容器,在空间不足时让多列内容重新排布、折叠次要信息或允许有界滚动;长中文标题、英文标识、数字和操作按钮均应保持可读可用,避免单字竖排、按钮裁切和整页横向溢出。
市场、工作台切换和设置等公共入口由 DSH 保留,业务面板不得遮挡。使用 customFrame(见 3.5)的工作台必须限制在宿主分配的主内容区域内:根容器应按正常 flex 布局填满该区域;内部使用绝对定位、窗口最大化或拖拽换位时,都不得越过宿主容器的定位与裁剪边界,也不得覆盖 Desktop 左侧会话栏。原生会话由宿主提供的 conversation 节点放进业务布局,不能再创建一套聊天界面。原生会话能力与模式切换沿用 Desktop 的规则。
macOS 收起侧边栏后,窗口按钮与侧边栏展开按钮占用主内容区左上角。宿主会给左侧嵌入式业务面板和 customFrame 的根节点内、作为首个子元素的语义 <header> 预留 --dsh-frame-leading-clearance 宽度;工具栏可留在原来的 48px 顶部行,主体无需整体下移。自定义工具栏若不是这个结构,应在自身样式中使用同一变量避让,不要覆盖窗口按钮或 shell.leading。
5. 工作台、会话与工作区
- 一个工作台可以关联多个会话,每个会话最多归属一个工作台。
- 工作区是 DSH Desktop 的项目资料环境;每个会话如绑定工作区,最多绑定一个工作区。同一工作区内的不同会话可以属于不同工作台。
- 一个工作台可以处理多个工作区,不同工作台也可以使用同一个工作区。
- 工作台内部的档案、业务项目不等同于 DSH 工作区,不要求重复绑定。例如,玄学档案和选址项目继续使用各自原有的创建、选择流程。DSH 工作区目录是用户资料位置,不因打开或创建业务项目而自动归属某个工作台。
6. 未绑定会话时的使用
打开工作台后,即使没有会话或工作区,也应立即显示业务面板。浏览、创建、选择业务档案或项目,不得以已有原生会话或工作区为前提。
仅当用户执行向 Agent 发起请求、写入会话草稿等依赖会话的操作时,才检查当前会话是否属于该工作台。尚未绑定时,在该操作处引导创建或打开会话,不阻断其他业务功能。
工作台内部应提供“在此工作区新建工作台会话”或“选择资料位置并开始工作台会话”等明确动作。业务项目本身不需要文件系统时可以先创建业务记录;一旦需要保存文件或创建 DSH 工作区,必须先调用宿主目录选择器,由用户选择已有目录或在系统选择器中明确新建目录。工作台不得在默认位置、用户主目录、当前仓库或其他推测路径中静默创建文件夹。确认位置后再创建工作区和会话、登记归属、保存业务关联并填入开场草稿;取消时不得留下目录、空项目、工作区、会话或绑定。已有业务资料只能恢复用户此前确认的位置;位置不存在时重新选择,不得自动创建同名目录。失败时保留可重试状态,不得默默改用无关工作区。
先选择业务档案或项目,再创建第一条会话时,应保留当前业务选择。打开已有会话时,优先恢复该会话已有的业务映射,不被其他会话最近选择覆盖。
接入已有工作台时保留原有的项目创建引导和独立业务流程。用户无需先手工新建会话;工作台通过 Desktop 接口发起创建或恢复,由宿主校验并登记归属。开场草稿保留用户已输入的内容并由用户发送;创建失败或延迟时保留草稿供重试。自动执行的业务流程必须在正确归属的会话中运行,不能与开场草稿混用,也不能由隐藏工作台触发误发送。
7. 模式入口与切换
宿主在侧栏顶部提供单一模式切换器:按钮只显示当前模式,展开后可在“原生会话”和已添加工作台之间切换;“工作台管理”入口常驻最右侧。工作台不得复制、遮挡或替换这些公共入口。切换模式只改变前台展示和会话筛选,不执行卸载重装,也不停止后台任务。
“原生会话”和各工作台是平行模式,当前模式决定可见会话和新建归属:
- 工作台模式:只显示当前工作台的会话。“新建会话”或切换工作区时,只能打开当前 owner 的会话;目标工作区没有时创建新的 owner 会话,并在显示前持久化归属和最近会话。不得复用、收编或改绑普通会话及其他工作台会话。
- 原生会话模式:只显示未绑定会话。“新建会话”或切换工作区时,只能打开未绑定会话;目标工作区没有时创建一条。不得根据同一工作区中的工作台会话推断或切换工作台。
显式打开未绑定会话时切换到“原生会话”;显式打开已绑定且 owner 可用的会话时切换到对应工作台。owner 已移除、卸载或不可用时按普通会话处理,不自动唤起或重装。异步创建期间如果用户继续导航、切换模式或移除 owner,不得把界面拉回旧模式、覆盖后续选择或绑定到失效 owner。
切换模式不得自动收起或展开左侧会话栏;侧栏状态由用户控制并在模式间保持。工作台会话标题前显示所属工作台的小图标,普通会话不显示;图标只表示归属,并提供可访问名称或提示。折叠态与展开态中的按钮、菜单、选中态和焦点轮廓都不得裁切、重叠或溢出。
首次进入工作台可以显示首页、空会话状态或按工作台约定初始化会话,但业务面板不能依赖会话初始化完成。后续进入恢复该工作台最近会话。导航和切换不得删除会话、业务资料、项目文件、收藏或笔记。
8. 本地自测清单
开发完成后按责任逐项确认。“宿主负责”是对当前 Desktop 能力的观察和问题反馈,插件作者不得为此复制宿主界面;标为“仅使用该能力时适用”的项,不使用时记“不适用”及原因。全部适用项有证据通过,才能称为本机自测通过。
包与加载
- 插件负责:第 3 节全部“必须”项通过。运行
pnpm pack,用tar -tzf <产物.tgz>核对package.json、服务端和客户端入口、cordis.patch.yml;从该产物安装,而非只从源码启动。 - 插件负责:按 3.6 安装并完成所需重启;若 Agent 在目标 DSH Desktop 内运行,由用户手动完整退出并重新打开应用,用户确认后再验收。
dsh --profile web --dump-config中找到本包插件层,在 Desktop“工作台管理/已安装的工作台”找到条目,再从左侧入口打开业务面板。分别记录配置、列表和真实界面证据;重启前这些加载与界面项目保持待验证。
第 4 节:界面边界
- 插件负责:打开业务面板,缩放窗口并切换原生会话/工作台,确认面板不遮挡侧栏、市场和管理入口;键盘可到达业务操作。
- 插件负责:分别在首次进入且无工作台会话、打开已关联会话时,检查业务入口与会话相关操作。标准分栏要检查宿主通用引导与业务面板并列时的阅读和操作;
customFrame要检查自己提供的首次使用和无会话入口。 - 插件负责:在侧栏展开、收起及较窄窗口下,用真实长度的中英文标题、标识、数字和按钮检查业务区;不得出现单字竖排、关键控件裁切或整页横向溢出。按业务容器宽度验证多列内容的重排,而非只按整窗宽度判断。
- 仅使用该能力时适用,插件负责:若使用
customFrame,缩窄窗口并操作布局、弹层和拖拽,确认都在宿主主内容区域内;使用原生会话时确认宿主提供的conversation节点可用。
第 5–6 节:工作区与会话
- 仅使用该能力时适用,插件负责:业务流程需要创建文件或工作区时,从业务入口触发宿主目录选择器;取消后核对没有新目录、空项目或绑定,确认后核对文件只在所选位置。原目录丢失时验证重新选择和失败恢复。
- 仅使用该能力时适用,插件负责:业务操作要给 Agent 发送或写会话草稿时,先在无会话状态打开面板,确认非会话功能可用;发起依赖会话的操作时创建/恢复本工作台会话,草稿由用户发送,切换已有会话后恢复其业务选择。
- 宿主负责,插件配合核验:在同一工作区分别创建原生会话和两个工作台会话;从侧栏逐个打开,核对各会话只属于一个 owner,项目资料不因模式切换被搬移。
第 7 节:模式切换与保留
- 宿主负责:用侧栏顶部模式切换器在“原生会话”和各工作台间切换,核对只显示对应会话,工作台图标、管理入口、焦点和折叠状态正确;切换工作区、新建会话后再核对归属。异常时记录 Desktop 版本和复现步骤,不能由插件私自改写宿主状态。
- 宿主负责,插件配合核验:关闭重开、卸载后检查已有会话、项目文件、草稿、笔记和收藏仍在原位置;安装/卸载动作与数据保留分别记录。
- 插件负责:记录 Desktop 版本、操作系统、架构、包版本、执行的 UI 路径及未验证项;无法安装时按第 9 节交付,不能勾选安装后的项目。
9. 失败时如何交付
最终必须列出真实结果和证据:修改的文件、包版本、本机安装与自测结果、未验证的项目。缺哪一项就写哪一项,不虚构成功。缺少工具链、安装失败或宿主接口不可用时,保留已完成的代码,说明原因和下一步。
参考
- DSH 插件打包与发布:deepseek-harness 仓库
docs/user/develop/basic/publish.md、config.md;包清单类型@deepseek-ai/dsh-package-manifest;客户端模块加载@deepseek-ai/dsh-client-modules。 - 上架到工作台市场:《工作台市场验收规范》:https://dshdesktop.com/workbench/docs/market-acceptance/ 。