Extension Protocol v1 for Sidecars in DeepSeek-Reasonix: Intercepting Runtime Events

Extension Protocol v1 defines a JSON-RPC 2.0 interface over STDIO that allows sidecar processes to intercept and rewrite runtime events—most notably user input via the input.receive event—before they reach the language model.

DeepSeek-Reasonix implements Extension Protocol v1 to communicate with out-of-process sidecars that extend the host's capabilities. This stable wire contract, defined in the esengine/DeepSeek-Reasonix repository, enables separate executables defined in a plugin's Manifest v1 runtime entry to intercept runtime events, modify requests, and inject custom behaviors while maintaining compatibility across Reasonix releases.

Protocol Architecture and Transport

Extension Protocol v1 operates over JSON-RPC 2.0 via standard input and output streams. When the Reasonix host initializes a session, it spawns the sidecar executable and establishes a bidirectional communication channel over STDIO, as implemented in sdk/go/sdk.go.

The protocol requires an explicit version handshake. According to internal/extension/protocol/schema.generated.json, the protocolVersion field in HostCapabilities must be set to "v1" to indicate compliance with this specification.

Sidecar Lifecycle and Initialization

Before processing any runtime events, the sidecar must complete an initialization sequence. As documented in sdk/go/sdk.go lines 46-51, the sidecar receives InitializeParams and must respond with an initialization confirmation before the host sends any other callbacks. This ensures both processes agree on capabilities and event handlers before intercepting live traffic.

Intercepting Runtime Events

The primary purpose of Extension Protocol v1 is to allow sidecars to intercept and potentially modify events flowing through the Reasonix host. The sdk/go/types_generated.go file (lines 82-107) defines the EventParams DTO, which includes several interceptable events:

  • input.receive: Intercepts incoming user text before it reaches the model
  • session.start: Hooks into session initialization
  • session.end: Handles session cleanup
  • provider.request: Intercepts or augments requests to model providers

Rewriting User Input with input.receive

The most commonly intercepted event is input.receive, which allows sidecars to rewrite or augment user text in real-time. When a sidecar registers a handler for this event, it receives the raw input payload and can return a modified version with the InterceptDecisionRewrite decision before the host forwards it to the model.

Implementing a Sidecar in Go

The DeepSeek-Reasonix SDK provides Go bindings that abstract the JSON-RPC wire protocol. Below are practical implementations demonstrating event interception.

Starter Sidecar Example

The starter sidecar example in sdk/go/examples/starterextension/main_test.go demonstrates a minimal implementation that intercepts inputs starting with starter: and rewrites them:

// File: sdk/go/examples/starterextension/main_test.go
result, err := interceptInput(
    context.Background(),
    "input.receive",
    json.RawMessage(`{"text":"starter: explain sidecars"}`),
)
want := `{"text":"explain sidecars [rewritten by starter-extension]"}` // ✅ passes

This handler checks for the starter: prefix and transforms the payload by appending a suffix before returning the modified JSON.

For more complex scenarios, the full sidecar example in sdk/go/examples/fullsidecar/main.go shows how to register multiple intercept handlers and manage the sidecar lifecycle:

// File: sdk/go/examples/fullsidecar/main.go
func main() {
    // …setup extension server…
    // Register intercept handler
    ext.OnIntercept("input.receive", func(ctx context.Context, p extension.InterceptParams) (extension.InterceptResult, error) {
        var in struct{ Text string `json:"text"` }
        json.Unmarshal(p.Payload, &in)
        if strings.HasPrefix(in.Text, "fullsidecar:") {
            in.Text = strings.TrimPrefix(in.Text, "fullsidecar:") + " [rewritten by fullsidecar]"
        }
        out, _ := json.Marshal(in)
        return extension.InterceptResult{Decision: extension.InterceptDecisionRewrite, Payload: out}, nil
    })
    // …run the sidecar…
}

When running this sidecar and sending fullsidecar: hello, the model receives hello [rewritten by fullsidecar], demonstrating the end-to-end interception flow:

> starter: explain sidecars

# The starter sidecar intercepts the input, rewrites it, and the model receives:

explain sidecars [rewritten by starter-extension]

Protocol Stability and Versioning

Extension Protocol v1 guarantees backward compatibility through a frozen contract. According to internal/extension/protocolgen/sdkgo.go lines 160-165, method names and data structures are generated from the internal/extension/protocol definitions and are explicitly frozen for version v1.

This stability ensures that sidecars built against Protocol v1 continue functioning across Reasonix releases without recompilation, enabling reliable caching and safe hot-reloads of extensions.

Key Source Files

Understanding the protocol implementation requires examining these specific files in the esengine/DeepSeek-Reasonix repository:

Summary

  • Extension Protocol v1 uses JSON-RPC 2.0 over STDIO to communicate with out-of-process sidecars
  • Sidecars must complete initialization via InitializeParams before handling runtime events
  • The input.receive event allows rewriting user input before it reaches the model
  • Protocol contracts are frozen in v1, ensuring long-term compatibility across Reasonix versions
  • Reference implementations in sdk/go/examples/ demonstrate practical interception patterns

Frequently Asked Questions

What transport mechanism does Extension Protocol v1 use?

Extension Protocol v1 transmits messages via JSON-RPC 2.0 over standard input and output streams (STDIO). As implemented in sdk/go/sdk.go, the host spawns the sidecar process and establishes a bidirectional channel over STDIN/STDOUT, eliminating the need for network sockets or shared memory.

Which runtime events can a sidecar intercept?

According to sdk/go/types_generated.go, sidecars can intercept multiple events including input.receive for user text, session.start and session.end for lifecycle management, and provider.request for model provider calls. Each event passes structured data via the EventParams DTO.

How does the protocol ensure version compatibility?

The protocol requires an explicit version handshake where protocolVersion in HostCapabilities must equal "v1". Additionally, internal/extension/protocolgen/sdkgo.go generates frozen DTOs and method names that remain stable across releases, preventing breaking changes for compiled sidecars.

Can sidecars modify user input before it reaches the model?

Yes. By registering a handler for the input.receive event, sidecars receive the raw input payload and return an InterceptResult with Decision: InterceptDecisionRewrite and modified payload data. Examples in both starterextension and fullsidecar demonstrate rewriting text by checking prefixes and transforming content.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →