capabilityruntime

package module
v0.0.0-...-31292c5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 29, 2026 License: MIT Imports: 11 Imported by: 0

README

executor-go

The official Go SDK for building Neuron capability runtimes. Implement a capability as a plain Go Handler; the SDK handles protocol negotiation, Unix domain socket setup, readiness signaling, and lifecycle management.

A capability runtime is a program that exposes the Neuron execution contract: an input map in, an output map (or a controlled error) out.

flowchart LR
    S[Neuron Capability<br/>content.document-metadata] --> C[Capability Runtime Contract<br/>executor.json]
    C --> G[Go Capability Runtime<br/>Handler + Serve]
    G --> P[Process Runtime<br/>gRPC worker]
    G --> W[WASM Runtime<br/>JSON over stdio]

Go License


Module

github.com/neuron-runtime/neuron/packages/executor-sdks/golang

Requirements:

  • Go 1.26 or newer
  • google.golang.org/grpc
  • the shared Neuron contract module github.com/neuron-runtime/neuron/shared

Success on both runtimes

The same Go source works in both execution modes N.O.R.E. supports, selected automatically at startup from the environment the runtime provides:

  • as a long-lived gRPC worker speaking neuron/capability-runtime-v1 over a Unix domain socket, and
  • as a one-shot command speaking neuron/capability-runtime-v1-json on stdin/stdout.

You never select the mode yourself. Write the capability runtime once, declare it once in executor.json, and the same source serves the process and wasm runtime backends — see One source, two runtimes.


The scenario: document metadata extraction

Throughout this guide the example is a realistic capability: content.document-metadata, which extracts metadata from a markdown document.

Input:

{
  "document": {
    "name": "quarterly-report.md",
    "content": "# Q3 Revenue\n\nRevenue increased by 18%."
  }
}

Output:

{
  "metadata": {
    "title": "Q3 Revenue",
    "headings": ["Q3 Revenue"],
    "wordCount": 3,
    "paragraphCount": 1
  }
}

This is a production-shaped capability runtime — real input structure, real output structure, structured errors for malformed input. An echo handler shows the mechanics; this shows a capability.


The Handler contract

A capability runtime is implemented as an executor.Handler with four callbacks:

Callback When it runs Responsibility
Initialize Once per process, before anything else Negotiate protocol version; return identity and capabilities
Execute Once per execution Run the capability and return the output map
Health Periodically by the runtime Report readiness to accept requests (nil → always healthy)
Shutdown Before the process terminates Release resources gracefully (nil → terminate immediately)
type Handler struct {
    Initialize func(ctx context.Context, protocol string, metadata map[string]string) (*InitializeResult, error)
    Execute    func(ctx context.Context, input map[string]any) (map[string]any, error)
    Health     func(ctx context.Context) error
    Shutdown   func(ctx context.Context) error
}

Serve requires both Initialize and Execute; a handler missing either is rejected at startup.

InitializeResult carries the capability runtime's side of the negotiation:

type InitializeResult struct {
    ProtocolVersion string
    Capabilities    []string
    Metadata        map[string]string
}

Return the protocol version you support in ProtocolVersion. A known protocol is mirrored back; when left empty, the SDK fills in the canonical value (neuron/capability-runtime-v1). The constants live in shared/types/capabilityruntime.


A complete capability runtime

package main

import (
	"context"
	"fmt"
	"log"
	"strings"

	executor "github.com/neuron-runtime/neuron/packages/executor-sdks/golang"
	shadexec "github.com/neuron-runtime/neuron/shared/types/capabilityruntime"
)

// Document is the capability runtime's input contract.
type Document struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

// Metadata is the capability runtime's output contract.
type Metadata struct {
	Title          string   `json:"title"`
	Headings       []string `json:"headings"`
	WordCount      int      `json:"wordCount"`
	ParagraphCount int      `json:"paragraphCount"`
}

// extractMetadata is the capability itself. It is pure and independent of
// any transport, which makes it trivial to unit-test and reuse.
func extractMetadata(doc Document) Metadata {
	var (
		title    string
		headings []string
		words    int
		paras    int
	)
	for _, line := range strings.Split(doc.Content, "\n") {
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}
		if strings.HasPrefix(line, "#") {
			heading := strings.TrimLeft(line, "# ")
			if heading == "" {
				continue
			}
			if title == "" {
				title = heading
			}
			headings = append(headings, heading)
			continue
		}
		if strings.HasPrefix(line, "- ") || strings.HasPrefix(line, "* ") {
			continue
		}
		paras++
		words += len(strings.Fields(line))
	}
	return Metadata{Title: title, Headings: headings, WordCount: words, ParagraphCount: paras}
}

