DeepSeek Harness — the harness with no core
A model lab shipped its own harness and made one claim about it: everything is a plugin. Not the tools — everything. The model adapter, the tool registry, the session log, the sandbox, and the agent loop itself are all rows in a config tree, and every row can be replaced from a file. The three sheets before this one describe harnesses with a centre. This one argues there does not have to be a centre at all.
Identification
- Repository
- deepseek-ai/deepseek-harness
- Steward
- DeepSeek AI
- Opened
- 13 August 2026 · developer preview
- Licence
- MIT
- Runtime
- TypeScript on Node · pnpm workspace
- Substrate
- Cordis, vendored
- Composition
- 219 packages across 49 families
- Surfaces
- web UI at 127.0.0.1:3080 · headless runner
LineageThe interesting ancestry is not DeepSeek's. The plugin framework underneath, Cordis, is a third-party project by the cordiverse group — described as a meta-framework of spatiotemporal composability, with its own paper and its own unstable API — and it is vendored into this repository rather than depended on. So the architectural argument on this sheet was not invented for an agent harness; an agent harness was fitted to it. That is why the vocabulary reads oddly for the field: contexts, services, effects and waterfalls, not sessions and callbacks.
Read it as
A ship of Theseus, built that way on purpose
Every plank is replaceable, including the keel, and the vessel is still the vessel. What stays constant is not any part — it is the sockets the parts plug into, and the order in which they are fitted.
The drawing, in one paragraph
One sentence in the architecture document generates the rest of this sheet: there is no privileged core to patch. A running dsh is a plugin tree composed at boot from ordered layers — a base bundle, then whatever bundles the profile stacks, then the profile's patch file, then the machine's, then anything passed for this run alone — applied to an empty entry list. Each layer targets a row by id and replaces its whole config, or inserts a new one. Plugins claim a stable key on a shared context (ctx.tools, ctx.llm, ctx.sessions), declare what they need by key rather than by import, and install everything they do — prompt sections, tool schemas, adapters, listeners — as reversible effects that unwind when the plugin unloads. The consequence is that the eleven slots below are not answered by features. They are answered by seams: a service definition declaring an interface, a provider implementing it, a consumer using it, and no consumer ever naming a provider.
composed on the left · the context in the middle · what it exposes on the right
The examination — eleven slots, one harness
- Built in
- Ships in the core; works with no configuration.
- Via config or extension
- The slot is real but you fill it — config, extension, or convention.
- Deliberately omitted
- Left out on purpose, with a stated argument for the gap.
There is no prompt file at the centre. ctx.systemPrompt is a registry: plugins contribute prompt sections and tool schemas, and the assembly runs fresh at every step, so what the model is told is a function of which plugins are mounted. A preset can compose a different capability set — and therefore a different prompt — for one session without touching the deployment.
Built in
ctx.systemPrompt · sections per plugin · presets
Filesystem, web and language-server access each arrive through their own seam, so search can be Exa, Perplexity or DeepSeek's own behind one unchanged tool. The unusual channel is lateral: a resolver projects a bounded snapshot of another session into this one as durable, explicitly untrusted context. Injected material does not interrupt — it waits in the inbox until a real message wakes the loop.
Built in
ctx.fs · ctx.web · ctx.lsp · agent.inject()
Pressure is measured, not guessed: a token meter keeps isolated per-session replay folds and publishes immutable revisioned measurements that compaction consumes after each step. Two mechanisms run before summarisation — a pruner that rewrites oversized current tool results as replayable surface replacements, and a spill store that moves oversized tool text out and hands the model a locator plus a retrieval hint. Notably, there is no compact tool the model can call; the harness decides.
Built in
token meter · pruner · spill · no compact tool
Every call runs a fixed pipeline — a pre-execute waterfall, monotonic guards, around-dispatch, a post-execute waterfall, then final content invariants — and registering on ctx.tools is what puts a schema into prompt assembly. Code Mode is the variant worth noting: rather than one call per step, the model writes a program that the code runtime executes against host bindings, and its sub-calls are logged individually so the transcript stays honest.
Built in
guarded pipeline · Code Mode · MCP client
Consumers hand the sandbox the exact argv they are about to spawn; the backend wraps it under a per-call policy and reports what it enforced. One detail carries the design: the default mode and workspace root live in a single policy service that both the shell executor and the filesystem provider read, deliberately, so bash and fs cannot end up confined to different roots. Approval is a waterfall that fails closed when nobody is listening.
Built in
argv handover · one policy home · fails closed
The session log is an append-only event stream, and model history is projected from it rather than stored beside it. The rule is enforced rather than documented: anything that reaches a model request must be reconstructable from the log, and a runtime invariant asserts it — which is why adding a new model-visible input means adding a new session event. Backends are swappable (JSONL or SQLite), and a cache of folded projections means listing sessions never replays full logs.
Built in
append-only log · model-visible means logged
A step is one model request plus its tool calls; a turn opens when input is claimed and closes when nothing is owed. The extension points are typed events with declared dispatch modes, and the one that matters is agent/pre-step — a waterfall that can rewrite what the model is about to see or reject it outright. A rejected first claim still closes a durable turn that spent no step, so the log records the attempt rather than hiding it.
Built in
turn / step · agent/pre-step waterfall · one inbox
Delegation is a seam with six providers behind it, and three of them leave the process entirely — ACP, Codex, and Claude Code. A dsh run can hand a turn to a competing harness and treat the result as an ordinary subagent return. The service also owns continuation, so a delegation can be followed up rather than only awaited.
Built in
6 providers · incl. Codex and Claude Code
Skills are a seam too: providers publish catalogues, the service merges them, and the model-facing tool renders a short catalogue into the session prefix and loads a full body only when asked. The same accommodating instinct shows up beside it — dedicated packages read Claude Code's and Codex's hook formats, so know-how already written for another harness runs here without translation.
Built in
ctx.skills · catalogue then body · rival hook formats
Telemetry is a seam ending in OpenTelemetry, and the log itself is the trace. Two choices stand out. The language-server seam offers exactly four normalised operations and no protocol escape hatch, which forces backends to translate rather than leak. And invariants are a first-class service: packages register their own runtime checks, and a failure is attributed to the package that owns it — the harness reports which part broke its own contract.
Built in
OTel · 4-operation LSP · attributed invariants
The machinery for self-modification is further along than anywhere else on this register: because registrations are reversible effects, plugins mount and unmount live, and a model-facing tool lets the agent define a new Cordis package — syntax-checked, shown to the user as a card with a start control — then run it in a sandbox inside the running process. But those packages live only in process memory and disappear on restart. The harness can rewrite itself for an afternoon; making the change last is still a human writing a patch row.
Via config or extension
cordis_define / cordis_run · in-memory only
Where this design runs out of road
If every plank is replaceable, the name stops picking out an object. Two dsh installations can share no row and both be DeepSeek Harness, which makes every question a reader might ask — what is in the prompt, where does bash run, what happens after a tool call — unanswerable without inspecting that machine's tree. The project knows it: --dump-config exists precisely because you cannot otherwise know what you are running. And the composition is not small, at 219 packages across 49 families, so the plugin surface is itself the learning curve. The sharpest version of the trade appears in DeepSeek's own evaluation note. The published agent scores were produced with a minimal mode of this harness marked to be released — so at the moment the numbers were set, the configuration that produced them was not one you could check out. A harness that can be composed any way is a harness whose results travel only with their config.
06Side by sideThe comparison table — one row per primitive, one column per harnessRead from — every finding traces to one of these
- deepseek-ai/deepseek-harnessRepository — packages/, bundle/, boot/
- Architecture documentationProfiles and bundles, turn flow, capability seams
- Cordis primerContexts, services, inject, dispatch modes, effects
- Capability seams and core servicesGenerated service graph — owners, providers, consumers
- tool-cordisPackage README — cordis_define, cordis_run, lifetime
- DeepSeek-V4-Flash-0731 model cardEvaluation note — minimal mode, max effort, Terminal-Bench 2.1 82.7
- cordiverse/cordisThe vendored framework, upstream