Extension Protocol v1 and Sidecar Runtime Event Interception in DeepSeek-Reasonix

The Extension Protocol v1 is a stable RPC protocol that lets out-of-process sidecars intercept, modify, or consume runtime events in DeepSeek-Reasonix, enabling plugins to replace built-in behaviors and contribute custom model providers.

DeepSeek-Reasonix's plugin architecture separates declarative contributions (skills, agents, prompts) from runtime contributions through the Extension Protocol v1. When a plugin's reasonix-plugin.json manifest specifies a runtime entry, Reasonix launches a sidecar binary that communicates with the host via this protocol. This article explains the protocol's design, how sidecars establish connections, and the specific mechanisms for runtime event interception.

What Is Extension Protocol v1?

Extension Protocol v1 defines the wire format and RPC methods for host-sidecar communication in DeepSeek-Reasonix. It is a versioned, stable contract that ensures backward compatibility while allowing the platform to evolve.

The protocol uses stdio-based JSON-RPC by default, though the transport layer is pluggable. All message types are generated as strongly-typed DTOs in sdk/go/types_generated.go, including:

  • InitializeParams / InitializeResult — protocol handshake
  • InterceptParams / InterceptResult — runtime event interception
  • UIPublishParams, UIActionDecl — UI contributions
  • ProvideParams / ProvideResult — model provider registration

The protocol enforces strict version negotiation. During initialization, the host advertises its supported protocol version. Sidecars using an incompatible major version are rejected, as verified in internal/boot/extension_sidecar_test.go. This prevents runtime crashes from version skew.

How Sidecars Intercept Runtime Events

Sidecars gain the ability to intercept events through a capability-based handshake. After successful initialization, the host forwards specific event types to registered sidecars, which can then consume, modify, or allow each event to proceed.

Event Interception Flow

  1. Event generation — The Reasonix runtime produces events (ResourcesChanged, Shutdown, UI notifications, etc.)
  2. Dispatch — The host's internal/extension/uihub/hub.go routes events to applicable sidecars based on declared capabilities
  3. Sidecar decision — The sidecar's Intercept handler returns an InterceptDecision:
    • Allow — Event continues unchanged
    • Modify — Event payload is replaced with sidecar's version
    • Consume — Event is dropped, no further processing

The hub implementation manages this dispatch efficiently, ensuring that slow sidecars don't block the main runtime through internal timeouts and cancellation propagation.

Key Interception Capabilities

Sidecars can intercept several event categories:

Event Category Example Events Typical Use Case
Resource lifecycle ResourcesChanged, ResourceLoad Custom resource validation, caching
System Shutdown, ConfigChange Graceful cleanup, dynamic reconfiguration
UI UINotify, UIAction Custom panel injection, action handling
Model inference InferenceRequest Provider selection, request transformation

Sidecar Lifecycle and Handshake

The host-sidecar relationship follows a strict lifecycle defined in internal/extension/sidecar/doc.go:

  1. Spawn — Host launches the sidecar binary specified in runtime.entry
  2. Initialize — JSON-RPC handshake negotiates protocol version and capabilities
  3. Register — Sidecar declares which events it wants to intercept and which providers it offers
  4. Serve — Bidirectional RPC loop begins; sidecar processes requests until shutdown
  5. Teardown — Host sends Shutdown event; sidecar performs cleanup and exits

The doc.go file documents host-side responsibilities including stderr log forwarding, process health monitoring, and graceful termination timeouts.

Implementing a Runtime-Intercepting Sidecar

Below is a complete Go sidecar that intercepts resource change events and logs them before allowing continuation:

// main.go — minimal sidecar with event interception
package main

import (
	"context"
	"encoding/json"
	"log"
	"os"

	extension "github.com/esengine/DeepSeek-Reasonix/sdk/go"
)

