dsh-agent-picker
Agent mode picker for DSH: pick an external Agent CLI (Claude Code, Codex, Qwen Code, Gemini CLI, Aider, Goose, Hermes…) as the session's default executor from a control next to the input box, instead of editing configuration files. The agent roster is data-driven, and installed CLIs are discovered
Install
dsh plugin --profile web add dsh-agent-picker
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-agent-picker
Agent 模式选择器 —— 在 DSH(DeepSeek Harness)Web 界面的输入框右侧加一个控件,
像选推理档位那样选定一个外部 Agent CLI作为当前会话的默认执行体。
它把"有哪些外部 Agent、各自怎么启动"做成数据(agents.json),
所以加一个新 Agent 只需加一条数据,不必改代码。
从旧版本升上来? 先看 [CHANGELOG](./CHANGELOG.md) —— 0.5.0 的行为和 0.4.1
有明显区别(列表变成"你这台机器上装了什么")。
它解决什么问题
DSH 本身能调用外部 CLI,但"调哪一个"通常要写死在配置里。这个插件把选择权交回给你:
输入框右边一个下拉,选谁,这一轮就交给谁。名册驱动的设计意味着
同一个插件能挂任意多个 Agent,包括你自己写的。
安装
dsh plugin add dsh-agent-picker
装完重启 DSH。插件第一次启动会把自带的 agents.json 复制一份到
$DSH_HOME/agent-picker.agents.json(默认 ~/.dsh/),之后你改的是这一份,
插件升级不会覆盖它。
名册:怎么加一个新 Agent
编辑 $DSH_HOME/agent-picker.agents.json,往 agents 数组里加一条:
字段 · 说明
id · 唯一标识
name · 显示名
tool · DSH 里对应的工具名
bin · 包装器文件名(用于"是否已安装"的探测)
available · 初始可用性建议;真实可用性由插件探测包装器是否存在
kind · task=任务型(结果可概括)/chat=对话型(原样转述)
expertise · 菜单里显示的「擅长」一行
note · 健康状态/接线说明
desc · 展开后的详细能力介绍
launch · 可选。自带执行配方:bin / argv / env / keepEnv / timeoutMs / graceMs / maxBytes。写了它,本插件就自己注册 cli_<id>_direct 工具
launch.keepEnv · 可选。要从父进程继承的环境变量名白名单(名字里带 KEY/TOKEN/SECRET/PASSWORD 的变量默认会被剥离,靠环境变量授权的 CLI 必须写在这里)
keep · 可选。写 true 表示永不自动清理(见下面"旧版残留会自动清理")
改完重启 DSH 生效。
旧版残留会自动清理(0.6.0 起)
插件只在你没有名册文件时才生成一份,存在就永不覆盖。但旧版本留下的名册里
常有一批指向别的机器路径的条目(比如 *-dsh.ps1)——它们在新机器上永远跑不起来,
却一直占着列表。所以每次启动会做一件事:
- 把名册里能证明跑不起来的条目删掉(判据:配方
argv引用的脚本在本机不存在) - 删之前完整备份到
<名册>.legacy-<时间戳>.bak,想找回就改回文件名 - 没有
launch的"借用型"条目绝不碰(工具可能由别的插件提供) - 一条都不用删时,文件一个字节都不动
- 想保护某一条?在它里面加
"keep": true
launch.argv 的路径规则(重要)
名册是跨机器的,所以不要写死绝对路径。argv 里写裸文件名即可,
插件会在运行时按下面顺序解析:
codex-dsh.ps1 -> <cliBinDir>/codex-dsh.ps1
{cliDir}/codex-dsh.ps1 -> <cliBinDir>/codex-dsh.ps1
C:\some\where\x.ps1 -> 原样保留(你想钉死绝对路径时用)
cliBinDir 的取值:环境变量 DSH_AGENT_PICKER_CLI_DIR 优先,
否则默认 ~/dsh-clis/bin(与 dsh-sub-cli 的约定一致)。
占位符
argv 里可用的占位符:{task}(任务正文)、{permflags}、{permission}、{model}、{image}。
{permflags} 是特殊的:它会展开成多个参数,取值来自名册里的
permFlags[<权限档>];没指定权限档时取 defaultPermFlags。
所以一条模板就能携带"权限档 → 这个 CLI 自己的 flag"的映射,调用方不必知道每个 CLI 的语法。
{image} 只对命令行真的支持图片参数的 CLI 有意义(例如 Codex 的 -i/--image)。
其余 CLI 就算它自己有读图能力,也不是靠这个占位符——那种情况请把图片路径写进任务正文,
让那个 Agent 用自己的读文件工具去读。
你需要自备什么
这个插件只负责调度,不附带任何 Agent。装好一个 CLI,它就会被自动发现并列出来。
探测来源(按顺序):PATH → 托管目录(~/dsh-clis/bin,可用 DSH_AGENT_PICKER_CLI_DIR 覆盖)
→ ~/.local/bin。
出厂名册是空的,这是有意的 —— 列表里的成员全部来自"本机实际探测"。
所以别人机器上看到的列表,取决于他装了哪些 CLI。
各 Agent 的兼容性(实测声明)
内置识别 31 个 Agent 名字。分两类:
- 11 个带启动配方 → 探测到即可直接调用
- 20 个只识别 → 探测到会出现在列表里(带名字和介绍),但需要你补一条启动配方才能真正调用
为什么不全给配方:启动参数写错比不写更糟 —— 那会变成"列表里能点,一点就报错"。
所以只有参数经过验证的才给配方,其余诚实标成"需配置"。
✅ 有启动配方(探测到即可调用)
Agent · 启动参数 · 权限映射 · 参数验证
Aider · --message {task} · --dry-run / --yes-always · --help 复核 ✓
Qwen Code · -p {task} · --approval-mode plan / yolo · --help 复核 ✓
Gemini CLI · -p {task} · --approval-mode plan / yolo · --help 复核 ✓
Goose · run -t {task} · — · --help 复核 ✓
Hermes · -z {task} · — · --help 复核 ✓
Codex · exec --skip-git-repo-check {task} · -s read-only / workspace-write / danger-full-access · 取自已跑通的包装脚本
Claude Code · -p {task} · --permission-mode plan / acceptEdits / bypassPermissions · 取自官方参数(未本机复核)
Ollama · run qwen3:4b {task} · — · 见下方条件
opencode · run {task} · — · 官方文档给出 run 子命令;未实机跑过
Cursor CLI · -p --trust {task} · --mode plan / --force · 官方 --help 实测记录 ✓
Kimi · -p {task} · 非交互模式自带 auto 权限 · 官方文档 ✓
🔍 只识别、不给配方(会显示"需配置启动方式")
GitHub Copilot CLI · Trae · Amp · Droid · Augment Code ·
OpenHands · Cline · Windsurf · Qoder · CodeBuddy · Grok CLI ·
CodeGeeX · Plandex · CodeBuff · gptme · Open Interpreter ·
(OpenClaw · Kilo Code · Crush · WorkBuddy)
这些出现在列表里时是这样的:
○ GitHub Copilot CLI 已检测到,需配置启动方式 自动发现(…\copilot.CMD);识别到 CLI,但还没有启动配方 ───────────────────────────────────────────── GitHub 官方的命令行 Copilot,和 GitHub 生态贴得最近。 —— 用约定目录或名册补一条 launch 就能调用
怎么补一条配方(插件里有现成引导)
不用翻这份文档 —— 在列表里点那一行的 「怎么补?▼」,会就地展开三步:
1. 查出它的参数 —— 命令里已经填好这个 CLI 的真实路径,一键复制:
"C:\...\copilot.CMD" --help
2. 找“一次性执行”的标志 —— --prompt / -p / exec / run 这类
3. 存成约定目录里的文件 —— 路径和模板都由插件给出,id / 名字 / bin 已填好,
你只改 argv 这一行,模板可一键复制:
{
"id": "copilot",
"name": "GitHub Copilot CLI",
"tool": "cli_copilot_direct",
"kind": "task",
"launch": { "bin": "C:\\你的路径\\copilot.CMD", "argv": ["-p", "{task}"] }
}
存好后重启 DSH,它就会从「可安装」升到主列表。
引导是纯提示,不写盘、不拦截 —— 现在不想配也完全可以,那一行就安静待着。
关于探测名的取舍
探测名越短越容易误报(机器上有个同名的无关程序,就会被当成某个 agent)。
所以本项目有一条硬规则:只接受 4 个字符以上的探测名 —— amp 是唯一例外,
因为它是 Sourcegraph 官方 CLI 名。Pi、Roo Code 这类既有条目因此被移除,
而不是靠猜名字去凑数量。
另外 Crush 目前只识别、不给配方:Charm 的仓库里有一个未关闭的 issue 在请求
“非交互批处理模式”(charmbracelet/crush#1030),说明 crush run <任务> 这条路
当时并不存在。猜一个不存在的子命令 = 用户点了必报错,所以宁可不给。
查过、但没收进目录的(都有原因)
工具 · 为什么没加
iFlow CLI · 官方文档写明 2026-04-17 已停止服务,并要求迁移到 Qoder
通义灵码(Lingma) · 已并入 Qoder,所以只留 qoder 一条,不重复
文心快码 / Zulu-CLI · 只查到产品名,没查到确切命令名;写错等于死条目
ZCode · 旧版本里有这一条,但探测名始终无法核实 —— 0.5.1 已移除
原则:名字可以少,但不能猜。少一个的代价是"没被发现",写错一个的代价是
"列表里出现一条永远点不动的东西"。
⚠️ 需要额外条件
Agent · 条件
Ollama · 本机要有 ollama 服务在跑;配方里模型名写死为 qwen3:4b,装的是别的模型请改名册或约定目录
Gemini CLI · 还要一个协议翻译层(如 LiteLLM)把你的端点转成 Gemini 协议
Qwen Code · 需要 DEEPSEEK_API_KEY(它自己读 ~/.qwen/.env)
Goose · 需要 GOOSE_PROVIDER / GOOSE_MODEL / OPENAI_API_KEY / OPENAI_HOST
⚠️ 上表里名字带 KEY 的变量,默认不会被传给子进程(见下面"安全边界"一节)。
如果你就是靠环境变量给它授权,请在名册该条目里显式白名单:
```json
"launch": {
"bin": "goose",
"argv": ["run", "-t", "{task}"],
"keepEnv": ["OPENAI_API_KEY", "OPENAI_HOST", "GOOSE_
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::11,最后更新 2026-11-01