DeepSeek Harness DSH plugin: ctx, inject, events, reversible

Plugin DevelopmentPublished 2026-10-02Author: DeepSeek Plugin Market
DSH pluginDeepSeek HarnessCordisContextService
DeepSeek Harness DSH plugin on Cordis: Context holds services, inject declares dependencies, typed events carry messages, and registration is reversible.

Cordis is the plugin framework vendored under DeepSeek Harness, and it defines everything a DSH plugin does when it mounts, depends, and communicates — in Cordis, everything is a plugin (source). The official docs ask plugin authors to master five core concepts before reading the generated service and event references on subsystem pages: a plugin is an object that implements a Service, the context is a service container, inject declares dependencies, typed events carry messages, and registration is a reversible side effect.

Service and Context in a DSH plugin: everything is a plugin

In a DSH plugin, everything is a plugin: a plugin is either a function with optional inject and apply(ctx) or a Service subclass, while Context is the container that carries those services (source). For a DeepSeek Harness plugin author, that maps to two rules:

  1. A plugin is an object that implements a Service — it can be a function with optional inject and apply(ctx), or a Service subclass. Expect: Cordis mounts its lifecycle onto the current context.
  2. The context is a service container — one service occupies a stable ctx.<key>, such as ctx.tools, ctx.llm, or ctx.sessions. Expect: plugins look services up by key instead of importing a concrete implementation, so you can watch a whole implementation be swapped behind the same key.

Why "services are looked up by key" matters so much: it means someone else can swap a service implementation without touching the caller, which is exactly the basis for the extension-point taxonomy discussed in capability seams.

inject in a DSH plugin: declare dependencies to order startup

Context makes lookups go by key, and inject turns load order into a dependency relationship — you organize providers and consumers in three steps (source).

  1. Write a provider — attach the capability to ctx.<key>, or use a Service subclass. Expect: other plugins can reach it by key.
  2. Write a consumer — declare the service keys it depends on with inject. Expect: it starts only after the provider is ready; otherwise it stays at PENDING.
  3. Depend only on the abstraction — the caller does not import a concrete implementation. Expect: swapping the implementation leaves the caller untouched.

PENDING is a legal state, not an error, and it is also the entry point for debugging "the plugin does nothing" — see Cordis HMR for the details.

Events and reversible side effects in a DSH plugin: dispatch modes and effect

Each event has exactly one dispatch mode and can only be dispatched through the matching method — the mode is part of the event's public contract (source). Here is the comparison table:

ModeAwaitsDispatch orderReturns a value
emitNoObserve in registration orderNo
waterfallNoObserve in registration orderYes
parallelYesAll listeners in parallelNo
serialYesObserve in registration orderYes
bailNoIn registration order, until the first bail valueYes

ctx.waterfall is surrounding middleware: a listener receives (...args, next), calling next() runs downstream and returns its value so this layer can wrap it, and returning without calling next() short-circuits. A listener that only annotates or observes must delegate; only a policy listener with decision authority should short-circuit, and use prepend: true only when a listener must run before ordinary registrations.

Every registration should have a matching disposer: either return one from ctx.effect(), or rely on a Cordis helper to handle it automatically. If teardown order matters, keep the related work in the same effect so resources are released in the expected order.

The practical rule in one line: prefer events when you need to intercept or apply policy, and prefer service methods when you need a direct capability call — tool pipeline events live on ctx.tools, model streaming output on ctx.llm, and live agent coordination on ctx.agents. Run three self-checks when you finish: do you depend only on service keys and not implementations; does inject cover every dependency; does every registration have a disposer. To continue into hands-on events, read events; to find plugins written with these concepts, search the DSH Plugin Hub.

FAQ

What is Cordis in a DSH plugin, and why read it first?

Cordis is the plugin framework vendored under the DSH plugin runtime, and it defines how plugins mount, depend, and communicate. The official docs require plugin authors to master its core concepts before reading the generated service and event references, because otherwise the registration and lifecycle semantics will not make sense.

How do Context and Service relate in a DSH plugin?

In a DSH plugin, the context is a container of services, and each service occupies a stable ctx.<key> such as ctx.tools, ctx.llm, or ctx.sessions. Other plugins look services up by key instead of importing a concrete implementation, which is exactly what lets providers be swapped.

What does inject do in a DSH plugin?

A DSH plugin uses inject to declare the services it needs, and it starts only after those services are ready. Load order is therefore expressed as service dependencies rather than a hand-written startup sequence; when a provider is missing, the plugin stays at PENDING instead of throwing.

Why is registration in a DSH plugin called reversible?

Registration in a DSH plugin is a reversible side effect: prompt fragments, tool schemas, adapters, providers, and listeners are all installed through ctx.effect() or ctx.on() and are undone on reload or teardown. That is why hot reload can safely replace a plugin without leaving stale listeners behind.

Should a DSH plugin intercept with events or call a service?

The practical rule for a DSH plugin is to prefer events when you need to intercept or apply policy, and to prefer service methods when you need a direct capability call. Tool pipeline events live on ctx.tools, model streaming output on ctx.llm, and live agent coordination on ctx.agents.

Related Terms

Cordis
Cordis is the plugin framework vendored under DeepSeek Harness that provides the context, service, dependency injection, typed events, and reversible side effects a DSH plugin builds on.— https://deepseek-harness.github.io/deepseek-harness/en/reference/cordis-primer
Context
Context is the container that carries services in a DSH plugin, where each service occupies a stable ctx.<key> and plugins look services up by key instead of importing concrete implementations.— https://deepseek-harness.github.io/deepseek-harness/en/reference/cordis-primer
Service
Service is the unit of capability a DSH plugin exposes to other plugins; a plugin itself can be a function with inject and apply(ctx), or a Service subclass whose lifecycle the framework mounts onto the current context.— https://deepseek-harness.github.io/deepseek-harness/en/reference/cordis-primer
inject
inject is the field a DSH plugin uses to declare its service dependencies; after declaring them, the plugin waits for those services to be ready before starting, which expresses load order through dependencies.— https://deepseek-harness.github.io/deepseek-harness/en/reference/cordis-primer

Sources