# Go SDK Architecture for Developing Extensions in Reasonix: A Technical Deep Dive

> Explore the Reasonix Go SDK architecture for developing extensions. Discover its JSON-RPC 2.0 sidecar implementation, state-machine server, and modular interfaces for a deep technical dive.

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

---

**The Reasonix Go SDK implements the Extension Protocol v1 as a sidecar that communicates via JSON-RPC 2.0 over NDJSON, using a state-machine-driven server that manages the lifecycle through strict handshake barriers, concurrent callback handling, and modular interfaces for interceptors, providers, and UI handlers.**

The `sdk/go` package in the `esengine/DeepSeek-Reasonix` repository provides a robust framework for building sidecar extensions that extend Reasonix's core functionality. This Go SDK architecture for developing extensions in Reasonix centers on a JSON-RPC transport layer, a rigorous state machine for protocol compliance, and carefully isolated concurrency boundaries to ensure reliable host communication.

## Core Architectural Components

### Server and Transport Layer

The `server` struct in [`sdk/go/sdk.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/sdk.go) orchestrates the entire extension lifecycle, managing the transport layer and routing incoming requests. It wraps a `conn` object—created by `newConn`—that handles low-level NDJSON framing for JSON-RPC 2.0 messages. This connection layer serializes messages, assigns request IDs, and performs raw `call` and `notify` operations that underpin all host communication.

### Handler Interface and Initialization

Every extension must implement the `Handler` interface defined at lines 43-49 of [`sdk.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk.go). The `Initialize` method serves as the mandatory entry point where extensions announce their name, version, and capabilities through `InitializeResult`. This handshake occurs while the internal state machine is in `stateHandshake`, ensuring the host receives the extension manifest before any operational methods are invoked.

### Configuration and Concurrency Safety

The `Options` struct (lines 28-58) configures the sidecar's behavior, including stdin/stdout redirection, interceptors, provider implementations, and UI callbacks. Critically, the SDK may invoke up to **32 callbacks concurrently**, requiring extension developers to protect shared state with synchronization primitives like `sync.Mutex`. The `Shutdown` callback, also configured via `Options`, enables graceful termination when the host requests shutdown via `handleShutdown` (approximately lines 44-84).

### Event Interception System

Interceptors allow extensions to inspect and modify events through `InterceptorFunc` types defined at lines 51-57. The `handleIntercept` function (approximately lines 88-125) processes these rules, enabling extensions to **Continue**, **Block**, **Replace**, **Allow**, or **Deny** intercepted events based on custom logic.

### Provider Streaming Architecture

The `Provider` interface (lines 58-73) enables extensions to supply model catalogs and streaming inference results. Implementations must provide `Catalog` for model discovery and `Stream` for opening token streams. The SDK manages these through `handleStreamOpen` and `pumpStream`, ensuring chunks are delivered to the host while preserving ordering and handling cancellation signals properly.

### UI Integration and Host Communication

Extensions implement `UIHandler` (lines 17-26) to respond to host-side UI actions like `Action` and `Submit` events. Conversely, the `HostUI` client (starting at line 46) allows extensions to initiate host-side interactions, presenting status cards, notifications, and user prompts through methods like `RequestConfirm` and `PublishStatus`.

### Protocol State Machine

The SDK enforces strict protocol compliance through a state machine with four phases: `stateNew`, `stateHandshake`, `stateReady`, and `stateShutdown`. The `gateRequest` and `gateNotification` functions (approximately lines 25-70) reject all calls until the host completes the handshake sequence: first sending `extension/initialize` (triggering `Handler.Initialize`), then `extension/initialized` (transitioning to `stateReady`).

### Content References and Error Handling

For large payloads, the SDK externalizes data via content references. The `ReadContentRef` (approximately lines 998-1055) and `ResolveExternalized` (approximately lines 1068-1085) helpers paginate, verify SHA-256 checksums, and safely re-assemble data. Host-side JSON-RPC errors are mapped to typed `ProtocolError` structures via `mapCallError` (lines 127-137), providing extensions with specific failure reasons like `ErrProtocolError` and `ErrProviderFailed`.

## Implementation Examples

### Basic Extension Setup

The following example demonstrates the minimal structure required to implement the `Handler` interface and start the server:

```go
package main

import (
	"context"
	"log"
	"os"

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

type MyHandler struct{}

func (h *MyHandler) Initialize(ctx context.Context, p ext.InitializeParams) (*ext.InitializeResult, error) {
	return &ext.InitializeResult{
		Name:    "demo-extension",
		Version: "0.1.0",
	}, nil
}

func main() {
	h := &MyHandler{}
	opts := ext.Options{
		Name:    "demo-extension",
		Version: "0.1.0",
		Logger:  log.New(os.Stderr, "demo: ", log.LstdFlags),
	}
	if err := ext.Serve(context.Background(), h, opts); err != nil {
		log.Fatalf("extension terminated: %v", err)
	}
}

```

### Implementing Interceptors

Interceptors examine events and return control directives to the SDK:

```go
func blockSensitive(ctx context.Context, event string, payload json.RawMessage) (*ext.InterceptResult, error) {
	if event == "session.start" {
		return ext.Block("session starts are not allowed in demo mode"), nil
	}
	return ext.Continue(), nil
}

opts := ext.Options{
	Interceptors: map[string]ext.InterceptorFunc{
		"*": blockSensitive,
	},
}

```

### Building a Custom Provider

Providers stream model responses through Go channels:

```go
type DemoProvider struct{}

func (p *DemoProvider) Catalog(ctx context.Context) ([]ext.ProviderDescriptor, error) {
	return []ext.ProviderDescriptor{
		{Ref: "demo-model", Name: "Demo Model", Owner: "demo-org"},
	}, nil
}

func (p *DemoProvider) Stream(ctx context.Context, req ext.StreamRequest) (<-chan ext.StreamChunk, error) {
	ch := make(chan ext.StreamChunk)
	go func() {
		defer close(ch)
		ch <- ext.TextChunk("Hello, ")
		time.Sleep(100 * time.Millisecond)
		ch <- ext.TextChunk("world!")
		ch <- ext.DoneChunk()
	}()
	return ch, nil
}

opts := ext.Options{Provider: &DemoProvider{}}

```

### Host UI Interaction

Extensions can prompt users through the host interface during initialization or runtime:

```go
func (h *MyHandler) Initialize(ctx context.Context, p ext.InitializeParams) (*ext.InitializeResult, error) {
	confirm, err := ext.HostUI{}.RequestConfirm(ctx, "sess-1", 0, "confirm-1", "Proceed?")
	if err != nil || !confirm {
		return nil, fmt.Errorf("user declined")
	}
	return &ext.InitializeResult{Name: "demo-extension", Version: "0.1.0"}, nil
}

```

## Key Source Files

- **[`sdk/go/sdk.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/sdk.go)** – Core server implementation, lifecycle orchestration, transport management, and public API definitions.
- **[`sdk/go/wire.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/wire.go)** – Low-level JSON-RPC wire protocol definitions, message structs, method constants, and error types.
- **[`sdk/go/types_generated.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/types_generated.go)** – Auto-generated type definitions for the extension protocol, including catalog entries and stream chunks.
- **[`sdk/go/types_ext.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/types_ext.go)** – Extensions to generated types, providing convenience helpers and custom error values.
- **[`sdk/go/sdk_test.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/sdk_test.go)** – Unit tests exercising the server state machine, interceptors, provider streams, and UI client helpers.
- **[`sdk/go/ui_test.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/ui_test.go)** – Tests for the `HostUI` client covering prompts and surface publishing.
- **[`sdk/go/provider_test.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk/go/provider_test.go)** – Example provider implementations used in the test suite.

## Summary

- The SDK uses **JSON-RPC 2.0 over NDJSON** for host communication, implemented in the `conn` type within [`sdk.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk.go).
- A **strict state machine** (`stateNew` → `stateHandshake` → `stateReady`) gates all operations until the handshake completes.
- Extensions must implement the **`Handler`** interface, providing initialization metadata and optional capabilities.
- The **Provider** interface enables streaming model responses through managed channels with automatic pumping and cancellation.
- **Interceptors** can modify, block, or allow events using the `InterceptorFunc` signature processed by `handleIntercept`.
- Up to **32 concurrent callbacks** may execute simultaneously, requiring thread-safe extension code.
- Large payloads use **content references** with SHA-256 verification via `ReadContentRef` and `ResolveExternalized`.
- UI integration works bidirectionally through **`UIHandler`** (host-to-extension) and **`HostUI`** (extension-to-host).

## Frequently Asked Questions

### How does the Reasonix Go SDK handle concurrent requests?

The SDK maintains an internal worker pool that can execute up to 32 callbacks concurrently according to the `Options` struct configuration. Because the host may invoke interceptors, providers, and UI handlers simultaneously, extension developers must protect shared state using synchronization primitives like `sync.Mutex` or atomic operations to prevent race conditions.

### What is the extension handshake protocol in the Go SDK?

The protocol requires a two-step handshake: after startup (`stateNew`), the host sends `extension/initialize` which triggers the extension's `Handler.Initialize` method while in `stateHandshake`. The extension returns its manifest, then the host sends `extension/initialized`, transitioning the state machine to `stateReady`. The `gateRequest` and `gateNotification` functions reject all other calls until this barrier opens.

### How do interceptors work in the Reasonix extension architecture?

Interceptors are functions matching the `InterceptorFunc` signature defined at lines 51-57 of [`sdk.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/sdk.go). Registered in the `Options.Interceptors` map, they receive event names and raw JSON payloads, then return `InterceptResult` values that instruct the SDK to **Continue**, **Block**, **Replace**, **Allow**, or **Deny** the event. The `handleIntercept` function (lines 88-125) evaluates these rules before passing events to downstream handlers.

### What is the purpose of the Provider interface in the Go SDK?

The `Provider` interface (lines 58-73) abstracts model inference capabilities, requiring implementations to provide `Catalog` for model discovery and `Stream` for generating token responses. When the host requests inference, the SDK invokes `handleStreamOpen` to establish the stream, then uses `pumpStream` to deliver chunks to the host while managing backpressure and cancellation tokens.