DeepSeek Harness CLI Cheat Sheet: Commands, Flags, Env Variables
A reference for the dsh command line: the four entry modes, launcher flags, web and headless app parameters, plugin management, and every environment variable.
The dsh CLI has four entry modes (--profile, --profile headless, web, plugin), a small set of launcher-level flags that must appear before app-specific arguments, and roughly a dozen documented environment variables. This is the reference version — for the ideas behind profiles/bundles and config layering, see Profiles and Bundles and Configuration Guide.
The four entry modes
| Command | What it does |
|---|---|
dsh --profile <name> | Starts the profile at $DSH_HOME/profiles/<name> |
dsh --profile headless "task text" | One-shot task: creates a persistent session, runs it, prints the final answer, exits (completed → exit 0, otherwise 1) |
dsh web | Hardcoded alias for dsh --profile web |
dsh plugin --profile <name> <pnpm args...> | Plugin management — forwarded verbatim to pnpm inside that profile's directory |
dsh --profile headless and dsh web are both really just dsh --profile <name> with a specific profile — web is a shortcut name, headless requires the explicit form.
Launcher flags (must come before app args)
The launcher parses its own flags first; the first token it doesn't recognize is treated as the start of app-specific arguments. Put these before that boundary:
# print launcher version — must appear before the app-arg boundary
dsh -V
# apply an extra YAML patch layer (repeatable, applied in argv order)
dsh --profile web --patch ./local-override.yml
# print the composed config tree and exit, no session started
dsh --profile web --dump-config
# print only the bundle-layer config (before profile/machine/--patch layers)
dsh --profile web --dump-default-config
# launcher help (no profile) vs app help (with profile)
dsh --help
dsh --profile web --help
--dump-config and --dump-default-config are covered in more depth, including why you'd reach for one over the other, in Configuration Guide.
App-specific arguments, by profile
Once past the launcher-flag boundary, the remaining arguments are forwarded to a dsh-cmdline service specific to that profile:
| Profile | Accepted arguments |
|---|---|
web | --host (does not support 0.0.0.0 — the documented reason is that it would expose remote code execution to the network), --port, repeatable --trusted-host |
headless | Positional argument = the task text |
dsh --profile web --host 127.0.0.1 --port 3080
dsh --profile headless "Summarize the open PRs in this repo."
dsh plugin — plugin management
dsh plugin --profile <name> add <specifier> # install
dsh plugin --profile <name> remove <package> # uninstall
dsh plugin --profile <name> update [package] # update one or all
dsh plugin --profile <name> why <package> # trace why it's installed
All of it is pnpm underneath the profile directory — see How to Install DeepSeek-Harness Plugins for the full command walkthrough, the three install-source forms (npm, GitHub, local path/tarball), and the allowBuilds security prompt that GitHub-sourced plugins can trigger.
Environment variables
| Variable | Effect |
|---|---|
DSH_HOME | Harness home directory, default ~/.dsh; profiles live at $DSH_HOME/profiles/<name> |
DSH_PERMISSION_MODE | Overrides the process-level permission preset fallback (new sessions default to workspace-write) |
DSH_TOOLS_MODE | native / code / both — native tool calling vs. Code Mode (model writes code that calls tools) vs. both; any other value fails startup |
DSH_TELEMETRY_MODE | FULL (report every session event as OTLP/HTTP) or FEEDBACK_ONLY (only report a session log when the user submits feedback); default is no local reporting |
DSH_TELEMETRY_OTLP_URL | Custom OTLP collector endpoint |
DSH_TELEMETRY_DISABLED | Any non-empty value hard-disables telemetry — takes precedence over the two variables above |
NODE_USE_ENV_PROXY=1 | In source-checkout mode, makes HTTP_PROXY/HTTPS_PROXY take effect |
DEEPSEEK_API_KEY | Auth for the base bundle's web_search tool (DeepSeek's native search); also the default credential variable in Python SDK examples |
DEEPSEEK_SEARCH_BASE_URL | Custom DeepSeek search endpoint |
DEEPSEEK_BASE_URL | Python SDK examples: used when routing model calls through an OpenAI-compatible proxy |
DSH_MODEL / DSH_SYSTEM_PROMPT | Read by the Python SDK's minimal.py example to override model name / system prompt |
These are covered in the context of running a team fleet of dsh instances (shared telemetry policy, sandbox defaults) in the security-focused entries listed on the Development & Runtime category page.
Exit codes and process behavior
dsh --profile headless "task"exits 0 when the task status iscompleted, and non-zero (1) otherwise.SIGTERMis treated as a normal orchestration stop request in any mode: always exit code 0.SIGINT(Ctrl+C) exits with code 130.- The plugin tree gets up to a 5-second graceful shutdown window; a second signal forces immediate exit.
The launcher-flag boundary, in practice
The rule "launcher flags must come before app args" is easy to state and easy to get wrong the first time you combine flags. The launcher walks the argv list token by token; the moment it hits something it doesn't recognize as one of its own flags, everything from that token onward — including tokens that look like launcher flags — is handed to the app unparsed. Concretely:
# --dump-config is a launcher flag, recognized before the boundary: works as expected
dsh --profile web --dump-config
# --host is a web-app arg; once the launcher hits it, --dump-config placed AFTER
# it would just be passed through to the app instead of being parsed by the launcher
dsh --profile web --host 127.0.0.1 --dump-config # --dump-config here is an app arg, not a launcher flag
In practice this means: order matters. Put every launcher-level flag (--patch, --dump-config, --dump-default-config, -V) immediately after dsh or dsh --profile <name>, before any profile-specific argument like --host or a headless task string.
Profile bootstrap on first use
dsh --profile <name> and dsh plugin --profile <name> <args> both trigger profile initialization the first time that name is used — but they don't initialize it the same way. web and headless bootstrap from full starter templates (@deepseek-ai/dsh-base + @deepseek-ai/dsh-web-app, and @deepseek-ai/dsh-base + the headless bundle, respectively). Any other profile name bootstraps with just @deepseek-ai/dsh-base and nothing else — see Profiles and Bundles, Explained for the full mechanics and why that asymmetry is intentional.
Credential resolution order
Not a flag, but worth having next to the env var table: model provider credentials resolve in this order — inherited process environment → $DSH_HOME/.credentials.yaml → a .env file in the invoking directory → $DSH_HOME/.env. Managed credentials are never written to process.env directly.
FAQ
What's the difference between dsh web and dsh --profile web?
None — dsh web is documented as a hardcoded alias for dsh --profile web. They start the same profile the same way.
Why can't I bind the web UI to 0.0.0.0?
It's intentional. The documented rationale is safety: binding to all interfaces would expose an agent capable of executing code to the network. Use 127.0.0.1 and, if you need remote access, your own port-forwarding or tunneling setup — dsh itself doesn't support the network-exposed case.
Does dsh plugin support every pnpm subcommand?
Yes — dsh plugin --profile <name> <args...> forwards <args...> verbatim to pnpm, run inside the profile directory. add, remove, update, why, and anything else pnpm accepts is fair game, as long as pnpm is on your PATH.
Where do --patch and --dump-config fit relative to app arguments?
They're launcher flags, so they need to appear before the first token the launcher doesn't recognize — that's the boundary where app-specific arguments (like --host for web) begin.
Is there a headless equivalent of --host/--port?
No — the headless profile doesn't mount ApiProxy, an HTTP server, or a web runtime at all, so there's no port to configure. Its only app argument is the task text itself.
Next steps
Pair this cheat sheet with DeepSeek Harness Configuration Guide for how the flags interact with the four config layers, and Profiles and Bundles for what a profile actually is under the hood. Browse the full plugin catalog or Development & Runtime — plugin-registry is a good example of a plugin that wraps some of this CLI surface in a browser console.