← Home

Guide

DeepSeek Harness (dsh), Explained

DeepSeek open-sourced its agent harness on 13 August 2026, hours after the DeepSeek V4 Pro release. It is MIT-licensed, it runs from a single npx command, and it is a developer preview that says so in the README. This guide is written from the repository rather than the launch coverage — including the parts the coverage got wrong.

What DeepSeek Harness Actually Is

DeepSeek Harness (the command is dsh) is not a model and not an API client. It is an agent harness: the layer that connects a model to a filesystem, a shell, a code editor, the web and other agents, then records what it did and constrains what it may do. The repository describes its own architecture in four words — everything is a plugin — and it means it literally. The agent loop itself is a plugin.

It is built on Cordis, a microkernel whose design is published as a paper, A Programming Paradigm for Spatiotemporal Composability. A running harness is a Cordis context; packages register services, events and capabilities into it, and a configuration file decides which of them a given agent gets.

The practical consequence is that the shipped coding agent is the framework's first customer rather than its point. Filesystem, terminal, subprocess, PTY, language servers, web access, skills, subagents, workflows, plan mode, session persistence, settings, credentials and telemetry each live in their own package, behind their own interface.

Status check: the README states that DeepSeek Harness is in developer preview and that there will be compatibility-breaking changes. Treat anything you build on it — including the config shapes on this page — as provisional.

Install and Run It

Install Node.js, then run one command:

npx @deepseek-ai/dsh web

That starts the Web UI, served at http://127.0.0.1:3080 by default. The directory you ran it from becomes the default workspace root, but a fresh Web UI has no workspace selected — the session composer stays unavailable until you click Choose workspace and add one. That trips people up on first launch.

To run from a checkout instead:

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

Point It at a Model

Open Settings → Models and enter a DeepSeek API key. The route becomes usable immediately — no restart. Keys are write-only from the UI's point of view: after saving, the page only ever receives a redacted descriptor. The secret is stored in $DSH_HOME/.credentials.yaml, and your settings keep nothing but a reference to it.

Credentials resolve in a fixed order: the inherited environment, then $DSH_HOME/.credentials.yaml, then the invoking directory's .env, then $DSH_HOME/.env. The managed credentials document is never materialized into process.env.

Other providers work through Add provider (Anthropic, OpenAI and the rest of the installed catalog) or Add a custom provider for a company gateway or self-hosted endpoint, where you supply a provider ID, base URL, protocol, credential and at least one model. Two things worth knowing before you fight them:

  • The provider ID is permanent. Requests, saved sessions, model defaults and credential references all key off it. Renaming means adding a new provider and deleting the old one.
  • A hand-entered model is text-only until it says otherwise. Nothing can ask an endpoint which modalities it accepts, so attaching an image is refused before it is sent. Give the model input: [text, image] in $DSH_HOME/settings.yaml — the form has no field for it.
llm-pi-ai:
  providers:
    my-gateway:
      apiKeyEnv: GATEWAY_API_KEY
      api: openai-completions
      baseURL: https://gateway.example/v1
      models:
        - id: legacy-chat
        - id: vision-preview
          input: [text, image]

DeepSeek's own chat-completions route is text-only and cannot be configured otherwise.

The Four Agent Presets

The Web UI ships four presets. They are not four separate agents and not four prompt styles — they are four compositions mounted on one shared host, so the model route, session persistence, sandbox and approval stack stay identical while the tools and prompt sections change.

Preset IDShipped labelWhat it composes
standard标准模式The full coding agent: file editing, shell, file and web search, skills, plan, goals, subagents and workflows.
codePTC 模式Everything in standard, but tools are presented through the Code Mode SDK so the model writes one TypeScript program instead of many round-trips.
minimal极简模式Two tools only — persistent bash and str_replace_editor — with a fixed one-line system prompt and no context compaction.
cordis创造模式Standard plus runtime inspection, temporary plugin experiments and preset-authoring guidance. The agent can reshape its own runtime, so it is a high-trust mode.

Yes, those labels are Chinese in the shipped preset descriptors, in an otherwise bilingual repository. If you are reading English docs and hunting for “Standard” in the UI, that is why. The directory names — standard, code, minimal, cordis — are what the code actually keys on.

