Ask “how do I run DSH” and the honest answer is: it depends on what the run is for. dsh is not one app but one launcher with several shipped profiles, and each profile is a different surface onto the same agent core. This guide walks every surface the CLI reference documents, states plainly what each is for, and ends with where the community-built clients fit.
One launcher, five shipped profiles
The CLI behavior reference defines five profiles that auto-initialize from shipped templates on first use: web, headless, sdk, sdk-minimal, and acp. Any other profile name fails loud with a hint to run dsh plugin --profile <name> add <package> — profiles beyond the shipped five are something you assemble, which is exactly how terminal UIs get added (more on that below).
| Profile | You run | What you get |
|---|---|---|
web |
dsh web (alias for --profile web) |
The Web UI on http://127.0.0.1:3080, browser handoff on local launch |
headless |
dsh --profile headless "task text" |
One-shot run: final text on stdout, exit code contract |
sdk |
a stdio client connects | JSON-RPC over stdio, base bundle included |
sdk-minimal |
started by the Python SDK | JSON-RPC over stdio, standalone minimal tree |
acp |
your ACP-speaking editor launches it | Agent Client Protocol over stdio |
The web profile: the default front door
The upstream README’s Run section leads with one command — npx @deepseek-ai/dsh web — and it is the right first stop for a newcomer. Per the CLI reference, dsh web is a hardcoded alias for --profile web; the production runner serves http://127.0.0.1:3080 by default and opens the browser after the loader tree settles. Two remote-relevant behaviors are worth knowing before you reach for flags: a launch under SSH_CONNECTION prints the host URL but skips the browser handoff because your SSH client owns the forwarded address, and the CLI intentionally does not support --host 0.0.0.0 — it exits with a usage error rather than exposing the UI broadly. --trusted-host adds named authorities accepted by the /api browser-trust fence.
Inside the web profile you choose an agent preset per session — the web app exposes cordis, ptc, and standard presets, plus the shipped minimal preset (极简模式 in the UI) that composes only persistent bash and str_replace_editor. How to point those sessions at models and providers is its own topic, covered in Configure Models and Providers in DSH.
Headless: one task, one exit code
dsh --profile headless "run the tests" is the documented automation surface. The task text is the positional argument; the run creates one fresh persisted Agent, submits the task, and waits for quiescence. Output discipline is strict: reasoning deltas stream to stderr under a dsh: reasoning: heading, stdout carries only the final assistant text, and the process exits 0 for completed and 1 otherwise. Nothing listens: the shipped headless profile mounts no browser connection, HTTP server, web runtime, or browser client, and opens no listening port. That combination — a clean stdout contract, an exit code, no server — is what makes it the CI and scripting surface.
SDK and sdk-minimal: embedding DSH in your program
The Python SDK guide documents the embedding path: install the SDK, point it at a base URL, and the SDK starts the bundled dsh --profile sdk-minimal process lazily, reusing it until the context manager exits. Both sdk and sdk-minimal speak JSON-RPC over stdio; neither takes options. The difference is scope: sdk composes the base bundle with the sdk-app bundle, while sdk-minimal runs its standalone bundle — it uses the invoking directory as its filesystem and sandbox root, omits instruction discovery and SQLite, and pins danger-full-access instead of the usual workspace-write. Embedders get a quieter tree; they also inherit full-access defaults, which is worth reading twice before pointing it at a machine you care about.
ACP: editors as clients
The acp profile takes no options and carries the Agent Client Protocol over stdio — the protocol editors speak when they embed an agent. The ecosystem side of this is the deepseek-harness-acp bridge on our map, which connects Zed-class editors to DSH. If your daily driver is an editor rather than a browser tab, this is the surface to watch.
Shared plumbing every base-backed profile gets
The surfaces differ at the edges, but the plumbing underneath is common, and the CLI reference is explicit about it:
- Configuration composes in layers: bundle patches named in the profile manifest, then the profile’s own
cordis.patch.yml, then the home-level$DSH_HOME/cordis.patch.yml, then any--patchoverlays in argv order — later layers win per row. Our DSH Profiles and the dsh plugin Command guide walks this in depth. - Plugins are pnpm under the hood:
dsh plugin --profile <name> add|remove|why|updateforwards to pnpm, and a dependency whose manifest declares adsh.bundle.patchjoins the layer stack automatically. Bundle membership changes land on the next profile start; patch-file edits hot-reload inliveprofiles. - Credentials resolve in a fixed order: the inherited environment, then
$DSH_HOME/.credentials.yaml, then the invoking directory’s.env, then$DSH_HOME/.env. - Permissions default to
workspace-writein base-backed profiles: bash and filesystem mutations are confined to the session workspace and platform temporary roots, while reads and network access are not confined. The standalonesdk-minimaltree is the documented exception (danger-full-access). - Instruction files load with a budget: base-backed modes treat the invoking directory as the workspace root and load applicable
AGENTS.mdorCLAUDE.mdinstructions within a 65,536-byte render budget.
Where the community clients fit
The shipped profiles are not the end of the story, because the launcher treats a TUI as just another plugin: the CLI reference itself demonstrates adding a terminal UI into a dedicated tui profile with a git-hosted package spec and then launching dsh --profile tui. Around that mechanism a third-party client ecosystem has grown, and the ones that passed verification live on our map — the DSH TUI full-screen terminal, the Rust-based deepseek-harness-tui (Rust), the DSH Desktop desktop client, and the community DSH Desktop (community Electron distribution). They are community projects, not upstream surfaces — the README’s developer-preview warning (“THERE WILL BE COMPATIBILITY-BREAKING CHANGES”) applies to them with extra force, which is why our map entries carry verifiedAt dates and fact tables rather than vibes.
The short version
Daily interactive driving: dsh web. One task from a script or CI: dsh --profile headless "...". Your own program in the loop: the Python SDK. Your editor in the loop: ACP. A terminal you already live in, or a desktop window: the community clients on the map — installed as plugins, exactly like everything else in DSH. Newcomers should start with DeepSeek Harness in 5 Minutes and keep the profiles guide DSH Profiles and the dsh plugin Command at hand, because every surface above is configured through the same profile machinery.