Skip to content
Agentic Control Plane

dsh harness: DeepSeek Harness commands and config reference

David Crowe David Crowe · · Updated · 14 min read
dsh cli reference
Share X HN LinkedIn

dsh is the command for DeepSeek Harness. Start it with npx @deepseek-ai/dsh web for the browser UI, or dsh --profile headless "run the tests" to run one task from a script. Everything else on this page builds on one idea: a profile, which is an ordered stack of plugin bundles plus your own overrides, booted by one launcher.

DeepSeek Harness is in developer preview, and the README warns that breaking changes will come. The flags below come from the repository’s generated CLI help as of 2026-11-06. Run dsh --help on your version to confirm.

Install and launch

You need Node.js 24.9 or newer. The Node 24 upgrade guide dropped Node 22 support; older pages, including ours from launch week, say 22.

node --version            # must report 24.9 or newer
npx @deepseek-ai/dsh web  # starts the Web UI and opens it in your browser

Pass --no-open to serve without opening a browser. Over SSH, dsh prints the URL instead of opening it.

From source, per the README:

git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
pnpm install
pnpm run build
pnpm dsh web

The directory you launch from is the default workspace root. A fresh Web UI still asks you to pick a workspace before the composer unlocks.

The launcher and --profile

dsh [--profile] <name> [options] [app-args...]
dsh plugin --profile <name> <pnpm-args...>

dsh web and dsh --profile web are the same thing. The launcher parses its own flags, and the first token it does not recognize starts the profile’s own arguments, so dsh --profile web --port 8080 hands --port to the web app.

Launcher flag What it does
--profile <name> Boot the profile under $DSH_HOME/profiles/<name>
--from-default-profile <template> Replace a custom profile with a fresh copy of a shipped template, then boot it
--patch <path> Apply an extra patch overlay after the profile layer (repeatable)
--dump-config Print the composed profile tree and exit
--dump-default-config Print the tree without your user layer or --patch overlays
--dump-config-schema Print JSON Schema for profile entries and patches without mounting
-V, --version Print the version

Shipped profiles, per the CLI README:

Profile Purpose
web Browser UI
headless One task, answer to stdout, then exit
sdk, sdk-minimal SDK clients over JSON-RPC stdio
acp Editor clients over Agent Client Protocol stdio

These five initialize on first use. The name desktop is reserved for the desktop app, and the CLI refuses to boot it. To make your own profile from a template:

dsh rescue --from-default-profile web   # "rescue" is the new profile's name, not a subcommand

dsh acp here is Zed’s Agent Client Protocol for editors. It has nothing to do with the Agentic Control Plane. Which ACP is which sorts that out.

Where config lives

$DSH_HOME defaults to ~/.dsh.

Path Holds
$DSH_HOME/profiles/<name>/package.json Out-of-tree plugin dependencies and the dsh.profile manifest with its ordered bundles list
$DSH_HOME/profiles/<name>/cordis.patch.yml Your patch layer for that profile; the Web UI’s settings write here
$DSH_HOME/cordis.patch.yml A home-level patch applied to every profile
$DSH_HOME/.credentials.yaml API keys saved through the Models page

Layers compose in this order, last wins: each bundle’s patch in bundles order, then the profile’s cordis.patch.yml, then the home cordis.patch.yml, then any --patch overlays. With HMR on, which the shipped profiles use, edits apply live. Without it, restart.

Before you trust a change, check what actually mounted:

dsh --profile web --dump-config

The config catalog lists every plugin’s fields and defaults.

Choosing the model

The launcher has no model flag. Models are configured per profile, per the model configuration guide:

  1. Open Settings → Models in the Web UI.
  2. Paste a DeepSeek API key, or choose Add model provider for a shipped provider such as anthropic, openai, moonshotai or zai, or a Custom model API for a gateway that speaks OpenAI Chat Completions, OpenAI Responses or Anthropic Messages.
  3. Pick a model in the model picker. That also makes it the default for new sessions.

