dshseek

seek://guides/what-is-harness

What is DeepSeek Harness?

Aug 14, 2026Beginner← All guides

TL;DR

DeepSeek Harness (dsh) is DeepSeek's open-source agent framework where every capability — model access, tools, sessions, even the agent loop itself — is a plugin with no privileged core. This guide explains the harness concept, walks one turn through the system, and shows why the session log invariant 'model-visible means logged' makes the whole thing auditable.

Key points

  • dsh is an agent harness: the chassis around a model loop — model adapters, tools, sessions, permissions, UI
  • Everything is a plugin; there is no privileged core to fork, you extend by mounting plugins beside the rest
  • A turn is one drain of admitted input; a step is one model request plus its tool calls
  • The session log is the single source of truth: anything a model sees must be reconstructable from it
  • Capability seams (definition / provider / consumer) let one provider swap move whole feature families

$ dsh –what-is-this

Every few weeks a new agent framework ships, and every one of them eventually hits the same wall: the model is the easy part. The hard part is everything around the model — connecting to providers, exposing tools, remembering sessions, deciding what a subprocess may touch, rendering a UI — and doing it all in a way that still works when a user installs three plugins from three strangers.

DeepSeek Harness (dsh) is DeepSeek’s answer to that wall. It is an open-source agent harness, MIT-licensed, currently in developer preview, and built on one bet: everything is a plugin. Not “everything can be extended” — everything is an extension, including the parts you’d assume were the core.

What a harness is, actually

Strip an agent down to the model call and you have a chat completion endpoint. Useful, but it can’t read a file, remember yesterday, or ask permission before running rm. The scaffolding that adds those — and keeps them from stepping on each other — is the harness.

Concretely, dsh owns the chassis: model adapters, a tool registry with a guarded execution pipeline, an append-only session log, sandbox and approval policy, credentials, settings, and the Web UI. Every one of those is a plugin mounted into a shared context. The architecture doc says it flatly: “There is no privileged core to patch: you extend dsh by mounting a plugin beside the others, and registrations are effects that unwind when their plugin unloads.”

That sentence is the whole product. If the agent loop itself is a plugin, then a memory plugin, a TUI client, or a Feishu bridge are not second-class add-ons — they’re the same kind of citizen as the loop. That’s also why this site exists: when every capability is a plugin, the ecosystem is the product, and someone has to map it.

Five services that explain the system

Plugins contribute services to a shared context, and services claim stable keys. Five keys will orient you in almost any dsh conversation:

Service Owns Key
Sessions The append-only session event log ctx.sessions
System prompt Prompt-section and tool-schema assembly ctx.systemPrompt
Tools The scoped tool registry and execution pipeline ctx.tools
Agents The Agent interface, live registry, agent/* events ctx.agents
LLM Message/stream vocabulary plus the adapter seam ctx.llm

A plugin doesn’t import a concrete implementation of any of these — it requests them. A tool plugin declares inject: ['tools'] and the loader holds it back until the registry exists. Load order is expressed through requirements, not through someone’s careful boot sequence. (The framework that makes this work is Cordis; it has its own paper and its own guide.)

Anatomy of one turn

The glossary is unusually precise here, and worth internalizing:

  • A turn is one drain of admitted input in a session — it ends when the model and its tools stop, or a policy intervenes.
  • A step is one model request plus the tool executions its response causes. A turn contains zero or more steps.

So: input lands in the agent’s inbox. The driver claims a batch, a turn/start event opens the turn, and each step assembles the prompt from whatever sections and tool schemas the installed plugins registered. The model streams a reply (assistant/chunk events, appended live); if it asks for tools, each call runs through a guarded pipeline — pre-execute, execute, post-execute — and the results feed the next step. When nothing is owed anymore, turn/end closes it.

The interesting part is what’s missing: no hidden state. Steering messages and injected context go through the same inbox and the same claim path as ordinary input. There is one front door, and every visitor signs the book.

The log is the truth

Here is the invariant that separates dsh from a thousand agent wrappers: model-visible means logged. Anything that reaches a model request must be reconstructable from the session log — and a runtime invariant asserts it.

The session log is an append-only stream of SessionEvents. Forking, resuming, transcripts, telemetry, and persistence are all derived from that stream; the model’s view of history is a projection of it (deriveMessages()), not a parallel copy that can drift. If you want to add a new kind of model-visible input, you don’t sneak it into the prompt — you add a new session event and render from the log.

This is why we at DSHSeek care about this framework enough to map its ecosystem: an agent whose perception is fully logged is an agent you can audit, cite, and trust — or distrust, with evidence.

Seams: why one swap moves everything

A seam is a swappable capability with three roles: a Service Definition (who owns the interface), one or more Service Providers (who implements it), and Consumers (who uses it, often as a model-facing tool). The canonical example: dsh-shell defines the seam, dsh-bash-local and dsh-bash-sandbox provide it, dsh-tool-bash consumes it.

Because filesystem and subprocess providers share one execution world, repointing them at a remote sandbox moves Bash, PTY, and LSP along with them — no forks of anything. Subagents vary the same way behind one interface, from a fresh child agent to a delegated turn in another product.

When you evaluate a plugin from the map, the honest question is which seam it sits on. A plugin that owns a seam’s provider slot replaces a capability; a plugin that listens to tools/* events adds policy around it. Both are legitimate; they fail very differently.

Profiles, bundles, patches

A running dsh is a plugin tree composed at boot from ordered layers. A profile (like the shipped web and headless templates) lists the bundles it stacks and keeps your own cordis.patch.yml. A bundle is a distribution format for config rows plus the code they mount — so whatever it inserts stays patchable by the layers above it.

Layers apply in order: each bundle, then the profile’s patch, then the home-level one, then any --patch overlay. A patch targets a row by id and replaces or inserts whole rows. Want to see exactly what your machine boots?

dsh --profile web --dump-config

Any row it prints can be replaced by a patch of your own. That’s the promised land of configuration-driven composition: not a settings page, but a inspectable, diffable tree.

Try it

npx @deepseek-ai/dsh web

That starts the Web UI at http://127.0.0.1:3080. Two honest warnings before you do:

  1. It’s a developer preview. The README says it in caps: THERE WILL BE COMPATIBILITY-BREAKING CHANGES. Pin your versions.
  2. The ecosystem is young. The plugins on our map range from 86k-star tools to two-star weekend experiments — treat stars as a signal, not a warranty, and check verifiedAt.

Pitfalls

  • Don’t fork to customize. The architecture gives you events, seams, and patches precisely so you don’t have to. A fork freezes you out of every future fix.
  • Scope before you shoot. Registrations are global or scoped to one agent; a scoped tool shadows its same-named global twin for that scope only. If your tool appears everywhere, you registered globally.
  • Events have contracts. Some are waterfalls — your listener must call next() to delegate, and short-circuiting is a decision, not an accident. Read the event’s mode before listening.
  • Turn vs step vs round. A round is an outer policy iteration (a goal round, a fresh-agent attempt). Counting turns when you should count rounds will make your stats lie.

FAQ

Is this production-ready? No — developer preview, breaking changes promised. Build with it, learn with it, don’t bet an SLA on it yet.

Does it need a DeepSeek API key? The model layer is an adapter seam (ctx.llm) like everything else; adapters are plugins. What you point it at is configuration.

Why would I care about the Cordis paper if I just want a CLI? Because when two plugins both want to rewrite the prompt, someone has to have worked out the algebra of who wins and what unloads cleanly. That someone is the paper. Read what-is-cordis next.

Where to go next

Official references