Skip to content

Subsystem Binding Manifests

R2Kernel 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 r2kernel.subsystem manifest.

kind: r2kernel.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 R2Kernel 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 R2Kernel 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.

Spatial Declaration

Communication bindings and spatial topology are declared separately. A component provider maps the spatial ports required by its component.* spec to local frame names.

spatial:
  participation: required
  ports:
    base:
      direction: import
      semantic: mounting_frame
      frame: arm_base
    tool:
      direction: export
      semantic: tool_center_point
      frame: tool0

The component spec determines the required port names and directions. The subsystem manifest determines the concrete local frame names. A claim is rejected when required component ports are missing or have the wrong direction.

A compound can connect the spatial ports of its logical requirements.

spatial:
  participation: required
  mounts:
    - name: arm_on_body
      parent:
        requirement: mobility
        port: body
      child:
        requirement: manipulation
        port: base
      transform:
        translation: [0.18, 0.0, 0.12]
        rotation_xyzw: [0.0, 0.0, 0.0, 1.0]

Deployment validation resolves the requirement names through normal bindings. The runtime qualifies local names as <subsystem>/<frame> and combines compound mounts with dynamic transforms reported by subsystem SDKs. See Spatial Model And Frame Graph.

Deployment Manifest

A deployment manifest binds a consumer requirement to a provider interface.

kind: r2kernel.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: r2kernel.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 r2kernel.wrapper import ComponentSubsystem


class ArmController(ComponentSubsystem):
    def __init__(self) -> None:
        super().__init__(
            name="arm_controller",
            manifest_path="subsystem.yaml",
            deployment_manifest_path="r2kernel.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 R2KERNEL_SUBSYSTEM_MANIFEST, or start the package through r2kernel launch run or r2kernel deploy up. Launch and deployment bindings are passed to C++ through R2KERNEL_BINDINGS.

Diagram Model

The manifest split enables four diagram levels.

flowchart LR A["arm_controller<br/>requires joint_servo"] --> B["left_servo_gateway<br/>provides servo"] B --> C["runtime route<br/>host/port/socket"]
  • 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.
  • Spatial diagrams add resolved ports, static mounts, dynamic transforms, and stale-edge diagnostics from the runtime frame graph.

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.