DeepSeek Harness CLI 速查表:所有 dsh 命令、Flag 与环境变量
dsh 命令行参考:四种入口模式、launcher 自身的 flag、web 与 headless 的 app 参数、插件管理,以及每一个有文档记录的环境变量。
dsh CLI 有四种入口模式(--profile、--profile headless、web、plugin),一小撮必须写在 app 专属参数之前的 launcher 级 flag,以及大约十几个有文档记录的环境变量。这是速查参考版——关于 profile/bundle 背后的概念以及配置层叠,参见Profile 与 Bundle和配置指南。
四种入口模式
| 命令 | 作用 |
|---|---|
dsh --profile <name> | 启动 $DSH_HOME/profiles/<name> 下的 profile |
dsh --profile headless "任务文本" | 一次性任务:新建一个持久化 session,跑完打印最终回答后退出(completed → 退出码 0,否则 1) |
dsh web | dsh --profile web 的硬编码别名 |
dsh plugin --profile <name> <pnpm 参数...> | 插件管理——在该 profile 目录内原样转发给 pnpm |
dsh --profile headless 和 dsh web 本质上都是 dsh --profile <name> 加一个具体的 profile 名——web 是一个快捷名字,headless 需要写完整形式。
Launcher 自身的 flag(必须写在 app 参数之前)
Launcher 会先解析自己的 flag;它无法识别的第一个 token,会被当成 app 专属参数的开始。以下这些要写在那条边界之前:
# 打印 launcher 版本——必须出现在 app 参数边界之前
dsh -V
# 叠加一层额外的 YAML patch(可重复,按 argv 顺序生效)
dsh --profile web --patch ./local-override.yml
# 打印组装好的配置树后退出,不启动 session
dsh --profile web --dump-config
# 只打印 bundle 层的配置(在 profile/机器/--patch 层生效之前)
dsh --profile web --dump-default-config
# launcher 自己的帮助(无 profile)vs app 的帮助(带 profile)
dsh --help
dsh --profile web --help
--dump-config 和 --dump-default-config 的更深入用法,以及为什么该在两者之间做选择,见配置指南。
各 profile 自己认的 app 参数
一旦越过 launcher flag 的边界,剩下的参数会被转发给该 profile 注入的 dsh-cmdline 服务:
| Profile | 支持的参数 |
|---|---|
web | --host(不支持 0.0.0.0——文档给出的理由是这会把有能力执行代码的 agent 暴露到网络上)、--port、可重复的 --trusted-host |
headless | 位置参数 = 任务文本 |
dsh --profile web --host 127.0.0.1 --port 3080
dsh --profile headless "总结一下这个仓库里未合并的 PR。"
dsh plugin——插件管理
dsh plugin --profile <name> add <包说明符> # 安装
dsh plugin --profile <name> remove <包名> # 卸载
dsh plugin --profile <name> update [包名] # 更新一个或全部
dsh plugin --profile <name> why <包名> # 追溯为什么被安装
这一切底层都是在 profile 目录里跑 pnpm——完整命令走查、npm/GitHub/本地路径三种安装来源、以及 GitHub 来源插件可能触发的 allowBuilds 安全提示,见如何安装 DeepSeek-Harness 插件。
环境变量
| 变量 | 作用 |
|---|---|
DSH_HOME | Harness home 目录,默认 ~/.dsh;profile 都在 $DSH_HOME/profiles/<name> 下 |
DSH_PERMISSION_MODE | 覆盖进程级权限预设兜底(新 session 默认是 workspace-write) |
DSH_TOOLS_MODE | native / code / both——原生工具调用 vs Code Mode(模型写代码调用工具)vs 两者都用;其他值直接导致启动失败 |
DSH_TELEMETRY_MODE | FULL(把每个 session 事件当 OTLP/HTTP 日志上报)或 FEEDBACK_ONLY(只在用户提交反馈时上报一段 session 日志);默认本地不上报 |
DSH_TELEMETRY_OTLP_URL | 自定义 OTLP collector 地址 |
DSH_TELEMETRY_DISABLED | 非空即硬性关闭遥测——优先级高于上面两个变量 |
NODE_USE_ENV_PROXY=1 | 源码运行模式下,让 HTTP_PROXY/HTTPS_PROXY 生效 |
DEEPSEEK_API_KEY | base bundle 里 web_search 工具(DeepSeek 原生搜索)的鉴权;也是 Python SDK 示例默认读取的凭据变量 |
DEEPSEEK_SEARCH_BASE_URL | 自定义 DeepSeek 搜索 endpoint |
DEEPSEEK_BASE_URL | Python SDK 示例:模型调用走 OpenAI 兼容代理时使用 |
DSH_MODEL / DSH_SYSTEM_PROMPT | Python SDK 的 minimal.py 示例读取,用来覆盖模型名/系统提示词 |
关于在团队里跑一组 dsh 实例时如何统一遥测策略和沙箱默认值,开发与运行时分类页面下的安全相关条目有更多讨论。
退出码与进程行为
dsh --profile headless "任务文本"在任务状态为completed时退出码为 0,否则为非零(1)。- 任何模式下
SIGTERM都被当作编排系统的正常停止请求:退出码始终是 0。 SIGINT(Ctrl+C)退出码是 130。- 插件树有最多 5 秒的优雅关闭窗口;第二次信号会强制立即退出。
Launcher flag 边界在实践中的样子
"launcher flag 必须写在 app 参数之前"这条规则说起来简单,但第一次组合多个 flag 时很容易搞错。Launcher 会逐个 token 遍历 argv 列表;一旦它遇到一个它无法识别为自己 flag 的 token,从那个 token 开始的所有内容——包括那些看起来像 launcher flag 的 token——都会原样交给 app。具体来说:
# --dump-config 是 launcher 的 flag,在边界之前被识别到:按预期工作
dsh --profile web --dump-config
# --host 是 web app 的参数;一旦 launcher 碰到它,写在它*之后*的 --dump-config
# 只会被原样透传给 app,而不会被 launcher 解析
dsh --profile web --host 127.0.0.1 --dump-config # 这里的 --dump-config 是 app 参数,不是 launcher flag
实际操作中这意味着:顺序很重要。把每一个 launcher 级的 flag(--patch、--dump-config、--dump-default-config、-V)都紧跟在 dsh 或 dsh --profile <name> 后面写,写在任何 profile 专属参数(比如 --host 或 headless 的任务字符串)之前。
首次使用时的 profile 引导
dsh --profile <name> 和 dsh plugin --profile <name> <参数> 在某个名字第一次被使用时都会触发 profile 初始化——但初始化方式并不一样。web 和 headless 会从完整的启动模板引导(分别是 @deepseek-ai/dsh-base + @deepseek-ai/dsh-web-app,以及 @deepseek-ai/dsh-base + headless bundle)。其他任何名字的 profile 都只会用 @deepseek-ai/dsh-base 引导,别的什么都没有——完整机制以及这种不对称设计为什么是刻意为之,见Profile 与 Bundle 详解。
凭据解析顺序
虽然不是一个 flag,但值得和环境变量表放在一起:模型 provider 的凭据按以下顺序解析——继承的进程环境 → $DSH_HOME/.credentials.yaml → 调用目录下的 .env 文件 → $DSH_HOME/.env。托管的凭据从不会被直接写进 process.env。
FAQ
dsh web 和 dsh --profile web 有区别吗?
没有区别——文档明确写明 dsh web 是 dsh --profile web 的硬编码别名。它们以同样的方式启动同一个 profile。
为什么 web UI 不能绑定到 0.0.0.0?
这是有意为之的。文档给出的理由是安全:绑定到所有网卡会把一个有能力执行代码的 agent 暴露给整个网络。用 127.0.0.1,如果确实需要远程访问,用你自己的端口转发或隧道方案——dsh 本身不支持"暴露到网络"这种用法。
dsh plugin 支持所有 pnpm 子命令吗?
支持——dsh plugin --profile <name> <参数...> 会把 <参数...> 原样转发给 pnpm,在 profile 目录内执行。add、remove、update、why 以及 pnpm 支持的任何其他命令都可以用,前提是 pnpm 在你的 PATH 上。
--patch 和 --dump-config 相对于 app 参数应该放在哪?
它们是 launcher 级的 flag,所以必须出现在 launcher 无法识别的第一个 token 之前——那正是 app 专属参数(比如 web 的 --host)开始的边界。
headless 模式有 --host/--port 的对应物吗?
没有——headless profile 根本不挂载 ApiProxy、HTTP server 或 web runtime,所以没有端口可配置。它唯一的 app 参数就是任务文本本身。
下一步
把这份速查表和配置指南搭配着看,了解这些 flag 是如何和四层配置交互的;再看Profile 与 Bundle了解一个 profile 底层到底是什么。也可以逛逛完整插件目录或开发与运行时分类——plugin-registry 就是一个把这部分 CLI 能力包装成浏览器控制台的插件例子。