The kernel for your distributed system.

ControllerBus is an open-source framework for coordinating controllers with hot-reload, directive resolution, and deterministic lifecycle management.

Hot-reload

Swap controller implementations at runtime without restarting the process. Load new plugins, update configurations, and patch behavior live.

Directive-based

Controllers communicate through directives: declarative requests for capabilities. The bus resolves directives to running controllers automatically.

Deterministic lifecycle

Controllers have a well-defined lifecycle: construct, execute, release. Error handling, retry, and backoff are built into the framework.

Protobuf config

Controller configuration is defined in protobuf. Type-safe, versionable, and serializable. Configuration changes trigger controller restarts automatically.

Composable

Controllers can depend on other controllers via directives. Build complex systems from small, focused components that compose cleanly.

Cross-platform

Runs on any platform Go supports: Linux, macOS, Windows, WASM. The same controller code works in browsers and on servers.

Get started in Go

main.go
import (
    "github.com/aperturerobotics/controllerbus/bus"
    "github.com/aperturerobotics/controllerbus/controller"
)

// Define a controller with protobuf config.
type MyController struct {
    config *Config
}

func (c *MyController) Execute(
    ctx context.Context,
) error {
    // Controller is running.
    // Return nil to stay alive until context cancels.
    // Return error to trigger restart with backoff.
    <-ctx.Done()
    return ctx.Err()
}

// Register and run on a bus.
b, err := bus.NewBus(ctx)
if err != nil {
    return err
}
b.AddFactory(NewFactory())

// Apply configuration (triggers controller start).
err = b.ApplyConfig(ctx, myConfig)
go get github.com/aperturerobotics/controllerbus@latest

Used in Spacewave

ControllerBus is the coordination kernel at the heart of Spacewave. Every controller in the system (networking, storage, plugins, UI) is managed by the bus.

When you install a plugin, ControllerBus hot-loads it. When a device disconnects, ControllerBus tears down the associated controllers cleanly. The entire Spacewave lifecycle is bus-driven.