The minimal preset is the clearest illustration of the architecture. Its whole system prompt is the single sentence You are a helpful software engineer assistant., runtime context snapshots are suppressed, context compaction is absent, and the model gets exactly two tools: a persistent bash and str_replace_editor. Everything else in the harness is still running — it is simply not composed into that agent.

Profiles: How Configuration Actually Layers

Most launch write-ups describe a single cordis.yml. The shipped CLI is more specific than that. dsh is a launcher for profiles: ordered stacks of plugin-bundle patch layers with your own overrides on top.

CommandWhat it does
dsh webAlias of --profile web. Starts the Web UI on http://127.0.0.1:3080. Auto-initializes on first use.
dsh --profile headless "run the tests"One fresh persisted session. Prints the final assistant message and exits 0 on completion, 1 otherwise. Opens no port. Built for CI.
dsh --profile <name>Boot any profile under $DSH_HOME/profiles/<name>. Anything other than web and headless must be created first.
dsh plugin --profile <name> add <pkg>Install an out-of-tree plugin bundle into a profile by forwarding to pnpm in that profile directory.

The effective tree composes over an empty root in this order:

  1. each bundle patch named in the profile manifest's dsh.profile.bundles list
  2. the profile's own cordis.patch.yml
  3. the home-level $DSH_HOME/cordis.patch.yml, which outranks the per-profile layer
  4. each --patch <path> overlay, in argv order
The gotcha worth writing down: a patch replaces the targeted row's complete config value rather than deep-merging keys. Write one new field and the API key, base URL and everything else on that row disappear with it. It is consistent, and it is not what most people expect on their first patch.

A related trap: some shipped rows read runtime services through expressions, such as port: !!js ctx.webStartup.port ?? 3080. Replace that whole config with literals and you have quietly removed the runtime read, so the command-line flag stops beating the file. Use --dump-default-config and --dump-config to inspect the composed tree without booting it.

Bundle names 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 pnpm-managed node_modules.

The TUI Is Not Bundled

Coverage of the launch tends to list “Web, TUI, headless and SDK” as four shipped front doors. Three of those are in the box. The terminal UI is an out-of-tree plugin you install into a profile you create yourself:

dsh plugin --profile tui add github:deepseek-harness/turtle-ui
dsh --profile tui

Only web and headless auto-initialize from shipped templates on first use. Any other profile name fails loudly with a hint to install a bundle into it first.

Sandbox and Approvals

A coding agent with shell and filesystem access can modify code, install dependencies and start processes. DeepSeek Harness treats that as an architecture problem rather than a confirmation dialog. Filesystem effects are governed by a sandbox mode:

ModeEffect
read-onlyThe backend denies writes. POSIX runners still grant the /dev/null sink their shells need.
workspace-writeWrites permitted under the workspace root and the backend’s promised temp area. This is the default, paired with the ask approval policy.
danger-full-accessConfinement bypassed entirely, paired with the never approval policy. The deployment has to choose it explicitly.

Enforcement is platform-specific: bwrap and Landlock on Linux, Seatbelt on macOS, and an ACL restricted-token backend on Windows. It is also a reported fact rather than an assumption — a backend reports full or partial enforcement, and older Landlock ABIs and the Windows ACL runner's boundaries are current partial cases. The seam is fail-closed by design: a runner must return enforcing arguments or fail, and silently passing an unconfined command through is forbidden.

The permission selector you see in the UI bundles two independent knobs — sandbox mode and approval policy — into named presets. The default table ships workspace-write (workspace-write + ask) and danger-full-access (danger-full-access + never).

One security decision deserves a callout because it runs against the industry default: no MCP server is enabled out of the box. The MCP client ships as a dependency for patch layers, but each server command is trusted executable code living outside the agent sandbox, so enabling one is your explicit act. Compare that to how most agent runtimes ship MCP.

The Session Log Is the Source of Truth

The rule the project sets itself is that anything the model saw must be reconstructable from the log. User messages, runtime context, model request metadata, streaming chunks, tool calls and results, compaction events, permission switches and cancellation reasons all append to one event stream. The UI, persistence, resume, fork, telemetry and replay all derive from that single source instead of each keeping its own approximately-correct copy.

