Spokes.wiki Search About
Created
Updated

DeepSeek Harness (dsh)

An open-source agent harness from DeepSeek AI, MIT-licensed, TypeScript, published 2026-08-13 — the repository was created that morning and had 37,128 stars and 2,869 forks by that evening. It ships as a developer preview whose README says, in capitals, that there will be compatibility-breaking changes.

Read it as a primary source about architecture, not about results. It is a day old, it publishes no evaluation, and the star count measures attention rather than quality — a BENCHMARK.md exists and its entire content is an instruction to install the Python SDK and run the jsonrpc-agent variant.

The claim: everything is a plugin

The design rests on Cordis, and the architecture doc states the consequence plainly: "Every part of the product is a plugin, including the model adapter, the tool registry, the session log, and the agent loop itself, so every part is replaceable from configuration." 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.

This is the strongest form of the agent-middleware idea the spoke has seen stated. LangChain's middleware hooks a loop that remains LangChain's; here the loop is core/agent-loop, one row in a tree, and swapping it is a config edit rather than a fork.

How a running instance is composed

A running dsh is a plugin tree assembled at boot from ordered layers:

  • A profile is a named composition stored in the Harness home — the bundles it stacks, any out-of-tree plugins, and the user's cordis.patch.yml. web and headless ship as templates.
  • A bundle distributes Cordis config rows plus the code they mount, and stays patchable by the layers above it.

Layers apply in order: each bundle in the profile's order, then the profile's patch, then the home-level patch, then any --patch overlay. A patch targets a row by id and replaces its config outright, or inserts new rows. dsh --profile web --dump-config prints the tree the machine actually boots, and every row it prints can be replaced.

Three bundles are named: dsh-base (model adapters, tools, persistence, sandbox and approval policy, settings, credentials, telemetry) is the first layer of every profile; dsh-web-app adds the browser application; dsh-headless adds a one-shot runner with no server at all.

The loop, stated as a protocol

The turn flow is written out as pseudocode. No other harness here documents its loop at this resolution, so the shape is quoted rather than paraphrased. A step is one model request plus the tools it calls; a turn is zero or more steps, opening before its first input is claimed and closing once nothing is owed:

turn/start
  claim next-step input plus one queued message
  assemble prompt sections + tool schemas
  -> agent/pre-step                   reject | enter(messages)
     step/start
     append entered messages as user/message
     derive model history from the log
     agent/request -> llm/stream -> assistant/chunk* -> assistant/message
     tool/call* -> tools/pre-execute -> tools/execute -> tools/post-execute -> tool/result*
     step/end
  -> agent/turn-stopping
turn/end

Extension happens through events in three domains, and picking the domain is the first decision in most changes: session events are durable facts appended to the log (use one when the fact must survive a reload), agent events carry a live agent for observing or intercepting work in flight, and capability events attach policy and adapters to a seam (fs/*, tools/*, telemetry/*) without importing the loop. agent/pre-step, agent/request, llm/stream and the three tools/* events are waterfalls whose listeners must call next() to delegate.

agent/pre-step is where a listener decides what the model sees — it may rewrite the claimed messages or reject them outright, and a rejected first claim still closes a durable turn that spent no step, so the log records the attempt.

Model-visible means logged

The session log is the source of the context the model sees; deriveMessages() projects model history from it, and raw assistant/chunk events are kept for replay and UI fidelity. The rule is enforced, not merely advised: "Anything that reaches a model request must be reconstructable from the log, and a runtime invariant asserts it." Adding a new model-visible input therefore requires a new session event type.

That invariant is a direct answer to the failure model-or-harness-taxonomy uses as its worked example — an agent ignoring an earlier instruction, where you cannot tell whether compaction dropped it or the model disregarded it. If every model-visible byte is reconstructable from an append-only log, that ambiguity is decidable after the fact. Nobody at DeepSeek claims this motivation, and the harness still has a compaction package that can drop things; what the invariant buys is that the dropping is recorded.

Capability seams

A seam is a swappable capability with three roles — a Service Definition declaring the interface, a Service Provider implementing it, and a Consumer using it (commonly a model-facing tool). One role alone is not a seam, and adding a capability means designing all three.

The payoff claimed: filesystem and subprocess providers share one execution world, so pointing them at a remote sandbox moves Bash, PTY and LSP with them, with no provider forks. Subagent providers vary behind one interface from a fresh child agent to a delegated turn in another product.

What is in the box

Roughly fifty packages, and the list is a fair census of what a 2026 harness is expected to have: mcp (a client bridge registering external MCP server tools on ctx.tools), acp, lsp, sandbox and e2b, subagent, skill, compaction, plan, goal, guard, todo, workflow, jobs, schedule, credentials, terminal, shell, workspace, spill. Apps are a cli and a web client; there is a Python SDK alongside the TypeScript core.

The skill package owns a ctx.skills registry that is deliberately backend-agnostic — it "does not know whether skills come from local files, embedded plugin data, HTTP, or another backend" — with the filesystem provider shipped separately. Registrations are scope-layered: host rows land in the global layer, a plugin mounted by an agent preset lands in that preset's layer, and a read merges the global layer with the viewing scope's chain, nearest layer winning a duplicate name. That is agent-scope-isolation implemented at the registry level rather than bolted on.

Not locked to DeepSeek's own models

Two LLM adapters ship against the same seam. llm-deepseek owns the deepseek-official route with a hand-rolled fetch + SSE implementation of DeepSeek's wire format. llm-pi-ai is a generic multi-provider adapter backed by @earendil-works/pi-ai, where a route naming an installed provider inherits its endpoint, protocol and catalog, and a route pi-ai doesn't ship is declared outright — so "an OpenAI-compatible gateway, a self-hosted server, or a provider newer than the installed catalog is configuration rather than a code change." The two routes are named distinctly on purpose so one composition can mount both DeepSeek paths side by side.

Credentials are referenced by env-var name rather than embedded, and a reference that resolves to nothing fails the request with MISSING_CREDENTIAL instead of falling through to whatever unrelated key the environment holds.

Built to be read by agents

The repo carries AGENTS.md (agents-md) and CLAUDE.md (claude-md) at the root and inside package directories, and the architecture doc opens by recommending you "use an agent to explore the codebase and understand its architecture." Documentation is fully bilingual — every README has a .zh.md twin driven by an i18n YAML file.

What to watch

The developer-preview warning is the load-bearing caveat: an architecture whose whole promise is stable seams is shipping while the seams are still moving. The claim to test later is whether "replaceable from configuration" survives contact with third-party plugins — the dsh-plugin GitHub topic is the place that will show it.

cordis · agentic-coding-harness · agent-framework · agent-middleware · model-or-harness-taxonomy · agent-scope-isolation · deepseek · claude-code · oh-my-pi · agents-md