Skip to content

Build1 publisher3 min readPublished

DeepSeek Harness makes the agent loop a plugin, so pick your seam before you write code

Four subsystems are all Cordis plugins at the pinned commit, which turns extension into an architecture decision. The same guide records GitHub at rc.8 and npm at rc.7.

The Engineer · Build desk

Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

What happened

  • At the source snapshot checked for the guide (default branch master, commit 141eb6fef83422698aef7a981029e843e8161534), the model adapter, tool registry, session log and agent loop are all Cordis plugins.
  • A plugin contributes services, typed events and reversible effects to a shared context; profiles and bundles compose those plugins into a runnable product. DeepSeek Harness does not treat plugins as optional add-ons around a privileged core.
  • The guide's practical rule: use a service for a capability another plugin calls directly; an event to observe or intercept behavior without importing its provider; an effect for anything that must be undone on unload; a profile patch for one user's or one deployment's composition; a bundle when a reusable package needs to distribute a set of patchable rows.
  • Do not choose by directory name or YAML position. Choose by ownership, lifetime, dependency, and replacement boundary.
  • A context is the repository through which plugins find stable service keys such as ctx.tools, ctx.llm and ctx.sessions.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

A dev.to architecture guide to DeepSeek Harness reports that at the snapshot it checked, default branch master, commit 141eb6fef83422698aef7a981029e843e8161534, the model adapter, tool registry, session log and agent loop are all Cordis plugins [1]. That removes the usual shortcut of bolting an addition onto a privileged core: a plugin contributes services, typed events and reversible effects to a shared context, and profiles and bundles compose those plugins into a runnable product [2], so the only decision left is which seam you attach to.

The guide gives five placements: a service for a capability another plugin calls directly, an event to observe or intercept behaviour without importing its provider, an effect for anything that must be undone on unload, a profile patch for one user's or one deployment's composition, and a bundle when a reusable package needs to distribute a set of patchable rows [3]. Its stated selection rule is not to choose by directory name or YAML position, but by ownership, lifetime, dependency and replacement boundary [4].

Some of that is enforced by the runtime rather than by taste. The context is the repository through which plugins find stable service keys such as ctx.tools, ctx.llm and ctx.sessions [5]. A consumer declares hard requirements through inject; Cordis holds it PENDING until every required service exists, unloads it if a dependency disappears, and reloads it when the service returns [6]. Which is why, per the guide, YAML list order is not a startup contract: entries start concurrently and dependency declarations control readiness [7]. The lifecycle runs PENDING to LOADING to ACTIVE to UNLOADING to DISPOSED, with FAILED as the branch [8].

The event choice carries the sharpest failure mode. emit broadcasts synchronously, parallel awaits listeners together, serial awaits them in order, and waterfall wraps a continuation [9]; in a waterfall, an observer that forgets next() does not merely miss a callback, it can swallow the default behaviour for every downstream plugin [10]. That is the seam the guide recommends for policy, request rewriting or veto [11], so the cheapest place to add a policy hook is also the place where a one-line omission becomes a system-wide outage.

Cleanup is similarly load-bearing. Cordis already treats ctx.on(), child plugins, service registrations and Harness registry registrations as effects, but a raw interval, watcher, socket or file handle has to be acquired inside ctx.effect() with a disposer [12], and ordered asynchronous teardown must live in one disposer that awaits its steps, because separate async disposers may run concurrently [13]. Composition sits above all of this: a profile under $DSH_HOME/profiles/<name> lists ordered bundles in dsh.profile.bundles [14], each package declares dsh.bundle.patch and patch rows mount plugin fibers [15], and overrides apply as profile cordis.patch.yml, then home-level patch, then --patch overlays [16].

Then the caveat that governs the rest. DeepSeek Harness is still a Developer Preview [17]. GitHub published the dsh-v0.1.0-rc.8 pre-release on August 19 while npm still reported @deepseek-ai/dsh@0.1.0-rc.7 when checked on August 20 [18], one candidate apart on consecutive days [19], and the guide pins its claims to commit 141eb6f rather than implying every rc.8 package is installable [20]. It calls itself an architecture map, not a stability guarantee, and tells readers to repeat the config and lifecycle checks after every upgrade [21].

Watch whether the npm channel catches up with the GitHub tags, and whether the service keys named above survive the next candidates unchanged. If they do not, the seam you chose is the thing you rewrite.

Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories