DeepSeek's open-source agent harness where every capability — models, tools, sessions, even the agent loop — is a swappable plugin. CLI, profiles, patch layers and the gotchas that bite.
| Step | What to do |
|---|---|
| 1. Configure a model | Settings → Models, paste a DeepSeek API key, save. Takes effect on the next request — no restart. |
| 2. Choose a workspace | Click Choose workspace and add the project directory. The session composer stays disabled until you do — a fresh Web UI has no workspace selected. |
| 3. Run a task | Start a session and ask something. The agent reads and edits workspace files, runs commands, delegates work, and keeps a plan. |
- Harness developers — people building agent infrastructure, not just using an agent. The whole value proposition is that you can replace any layer.
- If you want a coding agent that works out of the box with no assembly, a finished product is a better fit. This is a framework with a reference application on top.
- Written in TypeScript, MIT licensed, and genuinely open source — no commercial tier gating the architecture.
- Plugins are discoverable via the
dsh-pluginGitHub topic.
| Group | Command | Does |
|---|---|---|
| Boot | dsh --profile <name> | Boot the profile at $DSH_HOME/profiles/<name>. |
| Boot | dsh web | Hardcoded alias for --profile web. Serves 127.0.0.1:3080. |
| Boot | dsh --profile headless "job" | One fresh persisted session, prints the final answer, exits. 0 on completion, 1 otherwise. |
| Web flags | --host / --port | Override the composed values. --host 0.0.0.0 is deliberately unsupported and exits with a usage error. |
| Web flags | --no-open | Skip the browser handoff. Auto-suppressed when SSH_CONNECTION or SSH_TTY is set. |
| Web flags | --trusted-host | Repeatable. Adds authorities accepted by the /api browser-trust fence. |
| Config | --patch <path> | Overlay a patch file. Repeatable; applied in argv order, last wins. |
| Config | --dump-default-config | Print only the bundle layers, without booting. |
| Config | --dump-config | Adds the profile and home patch layers plus --patch overlays. Comments name the file that supplied each row. |
| Plugins | dsh plugin --profile <n> add <pkg> | Forwards to pnpm in the profile directory. Every pnpm verb works — add, remove, why, update. |
| Plugins | dsh plugin --profile <n> add github:owner/repo | Git-hosted plugins. See the pnpm ≥10 allowBuilds gotcha. |
| Help | dsh --help | The launcher's help. dsh --profile web --help prints the web app's help and boots nothing. |
| Environment variable | Effect |
|---|---|
| DSH_HOME | Harness home — profiles, credentials, home-level patch layer. |
| DSH_TOOLS_MODE | native, code, or both. Any other value fails at boot. |
| DSH_PERMISSION_MODE | Changes the process-level permission fallback. |
| DEEPSEEK_API_KEY | Used by the built-in web_search tool. |
| DEEPSEEK_SEARCH_BASE_URL | Alternative search endpoint. |
| DSH_TELEMETRY_MODE | FULL streams every session event as OTLP/HTTP; FEEDBACK_ONLY uploads a log suffix when feedback is recorded. Read the privacy note before enabling. |
| DSH_TELEMETRY_DISABLED | Any non-empty value is an authoritative hard opt-out. |
| DSH_TELEMETRY_OTLP_URL | Point exports at your own collector. |
| NODE_USE_ENV_PROXY | Set to 1 so a supporting Node honours HTTP_PROXY / HTTPS_PROXY. |
| Concept | What it is |
|---|---|
| Profile | A named composition in the Harness home. Lists its bundles, holds out-of-tree plugins, keeps the user's patch. web and headless ship as templates and auto-initialise; any other name must be created via dsh plugin. |
| Bundle | A distribution format for config rows and the code they mount — so whatever it inserts stays patchable by layers above. |
| dsh-base | First layer of every profile: model adapters, tools, persistence, sandbox, approval policy, settings, credentials, telemetry. |
| dsh-web-app | Adds the browser application. |
| dsh-headless | One-shot runner with no server at all — no ApiProxy, Host, HTTP server or browser client, and it opens no listening port. |
| Step | One model request plus the tools it calls. |
| Turn | Zero or more steps. Opens before its first input is claimed, closes once nothing is owed. |
| Session log | Append-only SessionEvent record of everything the model saw. The traceability guarantee. |
ctx keyscore/session— append-only event log and in-memory store ·ctx.sessionscore/system-prompt— prompt-section and tool-schema assembly ·ctx.systemPromptcore/tools— scoped tool registry and guarded execution ·ctx.toolscore/agent— theAgentinterface, live registry,agent/*events ·ctx.agentscore/agent-loop— the default driver implementing that interface ·ctx.agentLoopllm/llm— message and stream vocabulary plus the adapter seam ·ctx.llmcore/scope— per-agent scoped registration. A library, noctxkey.
- Session events — durable facts appended to the log and broadcast via
session/event. Use when the fact must survive a reload. - Agent events (
agent/*) — carry a live agent: inbox, step, status, request, validation, continuation. Use to observe or intercept work in flight. - Capability events (
fs/*,tools/*,telemetry/*) — attach policy and adapters to a seam without importing the loop. - Registrations are reversible effects: they unwind when their plugin unloads.
- Picking the right event domain is the first decision in most changes.
- Settings → Models. The DeepSeek card takes one API key; changes apply on the next request without a restart.
- Add provider pulls endpoint, protocol and model list from the installed catalog — Anthropic, OpenAI and others.
- Add a custom provider for a company gateway or self-hosted server: lowercase Provider ID, base URL, API protocol, credential, at least one model. Fetch available models queries the endpoint you have typed.
- Keys are write-only. The page only ever receives a redacted descriptor; the secret lands in
$DSH_HOME/.credentials.yamland settings keep only a reference. - Resolution order: inherited environment →
$DSH_HOME/.credentials.yaml→ the invoking directory's.env→$DSH_HOME/.env. The managed document is never written intoprocess.env. - Bedrock, Vertex, Azure and Codex need native auth — AWS credentials and a region, an ADC project, an
api-version, and OAuth respectively. Filling only the API-key field does not configure them.
- New sessions default to the
workspace-writepreset. - Bash and filesystem mutations are restricted to the session workspace and platform temp roots. Reads and network access are not confined.
- Process visibility depends on the backend: bwrap uses a private PID namespace that hides host processes; Landlock and Seatbelt leave host process visibility unchanged.
- Stored General-settings permissions affect later Web sessions, not one already open.
- No MCP server is enabled by default — each server command is trusted executable code outside the agent sandbox.
@deepseek-ai/dsh-mcp-clientships as a dependency for patch layers to use.
- Codex and Claude Code are separate optional bundles, added and removed independently.
dsh plugin --profile <n> add @deepseek-ai/dsh-subagent-codexdsh plugin --profile <n> add @deepseek-ai/dsh-subagent-claude-code- On the next start each installed bundle registers only its dormant host provider — a copied preset must separately enable the matching tool row for new agents.
Gotchas
- Session telemetry stays local by default, which is the right default.
- But the shipped base has no telemetry redaction rule. If you explicitly enable exports, they can contain message text, tool arguments and results, and workspace paths.
- Do not turn on
DSH_TELEMETRY_MODE=FULLagainst a shared collector without thinking about what is in your sessions. DSH_TELEMETRY_DISABLED(any non-empty value) is a hard opt-out that outranks everything else.
- Bundle changes need a restart. A running profile keeps the bundle set it started with. Ordinary
cordis.patch.ymledits hot-reload; adding, removing or updating a bundle does not. - A patch replaces a row's whole
config, it does not deep-merge. Replacing a config with literals also removes any!!jsruntime read — which is how a CLI flag silently stops overriding it. - The home patch outranks the profile patch. Counter-intuitive if you expect the more specific layer to win.
- Git-hosted plugins fail on first install with pnpm ≥10. Their
preparescript is blocked until you copy the printedallowBuildskey into the profile'spnpm-workspace.yamland re-run. Built tarballs and local checkouts need no allowance. --host 0.0.0.0is intentionally unsupported and exits with a usage error.- Relative path specs anchor to the invoking directory, so
add .from a plugin checkout installs that checkout, not the profile. - Shutdown allows five seconds to dispose.
SIGTERMexits 0,SIGINTreports 130, a second signal forces immediate exit. - The launcher does not check artifact freshness — stale frontend bundles will happily run older browser code until you rebuild.
- Missing frontend bundles fail at startup telling you to run
pnpm run build; missing host artifacts fail earlier as bare module-resolution errors with no such hint.
Tips
dsh --profile web --dump-config prints the composed tree with comments naming the file that supplied each row and every overlay that changed it. It answers "why is this setting like that" instantly.
--dump-default-config shows bundles only; --dump-config adds your layers. Diffing them shows exactly what you changed versus what shipped.
A profile is just a package.json and a cordis.patch.yml. Given the preview status and promised breaking changes, keeping it in git is cheap insurance.
dsh --profile headless "task" opens no port, writes nothing to stderr on success, and exits 0 or 1 — a clean scriptable surface.
Every mode loads applicable AGENTS.md or CLAUDE.md from the workspace, with a 65,536-byte render budget.
The dsh-plugin GitHub topic is the discovery mechanism, and the convention for publishing your own.
Resources
packages/.
github.com
CLI behaviour reference
The authoritative source for layer precedence, flags, shutdown and deployment defaults.
github.com
Cordis
The plugin framework underneath. Worth reading first if the architecture feels opaque.
github.com
Community plugins
The dsh-plugin topic — discovery, and where to publish your own.
github.com
DeepSeek API
The models and pricing behind the default adapter — cache tiers and off-peak rates.
www.ty1er.com
Herdr
The other side of the problem — running several coding agents at once and knowing which is stuck.
www.ty1er.com