dsh-plugin-subagent-roles
File-defined subagent roles for DeepSeek Harness: roles live in project and global .dsh/roles files, a delegating agent sees one catalog line per role, and each role's tool policy decides which tools its child can see.
Install
dsh plugin --profile web add dsh-plugin-subagent-roles
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-plugin-subagent-roles
[English](README.md) | 中文 | [更新日志](CHANGELOG.md)



概述
dsh-plugin-subagent-roles 用文件来定义子代理角色。一个角色就是一个 Markdown 文件:frontmatter 里是显示名、路由描述、可选的模型路由、工具策略和可选的工具调用预算,正文是子代理要遵循的 persona。项目级角色放在 <项目>/.dsh/roles/,全局角色放在 ~/.dsh/roles/;同 id 同时存在时项目级生效。
插件注册一个委派工具,并把当前工作区里的角色以一行行的紧凑目录告知主代理。委派到某个角色时,子代理带着该角色的 persona 启动,且只保留策略允许的工具——主代理的上下文里不会出现 persona 正文,没有角色文件的项目也不会看到任何目录。角色还可以限制子代理能用多少次工具:这是由框架自己的 tool/call 事件计数的硬上限,因此不肯收尾的子代理会被强制停下。
安装
桌面版(DSH 桌面 App)——在 App 侧栏的 Plugins 页里安装:粘包名即从 npm 拉取,粘绝对路径则安装本地检出。
dsh-plugin-subagent-roles # 或本地检出 /path/to/dsh-plugin-subagent-roles
desktop 这个 profile 归 App 独占——dsh plugin --profile desktop … 会被明确拒绝(profile "desktop" is managed exclusively by the Electron application),所以桌面版走 Plugins 页。它会安装包、把 bundle 追加进 profile,随后该行会出现在设置页的清单里。宿主侧的行会即时加载;客户端界面(其它插件的侧栏/任务页/用量页)需要刷新一次页面才会出现。
命令行 profile(dsh web、TUI、headless)——按名字装进对应 profile,或 link 一个检出:
# 从 npm 安装 dsh plugin --profile web add dsh-plugin-subagent-roles # 或本地 checkout dsh plugin --profile web add link:/path/to/dsh-plugin-subagent-roles
装好后重启该 profile(dsh web)。包内自带 bundle patch,会自行插入它的那一行组合,无需手改 composition。要求 Node.js 20 以上,以及提供 @deepseek-ai/dsh-tools 与 @deepseek-ai/dsh-subagent 的 DSH 部署。
版本线:0.5.x 只支持 DSH 0.2.1-rc.1+;0.2.0 及更早请继续用 0.4.3。0.2.1 移除了 subagents.start / startContinuable、请求里的 persona / toolFilter 以及客户端设置服务,0.5.0 已按新 API 重写委派与 composition,角色文件格式与模型绑定不变。
快速开始
在项目里创建一个角色文件:
--- displayName: 代码审查员 description: 审查改动的正确性、安全性与测试覆盖,按严重级别给出结论。 provider: deepseek-official model: deepseek-v4-flash reasoningEffort: low tools: [read, grep, glob] --- 你是代码审查员。先读改动再下结论,区分阻塞项与建议项, 每条问题都给出文件与行号。
然后让主代理委派——“让代码审查员角色审一下这个改动”——或直接调用工具:
subagent_role({ role: "code-reviewer", prompt: "审查已暂存的改动。", description: "审查暂存改动" })
角色在组装提示词时读取、在委派开始时再读取一次,因此改角色文件不需要重启 DSH。同风格的派发提示词见 examples/delegation-prompts.zh.md。
角色文件
角色从哪里读取
优先级 · 路径 · 说明
1 · <项目>/.dsh/roles/<id>.md · <项目> 是从会话工作目录向上找到的第一个含项目标记(默认 .git)的目录;找不到标记时就是工作目录本身。
2 · ~/.dsh/roles/<id>.md · 跨项目共用。可用 dshHome 改位置。
角色文件可以是符号链接。文件按文件名寻址,因此 id 就是文件名(去掉 .md),必须是 kebab-case。
文件格式
frontmatter 是 YAML 映射,正文是 persona。
字段 · 必填 · 含义
description · 是 · 目录里显示的一行描述,主代理据此判断要不要委派。
name · 否 · 写了就必须与文件 id 一致,用来拦住"改了文件名却没改声明"。
displayName · 否 · 人可读的名字,默认取 id。
whenToUse · 否 · 追加在目录行末尾的补充路由提示。
provider、model · 否 · 子代理的模型路由。两者必须同时出现或同时省略;省略时继承主代理的路由。
reasoningEffort · 否 · 子代理的思考力度,随路由一起生效。
tools · 否 · 允许清单简写,如 [read, grep, glob]。
toolFilter · 否 · 显式策略:{ allow: [...], deny: [...] }。
maxToolCalls · 否 · 子代理工具调用次数的硬上限,整数。省略则继承行配置的 defaultMaxToolCalls;写 0 表示显式不限,它会覆盖行默认值。
maxToolCallsScope · 否 · delegation(默认)每次委派重新计数——continuable 子代理的每个 turn/start(即一次后台唤醒)也算新的一次;session 则按该子代理整个生命周期累计。
onToolCallBudget · 否 · 额度耗尽时的行为:wrap-up(默认)、interrupt 或 off。
graceToolCalls · 否 · wrap-up 注入通知后额外放行的调用次数,默认 1;0 表示在触发的那一次调用上直接收口。
tools 与 toolFilter 只能二选一。未知的 frontmatter 键会被拒绝而不是忽略,避免拼写错误悄悄放宽角色的工具范围。
maxToolCalls 族字段需要插件 ≥ 0.4.0。旧版本完全不认识这些键,会把整个角色文件判为非法而跳过,因此角色文件与插件版本是绑定的:给某个角色加上额度,就意味着每个使用该工作区的机器都要升级插件。
persona 正文可以使用 {{cwd}}、{{model}}、{{provider}}——恰好是 agent loop 注册的那三个,由框架在子代理侧插值。部署里若另有插件注册了更多变量,可在 personaVariables 中列出;除此之外的任何引用都会在读取角色文件时被拒绝,因为未知变量会让该子代理的每一轮都抛错。引用按精确规则匹配(花括号内不能有空格);而目录字段——description、displayName、whenToUse——完全不能出现 {{,因为目录文本在到达模型之前同样会经过插值。
配置
行配置如下;在 profile patch 里按 id 覆盖即可:
# ~/.dsh/profiles/web/cordis.patch.yml
- id: subagent-roles
name: dsh-plugin-subagent-roles
config:
catalogDescriptionMaxLength: 120
选项 · 默认 · 含义
toolName · subagent_role · 模型可见的委派工具名。
subagentProvider · spawn · 子代理传输 provider。
backgroundMode · one-shot · one-shot 或 continuable。
enableRunInBackground · true · 是否在工具上暴露 run_in_background。
maxDepth · 不设 · 委派深度上限;不设则由 provider 决定。0 表示拒绝任何委派。
defaultRole · 不设 · 调用未给 role 时使用的角色。
catalog · compact · compact 渲染角色目录;off 完全不渲染。
catalogScope · main · main 只向顶层 agent 展示角色;all 连子代理也展示。
catalogDescriptionMaxLength · 160 · 目录行里每条描述的截断长度。
projectRootMarkers · ['.git'] · 从会话工作目录向上寻找项目根的标记。
projectRootTtlMs · 5000 · 项目根结果被信任多久后重新向上查找,好让会话运行中 git init 也能被发现。
dshHome · $DSH_HOME 或 ~/.dsh · 全局 roles/ 目录所在位置。
maxBodyBytes · 65536 · persona 体积上限,按 UTF-8 字节计。超过该值加 64 KiB frontmatter 余量的文件在读取之前就被拒绝。
personaVariables · ['cwd', 'model', 'provider'] · 允许 persona 引用的提示词变量。仅当部署确实注册了更多变量时才扩充。
respectModelSelection · true · 是否遵守官方 subagent-model-selection 允许清单:先看会话已捕获的策略,再看实时设置。
onMissingTool · drop · 不可用的工具名:drop 告警后继续,error 直接拒绝委派。
timeoutMs · 不设 · 单次前台委派的工具调用超时。不设则不限时。
defaultMaxToolCalls · 0 · 角色文件未声明额度时使用的工具调用预算。0 表示不限,且默认就是 0:2277 个文件的大仓和一个小项目对"合理调用数"的定义不同,所以这个数字属于角色文件而不是全局硬编码。
maxToolCallsHardCap · 0 · 角色文件不得超过的上限,防止项目侧把额度开到失去意义。0 表示不设上限,且永不削顶显式的 maxToolCalls: 0——"不限"是哨兵值而不是数值零。
onToolCallBudget · wrap-up · 额度耗尽行为的行级默认值,可被角色文件覆盖。
graceToolCalls · 1 · 宽限次数的行级默认值,可被角色文件覆盖。
enableListTool · false · 是否注册诊断工具。
listToolName · subagent_roles · 诊断工具的名字,让第二行能与之共存。
childPromptTrim · full · 裁剪子代理提示词:full 丢弃子代理用不上的工具说明,外加命名过的提示词片段;tools 只丢前者;off 不注册该监听器。主代理的提示词永不改动。
childPromptTrimNames · `['harness:source', 'app:web-surface', 'ui:deliverable-file-references', 'context:file-r
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::11,最后更新 2026-10-17