The Design Bet Behind DeepSeek Harness: An Agent Made of Plugins

DeepSeek Harness is an open-source agent harness for building and running model-driven work. This opening chapter focuses on the design choice that organizes the project: instead of treating an agent as one large application, DeepSeek Harness assembles it from plugins that provide model access, tools, storage, policy, and user interfaces. Understanding that choice gives readers a way to judge the system’s behavior, not just memorize its features.

That distinction matters because an agent is not only a model that writes text. It can read a workspace, edit files, start processes, ask for approval, call another model, and continue after a restart. Each ability changes the consequences of a mistake. The useful question is therefore not simply “Which model does it use?” It is “Which part owns this action, how can that part be replaced, and what evidence remains when the action is over?”

The problem is an entangled agent

Imagine asking an agent to inspect a repository and repair a failing test. A successful run needs several different responsibilities: a model adapter must turn a request into the provider’s wire format; a tool must describe the allowed operation and execute it; a filesystem or shell implementation must reach the workspace; a permission layer must decide whether the action may proceed; a session store must retain what the model saw; and a UI or automation protocol must present progress and results.

Those responsibilities do not change for the same reasons. A provider may change its streaming protocol. A shell implementation may need a different operating-system runner. A UI may need a new card for file edits. A persistence backend may need crash-safe writes. If all of these decisions live inside one agent class, changing one concern risks changing the others. The result may still look like a chat application, but its seams are hidden and its behavior becomes difficult to replace or reconstruct.

DeepSeek Harness addresses this problem by making the runtime itself a composition. The project’s name for the composition is a plugin tree: plugins are loaded into a shared runtime context, discover services by stable names, communicate through typed events, and attach registrations to their own lifetimes. The important point is not that the repository contains many packages. It is that responsibility and ownership are represented in the running system.

What “everything is a plugin” means

DeepSeek Harness is built on Cordis, a plugin framework whose basic unit is a context containing services. A model adapter can register an LLM service, a tool runtime can register a tool registry, and the session package can register the service that holds live session logs. A consumer asks for the service it needs rather than importing a particular provider’s implementation. The dependency is therefore expressed as “I need this capability,” not “I must use this class.”

A plugin declares required services through inject. The loader waits until those services are available before activating the dependent plugin. This makes readiness part of the architecture. A model-facing tool that needs the shell service does not merely hope the shell was initialized first; its dependency is part of its activation conditions.

Plugins also communicate through typed events. Some events simply notify observers. Others run listeners in parallel or in order. A waterfall event behaves like cooperative middleware: a listener can inspect or transform a decision and call next() to delegate, or return without delegation when it owns the decision. DeepSeek Harness uses that distinction for places such as request admission and tool policy, while durable session facts travel through the session event feed.

Finally, registrations are reversible effects. A tool schema, prompt section, event listener, or provider registration belongs to the plugin that installed it. When that plugin unloads, its effect is removed. This is what makes replacement meaningful: a new implementation does not merely sit beside an old one whose listeners and registrations are still active.

“Everything” does not mean every component has equal status or that the system has no core. DeepSeek Harness’s core packages define the public Agent, Session, prompt, tool, and loop APIs. The default agent loop is still a concrete driver, and the session log is still a central source of truth. The plugin claim means those responsibilities are exposed through replaceable runtime roles rather than hidden inside one privileged application path.

flowchart LR A["dsh launcher"] --> B["ordered profile layers"] B --> C["Cordis plugin context"] C --> D["Agent loop"] C --> E["Capability seams"] D --> F["model"] D --> G["tools"] D --> H["Session log"] E --> I["replaceable providers"] H --> J["derived history"] C --> K["Web"] C --> L["headless"] C --> M["SDK"] C --> N["ACP"] P["policy + lifecycle"] -.-> C P -.-> D P -.-> E

The diagram shows the project’s organizing relationship. The dsh launcher selects a profile; the profile layers assemble a Cordis context; the agent loop connects model calls, tools, and the Session log; capability seams supply replaceable implementations; and different surfaces use the same composed runtime. Policy and lifecycle are not a single feature at the edge. They constrain how the context is assembled, how work runs, and how it is removed.

Three relationships make the system legible

