Let me start with context, so this doesn't read like another piece of marketing copy.
I've been hacking on an agent project for a while, and while shopping for a foundation I went through several frameworks — some so opaque you can't debug them, others where swapping a model adapter means editing core code. Last month I needed something whose capabilities come apart cleanly and where every step can be replayed, so I dove head-first into DeepSeek's open-source DSH (DeepSeek Harness) and spent a week chewing through the source plus its docs/architecture.md and AGENTS.md.
This isn't a restatement of the official intro. It's my own notes after reading, running, and face-planting. Here's DSH's one-line philosophy up front:
Agent = Model + Harness
The model is the soul; the harness is the shell that actually plugs it into the environment — files, shell, search, skills, sessions, sandbox, scheduling, UI, all hanging off of it.
What actually won me over wasn't that one-liner, though. It was the two rules baked into its bones: everything is a plugin and every run is traceable. More on both below — everything here is verified by me.
What it actually is: an agent shell, not a chatbot wrapper
Start with what it is not: DSH is not another chatbot skin. It's a harness that wires a model into a real environment.
Underneath it runs on the Cordis kernel (github.com/cordiverse/cordis), and every capability lives on a node of a "plugin tree." I assumed that was just fancy talk for "everything is a component" — until I read the source and confirmed that the model, tools, skills, sessions, sandbox, storage, loop, scheduling, and UI are none of them hardcoded in the core. They're all composed from plugins and swappable from config, without touching DSH itself.
By capability count, DSH ships four shapes. Day to day I live in Standard and Code:
- Standard — the full toolset: file editing, shell, search, skills, planning, subagents, workflows.
- Code — built on Standard, but tools are exposed through the Code Mode SDK, so the model can orchestrate multi-step operations inside a single TypeScript program. Delicious for coding agents.
-
Minimal — the bare-bones shape with only persistent bash and
str_replace_editor. This is for model benchmarks, not for your daily driver. - Creator — a workbench for authoring custom agent presets, with runtime checks and preset-writing guidance.
The two rules I only believed after reading the source
Both of these are shouted from the website and the README. But you only know they're real once you've tripped over them and gone digging.
Rule one: everything is a plugin
This is the most counterintuitive and the most elegant part. In other frameworks, swapping a tool provider or a model adapter usually means going spelunking through core code. DSH's core design is: capability seam = Service Definition + Service Provider + Consumer, and you need all three.
I specifically went to verify a claim that sounded exaggerated — that swapping out one fs provider moves the entire Bash / PTY / LSP stack into a remote sandbox. After reading how the plugin tree mounts things, it really is just: provide another Provider, point at it in config, and the capability moves. That's what "everything is a plugin" looks like as engineering: changing model, sandbox, or storage is a matter of changing one Provider, not a rewrite.
Rule two: every run is traceable
Model-visible ⟺ logged
Meaning: anything that reaches a model request — system prompts, reasoning, tool calls and results, subagent dispatch, context injection — must be reconstructible from a single append-only session log. In the Trajectory view you can audit each entry by source; resume, fork, search, and replay all ride on that same event stream.
In plain words: debugging an agent finally stops being guesswork. What it saw at each step, which tool it called, what came back — all of it is on the record. For an agent that's expected to keep working in a real environment, traceability isn't a nice-to-have; it's the engineering seatbelt. Without it you're stuck forever in the black box of "why did it get it wrong this time."
Getting started: two traps cost me half a day
Regular users need one line:
npx @deepseek-ai/dsh --profile web
# equivalent
npx @deepseek-ai/dsh web
If you want to modify source, clone it. I went the source route and tripped on step one:
git clone https://github.com/deepseek-ai/deepseek-harness
cd deepseek-harness
pnpm install
pnpm dsh web # web is an alias for --profile web; source runs directly via tsx
There's no global dsh command in the source repo — you launch it with pnpm dsh <subcommand>. pnpm dsh web is equivalent to pnpm dsh --profile web, and it's currently the only profile with a dedicated alias.
Two traps I personally ran into, so you don't have to:
-
Cannot find module 'node:sqlite', or pnpm complaining it "requires at least Node.js v22.13" — your Node is too old. Use v22.19+ or ≥24; v20 is simply not enough, since it relies on newer modules. -
Cannot find module '.../typert.host.js', or a startup error ofclient bundles not found— I had to runpnpm run buildonce (tsc emits lib/types, tsdown bundles the runtime) before it would come up. In theorypnpm dsh webruns source directly through tsx, but on a first run with missing client bundles, a build saves the day.
That's it — two traps, half a day gone.
Installing plugins: the "small thing" that wrecked me
DSH has no hot reload — plugin add only writes the plugin layer into the profile's on-disk config; a running server won't pick it up. So installing a plugin is a fixed sequence:
# 1) Ctrl+C the server first
# 2) install the plugin (works while the server runs, but nothing hot-loads)
pnpm dsh plugin --profile web add "github:NanmiCoder/dsh-auto-mode#main"
pnpm dsh plugin --profile web add "github:zhu1090093659/dsh-web-ui#main"
# 3) verify the bundle layer got mounted
pnpm dsh --profile web --dump-config
# 4) start it, with --patch (mandatory!)
pnpm dsh web --patch
Two hard-won lessons, learn them by heart:
- Installing a plugin edits the on-disk config; a running server won't load it — you must restart. The first time I installed one, I went looking for the new feature in the UI and found absolutely nothing.
-
You must start with
--patch. This is the one that really bites:plugin addreports success, but if you start without--patch, a bunch of plugins and skills simply won't activate — while everything still looks installed. Wasted effort.
To try a layer temporarily without installing it: npx @deepseek-ai/dsh web --patch ./cordis.patch.yml.
A few truths hiding behind those commands (confirmed by reading source and actually doing it):
-
dsh plugin --profile web add xxxisn't DSH installing a package itself — it forwards the remaining arguments verbatim to pnpm, equivalent to runningpnpm add xxxinside the profile directory. - The profile directory defaults to
~/.dsh/profiles/<name>/(on Windows:C:\Users\<user>\.dsh\profiles\<name>\). Usingwebas an example: after installing a plugin, new packages appear underdependenciesinpackage.json, anddsh.profile.bundlesregisters a layer automatically — which is why--dump-configcan see it. - If you install a marketplace UI entry (
dshmarket), the entry isn't a standalone page — it lives under Settings → Plugin Marketplace. The host needs to be ≥ 0.1.0-rc.6 for it to show up.
Command cheat sheet:
# install / remove / inspect dependencies
pnpm dsh plugin --profile web add <package>
pnpm dsh plugin --profile web remove <package>
pnpm dsh plugin --profile web why <package>
# start different profiles
pnpm dsh web # alias for the web profile
pnpm dsh --profile headless "your task" # headless, one-shot task
# inspect config
pnpm dsh web --dump-config # fully composed config tree
pnpm dsh web --dump-default-config # defaults, without your overrides
The plugin ecosystem: what I installed and how it feels
The marketplace is already busy. After installing dshmarket locally, the real marketplace shows up in DSH Local Builder's settings: dsh-market v1.24.0, with tabs for Discover / Themes / Installed / Advanced, and filters covering UI enhancement, themes & appearance, model & account access, tools & capabilities. The cards list things like dsh-web-ui-all, DSH-better-sidebar, modlens, dsh-vision-router, and dsh-vision-toolkit — all genuinely installable, not just names from docs.
Community plugins worth installing:
- dsh-web-ui / dsh-web-ui-all — the full UI bundle: task board, Git graph, sidebar, terminal, token stats, skins. Installing this is a step change in how it feels.
-
dsh-auto-mode (strongly recommended) — manages safe automatic permissions for you, handling shell and file approvals far more safely than hand-editing
global.json. - modlens (900+ stars) — gives plain-text models "eyes" by turning images into structured text.
- dsh-agent-teams (898) — multi-agent collaboration.
- dsh-memory (73) — cross-session memory; this is where an agent's recall comes from.
Then there are ZhijiangTang's 14 zero-config tool plugins, which I'd call the best textbook on plugin development around — each 100–500 lines, pure JS with no native dependencies, usable right after npm i. A few high-frequency ones:
-
dsh-safeguard— intercepts dangerous commands (rm -rf,push --force) and secret leaks (AKIA/sk-/ghp_) before execution. A life saver. -
dsh-http— structured HTTP: status code, latency, size, Bearer/Basic auth, automatic JSON parsing. -
dsh-fmt— JSON/YAML/TOML/SQL formatting and validation, with errors reported down to line and column. -
dsh-handoff— one-click session export (decisions / done / not done / next steps). -
dsh-password— strong password and diceware passphrase generation, with entropy annotated.
Install the whole bundle in one go:
dsh plugin --profile web add dsh-safeguard dsh-http dsh-case dsh-fmt dsh-clipboard \
dsh-fetch-file dsh-jwt dsh-cron-parse dsh-pkg-info dsh-dead-links dsh-when \
dsh-handoff dsh-url-tools dsh-password
There are also vendor bridge plugins, such as @wxg-prc-cpg/dsh-weknora (Tencent WeKnora knowledge retrieval: semantic search, document reading, RAG). Those wire an existing product into DSH — high star counts, but they're "bridges," not capabilities built from scratch. Don't confuse the two in your head.
Permissions: one line of advice — don't hand-edit
I can't state DSH's permission config file path with any confidence (sources online contradict each other, and I'm not going to invent it). But in my testing, just installing the dsh-auto-mode plugin is by far the least painful route — it manages shell and file approvals for you, far more reliably than hand-editing config:
pnpm dsh plugin --profile web add "github:NanmiCoder/dsh-auto-mode#main"
Want to write your own? Here's the shortest path
I'm planning one myself, so here's the route I noted down:
-
Grab the scaffold —
ZhijiangTang/dsh-plugin-template;scaffold.shgenerates the skeleton in one command. -
Read the minimal example —
superfly/sprites-deepseek-plugin(a 169-line README that explains exactly howcordis.patch.ymlandindex.jscombine an MCP client with a skill). - Read all 14 tiny zero-config plugins closely — you can finish one in an afternoon, which beats reading docs.
A standard bundle looks like this:
my-dsh-plugin/
├── cordis.patch.yml # declares which dsh packages to mount + config
├── index.js # entry: resolves assets via import.meta.url, mounts dsh services
├── package.json
└── skills/ # optional: bundled skill resources
A few conventions the community agrees on: zero config, small single-package surface, normalized failure values (a failing tool returns a human-readable error instead of throwing), and every package self-checks. Tag your repo #dsh and the community directory picks it up automatically.
Before you touch the source, etch these in
If you plan to modify DSH itself (as I do, since I want to fold it into the agent project I'm building), here are the conventions you'll hit constantly. The full list lives in the repo's AGENTS.md:
- Every npm package is named
@deepseek-ai/dsh-<name>; ESM everywhere ("type": "module"). -
Registrations are effects — every contribution goes through
ctx.effect()/ctx.on(). -
Waterfall listeners MUST call
next()— skip it and you short-circuit the whole chain. Reading the docs didn't make this click; crashing did. - Misconfiguration fails loud — if it can be self-contained, fail at load time, never silently skip.
- Exactly one trailing newline at end of file;
git diff --cached --checkis the pre-commit gate.
Closing thoughts
What made DSH click for me wasn't that it has the most features. It's that it treats composability and traceability as first-class citizens rather than retrofitted patches.
Whether a system can grow depends on how clean its seams are. DSH's Service Definition / Provider / Consumer trio leaves a whole rack of standard slots for an agent — swapping model, sandbox, or storage is a one-Provider change. Add the "model-visible means logged" seatbelt on top, and together they're what move it from "yet another framework" to "something I'd bet my project's foundation on."
Next step: I want to wire that local TencentDB Agent Memory into DSH as a callable tool and run a real end-to-end scenario. I'll write it up once it actually works.
Entry points if you want to keep digging:
- Official repo: https://github.com/deepseek-ai/deepseek-harness
- Website: https://deepseek.com/harness/en/
- Developer docs: https://deepseek-harness.github.io/deepseek-harness/en/guide/quickstart
- Plugin marketplace: https://dshhub.org/ (9,400+ plugins, continuously scanned)
- Cordis kernel: https://github.com/cordiverse/cordis
原文发表于 沐沐ai专题
关注「沐沐ai专题」公众号,获取更多 AI 实战干货

Top comments (0)