$dshubuser@dshub:~/plugins$
  • Plugins
  • Submit
  • Blog
Services and Context: Share Capabilities Without Binding Implementations
2026/08/22

Services and Context: Share Capabilities Without Binding Implementations

Use Service, Context, and declaration merging to understand how providers, consumers, and scopes connect DeepSeek Harness capabilities.

In one sentence: a service provides a stable capability name, Context provides the lookup, and consumers depend on the name instead of a provider file or class.

“Swap the implementation” therefore does not mean editing every caller. Change the provider in composition; consumers still read the same ctx.<key>.

01 / A service has three roles

Cordis service definition provider and consumer roles connected through Context

A replaceable capability has at least three roles:

RoleResponsibilityCordis location
Service DefinitionNames the capability and its callable interfaceTypeScript types and service agreement
Service ProviderCreates and registers an instanceService subclass or registry
ConsumerUses the capabilityinject plus ctx.service

One role alone is not a complete replaceable capability. A provider without consumers is unused; a consumer that imports the provider has lost the replacement point.

02 / How a provider enters Context

import { Service, type Context } from '@deepseek-ai/cordis'

declare module '@deepseek-ai/cordis' {
  interface Context {
    greeter: GreeterService
  }
}

export class GreeterService extends Service {
  constructor(ctx: Context) {
    super(ctx, 'greeter')
  }

  greet(who: string) {
    return 'Hello, ' + who + '!'
  }
}

export function apply(ctx: Context) {
  ctx.plugin(GreeterService)
}

super(ctx, 'greeter') registers the instance in the greeter service slot. Registration is an effect owned by the current Fiber, so unloading the provider removes the service from the scope.

declare module performs TypeScript declaration merging only; it does not wire runtime behavior. Runtime wiring comes from Service registration. The declaration gives consumers type-safe access to ctx.greeter.

03 / A consumer declares what it needs

Cordis Context resolving a named provider through root and isolated child scopes
import type { Context } from '@deepseek-ai/cordis'

export const name = 'consumer'
export const inject = ['greeter']

export function apply(ctx: Context) {
  console.log(ctx.greeter.greet('world'))
}

inject guarantees that the service exists when apply runs. The consumer does not import GreeterService, so composition can point greeter at a different provider.

For an optional dependency, probe with ctx.get('greeter'). By default, ctx.get() returns only an ACTIVE service; without an available provider it returns undefined and creates no dependency edge. Do not read an undeclared ctx.greeter property directly; the proxy can throw because inject is missing.

04 / Context has more than one plane

Cordis Context is the entry point for service resolution, plugin registration, and event dispatch. Child contexts can be created below the root:

  • extend() adds child metadata without mutating the parent.
  • isolate(name) creates an independent service scope.
  • intercept(name, config) adds local service configuration for a subtree.

The same service name can therefore resolve to different instances in different groups. DeepSeek Harness uses this idea for profiles, agent presets, and isolated capability compositions.

05 / Named capabilities in DSH

DeepSeek Harness Context connecting tools llm agents and sessions services

In the Harness architecture, the tool registry, LLM adapters, live Agent registry, and session store are Context-connected capabilities:

  • ctx.tools owns tool registration and execution.
  • ctx.llm carries message, stream, and model-adapter capabilities.
  • ctx.agents owns live Agents and agent/* events.
  • ctx.sessions owns the durable session event log.

Providers can change while consumers keep the stable service name. That is why a capability seam can turn one provider choice into product-wide behavior.

Where to go next

  • inject: Let Dependencies Decide Load Order
  • Events: Notify Without Knowing Who Listens
  • Cordis Inside DeepSeek Harness

Sources: services tutorial, Context implementation, Service implementation, and Harness architecture.

All Posts

Author

avatar for DSH Research
DSH Research

Categories

  • Agent Infrastructure
01 / A service has three roles02 / How a provider enters Context03 / A consumer declares what it needs04 / Context has more than one plane05 / Named capabilities in DSHWhere to go next

More Posts

inject: Let Dependencies Decide Load Order, Not YAML Line Numbers
Agent Infrastructure

inject: Let Dependencies Decide Load Order, Not YAML Line Numbers

Understand PENDING, dependency tracking, and optional service probes, including why provider swaps move consumers automatically.

avatar for DSH Research
DSH Research
2026/08/23
waterfall: Intercept, Wrap, and Short-Circuit with next()
Agent Infrastructure

waterfall: Intercept, Wrap, and Short-Circuit with next()

Follow a Cordis waterfall chain to see listeners delegate downstream, wrap results, or short-circuit when they own the decision.

avatar for DSH Research
DSH Research
2026/08/26
Cordis Inside DeepSeek Harness: Making Everything a Plugin
Agent Infrastructure

Cordis Inside DeepSeek Harness: Making Everything a Plugin

Trace dsh-base, Context services, event domains, and the tool pipeline to see how Cordis organizes a replaceable Agent runtime.

avatar for DSH Research
DSH Research
2026/08/29

Newsletter

Join the community

Subscribe to our newsletter for the latest news and updates

[dshub] [zsh]$ dshub ls$ dshub submit$ dshub blog
-- NORMAL -- ✓ 2026 dshub