CLI & Profiles
Master the dsh launcher: entry modes, profile layer composition, headless one-shot tasks, dsh plugin, and dump-config
dsh is the DeepSeek Harness launcher for profiles. A profile is an ordered stack of plugin-bundle patch layers under the user's own overrides. This page covers every launcher entry mode and the layer semantics; model configuration and first launch live in installation.
Entry modes
| Command | Purpose |
|---|---|
dsh --profile <name> | Boot the profile under $DSH_HOME/profiles/<name> |
dsh --profile headless "job" | Run one fresh persisted session, print the final answer, and exit |
dsh web | Alias of --profile web |
dsh plugin --profile <name> <pnpm args> | Manage a profile's plugins by forwarding to pnpm in the profile directory |
The invoking directory is the default workspace root. The web and headless profiles auto-initialize on first use from shipped templates; any other profile must be created through dsh plugin.
Launcher flags vs. app arguments
The launcher parses only its own flags and hands everything after them to the booted profile. Launcher flags come first, and the first token it does not recognize starts the app's arguments:
dsh --profile web --port 8080 # --port belongs to the web app
dsh --profile headless "run the tests"
dsh --profile web --help # the web app's help, not the launcher's
dsh --help # the launcher's own helpThe shipped apps own these command lines:
| Profile | Arguments |
|---|---|
web | --host, --port, repeatable --trusted-host |
headless | the task text, as the positional argument |
The web profile serves http://127.0.0.1:3080 by default. The CLI does not support --host 0.0.0.0 yet and exits with a usage error; --trusted-host adds named authorities accepted by the /api browser-trust fence.
The dsh web alias
dsh web is a hardcoded alias for --profile web; the flags after it belong to the web app.
Profile layers
A profile directory holds:
package.json: out-of-tree plugin dependencies plus the profile manifestdsh.profileand its orderedbundleslist;cordis.patch.yml: the user's own patch layer.
The tree composes over an empty root, later layers winning:
- each bundle's patch in
dsh.profile.bundlesorder; - the profile's own
cordis.patch.yml; - the home-level
$DSH_HOME/cordis.patch.yml(machine-local preferences shared by every profile, so it outranks the per-profile layer); - each
--patch <path>overlay in argv order.
Bundles named in dsh.profile.bundles resolve from the dsh installation first (@deepseek-ai/dsh-base, @deepseek-ai/dsh-web-app, @deepseek-ai/dsh-headless), then from the profile's own node_modules, where pnpm installs out-of-tree plugins.
Boot and config layers at a glance
Headless one-shot tasks
dsh --profile headless "task text" creates one fresh persisted session, submits the task, waits for quiescence, then prints the last non-empty assistant text to stdout and exits. The exit code is 0 for completed, else 1. An invocation with no task is a usage error from that app.
The headless profile mounts no ApiProxy, Host, HTTP server, Web runtime, or browser client; a successful run writes nothing to stderr and opens no listening port. Configure model credentials first (DEEPSEEK_API_KEY, optionally DEEPSEEK_BASE_URL).
Inspecting the composed tree
Inspect the composed tree without booting it:
dsh --profile web --dump-default-config
dsh --profile web --patch ./extra.yml --dump-config--dump-default-configprints only the bundle layers;--dump-configadds the profile'scordis.patch.yml, the home-level$DSH_HOME/cordis.patch.yml, and--patchoverlays.
Both print comments naming the file that supplied each row and every overlay that changed it; !!js expressions remain unevaluated. A dump never runs app command-line providers, so it rejects an invocation that carries app arguments.
Shutdown and workspace
On shutdown the plugin tree gets up to five seconds to dispose. The first SIGINT/SIGTERM starts the graceful drain; SIGTERM exits 0 on every surface, SIGINT reports 130, and a second signal forces immediate exit.
All modes treat the invoking directory as the default workspace root and load applicable AGENTS.md or CLAUDE.md instructions. New sessions default to the workspace-write permission preset: Bash and filesystem mutations are restricted to the session workspace and platform temporary roots.
Next steps
- Manage plugin installs: Third-party Plugins.
- Compose agents per session: Agent Presets.
- Drive the harness programmatically: Python SDK.