DeepSeek Harness 速查表:命令、配置、环境变量一张收全
生命不息,折腾不止。这个系列前前后后折腾了十几篇,今天把它们全压成一张可收藏的速查表——从「怎么装」到「半夜自动跑」一条龙查得到,前面零散的命令,看完这篇就串起来了。
从 8 月底接入中转站到现在,我们在 DeepSeek Harness(下称 dsh)这条线上折腾了十几次:装插件、写插件、接 MCP、自定义 Provider、Creator 自进化、权限、沙箱、Trajectory 回放,最后到无头自动化。内容不少,散在十几篇里,真要抄命令得翻半天。这一篇做收口:把命令、配置、环境变量、目录结构全摊成表,当字典用。建议直接收藏。
一、先记住一句话:dsh 是「profile 启动器」
很多人以为 dsh 是个聊天终端,不是。官方定位很明确——dsh 是 profile 启动器,本身不管交互,只负责把你交给某个 profile(一组插件的组合)去跑。整个 CLI 只有四个入口,记住这张表基本就够用了:
| 命令 | 干什么 |
|---|---|
dsh --profile <name> |
启动 $DSH_HOME/profiles/<name> 这个 profile |
dsh --profile headless "任务" |
一次性任务:建会话 → 跑 → 打印最终回答 → 退出(completed 退 0,否则退 1) |
dsh web |
dsh --profile web 的硬编码别名,大家天天用的 Web 界面 |
dsh plugin --profile <name> <参数> |
插件管理,参数原样转发给 pnpm |
几个缩写和细节:
dsh <name>等价于dsh --profile <name>(缩写名必须紧跟dsh)。- 但
plugin是保留命令,想启动一个恰好叫 plugin 的 profile,得写全dsh --profile plugin。 web和headless都是内置保留 profile 名,首次用会从随附模板初始化:web= base + web-app,headless= base + headless。
二、命令行速查表(收藏这一节就够)
Web 界面
1 | dsh web # 默认 127.0.0.1:3080 |
注意:官方明确 --host 不支持 0.0.0.0,理由是那样会把「远程代码执行」暴露到公网。想给局域网用就配 --trusted-host,别硬绑 0.0.0.0。
无头(headless)
1 | dsh --profile headless "审查 src/server.ts 的鉴权逻辑,给 3 条建议" |
任务文本是位置参数(不是 flag),写清楚、可执行,别含糊。
插件管理(转发给 pnpm)
1 | dsh plugin --profile web add "github:owner/repo" # 从 GitHub 装 |
装第三方子代理 Provider(可选 bundle):
1 | dsh plugin --profile web add @deepseek-ai/dsh-subagent-codex |
配置诊断与补丁
1 | dsh web --dump-config # 打印完整合成配置(含 provider 细节,别外传) |
三、东西都藏在 ~/.dsh,目录结构一目了然
dsh 的所有状态集中在一个「单根主目录」,默认 ~/.dsh,可用 DSH_HOME 重定向。优先级:显式配置路径 > $DSH_HOME > ~/.dsh。
| 路径 | 放什么 |
|---|---|
$DSH_HOME/profiles/<name>/ |
每个 profile(一组插件的组合) |
$DSH_HOME/settings.yaml |
手写的模型/默认设置 |
$DSH_HOME/.env |
DEEPSEEK_API_KEY=... 等(环境层兜底) |
$DSH_HOME/.credentials.yaml |
API 密钥 |
$DSH_HOME/storages/(或 sessions) |
会话 / 轨迹存储 |
配置合成(effective tree)按这个顺序一层层叠,后写的一层胜:
- 空 root;
- profile manifest 里
dsh.profile.bundles列出的每个 bundle patch; - profile 自己的
cordis.patch.yml; - 家目录级
$DSH_HOME/cordis.patch.yml(机器级偏好,盖过 profile 层); - 命令行每个
--patch <路径>(按 argv 顺序)。
记住一个坑:patch 是「整行替换」而不是深合并——覆盖会替换掉目标行的完整值,别指望只改一个 key 还能保住同行的其它 key。
内置 bundle 有这几个(永远从当前 dsh 安装里解析):@deepseek-ai/dsh-base、dsh-web-app、dsh-headless、dsh-sdk-app、dsh-sdk-minimal、dsh-acp-app。
四、权限和沙箱:三个档位一句话记
沙箱三档(ctx.sandbox,只管文件写)
| 档位 | 允许什么 |
|---|---|
read-only |
完全不写;POSIX 后端额外放行 /dev/null |
workspace-write |
写限于会话工作区根 + 平台临时目录(默认档);不限制网络和进程可见性 |
danger-full-access |
零隔离,啥都能碰 |
后端按平台落地:Linux = bwrap / Landlock,macOS = Seatbelt,Windows = ACL。老版本 Landlock ABI 和 Windows ACL 只能「部分强制」,别把每个后端当成一样硬。
权限预设(沙箱档 + 审批策略打包)
| 预设 | 沙箱 | 审批 | 适用 |
|---|---|---|---|
workspace-write |
workspace-write | ask | 工厂默认,日常用 |
read-only |
read-only | ask | 只读任务 |
danger-full-access |
danger-full-access | never | CI / 全自动批量 |
审批策略真正的枚举只有 ask(先问)和 never(直接执行)两个。切档:会话里发 /permission(裸命令查当前值,带参数切);或用环境变量 DSH_PERMISSION_MODE 在启动时覆盖。
关键一条:预设只是「档位」,不是沙箱本身——设成 danger 也不会绕过沙箱,命令照样过 ctx.sandbox.confine。而且 fail-closed:没有应答者(比如 headless 里没人点弹窗)时,ask 一律按拒绝处理。所以无人值守场景要么 danger-full-access,要么自己配个终端应答器,否则会被卡死。
五、环境变量速查表
| 变量 | 作用 |
|---|---|
DSH_HOME |
主目录,默认 ~/.dsh |
DEEPSEEK_API_KEY |
官方 provider 凭据(也可放 ~/.dsh/.env) |
DEEPSEEK_BASE_URL |
把模型调用指到任意 OpenAI 兼容端点 |
DSH_PERMISSION_MODE |
覆盖进程级权限预设(新会话默认档) |
DSH_TOOLS_MODE |
native / code / both(原生工具调用 vs Code Mode) |
DSH_TELEMETRY_MODE |
FULL / FEEDBACK_ONLY(遥测策略) |
DSH_TELEMETRY_DISABLED |
任意非空值硬禁用遥测(优先级最高) |
DSH_MODEL / DSH_SYSTEM_PROMPT |
Python SDK 示例里覆盖模型名 / 系统提示 |
自定义 provider 那套:apiKeyEnv 默认取 DEEPSEEK_API_KEY,base URL 在落到官方地址前会先看 DEEPSEEK_BASE_URL。所以想接任意 OpenAI 兼容模型(或中转站,比如 ai.aklibk.com 这类多模型 + 按量便宜的服务),往往设这两个变量就够——具体接入套路在《接入中转站》那篇已经写过,这里不重复。
六、自动化契约:退出码 + headless
headless 是自动化(cron / CI / shell)的正主,靠退出码决定脚本走向:
| 退出码 | 含义 |
|---|---|
0 |
最终 turn 结束原因是 completed(正常完成) |
1 |
没到 completed,或 runner 本身挂了 |
130 |
收到第一个 SIGINT(Ctrl+C)后优雅关闭 |
两个必须记住的坑:
- 退出码 0 只证明「跑完了」,不证明文件真生成了、测试真过了——外部效果要自己另外验证。
- SIGTERM 被当正常停止,任何情况都退 0。用 systemd/CI 超时去杀它,和「正常完成」在退出码上分不出来,得另看输出。
最朴素的包装:
1 |
|
配上 cron 和从 CI secret 注入的 DEEPSEEK_API_KEY,就能做到「写完睡觉、明早收结果」。
七、一句话总结 + 高频坑速记
- 模型:dsh 是 profile 启动器,不是聊天终端;
web/headless是内置 profile,plugin是保留命令。 - 装:
dsh plugin --profile <name> add <specifier>,specifier 支持github:/npm:/link:。 - 看:
dsh web --dump-config看合成配置,但里面有 provider 细节,别外传。 - 管:沙箱三档 read-only / workspace-write / danger-full-access;预设 = 沙箱 + 审批(ask / never)。
- 跑:
dsh --profile headless "任务",退出码 0 / 1 / 130,SIGTERM 恒 0。 - 安全:
--host 0.0.0.0被官方禁掉(会暴露 RCE);无人值守的 ask 会 fail-closed 卡死。 - 踩坑:旧教程里的
dsh run已移除,一次性任务统一用dsh --profile headless "任务"。
十几篇连载到这里收个口,这张表建议收藏,后面折腾别的框架时回来一查一个准。需要更细的某一块(比如 Trajectory 的事件流、Creator 的七个 cordis_* 工具),回对应那篇翻,本篇只做索引。
生命不息,折腾不止。下一篇我们开新坑,起一个「MCP 实战」系列:第一课先把「MCP 到底解决什么问题、它凭啥不是又一个 API 规范」讲透,再手把手跑通你人生中第一个 MCP Server,让任意 Agent 客户端都能调用你本地暴露出来的工具。