func main() {
	if err := executor.Serve(executor.Handler{
		Initialize: func(ctx context.Context, protocol string, metadata map[string]string) (*executor.InitializeResult, error) {
			return &executor.InitializeResult{
				ProtocolVersion: shadexec.ProtocolV1,
				Capabilities:    []string{"document.metadata.extract"},
				Metadata: map[string]string{
					"capability": "content.document-metadata",
				},
			}, nil
		},
		Execute: func(ctx context.Context, input map[string]any) (map[string]any, error) {
			raw, ok := input["document"].(map[string]any)
			if !ok {
				return nil, fmt.Errorf("input.document: expected an object")
			}
			name, _ := raw["name"].(string)
			content, _ := raw["content"].(string)

			meta := extractMetadata(Document{Name: name, Content: content})

			return map[string]any{
				"metadata": map[string]any{
					"title":          meta.Title,
					"headings":       meta.Headings,
					"wordCount":      meta.WordCount,
					"paragraphCount": meta.ParagraphCount,
				},
			}, nil
		},
	}); err != nil {
		log.Fatal(err)
	}
}

Serve blocks until the capability runtime is shut down. It returns nil after a graceful stop (or in one-shot JSON mode after one request) and an error otherwise.

[!TIP] Keep the business logic (extractMetadata) separate from the handler glue. The pure function is unit-testable without the SDK, and the handler stays a thin protocol adapter.


Transport selection

The SDK picks the transport at startup by inspecting the environment it was launched with:

flowchart TD
    A[capability runtime launched by N.O.R.E.] --> B{NEURON_CAPABILITY_RUNTIME_SOCKET set?}
    B -->|yes| C[gRPC worker<br/>neuron/capability-runtime-v1]
    C --> D[create readiness file<br/>NEURON_CAPABILITY_RUNTIME_READY]
    D --> F[long-lived worker pool]
    B -->|no| E[one-shot JSON<br/>neuron/capability-runtime-v1-json]
    E --> G[read request on stdin<br/>write response on stdout]
    G --> H[exit after one request]
Variable When set / meaning
NEURON_CAPABILITY_RUNTIME_SOCKET Path of the Unix domain socket. If set, the capability runtime starts a gRPC server listening there
NEURON_CAPABILITY_RUNTIME_READY Path of a file to create once the server is accepting connections (the launcher waits for this file)
NEURON_CAPABILITY_RUNTIME_PROTOCOL The execution protocol the runtime expects (informational; read via os.Getenv)
NEURON_CAPABILITY_RUNTIME_TYPE The logical capability runtime type, e.g. content:document-metadata (informational)
NEURON_CAPABILITY_RUNTIME_VERSION The resolved capability runtime version (informational)

Decisions made from this environment:

  • If NEURON_CAPABILITY_RUNTIME_SOCKET is set, the capability runtime runs as a gRPC worker on the Unix domain socket at that path and signals readiness by creating the file at NEURON_CAPABILITY_RUNTIME_READY once the server is accepting connections.
  • If it is not set, the capability runtime runs as a one-shot stdin/stdout command: it reads a single JSON request from stdin, writes a single JSON response to stdout, and exits. This is the mode a WASI module (and any legacy command) always uses, since WASI has no socket interface.

The SDK cleans up a stale socket file from a crashed process before listening, so a restart never fails because an old socket file is still present.


Data conversion

Inputs and outputs are dynamic maps (map[string]any). The SDK converts them to and from the protobuf Value type used on the gRPC transport:

Go type Preserved as
nil, bool null, boolean
float64, float32, int, int32, int64, uint, uint32, uint64 numbers
string, []byte string
time.Time RFC 3339 string
[]any, map[string]any recursively
anything else string rendering

On the way back, numeric protobuf values that are whole numbers are returned as int64; fractional values return as float64.


One source, two runtimes

Because the SDK selects its transport from the environment, the same Go source compiles into both runtime backends:

GOOS=$(go env GOOS) GOARCH=$(go env GOARCH) go build -o document-metadata .
GOOS=wasip1 GOARCH=wasm go build -o document-metadata.wasm .

Two manifests, one pair of binaries. The process binary declares the gRPC protocol (neuron/capability-runtime-v1) under the host's platform key; the WASM module declares the JSON protocol (neuron/capability-runtime-v1-json) under the portable wasm32-wasi key:

{
  "apiVersion": "neuron/v1",
  "kind": "Executor",
  "metadata": { "name": "content:document-metadata", "version": "1.0.0" },
  "runtime": { "type": "process", "entrypoint": "document-metadata", "protocol": "neuron/capability-runtime-v1" },
  "services": ["content:document-metadata"],
  "capabilities": ["document.metadata.extract"],
  "platforms": { "linux-amd64": { "artifact": "document-metadata", "sha256": "..." } }
}
{
  "apiVersion": "neuron/v1",
  "kind": "Executor",
  "metadata": { "name": "content:document-metadata", "version": "1.0.0" },
  "runtime": { "type": "wasm", "entrypoint": "document-metadata.wasm", "protocol": "neuron/capability-runtime-v1-json" },
  "services": ["content:document-metadata"],
  "capabilities": ["document.metadata.extract"],
  "platforms": { "wasm32-wasi": { "artifact": "document-metadata.wasm" } }
}

[!NOTE] capabilities describes what the capability runtime claims to provide; it is metadata, not permission. Actual permissions are enforced by the runtime at the execution boundary.

