Skip to content

Unix Domain Socket

The robot software to agent hop normally runs over local Zenoh. As an optional, drop-in alternative on the same host, the same Cap'n Proto messages can flow over a Unix domain socket instead. The payloads are byte-for-byte identical to what Zenoh carries, and the agent to cloud hop (mTLS) is unaffected.

The two local transports are mutually exclusive: the agent uses exactly one per run, selected by configuration. The ready-made Python and C++ client libraries connect to the agent over this socket, so if you use one, the integration is mostly a configuration setting. (For Zenoh you pair a client library's message types with your own Zenoh session.)

When to use it

  • Your robot software runs on the same Linux host as the agent.
  • You want a simple local socket instead of embedding a Zenoh session.
  • You are using a client library and prefer the socket transport.

For off-host messaging or richer pub/sub, use Zenoh.

Enabling it

The agent selects the local transport in its configuration (robot.toml):

[local_transport]
kind = "uds"                                    # "zenoh" (default) | "uds"
uds_socket_path = "/run/rover-agent/agent.sock" # optional; this is the default
  • Omitting [local_transport], or setting kind = "zenoh", keeps the local Zenoh behavior.
  • The default socket path is /run/rover-agent/agent.sock.

Connection model

  • The agent is the listener (server); your robot software is the client.
  • One client at a time: a new connection is accepted only after the current one ends.
  • While no client is connected, outbound commands are dropped, exactly like a Zenoh publish with no subscriber.

Security. Like the local Zenoh hop, the socket has no cryptographic authentication; filesystem permissions on the socket path are the access boundary. The agent sets the socket permissions so a robot-software process running as a different local user can connect.

Wire protocol

Each message is a length-delimited frame: a 4-byte big-endian length prefix, then the framed body.

[u32 BE length]                  # length of everything after this field
  [u8  frame_type]
  [u32 BE request_id]
  [Cap'n Proto payload bytes]    # the rover_nexus_core-serialized message
frame_type Name Direction Payload
1 Uplink robot → agent RobotUplinkMsg
2 Command agent → robot RobotCommand
3 FeaturesRequest robot → agent GetFeaturesRequest
4 FeaturesResponse agent → robot GetFeaturesResponse
5 SpatialDirectivesRequest robot → agent GetSpatialDirectivesRequest
6 SpatialDirectivesResponse agent → robot GetSpatialDirectivesResponse
7 SettingsRequest robot → agent GetSettingsRequest
8 SettingsResponse agent → robot GetSettingsResponse
  • request_id is 0 for the fire-and-forget types (Uplink, Command). For the three query round-trips, the client picks a nonzero id and the agent echoes it on the matching response frame so concurrent queries can be correlated.
  • An empty query payload means "all", mirroring the Zenoh queryables.
  • The RobotUplinkMsg and RobotCommand payloads are self-describing Cap'n Proto unions, so there is no per-topic routing: the receiver dispatches by variant. The agent applies the same rate limiting and backpressure to inbound uplink frames as on the Zenoh path.

The client libraries implement this framing for you.

Coordinate frames

Geometry in the RobotUplinkMsg and RobotCommand payloads uses the same coordinate-frame contract as the Zenoh path: uplink telemetry is normalized to WGS84, and downlink geometry is WGS84 by default or your local ENU frame when convert_commands_to_local is set. See Coordinate Frames.

Next steps