[English](README.md) | 中文 # dsh-custom-instructions(自定义指令) 给 Agent 的长期指令,对所有工作区生效:在 DeepSeek Harness **自己的设置面板**里新增一个 「自定义指令」页面,页面里的文本会加入该 profile 下每个会话的系统提示词。 它就是 DSH 版的 Codex 自定义指令 —— 一处写下「始终用中文回答」「优先用 pnpm」 「未经说明不要改写我的文件」;区别在于文本进入的是每次组装出来的系统提示词,而不是某个 项目里的文件,所以它对所有工作区、所有新会话、以及子代理都生效,不需要逐个项目配置。 ## 安装 ```sh dsh plugin add dsh-custom-instructions ``` 然后刷新 Web 界面,进入 **设置 → 自定义指令**。 通过插件管理器安装(设置 → 插件,或插件市场)是**热生效**的,不用重启宿主,只需刷新浏览器 即可看到新页面。如果是手工把包写进 profile 的 `dsh.profile.bundles`,则必须**先完全退出 DSH**, 因为 bundle 与 patch 层只在启动时合成。 ## 使用 | 控件 | 作用 | | --- | --- | | **启用自定义指令** | 总开关。关闭后仍保留文本,只是不再注入。 | | **用标题引出这段文本** | 默认开启。标题(`User custom instructions`)让模型知道这段要求来自你;如果文本本身就是完整的提示词片段,可以关闭。 | | **指令内容** | 文本本身。留空则不注入,所以「全选删除再保存」也是一种真正的关闭方式。 | 保存后,Agent 下一次组装请求时即生效;正在进行的会话会在下一轮拿到新内容。 页面显示的是**实际状态**,而不只是开关:会注入时显示「已生效」,开关关闭显示「已停用」, 文本框为空显示「未生效」。 ## 值存在哪里 这三个字段是 *volatile* 配置字段,因此写入会走 DSH 的设置文档,持久化在该 profile 的 patch 文件里(位于 DSH 主目录下)—— 一份文档被该 profile 的所有工作区共用。 不会向任何项目目录写入内容,也不会创建或修改项目级文件。 ## 它如何进入模型 插件只注册一个 `systemPrompt` 段落: | 属性 | 取值 | 原因 | | --- | --- | --- | | `name` | `custom-instructions` | 全局只注册一次,不会被任何 scope 遮蔽。 | | `order` | `100` | 紧跟部署人设前缀(`0`),位于所有策略与工具段落(`500` 起)之前:长期指令属于「Agent 是谁」,而不是工具说明旁边的补充。 | | `interpolate` | `false` | 提示词是普通散文,完全可能包含 `{{` 和 `}}`;否则assembler 的严格变量语法会替换它或直接报错。文本按字面处理。 | | `text` | 每次组装时解析 | 设置写入后,下一次组装的提示词即可见,无需重启。 | assembler 会丢弃空段落,这正是「关掉开关」和「清空文本框」能让内容从请求中消失、 而不是留下一个孤立标题的原因。 ## 配置 可以在上面的页面里编辑;也可以直接写在 profile 的 patch 文件里 (`~/.dsh/profiles//cordis.patch.yml`): ```yaml - id: dsh-custom-instructions name: dsh-custom-instructions config: enabled: true wrapHeading: true instructions: |- 始终用中文回答。 优先使用 pnpm 而不是 npm。 ``` | 字段 | 类型 | 默认值 | 含义 | | --- | --- | --- | --- | | `enabled` | boolean | `true` | 是否注入任何内容。 | | `wrapHeading` | boolean | `true` | 是否用标题引出文本。 | | `instructions` | string | `""` | 指令内容,纯空白等同于空。 | ## 环境要求 - DSH `>=0.1.0-rc.7 <0.3.0-0`(设置表单、`settings.section` 页面插槽、提示词段落注册表)。 上界是刻意的:后续小版本可能改动本插件所依赖的规则,安装被明确拒绝比运行中出问题更容易理解。 - Web 界面:该页面是浏览器端插件。宿主部分在没有设置界面的组合里同样会注册段落, 所以文本照常生效,只是没有地方编辑它。 ## 开发 ```sh npm run link:peers # 把受限的 peer 指向正在运行的 profile 中的副本 npm test # 决定「什么内容会到达模型」的规则 npm run check # 两侧语法检查 + 测试 npm run release:check # 市场收录前的机械自检(含 YAML 与 BOM 两类静默陷阱) ``` `lib/config.js` 保存了关于注入文本的全部规则,并被直接测试;`lib/index.js` 是 schema 加一次注册;`client/client.js` 是预构建的浏览器 bundle(相对平台模块表写的纯 JavaScript, 无需构建步骤)。 有两个检查之所以存在,是因为它们对应的是**静默失败**而不是报错:`scripts/release-check.mjs` 会拒绝一份 YAML 解析器会一声不响丢掉的 bundle patch(多了一个 tab,或 `config:` 的子键写成了 同级键);`scripts/verify-bundle-resolves.mjs` 则证明列表里的包在 profile 下**确实能解析并 import**——「名字在列表里」和「包能加载」是两件事,而栽在后者上的启动失败看起来就是什么都没发生。 `test/plugin.test.js` 交给插件的是一份 Cordis 风格的 Context:读任何未声明的属性都会抛错。 这不是花架子:把实时配置读成 `ctx.config` 会在插件加载期抛错,而 DSH 的启动是 all-or-nothing, 所以插件只能读自己的配置参数,别的都不能碰。 ## 许可证 MIT