To distribute both artifacts as one versioned unit, pack each pair into a canonical capability runtime package archive (<name>-<version>-capability-runtime.neuron.tar.gz: executor.json plus the platform artifact at the archive root). Registries prefer the archive over per-platform assets and reconcile the inner manifest at install time.


Smoke-testing locally

You do not need N.O.R.E. to exercise the JSON path. A one-shot capability runtime reads a single {"input": {...}} document on stdin and writes {"output": {...}} to stdout:

printf '{"input":{"document":{"name":"report.md","content":"# Q3 Revenue\n\nRevenue increased by 18%."}}}' | ./document-metadata
{"output":{"metadata":{"title":"Q3 Revenue","headings":["Q3 Revenue"],"wordCount":3,"paragraphCount":1}}}

Capability runtimes are language-independent

[!IMPORTANT] A Capability Runtime is a runtime implementation of a Capability contract. It is not required to be written in Go, nor compiled to WASM.

The implementation may be written in Go, .NET, Java, Rust, Python, another language, or authored as a WebAssembly module, whatever speaks the declared protocol. executor-go is one implementation SDK for building capability runtimes; it is never a requirement.

The two declared protocols are language-neutral:

  • neuron/capability-runtime-v1 — gRPC: implement CapabilityRuntimeService from the proto schema in shared/protocol/capabilityruntime/v1/capability_runtime.proto in any language with gRPC support.
  • neuron/capability-runtime-v1-json — one-shot: read one JSON request from stdin, write one JSON response to stdout, and exit.

Reference

Resource Path
Implementation packages/executor-sdks/golang/
gRPC schema shared/protocol/capabilityruntime/v1/capability_runtime.proto
Contract types shared/types/capabilityruntime
Process runtime docs/RUNTIME_PROCESS.md
WASM runtime docs/RUNTIME_WASM.md
Capability runtime model docs/MODULES.md
Reference capability runtime examples/capability-runtimes/echo (single source, native + WASI)

License

MIT — see the repository [LICENSE](../../LICENSE) for terms.

Documentation

Overview

Package capability runtime provides the Go SDK for implementing Neuron capability runtimes.

CapabilityRuntime authors implement the Handler interface and call Serve to start their capability runtime. The SDK handles protocol negotiation, transport setup, and lifecycle management.

Example:

func main() {
	err := capabilityruntime.Serve(capabilityruntime.Handler{
		Initialize: func(ctx context.Context, protocol string, metadata map[string]string) (*capabilityruntime.InitializeResult, error) {
			return &capabilityruntime.InitializeResult{ProtocolVersion: capabilityrt.ProtocolV1}, nil
		},
		Execute: func(ctx context.Context, in map[string]any) (map[string]any, error) {
			return in, nil
		},
	})
	if err != nil {
		os.Exit(1)
	}
}

The SDK supports two transports:

  1. gRPC over Unix domain sockets (when NEURON_CAPABILITY_RUNTIME_SOCKET is set — the long-lived worker mode used by the process runtime backend)
  2. stdin/stdout JSON (when NEURON_CAPABILITY_RUNTIME_SOCKET is not set — the one-shot mode used by WASM capability runtimes and single-execution processes)

The transport is selected automatically based on the environment provided by N.O.R.E. This means the same capability runtime binary works both as a long-lived gRPC worker and as a one-shot stdin/stdout command.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Serve

func Serve(h Handler) error

Serve starts the capability runtime. The transport is selected automatically:

  • if NEURON_CAPABILITY_RUNTIME_SOCKET is set, the capability runtime starts a gRPC server listening on the Unix domain socket and signals readiness by writing the NEURON_CAPABILITY_RUNTIME_READY file
  • otherwise, the capability runtime runs in stdin/stdout JSON mode

Serve blocks until the capability runtime is shut down (either via gRPC Shutdown or process termination). It never returns nil; an error is always returned, or a sentinel error indicating normal shutdown.

Types

type Handler

type Handler struct {
	// Initialize is called once per process lifetime after the gRPC connection
	// is established. It negotiates the protocol version and returns the
	// capability runtime's capabilities.
	Initialize func(ctx context.Context, protocol string, metadata map[string]string) (*InitializeResult, error)

	// Execute runs one execution and returns the output. The input is the
	// resolved execution input for the capability. Returning an error from
	// Execute records a controlled failure.
	Execute func(ctx context.Context, input map[string]any) (map[string]any, error)

	// Health reports whether the capability runtime is ready to accept requests.
	// It is called periodically by the runtime.
	Health func(ctx context.Context) error

	// Shutdown is called before the process terminates. It should complete
	// any graceful cleanup within the timeout.
	Shutdown func(ctx context.Context) error
}

Handler implements the business logic of a capability runtime. It is the contract that capability runtime authors implement. The SDK wraps it with the gRPC transport and lifecycle management.

type InitializeResult

type InitializeResult struct {
	// ProtocolVersion is the protocol version the capability runtime supports.
	ProtocolVersion string

	// Features declared by the capability runtime.
	Features []string

	// Metadata carries capability runtime-specific identity information.
	Metadata map[string]string
}

InitializeResult carries the capability runtime's response to protocol negotiation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL