Skip to content

Subsystem Binding Model

Librux separates interface declaration from deployment wiring.

A subsystem binary should not need to know which concrete gateway, component, compound provider, simulator, or remote instance it will use in a final robot deployment.

The base model has three layers.

subsystem manifest = role plus what this subsystem provides and requires
deployment manifest = which provider instance satisfies each requirement
runtime registry = where the selected provider is currently reachable

Robot applications add two composition manifests above this base.

robot manifest = gateway, component, and compound slots plus robot capabilities
app-role subsystem manifest = top-level application requirements
deployment manifest = robot + application + package instances + bindings

Declaration Versus Binding

The subsystem manifest answers this question.

What does this subsystem provide, and what does it require?

The deployment manifest answers this question.

Which concrete provider satisfies each requirement in this deployment?

This distinction lets the same component binary bind to a real gateway, a simulator gateway, a test stub, or a remote provider without changing source code.

Provides And Requires

kind: librux.subsystem
version: 1

subsystem:
  name: component.manipulator
  role: component

requires:
  actuator_servo:
    contract: api.actuator.servo.v1
    cardinality: one
    required: true

provides:
  manipulator:
    contract: component.manipulator.v1

provides names interfaces implemented by this subsystem. requires names logical dependencies that the subsystem code will use.

The names under requires are not provider identities. They are local logical names. Deployment supplies the provider identity later.

Deployment Binding

A deployment chooses the provider instance for each requirement.

kind: librux.deployment
version: 1

instances:
  component.manipulator:
    manifest: ./component.manipulator/subsystem.yaml
  gateway.servo:
    manifest: ./gateway.servo/subsystem.yaml

bindings:
  component.manipulator.actuator_servo:
    to: gateway.servo.servo

The binding key is the consumer requirement.

<consumer-subsystem>.<required-interface>

The binding target is the provider interface.

<provider-subsystem>.<provided-interface>

The deployment loader validates that both manifests exist, both interfaces exist, and their contracts match.

Multiple Instances

Reusable packages can be instantiated more than once. In that case the deployment names concrete runtime identities while pointing them at the same package or subsystem manifest.

kind: librux.deployment
version: 1

instances:
  component.left_manipulator:
    package: ./packages/manipulator
    params:
      robot_id: left
  component.right_manipulator:
    package: ./packages/manipulator
    params:
      robot_id: right
  gateway.servo:
    manifest: ./gateway.servo/subsystem.yaml

bindings:
  component.left_manipulator.actuator_servo:
    to: gateway.servo.servo
  component.right_manipulator.actuator_servo:
    to: gateway.servo.servo

The package can be reusable while each runtime instance keeps its own subsystem identity, parameters, state directory, resource lease, and lifecycle state.

Public And Internal Contracts

Subsystem public interfaces are the standardization boundary. Public contracts must resolve to Librux specs such as api.actuator.servo.v1, component.mobile_base.v1, or capability.mobility.teleop.v1.

App-facing requirements should normally use capability.*. A capability spec points to the backing API contract used for endpoint validation.

Private tutorial wiring can be marked explicitly.

provides:
  service:
    contract: tutorial.transport.service.v1
    visibility: internal

visibility: internal means the interface is not claiming product-level compatibility. Robot slots and capability implementations must bind through public Librux spec interfaces.

Endpoint names are not runtime data. Librux validates endpoint registration as a closed-world contract surface, so a subsystem cannot create a new Event topic or Procedure name for every task, object, or operation. Use fixed contract endpoints and carry changing identifiers inside payload fields.

Runtime Availability

Binding validation is structural. It answers this question.

Is the deployment wired correctly?

Runtime route resolution answers a different question.

Is the selected provider currently running and reachable?

Those states are intentionally separate. A deployment can be structurally valid while a provider process is starting, restarting, waiting on another subsystem, or temporarily disconnected.

State Meaning
INVALID_CONFIG Manifest or binding structure is invalid
WAITING_BINDING Binding is missing or not structurally usable
WAITING_TARGET Binding is valid but the provider route is not available yet
BOUND Binding target is known and route resolution succeeded
READY Required bindings and local registrations are ready
DEGRADED A previously available runtime binding was lost

What Goes Where

Layer Owns
Subsystem code logical requirement names such as actuator_servo
Subsystem manifest role, provides, requires, and interface contracts
Robot manifest gateway, component, and compound slots, kinematics, parts, and robot capabilities
App-role subsystem manifest top-level app subsystem and required platform labels or capabilities
Deployment manifest platform, application, package instances, selected slots, and selected provider instance for each requirement
Runtime registry current route, endpoint, host, socket, lifecycle, and health state
Package manifest reusable executable launch, parameters, environment, resources, and app assets

Diagram Model

The same data can be rendered at three levels.

flowchart LR A["component.manipulator<br/>requires actuator_servo"] --> B["gateway.servo<br/>provides servo"] B --> C["runtime route<br/>host, socket, health"]
  • Static interface diagrams use subsystem manifests.
  • Deployment wiring diagrams add robot, app-role subsystem, and deployment manifests.
  • Runtime diagrams add live route, binding, lifecycle, and health state from the control backend.