dshseek

seek://guides/choosing-a-dsh-surface

Choosing a DSH Surface: Web UI, Headless, SDK, ACP, and Community Clients

Sep 5, 2026Beginner← All guides

TL;DR

dsh is one launcher that ships five profiles — web, headless, sdk, sdk-minimal, and acp — each auto-initialized on first use. This guide maps each surface to the job the CLI reference documents for it: the Web UI for daily driving, one-shot headless runs for CI, the Python SDK for embedding, ACP for editors, plus the community TUI and desktop clients on this site's map.

Key points

  • dsh ships five profiles that auto-initialize from templates on first use — web, headless, sdk, sdk-minimal, and acp; any other profile name must be populated with dsh plugin add first
  • The web profile serves http://127.0.0.1:3080 by default, opens the browser on a local launch, suppresses that handoff under SSH, and deliberately rejects --host 0.0.0.0 with a usage error
  • The headless profile is a one-shot runner: the task text is the positional argument, reasoning streams to stderr, only the final text reaches stdout, exit 0 on completed else 1 — and it opens no listening port
  • sdk and sdk-minimal carry JSON-RPC over stdio; the standalone sdk-minimal omits instruction discovery and SQLite and pins the danger-full-access permission preset
  • The acp profile carries the Agent Client Protocol over stdio, which is the bridge editors speak
  • Terminal UIs are plugins too: the CLI reference demonstrates adding a TUI into a dedicated tui profile with a git-hosted spec and launching it with dsh --profile tui
  • Profiles compose configuration the same way — bundle patches, the profile patch, the home-level patch, then --patch overlays — and base-backed profiles resolve credentials from the environment, $DSH_HOME/.credentials.yaml, the invoking directory's .env, then $DSH_HOME/.env
  • Base-backed profiles default new sessions to the workspace-write permission preset; the standalone sdk-minimal tree instead pins danger-full-access

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 --patch overlays 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|update forwards to pnpm, and a dependency whose manifest declares a dsh.bundle.patch joins the layer stack automatically. Bundle membership changes land on the next profile start; patch-file edits hot-reload in live profiles.
  • 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-write in 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 standalone sdk-minimal tree 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.md or CLAUDE.md instructions 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.

Official references