DeepSeek-Harness Architecture: What "Everything Is a Plugin" Means
How DeepSeek-Harness implements tools, commands, skills, MCP, hooks, and permissions as one mechanism, with the capability-seam pattern and packages panorama.
DeepSeek-Harness's tagline is "everything is a plugin," and it's a testable claim, not marketing: every product feature — tools, slash commands, skills, MCP bridging, hooks, model adapters, permissions, background jobs, subagent delegation — is implemented by a plugin registering against a Cordis Context, with no parallel manifest format for any of them. This guide walks the actual feature-to-mechanism map and the packages/ tree that backs it.
The claim, made checkable
dsh's own developer cookbook documents a feature → mechanism table, mapping each product capability to exactly how a plugin implements it:
| Capability | Implemented as |
|---|---|
| Tool | ctx.tools.register(); schema is auto-assembled into the model prompt |
Command (human command, /xxx) | ctx.commands registration; never becomes a model message |
| Skill | Registers a prompt section plus a tool; content is injected into context when invoked |
| MCP | One plugin per MCP server: discovers its tools, then calls ctx.tools.register() (see our MCP guide) |
| Hook | Listens on lifecycle extension points (agent/session-start, agent/pre-step, tools/pre-execute, session/event); see our hooks and commands guide |
| Model adapter (LLM) | An LlmAdapter subclass registered via ctx.llm.registerAdapter() |
| UI / Web Client node | Listens on session/event, or registers a ConversationNodeDefinition to add a node to the built-in Web UI |
| Permissions / sandbox | Returns allow/deny/ask from tools/pre-execute; backed by ctx.sandbox |
| Background/scheduled job | Registered on ctx.jobs; timers fire a followup(..., {source: {kind: 'cron'}}) |
| Subagent delegation | Registered on ctx.subagents, a named provider registry (see our subagents guide) |
The point of this table isn't trivia — it's that Skill, Command, Hook, and MCP bridging, which have separate manifest formats and directory conventions in some other harnesses, are all the same mechanism used differently in dsh. There's no independent classification system or registration file schema per capability type.
Capability seams: the atomic unit underneath the table
Each row above is a capability seam — the naming dsh's glossary gives to a complete, replaceable unit made of a Service Definition, one or more Service Providers, and one or more Consumers. packages/shell is the canonical worked example:
- Service Definition:
dsh-shelldefines theShellExecutorabstraction as a CordisService. - Service Providers:
dsh-bash-localanddsh-bash-sandboxare two interchangeable concrete implementations — one runs commands directly, the other inside a sandbox. - Consumer:
dsh-tool-bashinjects the service and exposes it to the model as a tool.
Swap the provider (local vs sandboxed execution) and every consumer built against the seam keeps working unmodified, because they only depend on the abstract ShellExecutor interface, not a specific implementation. This pattern — define an abstract service, register interchangeable providers, let consumers inject without caring which provider is active — repeats across essentially every capability in the table above. For the Cordis primitives (Context, Service, inject, Fiber lifecycle) that make this pattern work mechanically, see Cordis explained.
A tour of the packages/ tree
dsh's packages/ directory has roughly 150 sub-packages. Grouped by capability domain, the major ones:
| Domain | Representative packages | What it covers |
|---|---|---|
| LLM adapters | llm-deepseek, llm-pi-ai, llm-retry | DeepSeek's official chat-completions adapter, plus a design-validation "twin" adapter and cross-provider retry logic |
| MCP | mcp/mcp-client | Client-role bridging of external MCP servers' Tools |
| Skill | skill, skill-filesystem, skill-badge | The skill provider registry plus a local-filesystem provider and a built-in "badge" skill |
| Subagent | subagent, subagent-claude-code, subagent-codex, subagent-acp, subagent-dsh-sdk, subagent-fork-in-process, subagent-spawn-in-process | Delegation to in-process sessions, external agents over ACP, or officially to Claude Code / Codex |
| Hooks bridge | hooks-claude-code, hooks-codex | Reuse existing Claude Code / Codex hooks.json shell-hook configs |
| Sandbox | sandbox-local, sandbox-policy, sandbox-windows-acl | Linux bwrap/Landlock, macOS Seatbelt, Windows ACL restricted-token backends |
| Web access | web-search-exa, web-search-perplexity, web-search-deepseek, web-fetch-http | Pluggable search providers plus an anonymous public HTTP(S) fetch provider |
| ACP | acp/acp | An "automation-only" ACP server for external GUI/orchestration clients |
| SDK | sdk/client, sdk/server, sdk/protocol | TypeScript SDK plus the shared stdio JSON-RPC protocol also used by the Python SDK |
| E2B cloud sandbox | e2b/e2b, e2b/fs-e2b, e2b/subprocess-e2b | Swaps local execution for E2B's cloud sandbox environment |
| LSP | lsp/lsp, lsp/lsp-stdio, lsp/tool-lsp | Language-server capability seam (ctx.lsp) for definition/references/hover |
| Terminal | terminal/terminal, terminal/tool-terminal | Persistent PTY session seam with owner-scoped IDs |
| Workflow | workflow/workflow, workflow/tool-ralph | A general workflow engine plus the Ralph loop tool |
| Goal | goal/goal, goal/command-goal | Persistent completion goals attached to a session |
| Session persistence | session-persistence-jsonl, session-persistence-sqlite | Two selectable on-disk session formats |
| Telemetry | session-telemetry, session-telemetry-otel | OTLP export, off by default |
This isn't an exhaustive list — it's the domains that matter most for understanding what "microkernel" means in practice: the core boot process is small, and essentially every feature you'd recognize as "part of dsh" is one of these ~150 packages loaded as a plugin, not something baked into a monolithic core.
What this buys you
- One lifecycle for everything. HMR, dependency resolution, and automatic cleanup on unload (via
ctx.effect()) apply identically whether you're building a tool, a hook, or a full UI panel — you learn Cordis once and it covers every feature category. - No manifest zoo. There's no separate schema to learn for skills vs commands vs hooks vs MCP — one plugin registration pattern covers all of them, which keeps the mental model small once you've internalized it.
- Swappable implementations by design. The capability-seam pattern (service + interchangeable providers + consumers) means things like sandboxing backend, memory storage, or search provider can be swapped without touching consumer code.
What it costs you
- Everything looks like the same shape from the outside. A tool registration and a hook registration both start as
apply(ctx) { ... }— you need to actually read what's inside to know which capability a given plugin provides, since there's no directory-naming or manifest convention that tells you at a glance (unlike, say, askills/folder withSKILL.mdfiles in some other harnesses). - You need Cordis literacy for any single feature, not just advanced ones. Because there's no shortcut manifest to skim, understanding even a simple hook requires understanding
Context/inject/lifecycle at a basic level — see Cordis explained for the primitives. - Coming from a harness with per-capability manifests can feel disorienting at first. If you're used to Claude Code's separate skills/commands/hooks/MCP manifest conventions, dsh's single mechanism takes a bit of relearning — see migrating from Claude Code for a direct mapping.
FAQ
Is "everything is a plugin" just marketing language?
No — it's checkable against the actual feature-to-mechanism table above. Every listed capability genuinely is implemented as a plugin registration against ctx, with no separate manifest format hiding underneath.
What's the smallest unit of "a feature" in dsh's architecture?
The capability seam — one Service Definition, its Provider(s), and its Consumer(s). Individual plugins are usually one of these three roles, not the whole seam by themselves.
Does "everything is a plugin" mean I can remove core features?
In principle, yes for anything implemented as a swappable plugin — that's the point of the design — but base bundles wire in the plugins most profiles need by default, so removing one usually means replacing it with an alternative, not running without it.
How many packages does dsh ship?
Roughly 150 sub-packages under packages/, spanning the domains in the table above — LLM adapters, MCP, skills, subagents, sandboxing, SDKs, and more.
Where do I start if I want to build on this architecture?
Start with a single tool or hook, since both use the same basic Context/apply() pattern — see the plugin development primer and Cordis explained for the primitives underneath.
Next steps
For the framework primitives (Context, Service, inject, Fiber lifecycle) that make this architecture work, read Cordis explained. For how MCP and hooks specifically fit into this same mechanism, see the MCP guide and hooks and commands guide. For terminology, check the glossary, and for how this compares to Claude Code's separate-manifest design, read DeepSeek-Harness vs Claude Code.