func main() {
	// Create client speaking Extension Protocol v1 over stdio
	client := extension.NewClient(os.Stdin, os.Stdout)

	// Register capabilities during initialization
	client.OnInitialize(func(ctx context.Context, params *extension.InitializeParams) (*extension.InitializeResult, error) {
		return &extension.InitializeResult{
			ProtocolVersion: "1.0",
			Capabilities: extension.ServerCapabilities{
				InterceptEvents: []string{"ResourcesChanged", "ConfigChange"},
			},
		}, nil
	})

	// Handle resource change interception
	client.OnIntercept(func(ctx context.Context, params *extension.InterceptParams) (*extension.InterceptResult, error) {
		var payload map[string]interface{}
		if err := json.Unmarshal(params.Payload, &payload); err != nil {
			log.Printf("Failed to unmarshal %s payload: %v", params.Event, err)
			// Fail open: allow event on parse error
			return &extension.InterceptResult{Decision: extension.InterceptDecisionAllow}, nil
		}

		log.Printf("[INTERCEPT] Event=%s Resource=%v", params.Event, payload["uri"])

		// Example: block certain resource patterns
		if uri, ok := payload["uri"].(string); ok && containsSensitivePattern(uri) {
			log.Printf("Blocking sensitive resource: %s", uri)
			return &extension.InterceptResult{
				Decision: extension.InterceptDecisionConsume,
				Reason:   "sensitive_resource_blocked",
			}, nil
		}

		return &extension.InterceptResult{Decision: extension.InterceptDecisionAllow}, nil
	})

	log.Println("Sidecar starting...")
	if err := client.Serve(); err != nil {
		log.Fatalf("Sidecar fatal error: %v", err)
	}
}

func containsSensitivePattern(uri string) bool {
	// Implementation omitted for brevity
	return false
}

The accompanying manifest (reasonix-plugin.json):

{
  "name": "resource-guard-sidecar",
  "version": "1.0.0",
  "manifestVersion": 2,
  "description": "Intercepts and audits resource access",
  "runtime": {
    "entry": "./resource-guard-sidecar",
    "protocol": "v1"
  }
}

Advanced Interception Patterns

Provider Replacement

Sidecars can declare model provider capabilities during initialization, replacing built-in inference backends. The host delegates InferenceRequest events to the sidecar's Provide method, which streams responses back via the protocol's streaming primitives.

UI Contribution with Event Interception

Sidecars combine interception with UI publishing. A sidecar can:

  1. Intercept a UINotify event
  2. Modify its payload to inject custom data
  3. Publish a new panel via UIPublishParams with UIActionDecl buttons that trigger future interceptable events

This creates reactive UI extensions without host code modification.

Protocol Evolution and Compatibility

Extension Protocol v1 uses semantic versioning with strict rules:

  • Major version changes break wire compatibility — sidecars must upgrade
  • Minor version changes add optional capabilities — ignored by older hosts
  • Patch version changes are transparent

The host rejects sidecars with unsupported major versions during Initialize. This is enforced in the test suite at internal/boot/extension_sidecar_test.go, which validates version mismatch handling.

Summary

  • Extension Protocol v1 is the stable RPC contract between DeepSeek-Reasonix and out-of-process sidecars, defined in generated types at sdk/go/types_generated.go

  • Sidecars intercept runtime events through capability-based registration, with the host dispatching events via internal/extension/uihub/hub.go and sidecars returning Allow/Modify/Consume decisions

  • Strict version negotiation during initialization prevents runtime incompatibilities, with major version mismatches rejected before any event processing begins

  • Sidecars can replace providers and contribute UI in addition to interception, making them full runtime participants

  • Implementation reference: lifecycle documentation in internal/extension/sidecar/doc.go, type definitions in sdk/go/, and host dispatch logic in internal/extension/uihub/hub.go

Frequently Asked Questions

What transport does Extension Protocol v1 use?

Extension Protocol v1 uses stdio-based JSON-RPC by default, with stdin for host-to-sidecar messages and stdout for sidecar-to-host responses. The protocol is transport-agnostic — alternative implementations could use named pipes, TCP sockets, or WebSockets while preserving the same message format.

Can multiple sidecars intercept the same event?

Yes. The host in internal/extension/uihub/hub.go dispatches interceptable events to all registered sidecars sequentially. Each sidecar's decision affects the event state: a Consume decision short-circuits further processing; Modify updates the payload for subsequent sidecars; Allow passes the current state unchanged. The final modified event (or lack thereof) determines the host's behavior.

How do I debug a sidecar that fails to connect?

Start by checking stderr output — the host forwards sidecar stderr to its own logs. Verify that your reasonix-plugin.json includes a valid runtime.entry pointing to an executable binary. Confirm protocol version compatibility: your sidecar must implement "1.0" in its InitializeResult. Finally, examine internal/extension/sidecar/doc.go for host-side timeout and health-check configurations that may cause silent failures.

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 →