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 handshakeInterceptParams/InterceptResult— runtime event interceptionUIPublishParams,UIActionDecl— UI contributionsProvideParams/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
- Event generation — The Reasonix runtime produces events (
ResourcesChanged,Shutdown, UI notifications, etc.) - Dispatch — The host's
internal/extension/uihub/hub.goroutes events to applicable sidecars based on declared capabilities - Sidecar decision — The sidecar's
Intercepthandler returns anInterceptDecision:Allow— Event continues unchangedModify— Event payload is replaced with sidecar's versionConsume— 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:
- Spawn — Host launches the sidecar binary specified in
runtime.entry - Initialize — JSON-RPC handshake negotiates protocol version and capabilities
- Register — Sidecar declares which events it wants to intercept and which providers it offers
- Serve — Bidirectional RPC loop begins; sidecar processes requests until shutdown
- Teardown — Host sends
Shutdownevent; 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:
- Intercept a
UINotifyevent - Modify its payload to inject custom data
- Publish a new panel via
UIPublishParamswithUIActionDeclbuttons 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.goand sidecars returningAllow/Modify/Consumedecisions -
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 insdk/go/, and host dispatch logic ininternal/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →