dsh-novel-solo
"Single-Core Writing" plugin for DeepSeek Harness: Thoroughly tool-streamlined and output-hardened for quantized small models, suitable for running long-novel pipelines locally with on-device models.
Install
dsh plugin --profile web add dsh-novel-solo
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
dsh-novel-solo
DeepSeek Harness 的「单核写作」插件:一个 子 agent 并发数量设置 + 一套完整的小说创作预设(persona)。面向量化小模型做了充分的工具瘦身与输出加固,适合在本机用本地模型跑长篇小说流水线。
特性
- GUI 设置:在插件页提供「子 agent 数量(1-12)」设置卡片(0.1.7 在左侧栏「插件」,0.1.6 在「设置 → 插件」),随插即用,支持中/英双语。
- 完整创作预设:随插件附带
novel-solo预设,内置自驱写作 persona——按固定流水线完成 叙事方法 → 核心世界观 → 名词索引 → 大纲 → 章节目录 → 人物档案 → 逐章写作 → 章节审核 → 全书终审与合订。 - 量化安全协议:输出只用常用汉字/普通标点、禁 JSON、禁转义、少用易崩 token;非必要不调工具、一次只调一个。
- 审核闭环:每章必审(绿黄红三色),A–G 七个维度(设定/人物性格/目录/叙事/正文规则/禁AI腔/剧情逻辑),审核报告落盘为 md;全书完成后统一终审并合订为单本书。
- 禁AI腔:按六维度判定(句式模板/词汇套话/情绪直给/结构雷同/信息稀释/人物失真),区分叙述层重复与人设层一致,写作与审核共用。
- 工具瘦身:预设内行级禁用 shell/jobs/skills/goals/web 等整行工具,压缩工具目录 schema。
- 版本化写作:每章
第N章-章节名字-vX.md,整章重写先复制 v(X+1)、旧版永不覆盖。
安装
dsh plugin --profile web add "dsh-novel-solo" dsh web
打开插件页——0.1.7 是左侧栏的「插件」,0.1.6 是「设置 → 插件」——即可看到 dsh-novel-solo 的「子 agent 数量」卡片。
0.1.7 之前的宿主还会把 template/ 里的预设幂等铺设到 <dshHome>/.agent-presets/novel-solo/(那是旧宿主唯一的预设入口;目标已存在则跳过,绝不覆盖你已编辑的预设)。0.1.7 起不再铺设,预设就是 profile patch 里的一行声明。
宿主版本兼容性
本插件支持 DSH 0.1.6-alpha.1 / 0.1.6-alpha.2,以及 0.1.7-alpha.1 起往后的每一个宿主版本,按宿主自身版本二选一走哪条路。版本探测由两半各做一次、口径一致:cordis.patch.yml 里 preset-novel-solo 行的 disabled: !!js,以及 lib/index.js 的 isLegacyHost,都从 ctx.profileContext.installAnchor 读宿主版本,读不出来一律退回 0.1.6 路径。0.1.7 及以后的宿主(含 0.2.0)走同一条路。
· 0.1.6 · 0.1.7 及以后
预设交付 · 铺设 template/ 到 <dshHome>/.agent-presets/novel-solo/ · patch 里的声明行 @deepseek-ai/dsh-agent-preset
N 存哪里 · 插件自己向 settings 服务注册的 dsh-novel-solo 命名空间 · 本包的 Config(count 标了 volatile),由宿主投影进 profile patch
卡片挂载 · settingsScope + settings.plugin.item 插槽 · configForms + plugins.item 插槽
两条路都在真宿主上跑过:0.1.7 一侧用 0.1.7-rc.1 验证(卡片出现在「插件」页、保存落进 cordis.patch.yml、预设进入选择器);0.1.6 一侧因为本机没有 0.1.6 的宿主可执行文件,只做了同一版本门控的离线验证。本机现在的宿主是 0.2.0-rc.1、0.2.1-alpha.3、0.2.1-rc.2,两个插件在它们上同时装、同时起 web 跑过:node 半区在跑(.dsh-novel-solo-data 镜像照写)、--dump-config 里两条声明行与 roster id novel-solo 都在、没有任何整行被禁用;卡片本身没在 0.2.1 的浏览器里重新点过,但这条路上会用到的接口都对着 0.2.1-rc.2 的宿主源码逐个核过——plugins.item 插槽、configForms.get / whileServed、settings.configure / update、client manifest 的 id/url/rev、@deepseek-ai/dsh-client-locale 的 bind / register,与 0.1.7-rc.1 完全一致;这份接缝清单在 0.2.1-rc.3 又重读了一遍,无一变动(插件管理页只多了一个给新 entry-customization 插件用的增量 openList() 反射方法)。0.1.7-rc.2、0.2.0-rc.2、0.2.1-alpha.1 仍然只读源码、没实跑。
0.2.x 真的动过、本包已跟上的四处:@deepseek-ai/dsh-workflow-worker-thread 被并进 PTC 引擎,那行改成 @deepseek-ai/dsh-workflow-ptc(仍 disabled: true);tool-subagent 删掉了 backgroundMode 与 enableRunInBackground,留着不报错但纯属死配置,已从行里移除;0.2.x 起浏览器只装载与宿主同版本的 client graph,所以宿主升级后要刷新页面,卡片才会重新挂上。第四处是 persona 的插值口径:从 0.2.1 起宿主对 {{…}} 做严格解析,未注册的变量名直接抛 unknown prompt variable ... in section "deployment:persona-prefix",而 persona 里原有的 {{cwd}} 从来不是宿主变量(整个宿主只注册了 provider 与 model),于是预设整行装载失败、一条对话也发不出去——就是 issue #2。现已改成不依赖模板变量:工作目录取运行时上下文里 required 的 Current working directory(complete / includeRuntimeContext 都压不掉它),需要绝对路径时调 working_directory 工具查;npm run check 也加了一条门禁,persona 里再出现未注册变量会直接让 CI 红。
0.2.2-alpha.2 上确实动了一件与本预设有关的事:@deepseek-ai/dsh-tool-subagent-control/list-agents 这个子路径入口没有了——list_agents 工具并进该包主入口,出厂 standard 也在同一版删掉了自己的 tool-subagent-list-agents 行。所以这一行改成探测而非硬写:disabled 去 resolve 子路径,探不到就禁用整行——0.2.1 上工具照常可用,0.2.2 上不会重复注册;disabled 行在 Loader 解析包名之前就被过滤,缺这个子路径的宿主不会因此丢掉别的行。0.2.2 另外两件与本包无关的事实:tool-subagent 把 modelSelectionSettings 改名成 modelSelection(本预设从没设过这个键),以及 {{…}} 插值机制本身没变——persona 已经不再引用任何模板变量,已注册变量的集合不是本预设依赖的东西。template/agent.cordis.yml 是整份行列表的唯一来源:cordis.patch.yml 的生成区由 node scripts/sync-preset-patch.mjs 从它生成,所以探测写在模板里、补丁重新生成,不要手改生成区。
插件能不能加载,在它的代码跑起来之前就定完了:从 0.1.7-rc.1 起宿主会拿 peerDependencies 里每一个 @deepseek-ai/dsh* 范围去比对当前版本,对不上就把整行禁用;从 0.2.1-alpha.4 起改成先看 engines.dsh——只要写了它,就只由它决定,peerDependencies 不再参与(两条规则分别在 0.2.1-alpha.3 与 0.2.1-rc.2 的宿主代码上实测过)。所以两份清单都留着:从 0.1.6-alpha.1 点名到 0.2.2-alpha.2,再以 >=0.1.7-alpha.1 开区间收尾、不写上界——因为本插件不绑定任何特定宿主构建:走哪条路由它自己的版本门控在装载时才决定,那么一个还没人核对过的版本也该照常把插件跑起来,而不是被一道失败即关的检查整个挡掉。开区间之前被点名的版本才是真正逐一比对过的。开区间不承诺的是契约变更后的行为:将来若出事,先坏的会是声明式预设行,而那一次的修改属于 patch 文件,不属于范围——同理,开区间只保证「能装载」,不代表这份预设会跟着出厂 standard 一起长新行;出厂新增的 time-context、tool-schedule、plugin-market/tools 本预设至今不带,要跟上得改 cordis.patch.yml。装到此前拒绝本插件的宿主上要重启 dsh web,因为这个判定发生在 profile 组装阶段。
0.1.5 起 persona 使用 @deepseek-ai/dsh-persona 的新配置字段 prefix(0.1.2-rc.1 的旧字段 text 已移除),更老的宿主需要手工把 persona 行的 text: 改名成 prefix:(complete / includeRuntimeContext 不变)。每个宿主 home 各持一份铺设副本,旧 home 的 text: 副本切回旧宿主仍可用。
子 agent 数量如何影响行为
DSH 的 agent/request 瀑布只允许插件改写 LLM 路由/config,不能注入或改写 system/messages,所以「GUI → 模型提示」的动态注入不能走请求瀑布。本插件改用文件中转:
1. 设置卡片把 N 存进宿主设置(见上表),那里才是事实源。
2. 装载时 node 半区把它镜像到 <dshHome>/.dsh-novel-solo-data/agent-count.json。
3. persona 行在预设装载时用 !!js 读 template/persona.md,把文件里的同步锚点 并发上限 N=<数字> 换成镜像里的数字。persona 据此决定:N=1 全部由主代理一人完成;N>1 写作/审核交给子代理、主代理只派活并静默等待。
注意:镜像和 persona 都是在宿主装载插件的过程中解析的,所以改完数量要重启宿主才会进到提示词。0.1.7 的 volatile 设置在 node 侧没有变更回调,实时推送做不了。
预设内容速览
persona 正文在 template/persona.md;template/agent.cordis.yml(同步进 cordis.patch.yml)负责它周围的工具行。内容:
区块 · 内容
分工模式 · 并发上限锚点 N=1(默认),N=1 / N>1 两种执行路径
量化安全铁律 · 输出与工具调用的最优先级约束
六类文档标准结构 · 叙事方法 / 核心世界观 / 名词索引 / 大纲 / 章节目录 / 人物档案 逐字段模板
写作与审核规范 · 正文规则、禁AI腔清单、章节审核 A–G + 绿黄红、审核报告 md、全书终审与合订
工具使用标准 · read/write/edit/glob/grep/subagent 等逐工具铁律
项目与纪律 · 项目目录=工作目录下的 项目名 文件夹;路径一律取运行时上下文给出的 Current working directory 或 working_directory 工具,不写模板变量、一次只做一件事等
工具瘦身
预设通过行级 disabled: true 硬禁用:tool-bash、tool-jobs、skill-filesystem、tool-skill、tool-goal、plan-mode、subagent_codex、subagent_claude_code、workflow-ptc、tool-workflow、tool-ralph、tool-todo、tool-web。保留 tool-fs(read/write/edit,read_image 关掉)、tool-fs-search(glob/grep)、str-replace-editor(view/create/str_replace/insert)、tool-pwsh(已解禁,仅做文件系统管理:改文件夹/文件名、删除文件夹/文件)、subagent/subagent_fork、list_agents 等。
0.2.
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::15,最后更新 2026-11-02