Write Reasonix extensions in
Go. An extension is a small sidecar process speaking Extension Protocol
v2 (reasonix.extension.v2) over stdio: Reasonix launches it, hands it the
initialize handshake, and then drives intercepts, event observation,
extension-hosted provider streams, and structured UI surfaces.
The module is standard library only — zero dependencies.
go get github.com/esengine/DeepSeek-Reasonix/sdk/go@v1.0.0Requires Go 1.23+. SDK releases use immutable sdk/go/vX.Y.Z repository
tags; sdk/go/v1.0.0 is published with the first product release containing
Extension Protocol v2. Before that tag exists, develop against a source
checkout instead of depending on an unversioned API.
package main
import (
"context"
"encoding/json"
"os"
extension "github.com/esengine/DeepSeek-Reasonix/sdk/go"
)
type ext struct{}
func (ext) Initialize(_ context.Context, p extension.InitializeParams) (*extension.InitializeResult, error) {
return &extension.InitializeResult{
Name: "my-ext",
Version: "0.1.0",
Subscriptions: []string{"tool.before"},
}, nil
}
func main() {
err := extension.Serve(context.Background(), ext{}, extension.Options{
Interceptors: map[string]extension.InterceptorFunc{
"tool.before": func(_ context.Context, event string, payload json.RawMessage) (*extension.InterceptResult, error) {
return extension.Continue(), nil // or Block / Replace / Allow / Deny
},
},
})
if err != nil {
os.Exit(1)
}
// Serve returned nil: the host asked for shutdown. Exit 0.
}Everything else is optional and declared through Options: an Observer
for fire-and-forget events, a Provider for extension-hosted model
providers, UI callbacks plus the HostUI client for structured surfaces
(status, cards, forms, notifications and blocking prompts — never HTML/JS),
ReadContentRef/ResolveExternalized for large externalized payloads, and a
Shutdown hook.
Initialize runs once and completes before any other callback. After that,
the SDK may run up to 32 inbound callbacks concurrently: interceptors,
observers, resource notifications, provider Catalog/Stream, and UI
callbacks can overlap, and multiple provider streams may be active at once.
Treat callback inputs as call-local and protect mutable state shared by
callbacks with a mutex, atomics, channels, or another explicit ownership
scheme. Cancellation and shutdown may overlap work already in flight, so
callbacks and stream producers must honor their contexts.
The SDK serializes protocol writes itself; extensions must not write directly to stdout. stderr remains available for diagnostics.
examples/starterextension is the
copyable first extension: it includes a Manifest v2 file, a minimal sidecar,
cross-platform build commands, linked installation, /reload, and a visible
input-rewrite check.
examples/fullsidecar is the reference
extension: input rewriting (try the /fs trigger), tool interception
(block + argument rewrite), system-prompt strategy replacement, a fake
streaming provider (text chunks, a tool call, usage), structured UI (status +
card on session start, a form prompt behind the demo action), and a clean
bounded shutdown — all in one small stdlib-only program.
mkdir -p /tmp/full-sidecar/bin
cp ./examples/fullsidecar/reasonix-plugin.json /tmp/full-sidecar/
go build -o /tmp/full-sidecar/bin/full-sidecar ./examples/fullsidecarThe resulting directory is a complete Manifest v2 plugin package. The binary
speaks the protocol on stdin/stdout, so install the directory as a plugin
package (or point the host-side conformance suite at it) rather than running
the binary interactively. It is installed into a temporary Reasonix home and
driven end-to-end against the real host by internal/extension/conformance in
the Reasonix repository.
types_generated.go is produced from the host's frozen protocol registry by
go run ./cmd/extension-protocol-gen -root . (repository root). Edit nothing
in that file; the handwritten half of the type layer (validators, error
constructors, enum helpers) lives in types_ext.go.
- Method/DTO contract:
docs/EXTENSION_PROTOCOL.generated.md - Canonical JSON schema:
internal/extension/protocol/schema.generated.json - Transport: strict JSON-RPC 2.0 over NDJSON (one object per line), integer request ids, object params, 8 MiB frames.
Extension Protocol v2's compatibility promise applies: within major version 2, only optional fields, new enum values, and new methods are added; existing required fields, method names, directions, limits, error reasons, and semantics never change. This SDK tracks that contract — compatible SDK updates that target protocol v2 do not break a compiled extension.