dsh-roles-zeta
Verifieddsh-roles-zeta · v0.5.0 · MIT · Web UI
Role-based subagent delegation for DeepSeek Harness: one delegate tool over a folder of role files, with a roster that ships and stays overridable
Install
dsh plugin add dsh-roles-zeta Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Readme
dsh-roles-zeta
dsh-roles-zeta 給 dsh agent 一支 delegate 工具與一個角色檔資料夾。呼叫時指定角色,角色檔提供該 child 的 persona、模型路線、reasoning effort 與工具範圍。它架在內建 subagent 工具用的同一個 ctx.subagents 服務上,所以 provider、委派深度、續談與背景結算全部照舊。內建的 subagent 與 subagent_fork 繼續掛著:它們讓模型每次呼叫自己挑路線,而角色是寫檔時就固定的。
每個角色以 Agent Preset 的形式交給 child:複製呼叫者自己的 preset,換上角色的 persona,只保留角色工具需要的插件(見角色即 agent preset)。需要 dsh 0.2.1-rc.2 以上;從這版起,委派請求本身不再帶 persona 或工具過濾器。
工具旁邊有三個介面,各自只在對應的 host 服務存在時掛載:Web 輸入框裡每個角色一條斜線指令、Web 設定裡的「角色代理」頁,以及角色目錄的監看,改動不必重新組合 profile 就會進到下一次呼叫。
安裝
dsh plugin --profile web add dsh-roles-zeta
# 重啟 host
profile 是各自獨立的安裝根,要用的每個 profile 都裝一次。github:zeta987/dsh-roles-zeta 與 file:<path> 也可以。第一次載入時八個角色檔會寫進 $DSH_HOME/agents($DSH_HOME 預設 ~/.dsh),新 session 就有一支 delegate 工具,描述裡列出它們。
~/.dsh/agents
├── code-mapper-lite.md explorer.md log-distiller.md triage.md
├── deep-coordinator.md hypothesis-debate.md reviewer.md worker.md
└── .seeded.json
更新
不會自動更新:dsh plugin 是在 profile 目錄裡轉發給 pnpm,啟動 host 不會安裝任何東西,也沒有任何頁面會查 registry。要換到某個版本:
dsh plugin --profile web add [email protected]
# 重啟 host
版本要明講。update 只在安裝時 pnpm 寫下的 ^0.x 範圍內移動;pnpm 11 起會把發布未滿 24 小時的版本從 outdated 與 @latest 裡藏起來(minimumReleaseAge),明確指定版本則立刻能裝。你改過的角色檔不會被動;沒碰過的內建角色會在下次載入時刷新。
斜線指令
每個載入的角色都是 Web 輸入框裡的一條指令。輸入 / 就會看到它們和 /plan、/goal 並列;/reviewer look at lib/index.js 會排進一輪對話,要求 agent 以 reviewer 角色呼叫 delegate、把這段文字當任務、在前景跑完並轉述結果。所以委派會留在對話紀錄裡,就是一次普通的工具呼叫,跟 /plan <message> 放訊息的位置相同。
指令跟著名冊走:新增、改名或移除角色都會重新註冊,選單自己更新。角色 id 撞到其他 plugin 的指令名時,該角色不註冊成指令(log 會說明),但仍可透過工具使用。commands: false 就完全不掛;commandPrefix: "r-" 得到 /r-reviewer。

設定頁
設定 → 角色代理 列出名冊,每個角色有標籤(內建、自訂、已修改),一次編輯一個角色:id、when 說明、路線(session 允許的路線會列成建議)、推理強度、工具(目前已註冊工具的勾選清單,或「沿用全部」加上委派開關)以及角色指示。儲存會把 <id>.md 寫進 $DSH_HOME/agents,跟你手寫的是同一個檔案。
| 按鈕 | 對磁碟做的事 |
|---|---|
| 刪除(自訂角色) | 移除檔案 |
| 刪除(內建角色) | 留下 disabled: true 停用檔,套件內的副本不再載入;恢復前列在「已停用的內建角色」 |
| 恢復此角色 | 把套件內的檔案複製回來覆蓋你的版本 |
| 恢復內建角色 | 八個一起做;你自己新增的角色一律不動 |
這頁是 /__dsh/roles-zeta/ 底下幾條 JSON 路由之上的瀏覽器模組,跟其他 Web API 一樣受瀏覽器 session cookie 與 Host/Origin 信任檢查把關。settingsPage: false 就兩者都不掛。