A session that has already sent a request keeps the model recorded in its own log. The API-key DeepSeek adapter’s credential reference defaults to DEEPSEEK_API_KEY.

For hand edits, the providers live in $DSH_HOME/profiles/<profile>/cordis.patch.yml, the same file the page writes. For dsh web that is $DSH_HOME/profiles/web/cordis.patch.yml. The default model is a plugin row with three fields, provider, model and an optional reasoningEffort.

The tool set

The tool catalog is generated by booting each tool plugin. The core names the model sees:

Area Tools
Shell bash (Linux, macOS), pwsh (Windows)
Files read, write, edit, apply_patch, read_image, str_replace_editor
Search glob, grep (bundled ripgrep, no host rg needed)
Web web_fetch, web_search
Delegation subagent, list_subagent_models, send_message, wait_agent, list_agents, interrupt_agent
Background jobs job_list, job_output, job_kill
Planning todo_write, exit_plan_mode, ask_user_question
Code Mode run_code, which runs a program whose sub-calls go through the same tool pipeline
Plugins plugin_manager, plugin_market

Which tools a session gets depends on the profile’s bundles. apply_patch, for example, registers only when its plugin is configured with applyPatch: true. MCP tools appear as mcp__<server>__<name> and run through the same pipeline. How that pipeline can be intercepted is in the dsh hooks reference.

The sandbox

dsh confines shell commands with a file-write sandbox. The sandbox reference defines three modes:

  • read-only: writes denied. The documented default and fail-safe.
  • workspace-write: writes allowed under the workspace root, any extra directories you name, and the backend’s temp area.
  • danger-full-access: no confinement.

Backends: bwrap or Landlock on Linux, Seatbelt on macOS, a restricted-token ACL runner on Windows. Each reports its enforcement as full or partial; older Landlock versions and the Windows runner are documented partial cases. The modes cover file effects only. Network and process visibility are outside them.

In the UI you pick a permission preset, which pairs a sandbox mode with an approval policy. The presets reference ships two:

Preset Sandbox Approval
workspace-write workspace-write ask
danger-full-access danger-full-access never

The deployment default lives in the @deepseek-ai/dsh-sandbox-policy row, whose mode defaults to read-only. How approvals, presets and the session log fit together is covered in the dsh control model.

Installing plugins

dsh plugin --profile web add <package>
dsh plugin --profile web remove <package>
dsh plugin --profile web why <package>

dsh plugin forwards everything after the flags to pnpm, run inside the profile directory, and initializes the profile on first use. Two rules from the CLI docs:

  • Version checks. Installation and startup enforce the plugin’s engines.dsh range against dsh --version. A mismatch is refused unless you grant an explicit exact-version exemption, which the docs warn can crash or lose data.
  • No installing over an installed package with HMR. It now fails with already-installed. To upgrade, remove first, then add, per the upgrade note.

The agent can also manage plugins itself through the plugin_manager tool. Every action requires danger-full-access or an approval for that call, and changes apply to every session in the profile. Community plugins are tagged with the dsh-plugin topic on GitHub.

Headless use

dsh --profile headless "run the tests"
echo "run the tests" | dsh --profile headless
dsh --profile headless --json "run the tests"
dsh --profile headless --session-id <id> "continue"
dsh --profile headless --permission-mode workspace-write --add-dir /repo/.git "commit the fix"

The answer goes to stdout and diagnostics to stderr. Options:

Flag Effect
--json Newline-delimited run events on stdout instead of the final message
--session-id <id> Resume a persisted session; an unknown id is an error
--permission-mode <preset> Pick a configured permission preset for this task
--approval-policy ask\|never Override approval behavior after the preset
--add-dir <path> Allow writes to another absolute directory under workspace-write (repeatable)

