Subsystem Binding Manifests
Librux uses manifests to separate subsystem contracts from deployment wiring.
The rule is this.
subsystem manifest = role plus what this subsystem provides and requires
deployment manifest = how required interfaces are bound to provider instances
runtime registry = where the bound subsystem is currently reachable
Subsystem code should not hardcode the concrete subsystem name of another subsystem. It should use a logical requirement name, and the deployment manifest binds that requirement to a provider instance.
Subsystem Manifest
Every managed subsystem has a librux.subsystem manifest.
kind: librux.subsystem
version: 1
subsystem:
name: arm_controller
role: component
requires:
joint_servo:
contract: api.actuator.servo.v1
cardinality: one
required: true
provides:
manipulator:
contract: component.manipulator.v1
subsystem.role is required. Supported roles are app, component, gateway,
and compound. provides declares interfaces implemented by the subsystem.
requires declares logical dependencies used by the subsystem code. Contracts
on public subsystem interfaces must refer to installed Librux spec dictionary
contracts. Use component.* for component subsystems, api.* for gateway-facing
API contracts, and capability.* for app-facing compound capabilities.
Private or tutorial-only wiring must be explicit.
provides:
sim_debug:
contract: tutorial.robot_cleaner.debug.v1
visibility: internal
visibility defaults to public. Public interfaces are the compatibility
surface seen by robot slots, capability implementations, and applications.
Internal interfaces are allowed for mechanics tutorials, tests, and private
wiring, but they do not claim product compatibility. A platform slot or
capability implementation cannot be backed by an internal interface.
When a public interface contract is a canonical component.* id, the SDK
expands the component into its conformance API contracts and validates the
corresponding runtime registration against the installed spec dictionary.
Capability contracts resolve to their backing api.capability.* definitions for
endpoint validation. provides and requires decide binding direction. The
contract spec defines the public compatibility surface.
Do not repeat endpoint lists on public interfaces. Event, Control, Procedure,
and Operation endpoints are part of the referenced contract. The endpoints
field is only for explicit internal/tutorial wiring that is not claiming public
product robot compatibility.
Runtime endpoint registration is closed-world. A subsystem may only register
endpoints that come from its public Librux spec contracts or from explicit
visibility: internal endpoint lists in its manifest. Do not create Event,
Control, Procedure, or Operation endpoint names dynamically at runtime. Put
dynamic identifiers such as request_id, operation_id, object_id, or
task_id in the message payload.
Deployment Manifest
A deployment manifest binds a consumer requirement to a provider interface.
kind: librux.deployment
version: 1
subsystems:
arm_controller:
manifest: ./arm_controller/subsystem.yaml
left_servo_gateway:
manifest: ./left_servo_gateway/subsystem.yaml
bindings:
arm_controller.joint_servo:
to: left_servo_gateway.servo
For reusable packages, use instances:. Each key is the concrete runtime
subsystem identity. The entry may point directly at a subsystem manifest or at a
package directory containing package.yaml. By default, the package resolves
subsystem.yaml; use subsystem_manifest only for a non-default relative path.
kind: librux.deployment
version: 1
instances:
demo.left_manipulator:
package: ./packages/manipulator_servo
params:
subsystem.name: demo.left_manipulator
controller.robot_id: left_ps_ca
demo.right_manipulator:
package: ./packages/manipulator_servo
params:
subsystem.name: demo.right_manipulator
controller.robot_id: right_ps_ca
demo.isaac_sim_gateway:
manifest: ./subsystem.yaml
bindings:
demo.left_manipulator.actuator_servo_gateway:
to: demo.isaac_sim_gateway.actuator_servo_gateway
demo.right_manipulator.actuator_servo_gateway:
to: demo.isaac_sim_gateway.actuator_servo_gateway
subsystems: validates that the manifest's declared subsystem.name matches the
deployment key. instances: allows the same reusable manifest to appear under
multiple runtime identities.
The binding key is always.
<consumer-subsystem>.<required-interface>
The target is always.
<provider-subsystem>.<provided-interface>
Subsystem names may contain dots. Binding references split at the rightmost dot,
so demo.mobile_base_rc2_prototype.actuator_servo_gateway means subsystem
demo.mobile_base_rc2_prototype and required interface
actuator_servo_gateway.
The loader rejects missing subsystem manifests, missing provider interfaces, unsupported cardinality, duplicate subsystem or instance names, and contract mismatches before the subsystem becomes ready.
Deployments can also reference a robot manifest and application manifest. That layer validates robot slots, application-required capabilities, optional platform compatibility labels, and subsystem bindings before runtime reconciliation runs. See Robot/Application/Deployment Manifests.
Availability
Binding validation is structural. It does not require the provider process to already be running.
This distinction matters for cyclic or mutually dependent subsystems. A valid binding can be structurally configured while the route is still unresolved. In that case the subsystem can report a waiting or not-ready state instead of treating the deployment as invalid.
Use these state boundaries.
| State | Meaning |
|---|---|
INVALID_CONFIG |
Manifest or binding structure is invalid |
WAITING_BINDING |
Binding is valid but 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 |
SDK Shape
Python and C++ subsystems parse a manifest at construction time.
from librux.wrapper import ComponentSubsystem
class ArmController(ComponentSubsystem):
def __init__(self) -> None:
super().__init__(
name="arm_controller",
manifest_path="subsystem.yaml",
deployment_manifest_path="librux.deployment.yaml",
)
def move(self, params):
target = self.binding_target("joint_servo")
return self.call_procedure(
target=target,
procedure="set_position",
params=params,
)
Convenience APIs such as call_bound_procedure(...) and
start_bound_operation(...) can resolve the target internally from the logical
binding name.
C++ subsystems use the same manifest boundary. Pass
SubsystemOptions::manifest_path directly, set LIBRUX_SUBSYSTEM_MANIFEST, or
start the package through librux launch run or lbx deploy up. Launch and
deployment bindings are passed to C++ through LIBRUX_BINDINGS.
Diagram Model
The manifest split enables three diagram levels.
- Static interface diagrams use subsystem manifests only.
- Deployment wiring diagrams add the deployment manifest.
- Runtime diagrams add route and health state from the control backend.
The Web Console Runtime graph uses the live control status snapshot. When a subsystem SDK reports manifest and binding status, the graph can show running subsystems, provided interfaces, required interfaces, and binding edges in the same view as Event and timed-exchange endpoints.