Architecture Overview
deepseek-harness (dsh) is the open-source AI agent harness from DeepSeek. The first sentence of the repository README states its design thesis:
DeepSeek Harness (
dsh)… It uses an architecture where everything is a plugin, and is powered by Cordis…
"Everything is a plugin" is not marketing copy here — it is an engineering constraint enforced at the repository-structure level. This page gives the full picture first, then drills down into the subsequent chapters.
Layered Overview
dsh is a pnpm monorepo, structured in five layers from top to bottom:
- CLI (
apps/cli): parsesdshcommand-line arguments and dynamically boots per mode (profile/plugin/dump-config). Entry point atapps/cli/src/bin.ts:27-52. - Web UI (
apps/web): the React half of the browser, communicating with the host half over RPC and rendering sessions, tool calls, and the Cordis plugin panel. - Cordis framework (
vendor/cordis): the runtime core; seven modules make up its entire public surfacevendor/cordis/src/index.ts:1-14. - Capability plugins (
packages/*): each capability domain (fs/shell/llm/mcp/session/…) is its own pnpm package + Cordis plugin, totaling 360+ packages. - Mode patch layer (
packages/bundle/*): uses YAML patches to compose plugins into "ready-to-use bundles" —baseis the foundation,headless/web-appare variants.
How "Everything Is a Plugin" Shows Up in the Repo Structure
The key evidence lives in the patch file of the dsh-base bundle. The following capabilities look "core" but are in fact all patch lines:
packages/bundle/base/cordis.patch.yml:15-45 is the head of the dsh-base bundle's insert list — timer / hmr / llm / session / typert / agent-default-model / jobs / settings are all mounted in the form - id: <stable>, with no "privileged module" anywhere.Even more pointed are "the five lines mounted by every mode" packages/bundle/base/cordis.patch.yml:420-451: tools / system-prompt / agent-loop / fs-sandbox / llm-deepseek are the baseline capabilities mounted by all modes; everything else overlays on top. This means you can fork any dsh-* package and replace it without touching the others — no "core service" is hardcoded into the binary.
Profile: The User's Private Plugin Composition
dsh does not hardcode the plugin list; it lives in the user's private profile directory:
initProfilecreates a pnpm workspace (pnpm-workspace.yaml) under the user directory.dsh plugin add <pkg>actually runspnpm add, writing the package into dependenciesapps/cli/src/plugin.ts:120-158.- After pnpm finishes,
reconcilePluginsdiffs before/after: newly-added deps that declaredsh.bundle.patchget pushed onto thedsh.profile.bundleslayer stack; removed deps, or new versions that no longer declare a bundle, get spliced outapps/cli/src/plugin.ts:59-91. - If the new package carries
dsh.bundle.patch, it is treated as a bundle layer and pushed onto the stackapps/cli/src/plugin.ts:36-45.
So "install a plugin" = install an npm package + reconcile the bundle layer stack, fully reusing pnpm's dependency management.
Layering Order of Patches
cordis.patch.yml is not an ordinary config file — it is a patch merged by layering:
Each patch line has four fields: id / name / config / disabled. Of these, disabled: !!js <expr> is the only metadata field that gets interpolated — it is evaluated against the loader context on every mount decision, so platform/environment differences (e.g. process.platform === 'win32') are routed here. !!js expressions are interpolated at mount time by @deepseek-ai/cordis-plugin-include, and process.env / dshHomePath(...) can be injected into them.
Origin of the Cordis Framework
Cordis was not rewritten by DeepSeek; it was vendored from cordiverse/cordis — the Cordis framework by Shigma, the author of Koishi, at version 4.0.1 (upstream 4.0.0-rc.7). DeepSeek rescoped it to @deepseek-ai/cordis and applied 18 local modifications, documented in vendor/README.md, mainly:
- lifecycle hardening in
cordis/src/fiber.ts(patching three reentrant disposal leaks) - regeneration of all package.json / tsconfig
- extracting
applyEntryPatchesininclude/src/index.ts+ durable debounced writes - removing the i18n YAML dependency in
hmr/src/index.ts disabled: !!jsinterpolation inloader/src/config/entry.ts
A number of upstream Cordis ecosystem packages were also vendored: cosmokit / schemastery / loader / include / group / timer / hmr / logger-console. This means understanding the dsh runtime is essentially understanding Cordis's context/registry/service/fiber model — which is exactly what the three Cordis framework chapters cover next.
What to read next
- Cordis Context — what Context, this root container proxied by Proxy, actually is
- Plugin Registry — the two systems of static and dynamic registration
- Plugin Loading and Discovery — how the Loader and pnpm cooperate