
DeepSeek Harness 插件开发简易指南一、先理解架构DSH Cordis 插件系统 补丁式组合DSH 不是单体应用而是构建在Cordis 插件框架deepseek-ai/cordisKoishi 系之上的分层插件树。概念说明Profile$DSH_HOME/profiles/name/我的是C:\Users\AIcncc\.dsh\profiles\web。含package.json声明dsh.profile.bundles有序组合包列表 用户自己的cordis.patch.yml组合包bundle声明了dsh: { bundle: { patch: ./cordis.patch.yml } }的 npm 包。dsh-base、dsh-web-app都是 bundle补丁分层空条目根cordis.yml→ 各 bundle 的 patch按序→ profile 级cordis.patch.yml→ home 级~/.dsh/cordis.patch.yml→--patchoverlay。后层按id覆盖前层整段configinsert添加新行支持!!js表达式插件行每个插件是一行{ id, name, config?, disabled? }。name是模块说明符config由插件自己的Configschemastery校验安装dsh plugin --profile web add pkg把 pnpm 参数原样转发到 profile 目录把包装进 profile 的依赖激活Loader 并发挂载条目服务可用性驱动激活inject声明依赖先有提供方后激活消费方工具目录中几乎所有可见能力run_code、pwsh、todo_write、subagent、workflow…都是一个插件包例如dsh-tool-todo、dsh-tool-pwsh——这就是你插件的参照物。二、插件的标准形态源码确认的约定第一方插件使用命名空间导出无默认导出docs/postmortem/0001规定默认导出会丢失inject// lib/index.ts —— 一个最小但完整的工具插件importzfromdeepseek-ai/schemasteryimport{defineTool}fromdeepseek-ai/dsh-toolsexportconstnamemy-tool// 插件名kebab-case全局唯一exportconstinject[tools]// 声明注入的服务键Loader 据此排序exportconstConfigz.object({// schemastery 配置 schema可留空对象greeting:z.string().default(Hello from my plugin),})exportfunctionapply(ctx:Context,config:ConfigType){ctx.tools.register(defineTool({name:my_hello,// 模型可见的工具名snake_casedescription:Say hello. Returns a friendly greeting.,parameters:{name:{type:string,required:true,description:Who to greet},loud:{type:boolean,description:Uppercase the greeting},},output:{schema:{type:string},render:(_args,value)[{type:text,text:value}],},asyncexecute(args,exec){// exec.signal 必填且只读——必须观测/转发取消信号constmsg${config.greeting},${args.name}!returnargs.loud?msg.toUpperCase():msg},}))}三条硬性规范注册表强制校验output: { schema, render }必填——没有输出声明注册直接失败execute只能返回输出 schema 声明的无损 JSON通过exec.signal协作停止Config、name、inject、apply四个导出缺一不可Config可省但专业插件应带配置。三、五类插件按你的需求选型类型注入/API用途工具插件最常见ctx.tools.register()schema 自动流入系统提示词给模型新增能力读文件、查库、调 API…服务插件ctx.provide(myService, impl) 消费方ctx.inject([myService])在工具/其他插件之间共享状态如dsh-session、dsh-jobs-localSkill 插件ctx.skills.register(...)或dsh-skill-filesystem目录给 agent 注入指令/方法论比工具轻量不进工具列表客户端 UI 插件dsh-client-*系列ctx.slots.registerReact自定义 Web 界面会话卡片、设置页、工具调用展示Host 插件ctx.get(webserver)/apiproxy/frontend-static起服务、挂路由、托管静态资源组合包 bundle包内cordis.patch.yml把一组插件配置打包成可复用发行单元工具自带 UI 呈现用presentCall/presentResult返回 card 意图generic/terminal/read/diff/search/webUI 无需按工具名写特例。四、标准开发流程六步1. 初始化工程mkdirdsh-my-plugincddsh-my-pluginnpminit-ynpmi-Dtypescript tsup deepseek-ai/cordis deepseek-ai/dsh-tools deepseek-ai/schemastery# package.json: type: module, main: lib/index.js, types: lib/index.d.ts2. 写插件见上文模板3. 构建tsup lib/index.ts--formatesm--dts--out-dir lib4. 本地安装到 profile两种方式# 方式 A发布后安装dsh plugin--profilewebadddsh-my-plugin# 方式 B本地开发推荐file: 引用即改即用cd~/.dsh/profiles/webpnpmaddD:\path\to\dsh-my-plugin5. 注册进加载树——编辑~/.dsh/profiles/web/cordis.patch.yml# 当前你的文件是 []改成-insert:-id:my-pluginname:dsh-my-pluginconfig:greeting:你好要点id是 patch 寻址键后续可用- id: my-pluginconfig:覆盖name必须是 profile 依赖里真实存在的模块说明符。文件热重载watchUserPatches改了立即生效无需重启——但首次安装包后需要重启dsh web。6. 验证dsh web --dump-config# 离线合成配置树确认你的行已合入# 或进入会话后让模型执行 cordis_inspect自省工具列出全部已注册工具/服务/插件 fiber五、专业标准完整插件清单对标dsh-tool-todo/dsh-tool-pwsh源码里第一方工具普遍具备以下工程素养照做即是专业标准名称纪律包名dsh-*第三方常dsh-*或dsh-plugin-*插件namekebab-case 唯一工具名 snake_case 且描述首句就是完整指令模型看到的第一句决定它会不会用。Config 带默认值 部署语义z.object({ allowParallel: z.boolean().default(true) })——配置是部署者政策不是插件内部细节配置变更记录进描述如 todo 的并行策略会改写工具描述。类型化参数与严格 schemadefineTool参数用ParameterSchemaSpecadditionalProperties: false封闭对象让模型写错即失败INVALID_ARGS而不是静默吞掉。规范化输出契约输出{ schema, render, presentationMeta? }值机器消费与呈现模型消费分离render是纯函数UI 流式回放时会反复调用。错误即结果可预期的失败返回{ isError: true, error: { message, info } }而不是抛异常基础设施失败才抛HarnessError带name/code。协作取消execute(args, exec)必读exec.signal把signal透传给底层readFile(path, { signal })、fetch(url, { signal })绝不在已启动的 Promise 未结算时提前返回。并发安全声明可并发的工具实现isConcurrencySafe(args)返回 true共享状态竞态必须可交换否则拒绝。状态写入会话日志而非内存持久状态用exec.agent.session.append(my/write, data)事件溯源重放/UI 都从事件渲染todo 的todos投影就是这么做的。文档与双语文案README.mdREADME.zh.md含配置表、公开 API、扩展点、模型体验、KV Cache 影响、已知限制。测试与门禁schema 验证、执行器单测、verify门禁如verify-cordis-catalog防止契约漂移。六、调试与快速原型三板斧动态插件零安装验证会话里让模型执行cordis_define提交 host 半 可选浏览器半→cordis_run沙箱求值 →cordis_stop/cordis_undefine。原型验证用这个正式落地再走上面六步。注意动态包不跨重启、不写文件、不会自动变成正式插件。配置排障dsh web --dump-config看最终组合树--dump-default-config看 bundle 层不含你的 patch。HMR改cordis.patch.yml秒级生效改插件源码需重新 build 依赖引用为file:时自动跟随。七、安全边界必须知道否则插件不合格沙箱文件操作经dsh-fs-sandbox当前workspace-write命令经dsh-bash-sandbox/dsh-pwsh-sandbox。插件不能绕过只能走sandbox_permissions升级通道需用户批准。审批 seamctx.get(approval)ask/deny/allow未部署时ask退化为拒绝——插件必须把拒绝当正常路径处理。作用域普通上下文注册 全局agent.ctx注册 仅该 agent 并遮蔽同名全局。ctx.tools.restrict()是可见性组合不是权限边界。内容替换不是保密边界编程消费方不能收到的值要阻止或替换post-execute不能指望 finalizeContent 兜底。八、实践路径如果你的环境已就绪dshCLI、web profile、cordis_inspect自省工具都在。最省事的上手路线用cordis_define/cordis_run在会话里验证一个 30 行的工具原型比如读 Excel 并统计原型通过后按第四节的六步把它工程化成一个dsh-namenpm 包file:依赖挂进~/.dsh/profiles/web在cordis.patch.yml插入一行即可被当前 Web 会话加载。