A task argument of - reads stdin. With no approval service mounted, an ask resolves to deny rather than waiting forever; the controls page explains why that matters for unattended runs.

Common errors

Symptom Cause and fix
Boot fails with Promise.withResolvers is not a function or similar Node too old. Upgrade to 24.9 or newer.
MISSING_CREDENTIAL No key for the selected provider. Save it under Settings → Models or set the referenced environment variable.
UNKNOWN_MODEL The session names a model the provider does not list. Pick a configured model or add it to the custom provider.
Composer shows Select model and blocks input The saved default names a deleted provider. Pick another model.
Every request to a custom gateway is refused Request shape mismatch. Try compat.supportsDeveloperRole: false and compat.maxTokensField: max_tokens on the route.
already-installed on plugin add Remove the package first, then add the new version.
A plugin you added does not load Check --dump-config. On rc.6 we saw bare npx launches fail to resolve profile-installed plugins; a normal install or a --patch overlay by file path worked.
Shell writes fail with a permission error The session is running under read-only, the sandbox policy’s default mode. Switch the session to the workspace-write preset.

Limits

  • A stable interface. This is a developer preview. Flags, profile names and file layouts have changed since launch, including the Node requirement. Check dsh --help and --dump-config after every upgrade.
  • A full security boundary. The sandbox limits file writes. It does not restrict network access, and some backends report only partial enforcement.
  • Per-command rules. Core ships modes and presets, not allow and deny rules per command. Rules come from plugins on the tool pipeline; see the hooks reference.
  • The desktop app. It bundles its own runtime and owns the reserved desktop profile.

ACP has a dsh plugin that checks every dsh tool call, including custom plugins and Code Mode sub-calls, and logs it with your other coding agents (install guide). One gap as of 2026-11-08: when a rule says deny, the plugin reports it to the agent but does not stop the call. The fix is tracked. An ask is blocked and waits for your approval on the console or in the email, then dsh retries.

Frequently asked questions

What is the dsh harness?

dsh is the command for DeepSeek Harness, DeepSeek’s open-source coding agent harness, in developer preview. One launcher boots a profile, which is an ordered stack of plugin bundles plus your own overrides. dsh web starts the browser UI; dsh –profile headless runs one task and exits.

How does dsh --profile work?

dsh –profile boots the profile stored under $DSH_HOME/profiles/. The web, headless, sdk, sdk-minimal and acp profiles are created on first use from shipped templates. dsh --profile --dump-config prints the composed configuration without booting it.

How do I choose the dsh model?

In the Web UI, open Settings, then Models, add a DeepSeek API key or another provider, and pick a model in the model picker. The launcher has no model flag. The choice is saved to the profile’s cordis.patch.yml and becomes the default for new sessions.

How does the dsh sandbox work?

dsh wraps shell commands in a file-write sandbox with three modes: read-only, workspace-write and danger-full-access. read-only is the documented default. It uses bwrap or Landlock on Linux, Seatbelt on macOS and a restricted-token ACL runner on Windows. It confines file writes only, not network access.

How do I install a plugin in dsh?

Run dsh plugin –profile add . The plugin command forwards its arguments to pnpm inside that profile's directory, so remove and why work the same way. Plugins whose engines.dsh range does not match your dsh version are refused.

Where to read more

Running dsh? One command adds a native plugin. Each tool call is checked and recorded. A block is reported to the agent but not enforced by the plugin yet.

macOS · Linux · WSL
curl -fsSL https://agenticcontrolplane.com/install.sh | bash
Windows · PowerShell
irm https://agenticcontrolplane.com/install.ps1 | iex

What the installer writes  ·  dsh guide  ·  free up to 5 agents

Share X HN LinkedIn
Get the next data drop
What agents actually cost, new tool-surface captures, and the occasional incident post-mortem — sent when we publish something worth your inbox, not on a schedule. Unsubscribe anytime.
Share: Twitter LinkedIn
Related posts

← back to blog