DSH plugin protocol drivers: DeepSeek Harness ACP peers

Plugin DevelopmentPublished 2026-10-07Author: DeepSeek Plugin Market
DSH pluginDeepSeek Harnessprotocol driverctx.agentsACP
How does a DSH plugin connect an external protocol driver? This guide covers wiring ACP peers into ctx.agents and the followup() enqueue receipt.

An external protocol driver in a DSH plugin wires a protocol peer into ctx.agents, letting an external protocol (such as ACP) peer drive an agent to serve a UI or automation client (source). This article covers what a protocol driver is, request mapping and delivery semantics (including the followup() enqueue receipt), and teardown to quiescence with AgentHandle.dispose(); the opposite Host-to-Client direction is in the API gateway explainer, delegating a turn to another product is in subagent providers, while this article covers the protocol-peer-in side.

What a DSH plugin protocol driver is

A protocol driver is one shape a DeepSeek Harness plugin can take: it wires a protocol peer into ctx.agents and can serve a UI or an automation client (source). The basic shape:

  • A stdio driver owns stdout, so it must exclusively own that output channel to talk to the peer.
  • It creates or resumes an agent through a factory and maps protocol requests to followup() or cancel().
  • It injects the relevant services: export const inject = ['agents', 'sessions', 'sessionPersistence'].
  • Outbound, it listens on the session event stream and forwards assistant text/reasoning deltas to the client:
ts
export const name = 'my-protocol-bridge'
export const inject = ['agents', 'sessions', 'sessionPersistence']

export function apply(ctx: Context) {
  // Stream every logged assistant text/reasoning delta out to the client.
  ctx.on('session/event', (_session, event) => {
    if (event.type === 'assistant/chunk') {
      const chunk = event.data.chunk
      if (chunk.type === 'text-delta') {
        // sendToClient({ kind: 'message_chunk', text: chunk.text })
      }
    }
  })
}

The reference implementation is packages/acp/acp, a complete automation-only example: it serves fresh text sessions over ACP (Agent Client Protocol) JSON-RPC stdio, emits committed assistant text, and registers a one-shot machine permission answerer for the agents it owns; its README defines the exact methods, event order, and lifecycle conventions.

DSH plugin protocol driver request mapping and delivery semantics

The underlying prompt request returns its durable enqueue receipt; it does not obtain results by correlating a MessageId with turn/end (source). This semantics decides two things:

  1. Inbound prompt = create/resume + feed + return the enqueue receipt — on a protocol prompt, create or resume an agent, hand it the content, and return the enqueue receipt.
  2. Whole-agent status should be published separately — do not bind "the conclusion of this prompt" to a MessageId and some turn/end; no turn end belongs to this prompt, and whole-agent status is a separate notification.

The two consumers wait differently (source):

  • An automation method may await from the receipt to the next idle and summarize that interval as an explicitly owned span;
  • A UI usually observes the open-ended event stream continuously instead of waiting for a one-time completion signal.

DSH plugin protocol driver teardown and lifecycle

Tear an agent down through AgentHandle.dispose() so that disposal reaches full quiescence (stop and await exit) (source). This is easy to miss: merely issuing a cancel signal and returning is not teardown — only AgentHandle.dispose() brings disposal to quiescence, avoiding leftover running turns or unreleased resources.

Take the reference implementation as the lifecycle convention: the README of packages/acp/acp defines the exact methods, event order, and lifecycle conventions, so read it before writing your own protocol driver rather than inventing an event order.

Three self-checks when done: does an inbound prompt return only an enqueue receipt and is status published separately (not pretending to correlate turn/end); does the stdio driver exclusively own stdout; and does teardown go through AgentHandle.dispose() to quiescence. To find community implementations of protocol or integration plugins, search the DSH Plugin Hub; for extension-point ownership see the feature-to-mechanism map.

FAQ

What is an external protocol driver in a DSH plugin?

An external protocol driver in a DSH plugin wires a protocol peer into ctx.agents to serve a UI or an automation client. A stdio driver owns stdout, creates or resumes an agent through a factory, and maps protocol requests to followup() or cancel(). It is the opposite direction from gateway exposure: a protocol driver brings an external protocol peer in, rather than exposing Host capabilities to a client with @Remote.

How does a DSH plugin protocol driver map a protocol request into one prompt?

In a DSH plugin, a protocol driver creates a new agent or resumes an existing one on an inbound prompt, feeds it the content, and returns its durable enqueue receipt. The key semantics: the underlying prompt request returns an enqueue receipt and does not obtain results by correlating a MessageId with turn/end; whole-agent status should be published separately rather than attached to this prompt.

How does a DSH plugin protocol driver stream assistant output out?

A DSH plugin protocol driver listens on the session/event stream and forwards text deltas to the client when it sees an assistant/chunk whose chunk type is text-delta; this relies on injecting the agents, sessions, and sessionPersistence services. A UI usually observes that open-ended event stream continuously, while an automation client can await from the enqueue receipt to the next idle and summarize that explicitly owned interval.

How does a DSH plugin protocol driver tear down an agent correctly?

A DSH plugin protocol driver tears down an agent through AgentHandle.dispose() so that disposal reaches full quiescence (stop and await exit), rather than issuing a cancel and returning. The official reference implementation is packages/acp/acp: it serves fresh text sessions over ACP (Agent Client Protocol) JSON-RPC stdio, emits committed assistant text, and registers a one-shot machine permission answerer for the agents it owns; its README defines the exact methods, event order, and lifecycle conventions.

Related Terms

protocol driver
A protocol driver is a DeepSeek Harness extension form that wires a protocol peer into ctx.agents to serve a UI or automation client; a stdio driver owns stdout, creates or resumes an agent through a factory, and maps protocol requests to followup() or cancel(), the opposite direction from Host-to-Client @Remote exposure.— https://deepseek-harness.github.io/deepseek-harness/en/reference/cookbook/extension-cookbook
followup() enqueue receipt
In a protocol driver, the underlying prompt request is delivered through followup() and returns a durable enqueue receipt; it does not obtain results by correlating a MessageId with turn/end, whole-agent status must be published separately, and an automation caller can await from the receipt to the next idle.— https://deepseek-harness.github.io/deepseek-harness/en/reference/cookbook/extension-cookbook
AgentHandle.dispose()
AgentHandle.dispose() is how a protocol driver tears an agent down so that disposal reaches full quiescence (stop and await exit), rather than merely issuing a cancel and returning, ensuring teardown leaves nothing running.— https://deepseek-harness.github.io/deepseek-harness/en/reference/cookbook/extension-cookbook

Sources