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 settingkind = "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_idis0for 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
RobotUplinkMsgandRobotCommandpayloads 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.