The first relationship is between the live Agent and the loop that drives it. The public Agent API gives plugins and hosts a way to create or resume an agent, queue a follow-up, steer the next step, inject context, cancel work, and wait for idleness. The default loop turns that control surface into turns and steps. This separation allows a UI or an orchestrator to control an agent without depending directly on the loop’s internal implementation.

The second relationship is between the loop and the Session log. The loop performs live work, but the log records the facts that the model is allowed to see. User messages, assistant settlements, tool calls and results, system-prompt changes, and request metadata enter the append-only record. The model history is derived from that record. A live stream can help a UI show text as it arrives, but it is not the durable replay source. This distinction gives the system a place to recover from interruption and a way to inspect how a later request was constructed.

The third relationship is between capabilities and their surfaces. A capability such as shell execution has a definition, one or more providers, and a consumer that exposes it to the model. The same runtime can then place that capability behind a Web interface, a headless command, an SDK connection, or ACP automation. The surface changes how a person or program interacts with the agent; it does not require a second, unrelated agent architecture.

These relationships also explain why the project uses profiles and bundles. dsh-base supplies a shared composition for model access, tools, durable sessions, and safety defaults. The Web profile adds a browser server and client graph. Headless adds a one-shot runner. SDK and ACP add protocol servers. The minimal SDK profile deliberately builds a smaller standalone tree instead of inheriting the full base. A profile is therefore not just a command-line mode; it is a decision about which plugins are present, which lifecycles they own, and which boundaries the application exposes.

Why replaceability matters more for agents

In an ordinary application, replacing a library can be mostly an engineering concern. In an agent, replacing a provider can alter what the model sees, how a tool call is scheduled, how a credential is resolved, or whether a request can be replayed. DeepSeek Harness keeps some facts stable at the seam and leaves other facts explicitly provider-owned.

The LLM service owns a common vocabulary for messages, content blocks, stream chunks, model capabilities, and stable failure codes. The direct DeepSeek adapter and the pi-ai-backed adapter translate their own provider protocols into that vocabulary. The loop can therefore reason about a prepared model call without knowing whether the response came from direct HTTP streaming or another provider route. At the same time, image handling, reasoning effort, model catalogs, replay metadata, and wire compatibility remain adapter responsibilities. Replaceability does not erase differences; it places them where they can be named and tested.

The same logic applies to external effects. The tool registry knows how to validate a model’s arguments and route a call through policy and execution stages. A shell provider knows how to run a command. A sandbox provider knows how to wrap an exact process invocation under a file-effect policy. A UI presenter knows how to display the result. Keeping these jobs separate means a policy hook can cover several tool families without each tool importing that policy implementation.

This design also makes lifecycle ownership visible. A provider that creates a live process or child agent must define what happens on cancellation and disposal. A persistence backend must define which operation makes a write durable. A browser connection must define what reconnects and what does not. These are not optional implementation notes around the edges of the system. They are part of the capability’s public behavior.

The qualification: composition is not isolation

The architecture should not be mistaken for a security guarantee. The repository explicitly describes DeepSeek Harness as developer-preview software that has not undergone a security audit. It can execute model-generated code and commands, load third-party plugins, and access the network, processes, credentials, and files made available to it.

The project does provide meaningful controls. The base composition can resolve a per-session file policy, ask for one-time approval, fail closed when a requested sandbox backend is unavailable, and keep credential values out of configuration files. Agent scopes can give one session a different tool or prompt composition. But a scope is a trusted same-process registration mechanism, not a process boundary. The shipped sandbox governs stated file effects in the same host world; it does not by itself isolate the network, kernel, devices, process visibility, or resources the process already has permission to use.

That qualification strengthens the plugin thesis rather than weakening it. A boundary is useful only when its ownership and limits are explicit. DeepSeek Harness makes policy, providers, sessions, and transports visible enough to inspect and replace, but operators still need least privilege, disposable environments, backups, and review of plugins and proposed commands. A documented seam tells us where control belongs. It does not prove that the control is sufficient for an untrusted workload.

DeepSeek Harness is therefore best understood as a runtime architecture for composing agent behavior. Its value lies in the relationship among plugins, live control, durable evidence, replaceable capabilities, and named application surfaces. The next question is how Cordis enforces those relationships in practice: how independent plugins find one another, coordinate through event semantics, and disappear without leaving stale behavior behind.

References