角色檔
一個角色一個 Markdown 檔:frontmatter 放機器欄位,正文是 child 的 persona prefix。
---
id: reviewer
when: Deep read-only reviewer for correctness, regressions, edge cases, and missing tests.
route: deepseek-official/deepseek-flash
effort: high
allow: [read, glob, grep, web_search, web_fetch, skill]
---
Review like an owner.
Prioritize correctness, regressions, edge cases, and concurrency hazards.
| 欄位 | 必填 | 語意 |
|---|---|---|
id |
是 | 角色 id;底線寫法解析到同一個角色 |
when |
是 | 一行;模型的選單項目,也是指令說明 |
route |
否 | 模型 id(deepseek-flash)或完整的 provider/model |
effort |
否 | off/minimal/low/medium/high/xhigh/max,依路線夾到可用層級 |
allow |
否 | child 需要的工具名;註冊這些工具的插件會被保留(以插件為單位,見下文),之後 child 會被遮罩成只剩這些名稱;省略則繼承全部,[] 不保留任何工具插件 |
delegation |
否 | true 讓沒有 allow 的 child 保留委派插件 |
disabled |
否 | true 移除一個內建角色 |
有 allow 的角色只有清單裡列了委派工具才能委派;沒有 allow 的只有 delegation: true 才能。
角色從哪裡載入
兩層來源,後者覆蓋前者:套件自己的 roles/*.md,然後是 $DSH_HOME/agents。套件第一次載入時把名冊植入你的目錄,你不動它就一直由套件管理:
| 你做了什麼 | 下次載入 |
|---|---|
| 什麼都不做 | 內建檔跟著套件;新版本改了角色就更新 |
| 改了一個 | 它變成你的,不再被覆寫 |
| 刪了一個 | 不會再植入,但套件內的副本照樣載入;要真的拿掉角色,用 disabled stub 或設定頁 |
| 自己加一個 | 與內建角色一起載入 |
.seeded.json 記著套件寫了什麼。你放進去的檔案會依 id 取代內建角色;只有 id 與 disabled: true 的 stub 會移除它。目錄是被監看的,任何變動在安靜一小段時間後重新讀取。seedRolesDir: false 讓套件不寫入你的目錄;watchRolesDir: false 改成每次組合只讀一次。
設定
- insert:
- id: roles-zeta
name: dsh-roles-zeta
config:
provider: spawn
toolName: delegate
backgroundMode: continuable
maxDepth: 2
這裡沒有任何模型也沒有任何路徑:角色檔自己指名路線,插件負責解析。這條 row 在 host plane,所以每個 preset 的每個 agent 都看得到工具。
| 欄位 | 預設 | 語意 |
|---|---|---|
dshHome |
$DSH_HOME,否則 ~/.dsh |
角色目錄所依據的 harness home |
rolesDir |
$DSH_HOME/agents |
你的角色目錄:植入目標,也是覆蓋根 |
seedRolesDir |
true |
把內建名冊寫進 rolesDir,未改動的跟著套件更新 |
watchRolesDir |
true |
rolesDir 有檔案變動時重新載入名冊 |
commands |
true |
每個角色一條 /<id> 斜線指令 |
commandPrefix |
(空) | 放在每個指令名前面的文字 |
settingsPage |
true |
掛載設定 API 與設定頁 |
provider |
spawn |
ctx.subagents 的 provider 名 |
toolName |
delegate |
模型面工具名 |
backgroundMode |
continuable |
continuable 回傳 durable child id;one-shot 回傳 job id |
enableRunInBackground |
true |
是否暴露 run_in_background |
maxDepth |
2 |
被啟動 child 的委派深度上限 |
defaultRoute |
(空) | 角色沒寫 route: 時使用 |
routes |
{} |
別名表:deep: { provider: deepseek-official, model: deepseek-flash } 後角色可寫 route: deep |
路線怎麼解析
route: 依序查:row 的 routes 別名表;這個 session 的 subagent-model-selection 允許清單(你在 dsh 設定裡勾的模型);已註冊 provider 的模型目錄;角色檔行內的 model: { provider, model }。目錄那一步讓沒有設定介面的 headless profile 也能解析。允許清單開著時它也把關角色的路線:已註冊但不在清單裡的模型會得到明確錯誤,不會偷偷跑。
哪裡都沒指名路線時,child 沿用呼叫者的 provider 與 model,結果會註明;插件從不自己從允許清單挑。同一個模型 id 註冊在兩個 provider 底下時必須寫成 provider/model。
effort 會夾到該路線宣告的層級上,同距離取較高:deepseek-flash 提供 off/low/high/max,所以 medium 變成 high、xhigh 變成 max。內建角色一律寫 high。發生替換時會在委派結果裡註明。
角色即 agent preset
委派請求會指名一個讓 child 掛載的 Agent Preset,child 的 persona 與工具完全由那個 preset 決定。某個角色第一次被呼叫時,插件會針對「這個角色+呼叫者的 preset」註冊一個 preset:
- id 是
roles-zeta/<角色>@<父 preset>,例如roles-zeta/reviewer@standard,名稱為Role: reviewer (standard)。 - row 複製自父 preset 自己的插件 row。
@deepseek-ai/dsh-personarow 的prefix換成角色正文,suffix 與其他設定保留;父 preset 沒有 persona row 時會補一條。 - 工具插件以插件 row 為單位篩選,不是以工具為單位。 dsh 沒有記錄哪個插件註冊了哪支工具,所以插件內建一張表,列出內建工具插件與各自註冊的名稱(
dsh-tool-fs:read、write、edit、read_image;dsh-tool-fs-search:glob、grep;其餘類推)。有allow時,只要某個工具插件註冊了至少一個允許的名稱就保留。沒有allow時全部保留,但註冊委派工具(subagent、subagent_fork、workflow、ralph)的插件會拿掉,除非delegation: true。allow: []不保留任何工具插件。 - 表裡沒有的 row(第三方插件,或
dsh-skill-filesystem、compaction 這類基礎設施)原樣保留,因為其他 row 可能依賴它們。一個 group 的 row 全被拿掉時,整個 group 也拿掉。 - 逐工具遮罩:child 建立時,再在它自己的 scope 上套一層
tools.restrict()。有allow的 child 只看得到清單裡的名稱;沒有allow也沒設delegation: true的,會拿掉delegate、subagent、subagent_fork、workflow、ralph。保留插件的同組工具,以及不屬於任何 preset 的 host plane 工具,也一併涵蓋。
只要角色檔與父 preset 沒變,preset 就會重複使用;兩者任一改動,下次呼叫時會註冊新的。角色 child 再委派時,複製的是最初的父 preset,所以 persona 不會疊加。log 會寫出每個角色 preset 拿掉了哪些 row。
模型看到什麼
每個 session 一份工具 schema:描述裡每個角色一行,加上允許的路線;參數是 role、description、prompt、選配的 route 別名、session 開啟模型選擇時的 provider/model,以及 run_in_background。一次呼叫會解析角色、預檢路線、註冊或沿用該角色的 preset,然後在它上面啟動一個 child。前景呼叫回傳 child 的最終文字;continuable 背景呼叫回傳 started subagent <id>,再由 runtime 的通知結算。
已知限制
- preset 仍以整個插件載入,多出的工具由遮罩藏起來。 只允許
read的 reviewer,保留下來的dsh-tool-fsrow 仍會掛上write、edit、read_image;host plane 的工具(delegate、working_directory、MCP resource 工具、每個已連線 MCP server 的mcp__*工具)也仍存在於 preset 之外。兩者都到不了 child:逐工具遮罩會藏起allow沒給的每個名稱,沒有allow的角色則會失去delegate與委派工具,除非設了delegation: true。遮罩在 child 建立當下計算,所以之後才註冊的允許工具(例如晚一點才連上的 MCP server)對該 child 仍是隱藏的;child 在自己 scope 註冊的工具(它的結構化輸出工具)則永遠不會被遮罩。 - 角色 preset 會和內建 preset 並列。 它們是一般的 Agent Preset,所以 Web 的 preset 選單會把它們列在
standard、cordis等之後。 - host 重啟後恢復背景 child,需要先有它的 preset。 角色 preset 是第一次使用時才註冊。host 重啟前啟動的角色 child,在同一個角色從同一個父 preset 再委派一次之前,對它發訊息會得到 unknown preset 錯誤。
- 工具對照表依 dsh 0.2.1-rc.2 建立。 表裡沒列的工具插件會整個保留;之後的 dsh 版本若改了工具名,要等表更新才認得。
- 角色改變不了工作區指示鏈。 每個 child 與父載入同一條
AGENTS.md/CLAUDE.md鏈。 - 斜線指令是請求,不是保證。 委派由模型執行,對話紀錄會顯示它有沒有做。
- 設定頁改的是檔案,不是 session。 已啟動的 child 不受之後的修改影響;下一次啟動才讀新檔。
- 沒有 per-role 記憶。