dsh harness: DeepSeek Harness commands and config reference
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:
- Open Settings → Models in the Web UI.
- Paste a DeepSeek API key, or choose Add model provider for a shipped provider such as
anthropic,openai,moonshotaiorzai, or a Custom model API for a gateway that speaks OpenAI Chat Completions, OpenAI Responses or Anthropic Messages. - 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.dshrange againstdsh --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 --helpand--dump-configafter 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
desktopprofile.
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
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
Where to read more
- DeepSeek Harness repository and README
- dsh CLI help, generated
- CLI README: profiles and layering
- Configure models
- Process sandbox and permission presets
- Tool schema catalog and config catalog
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.
curl -fsSL https://agenticcontrolplane.com/install.sh | bash
irm https://agenticcontrolplane.com/install.ps1 | iex
What the installer writes · dsh guide · free up to 5 agents