Dev.to · 10 min read

DeepSeek Harness “Everything Is a Plugin”: choose the right Cordis extension seam

DeepSeek Harness “Everything Is a Plugin”: choose the right Cordis extension seam

DeepSeek Harness “Everything Is a Plugin”: choose the right Cordis extension seam Quick answer DeepSeek Harness does not treat plugins as optional add-ons around a privileged core. At the source snapshot checked for this 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. The practical rule is: use a service for a capability another plugin calls directly; use an event to observe or intercept behavior without importing its provider; use an effect for anything that must be undone on unload; use a profile patch for one user's or one deployment's composition; use 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. DeepSeek Harness is still a Developer Preview. 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. This article therefore pins source claims to commit 141eb6f and does not imply that every rc.8 package is already installable from npm. Who this is for This guide is for agent-framework developers deciding where to add a tool, policy, adapter, observer, UI surface, or deployment composition in DeepSeek Harness. It assumes you already have a disposable evaluation environment; if not, start with the DeepSeek Harness install and rollback checklist. It is an architecture map, not a stability guarantee. The source may change between preview candidates, so repeat the config and lifecycle checks after every upgrade. The architecture in one map profile: $DSH_HOME/profiles//package.json ordered dsh.profile.bundles each package declares dsh.bundle.patch patch rows mount plugin fibers plugin -> provides ctx. -> listens/emits typed events -> owns reversible effects then profile cordis.patch.yml then home-level patch then --patch overlays runtime dependency: inject -> PENDING until service exists lifecycle: PENDING -> LOADING -> ACTIVE -> UNLOADING -> DISPOSED \-> FAILED ~~~ A **plugin** is the lifecycle owner. Cordis accepts a function, an object with apply(ctx), or a Service subclass. A **context** is the repository through which plugins find stable service keys such as ctx.tools, ctx.llm, and ctx.sessions. A consumer declares hard requirements through inject. Cordis keeps it PENDING until every required service exists, unloads it if a dependency disappears, and reloads it when the service returns. That is why YAML list order is not a startup contract: entries start concurrently, and dependency declarations control readiness. ## Plugin, service, event, or effect? | Need | Put it here | Why | |---|---|---| | A callable capability with replaceable providers | Service on a stable ctx key | Consumers depend on an interface, not one implementation | | A model-callable action | Register with ctx.tools | The schema joins prompt assembly and execution stays in the tool pipeline | | Passive observation | emit listener | Producer does not need to know the observer | | Policy, request rewriting, or veto | waterfall listener | Around-middleware can delegate, transform, or deliberately short-circuit | | Timer, connection, watcher, or external handle | ctx.effect() with a disposer | Unload and HMR release the resource predictably | | A durable model-visible fact | Session event | Reload, replay, fork, and model history can reconstruct it | Events have different contracts. emit broadcasts synchronously; parallel awaits listeners together; serial awaits them in order; waterfall wraps a continuation. In a waterfall, an observer that forgets next() does not merely miss a callback—it can swallow the default behavior for every downstream plugin. Registrations should also unwind. Cordis already treats ctx.on(), child plugins, service registrations, and Harness registry registrations as effects. A raw interval, watcher, socket, or file handle must be acquired inside ctx.effect() and return a disposer. If several asynchronous cleanup steps require ordering, keep them in one disposer and await them there; separate async disposers may run concurrently. ## Profile, bundle, or local patch? A **profile** is the runnable composition stored under $DSH_HOME/profiles/. Its package.json lists ordered bundles in dsh.profile.bundles, installs out-of-tree dependencies, and sits beside the user's cordis.patch.yml. Shipped templates compose: - web: @deepseek-ai/dsh-base + @deepseek-ai/dsh-web-app; - headless: @deepseek-ai/dsh-base + @deepseek-ai/dsh-headless. A **bundle** is an npm package whose manifest declares a patch file through dsh.bundle.patch. The base bundle inserts model adapters, tools, persistence, sandbox and approval policy, settings, credentials, telemetry, and core subagent providers. Later bundles replace or add rows for a surface such as Web or headless execution. Use the profile patch for a local override. Publish a bundle when the composition itself is reusable, versioned, and installable. Keep one crucial constraint in view: a patch that targets a row replaces that row's **whole config**; it is not a deep merge. An override must restate every field it intends to preserve. Inspect what will actually boot instead of reasoning from package names: ~~~sh dsh --profile web --dump-config ~~~ The current rc.8 release notes reinforce this distribution boundary: the official Codex and Claude Code subagent providers can be installed on demand as Profile Bundles. That release fact does not change the placement rule—provider code owns the service implementation; the bundle owns how that provider is mounted. ## Extension placement decision tree ~~~text Does another plugin need to call this capability directly? yes -> define or use a service; inject the stable key no -> does it observe or intercept an existing operation? observe -> event listener with automatic disposal intercept -> waterfall; call next() unless intentionally vetoing neither -> does it own a timer/socket/watcher/external handle? yes -> reversible effect with one complete disposer no -> ordinary plugin-local logic Does the change select or replace several plugin rows? one machine/deployment -> profile cordis.patch.yml reusable distribution -> bundle with dsh.bundle.patch Must the fact survive reload, fork, or replay? yes -> append a typed session event; do not keep it only in memory ~~~ If one agent needs a different capability set, do not automatically fork the global profile. The architecture guide points to an isolated agent-preset realm for per-session composition. Likewise, a filesystem provider, sandbox provider, and model-facing tool are different roles even when one package happens to combine them. ## Seven lifecycle and HMR canaries | Canary | Pass evidence | Failure meaning | |---:|---|---| | 1. Effective tree | --dump-config shows the intended row IDs and full configs | A layer was resolved or patched differently than expected | | 2. Required dependency | Removing a test provider leaves the consumer PENDING, not half-active | Dependency was read without inject or diagnostics are missing | | 3. Service recovery | Restoring the provider unloads/reloads dependants into ACTIVE | Stale service references or incomplete effects remain | | 4. Disposal | HMR closes each timer, watcher, listener, and connection exactly once | A resource lives outside the plugin lifecycle | | 5. Stable identity | Editing one entry with a stable id remounts only that entry and dependants | Generated IDs caused removal-plus-addition churn | | 6. Waterfall delegation | An observer calls next(); a veto test alone short-circuits | A listener accidentally swallowed the operation | | 7. Bad configuration | Invalid schema or missing bundle metadata fails visibly before partial activation | The deployment can silently boot an incomplete tree | Also test a misspelled module path. The tutorial notes a sharp edge: an unresolved entry can be reported through the Cordis logger rather than crash, and an early report may be lost before a console exporter is watching. A plugin that “does nothing” therefore needs both fiber-state inspection and module-resolution verification. ## Common mistakes - **Treating YAML order as dependency order.** Use inject; sibling entries start concurrently. - **Putting every extension in a new service.** Observers and policies usually belong on an existing event contract. - **Forgetting a disposer.** HMR then duplicates timers, listeners, or connections. - **Forgetting next() in a waterfall.** That is an implicit veto, not harmless logging. - **Assuming patch configs deep-merge.** Row config replacement can silently discard required fields. - **Using a global service name casually.** Service names share one flat namespace; choose a distinctive key. - **Calling PENDING success.** A process can exit quietly while a consumer waits for a missing service. - **Equating a GitHub tag with npm availability.** Record repository, commit, release, and registry version separately. ## FAQ ### Does “everything is a plugin” mean every feature should be a separate package? No. Plugin is the lifecycle and composition unit. A package may expose one or several plugins, combine service roles, or ship a bundle whose main artifact is a patch list. Split by ownership and replacement boundary, not by slogan. ### When should I use a service instead of an event? Use a service when a consumer needs a direct capability call and a stable interface. Use an event when producers and consumers should remain decoupled, especially for observation, policy, interception, and lifecycle signals. ### What is the difference between a profile and a bundle? A profile is a named runnable composition in Harness home. A bundle is a distributable patch layer that a profile stacks. The profile is the deployment choice; the bundle is reusable composition material. ### Is HMR automatically safe? Only when all registrations and external resources are reversible, dependencies are declared, entry IDs are stable, and the replacement path is tested. HMR exposes lifecycle mistakes; it does not repair them. ### Is rc.8 available from npm? At the August 20 check, GitHub had published the dsh-v0.1.0-rc.8 pre-release and the repository declared rc.8, but npm latest and next still reported rc.7. Recheck the registry before installing and pin the exact version you verify. ## Sources - [DeepSeek Harness official repository and Developer Preview boundary](https://github.com/deepseek-ai/deepseek-harness) - [DeepSeek Harness dsh-v0.1.0-rc.8 pre-release](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.1.0-rc.8) - [npm: @deepseek-ai/dsh 0.1.0-rc.7](https://www.npmjs.com/package/@deepseek-ai/dsh/v/0.1.0-rc.7) - [Architecture at commit 141eb6f](https://github.com/deepseek-ai/deepseek-harness/blob/141eb6fef83422698aef7a981029e843e8161534/docs/architecture.md) - [Cordis primer at commit 141eb6f](https://github.com/deepseek-ai/deepseek-harness/blob/141eb6fef83422698aef7a981029e843e8161534/docs/cordis-primer.md) - [Lifecycle and reversible effects tutorial at commit 141eb6f](https://github.com/deepseek-ai/deepseek-harness/blob/141eb6fef83422698aef7a981029e843e8161534/docs/cordis-tutorial/02-lifecycle-and-effects.md) - [Services and inject tutorial at commit 141eb6f](https://github.com/deepseek-ai/deepseek-harness/blob/141eb6fef83422698aef7a981029e843e8161534/docs/cordis-tutorial/03-services.md) - [Events and waterfall tutorial at commit 141eb6f](https://github.com/deepseek-ai/deepseek-harness/blob/141eb6fef83422698aef7a981029e843e8161534/docs/cordis-tutorial/04-events.md) - [Composition and HMR tutorial at commit 141eb6f](https://github.com/deepseek-ai/deepseek-harness/blob/141eb6fef83422698aef7a981029e843e8161534/docs/cordis-tutorial/06-composition-and-hmr.md) - [Profile and bundle composition source at commit 141eb6f](https://github.com/deepseek-ai/deepseek-harness/blob/141eb6fef83422698aef7a981029e843e8161534/packages/boot/app-boot/src/profile.ts) - [Official bundle contract at commit 141eb6f](https://github.com/deepseek-ai/deepseek-harness/blob/141eb6fef83422698aef7a981029e843e8161534/packages/bundle/README.md) Originally published on [IndieSeek](https://indieseek.co/blogs/deepseek-harness-everything-plugin-cordis-architecture-guide/).

This is a summary aggregated from Dev.to. Read the complete article on the original site:

Read full article at Dev.to

More AI & Machine Learning News