This answers a question most agent stacks answer badly: when a run goes wrong, what did the model actually see? If a system stores only the final chat text, the workspace snapshot injected before the request, the truncated tool result, the silent model reroute and the mid-stream steering message are all gone. Persistence is itself a plugin, with JSONL and SQLite backends; resume continues the original session, and fork branches from a definite historical boundary.

Automation: Headless, ACP, JSON-RPC and Python

For CI, dsh --profile headless "run the tests" runs one task, waits for the agent to fully settle, prints the last non-empty assistant message on stdout and exits — 0 when the turn completed, 1 otherwise. The headless profile mounts no HTTP server, no web runtime and no browser client, and a clean run opens no listening port.

For programs that need structured events and continuous control, there is an ACP service and a JSON-RPC entry point. The Python SDK drives the bundled JSON-RPC runtime, so a Python application can start sessions, send tasks and receive notifications without embedding the Node core:

python -m pip install deepseek-harness-sdk
export DEEPSEEK_API_KEY=sk-your-key-here
# export DEEPSEEK_BASE_URL=http://127.0.0.1:8000/v1   # OpenAI-compatible proxy
# export DSH_MODEL=deepseek-v4-flash

The SDK needs Python 3.10+ and ships its own same-version runtime, so no system Node.js is required. Supported platforms are Linux x64, Linux arm64, and macOS 14+ on arm64.

What It Does Not Do

DeepSeek Harness is a coding harness that runs on the machine you are sitting at. That framing explains its gaps honestly:

  • No messaging channels. There is no Telegram, Discord, WhatsApp or WeChat surface. You talk to it through a local Web UI, a terminal, or code.
  • It is not always on. Close the laptop and the agent stops. Nothing is waiting to answer a message at 3am or run a scheduled job.
  • It is a developer preview. The README promises breaking changes, and the repository is moving fast enough that config shapes will drift.
  • It expects a workspace. The whole design assumes a checked-out project directory to read, edit and run commands in.

None of those are criticisms — they are the shape of the thing. They just describe a different job from an always-on personal agent.

DeepSeek Harness vs. a Hosted Agent

These are complements, not competitors. Use dsh when you want a model refactoring a repository you have open. Use a hosted agent when you want something that answers you on Telegram while your laptop is shut.

AspectDeepSeek HarnessOpenClaw Launch
What it isAn SDK and app framework for building agentsA hosted, always-on personal agent
Where it runsYour machine, while you have it openA dedicated container, 24/7
InterfaceLocal Web UI, terminal, headless, ACP/JSON-RPCTelegram, Discord, WhatsApp, WeChat, web chat
SetupOne npx command, then a config file per profileA visual form, then Deploy
Model choiceDeepSeek by default; any OpenAI-compatible endpointModel picker, BYOK, or OpenRouter
Best atCoding in a repository you have checked outAnswering you wherever you already chat
MaturityDeveloper preview — breaking changes promisedProduction

The models are the same either way. If you liked what V4 Pro or V4 Flash did inside dsh, you can point a hosted OpenClaw agent at the same models — from the model picker, with your own DeepSeek API key, or through OpenRouter. See running DeepSeek V4 Pro on OpenClaw and V4 Flash on OpenClaw.

Frequently Asked Questions

Is DeepSeek Harness free?

The harness is free and open source under the MIT license. Model inference is not — you supply an API key, and you pay whichever provider serves the model.

Is DeepSeek Harness a model?

No. It is the runtime around a model. It ships with a native DeepSeek adapter and connects to Anthropic, OpenAI and any OpenAI-compatible endpoint through its provider catalog or a custom provider.

How do I install DeepSeek Harness?

Install Node.js and run npx @deepseek-ai/dsh web. The Web UI serves at http://127.0.0.1:3080. Then open Settings → Models, add an API key, and select a workspace before starting a session.

Does DeepSeek Harness support MCP servers?

Yes, but none is enabled by default. The MCP client ships as a dependency for patch layers; you enable a server deliberately, because each server command is trusted executable code that runs outside the agent sandbox.

Can DeepSeek Harness reply on Telegram or WhatsApp?

No. It has no messaging-channel surface. It is reached through its local Web UI, an installable terminal UI, a headless one-shot command, or the ACP / JSON-RPC / Python interfaces. A hosted agent is the right tool for chat platforms.

Is it production-ready?

Not yet, by its own account. The README labels it a developer preview and states in capitals that there will be compatibility-breaking changes.

What's Next?