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

> Learn about Extension Protocol v1 and how sidecars intercept runtime events in DeepSeek-Reasonix. Discover how plugins replace built-in behaviors and add custom model providers.

- Repository: [YHH/DeepSeek-Reasonix](https://github.com/esengine/DeepSeek-Reasonix)
- Tags: deep-dive
- Published: 2026-08-11

---

**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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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:

```go
// 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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/reasonix-plugin.json)):

```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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/types_generated.go)

- **Sidecars intercept runtime events** through capability-based registration, with the host dispatching events via [`internal/extension/uihub/hub.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/extension/sidecar/doc.go), type definitions in `sdk/go/`, and host dispatch logic in [`internal/extension/uihub/hub.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/extension/sidecar/doc.go) for host-side timeout and health-check configurations that may cause silent failures.