Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Talos is a terminal-native tool for observing and interacting with ROS 2 systems.

The main idea is to separate the developer workstation from the ROS 2 runtime. The robot runs talos-agent, which talks to ROS 2 through rclrs. Developer machines run talos-tui or talos-cli, which connect to the agent over Unix domain sockets for local use or QUIC for remote use.

flowchart LR
    subgraph Workstation["Developer machine"]
        TUI["talos-tui"]
        CLI["talos-cli"]
        NoROS["No ROS 2 runtime needed"]
    end

    subgraph Target["Target device"]
        Agent["talos-agent"]
        Rclrs["rclrs"]
        ROS["ROS 2 graph"]
    end

    TUI -->|"UDS or QUIC"| Agent
    CLI -->|"UDS or QUIC"| Agent
    Agent --> Rclrs
    Rclrs --> ROS

Only the agent depends on ROS 2. The shared protocol, CLI, and TUI build and run without a ROS 2 installation.

What Talos Provides

  • Topic observation with live message data rendered as generic trees.
  • ROS 2 node discovery and graph inspection.
  • A filterable /rosout log view.
  • URDF-aware joint state display and joint command publishing.
  • A small CLI for scripts and one-shot checks.

Current Scope

Talos currently focuses on observation, basic joint control, and terminal workflows. It does not try to replace RViz, provide full ROS 2 service/action proxying, or expose arbitrary dynamic message support beyond the compiled-in message conversions in the agent.

Documentation Status

This book is the canonical project documentation. Keep it aligned with current behavior and use the design history pages for context on important choices.

Getting Started

Talos is a Cargo workspace with four crates:

  • talos-common: protocol, config, transport, session, and URDF support.
  • talos-agent: ROS 2 bridge process that runs on the robot.
  • talos-cli: command-line client.
  • talos-tui: terminal UI client.

Build Without ROS 2

The client crates and shared library do not require a ROS 2 environment:

cargo check -p talos-common -p talos-cli -p talos-tui

Build Everything

The agent depends on rclrs, so source the ROS 2/rclrs workspace first:

source rclrs_ws/install/setup.bash
cargo check --workspace

Enable QUIC

QUIC support is feature-gated:

cargo build --features quic

Without the quic feature, Talos builds UDS support only.

Run The Agent

With no --config argument, the agent looks for talos-agent.toml in the current directory. If the file is absent, it starts with default UDS transport and no configured topic subscriptions.

talos-agent --config talos-agent.toml

Run A Client

For local UDS access:

talos-cli list-topics
talos-cli echo /joint_states --count 5
talos-tui

For remote QUIC access, build with --features quic and pass --remote:

talos-cli --remote 192.168.1.50:4433 list-topics
talos-tui --remote 192.168.1.50:4433

Architecture Overview

Talos has a strict dependency boundary around ROS 2:

flowchart LR
    subgraph Clients["Workstation tools"]
        CLI["talos-cli"]
        TUI["talos-tui"]
    end

    Common["talos-common<br/>protocol, config, transports"]

    subgraph Runtime["Robot runtime"]
        Agent["talos-agent"]
        ROS["rclrs / ROS 2"]
    end

    CLI -->|"uses"| Common
    TUI -->|"uses"| Common
    Agent -->|"uses"| Common
    Agent -->|"links to"| ROS

talos-common is the shared base. It defines the protocol types, bincode framing, client session trait, transport setup, configuration model, and URDF parsing. It has no ROS 2 dependency.

talos-agent is the only crate that links to ROS 2. It creates the ROS 2 node, subscribes to configured topics, converts ROS 2 messages into DynValue, and serves Talos clients.

talos-cli and talos-tui are workstation tools. They only need the Talos protocol and a reachable agent.

Data Flow

  1. The agent starts and loads configuration.
  2. The ROS 2 bridge subscribes to configured topics.
  3. Each ROS 2 message is converted to a transport-neutral DynValue.
  4. Client tools connect to the agent and explicitly subscribe to topics.
  5. The router forwards topic data only to clients subscribed to that topic.

Important Boundaries

The agent owns ROS 2 message typing and conversion. Clients receive generic Talos protocol data and do not need ROS 2 message definitions.

The protocol layer hides transport differences from the CLI and TUI. UDS uses a single framed connection. QUIC uses a bidirectional control stream plus server-initiated unidirectional data streams.

The terminal UI is a client of the protocol, not a special case inside the agent. It reconnects, lists topics, subscribes, and renders the latest data it has received.

Agent And Clients

Talos uses one robot-side agent and one or more developer-side clients.

Agent

talos-agent is responsible for:

  • Loading talos-agent.toml.
  • Starting configured UDS and QUIC listeners.
  • Creating and spinning the ROS 2 node.
  • Subscribing to configured ROS 2 topics.
  • Converting supported ROS 2 messages into DynValue.
  • Answering graph queries for topics and nodes.
  • Publishing joint commands when control is configured.
  • Tracking client subscriptions and routing topic data.

The agent runs the ROS 2 bridge and IPC servers as async tasks. ROS 2 callback paths send converted topic data through a channel into the router, avoiding blocking the callback on client I/O.

Clients

talos-cli and talos-tui both use the ProtocolClient trait from talos-common.

Clients send control requests such as ListTopics, ListNodes, Subscribe, Unsubscribe, SetJointPosition, and ExecutePose. Topic data is received separately through the session interface.

Subscription Model

Clients do not receive all topic data automatically. They must subscribe to the topics they want.

This matters for remote links and high-rate topics. A CLI command echoing one topic should not pay the cost of receiving every other topic. The TUI normally subscribes to all discovered topics because its purpose is broad observation.

Client Lifetime

Each client connection gets a router entry with its own subscription set. When the client disconnects, the agent deregisters it and drops the routing state for that session.

Protocol

The Talos protocol is defined in talos-common.

Control messages use a four-byte big-endian length prefix followed by a bincode-encoded payload. The codec is implemented around Tokio async I/O and is used by both UDS and QUIC control paths.

Requests

Clients send Request values:

  • ListTopics
  • ListNodes
  • ListPoses
  • Subscribe { topics }
  • Unsubscribe { topics }
  • SetJointPosition { joint, position }
  • ExecutePose { name }

Responses

The agent replies with Response values:

  • TopicList
  • NodeList
  • PoseList
  • Subscribed
  • Unsubscribed
  • TopicData
  • Ok
  • Error

UDS carries control responses and topic data on the same framed connection. Because that connection carries data for multiple topics, UDS topic frames keep the topic name and type in each TopicData response.

QUIC uses a bidirectional stream for control and server-initiated unidirectional streams for topic data. A topic stream starts with a StreamHeader containing the topic and type name, then carries TopicFrame values with timestamp and data.

DynValue

DynValue is the generic representation clients receive for ROS 2 message payloads. It can represent:

  • Booleans.
  • Signed and unsigned integer primitives.
  • f32 and f64.
  • Strings.
  • Byte arrays.
  • Arrays of other DynValue values.
  • Structs with an ordered field list.

The agent handles typed ROS 2 subscriptions and conversions. Clients render or print the resulting DynValue tree without knowing the original ROS 2 message type at compile time.

Frame Limits

Oversized frames are rejected by the codec. The default maximum frame size is intended to protect the agent and clients from unbounded buffering.

Transports

Talos supports two transports: Unix domain sockets and QUIC.

Unix Domain Sockets

UDS is the default local transport. It is appropriate when the client and agent run on the same machine or inside an environment where the Unix socket path is shared.

The default socket path is:

/tmp/talos.sock

When the agent starts, it creates the socket listener. If a stale socket file is left behind from an earlier run, the UDS transport removes it before binding.

QUIC

QUIC is for remote observation and control across a network. It is built with quinn and is enabled with the Cargo quic feature.

cargo build --features quic

The default QUIC bind address is:

0.0.0.0:4433

QUIC uses one bidirectional control stream and server-initiated unidirectional streams for topic data. This gives each topic independent stream flow control and avoids mixing all topic data into one stream.

Security Posture

Current QUIC support is designed for trusted local networks. If no certificate paths are configured, the agent generates a self-signed certificate at startup. Clients use an insecure verifier so they can connect to that certificate.

Do not treat the current QUIC mode as suitable for untrusted networks. Proper certificate verification and authentication are future work.

Choosing A Transport

Use UDS for local development and single-machine workflows. Use QUIC when the agent runs on a robot and the client runs on a separate developer machine.

Agent

talos-agent runs on the machine that has ROS 2 access.

talos-agent --config talos-agent.toml

The --config argument is optional. Without it, the agent checks for talos-agent.toml in the current directory. If the file is not present, the agent uses defaults: UDS enabled at /tmp/talos.sock, QUIC disabled, no topic subscriptions, and no joint control.

Startup Behavior

On startup, the agent:

  1. Loads configuration.
  2. Starts configured transport listeners.
  3. Creates the ROS 2 bridge node.
  4. Subscribes to configured topics with supported message types.
  5. Waits for clients to connect and subscribe.

If neither UDS nor QUIC is configured, the agent logs an error and exits without serving clients.

ROS 2 Environment

The agent requires the ROS 2 and rclrs environment to be sourced before build or run:

source rclrs_ws/install/setup.bash

Logging

The agent uses tracing. Set RUST_LOG to adjust log verbosity:

RUST_LOG=talos_agent=debug talos-agent --config talos-agent.toml

CLI

The CLI binary is named talos-cli.

List Topics

talos-cli list-topics

This asks the agent for the current topic list and prints topic name, type, publisher count, and subscriber count.

List Nodes

talos-cli list-nodes

This asks the agent for discovered ROS 2 nodes and prints their names and namespaces.

Echo Topic Data

talos-cli echo /joint_states --count 5

echo subscribes to the requested topic before waiting for data. A count of zero means unlimited output.

Socket Selection

The default transport is UDS:

talos-cli --socket /tmp/talos.sock list-topics

With the quic feature enabled, --remote selects QUIC:

talos-cli --remote 192.168.1.50:4433 list-topics

--socket and --remote are mutually exclusive. If the binary was compiled without QUIC support, --remote returns an error.

TUI

talos-tui is the interactive terminal client.

talos-tui

By default it connects over UDS at /tmp/talos.sock. With the quic feature:

talos-tui --remote 192.168.1.50:4433

Views

The TUI has four tabs:

  • Topics
  • Nodes
  • Log
  • Joints

Use number keys 1 through 4 to switch tabs. Tab switches focus between panes. q quits.

Connection Behavior

The TUI reconnects when the agent connection is lost. After connecting, it asks for the topic list and subscribes to discovered topics so it can receive live data.

Topics

The Topics tab shows topic names and current message rates. Selecting a topic shows the latest DynValue tree for that topic.

Nodes

The Nodes tab lists ROS 2 nodes and shows publishers, subscribers, and services for the selected node.

Logs

The Log tab displays /rosout entries with timestamp, severity, node, and message fields. It supports severity, node, and text filtering.

Joints

The Joints tab combines URDF joint definitions with live /joint_states data. It can display limits, current position, velocity, effort, and configured poses. When control is configured, it can send joint position and pose commands to the agent.

Agent Config

The agent reads TOML configuration from talos-agent.toml or the path passed to --config.

Minimal UDS Config

[transport.uds]
socket_path = "/tmp/talos.sock"

QUIC Config

QUIC requires building with the quic feature:

[transport.quic]
bind_addr = "0.0.0.0:4433"
# cert_path = "/path/to/cert.der"
# key_path = "/path/to/key.der"

If cert_path and key_path are omitted, the agent generates a self-signed certificate at startup.

Dual Transport Config

UDS and QUIC can be enabled together:

[transport.uds]
socket_path = "/tmp/talos.sock"

[transport.quic]
bind_addr = "0.0.0.0:4433"

At least one transport must be configured for the agent to serve clients.

Topic Subscriptions

The agent subscribes to configured topics with compiled-in ROS 2 message types:

[[subscriptions]]
topic = "/odom"
type = "nav_msgs/msg/Odometry"

[[subscriptions]]
topic = "/cmd_vel"
type = "geometry_msgs/msg/Twist"

[[subscriptions]]
topic = "/robot_description"
type = "std_msgs/msg/String"

[[subscriptions]]
topic = "/joint_states"
type = "sensor_msgs/msg/JointState"

[[subscriptions]]
topic = "/rosout"
type = "rcl_interfaces/msg/Log"

Unknown message types are skipped by the agent.

Joint Control

Joint control is optional:

[control]
method = "topic"
topic = "/joint_commands"
type = "sensor_msgs/msg/JointState"

Named poses are stored under poses:

[poses.home]
shoulder_pan = 0.0
shoulder_lift = -1.57
elbow = 1.57

If control is not configured, joint command requests return an error.

Topic Observation

Talos observes ROS 2 topics through configured agent subscriptions.

The agent subscribes with concrete ROS 2 message types and converts received messages into DynValue. Clients receive the generic tree and can render it without ROS 2 type definitions.

Current Message Support

The current agent supports these message families:

  • nav_msgs/msg/Odometry
  • geometry_msgs/msg/Twist
  • std_msgs/msg/String
  • sensor_msgs/msg/JointState
  • rcl_interfaces/msg/Log

Support for arbitrary ROS 2 message definitions is future work.

Rates

The TUI keeps the latest value for each topic and renders on a fixed tick loop. High-frequency topics are naturally deduplicated by display rate: the UI shows the most recent received value at render time rather than drawing every incoming message.

CLI Echo

The CLI echo command subscribes to a single topic and prints received DynValue trees until interrupted or until --count messages have been printed.

Node Introspection

Talos can list ROS 2 nodes through the agent.

The agent uses ROS 2 graph APIs to discover node names, namespaces, publishers, subscribers, and services. Clients request this data with ListNodes.

CLI

talos-cli list-nodes

TUI

The Nodes tab shows discovered nodes on the left. Selecting a node displays its namespace, publishers, subscribers, and services.

Limits

Node introspection reflects the ROS 2 graph state visible to the agent. Network or ROS domain configuration issues outside Talos can affect what the agent sees.

Logs

The Log view is based on /rosout.

To use it, configure the agent to subscribe to:

[[subscriptions]]
topic = "/rosout"
type = "rcl_interfaces/msg/Log"

The agent converts log messages into DynValue, including fields such as severity, node name, timestamp, and message text.

TUI Filtering

The TUI Log tab displays messages in a table and supports:

  • Severity filtering.
  • Node filtering.
  • Text search.

The UI keeps log interaction local to the client. The agent still routes only the /rosout topic data to clients that subscribed to it.

Joint Control

Talos can display joint state and send joint commands when the agent is configured for control.

Joint Data

The Joints tab combines two sources:

  • /robot_description, containing URDF XML.
  • /joint_states, containing live joint positions, velocities, and efforts.

The URDF parser extracts non-fixed joints, parent and child links, joint type, and limits. Live joint state data is merged onto those definitions.

Display

The TUI shows each joint with current state and limit context. For joints with limits, the detail pane displays the current position relative to the allowed range.

If the URDF cannot be parsed, the Joints tab reports the error instead of silently hiding the problem.

Commands

When [control] is configured, clients can send:

  • SetJointPosition { joint, position }
  • ExecutePose { name }

The agent publishes command messages to the configured control topic. If control is not configured, the agent returns an error for command requests.

Pose Presets

Pose presets are configured in TOML under [poses.<name>]. The TUI displays available poses and can request execution by name.

Design History

This section records high-level design decisions that explain why Talos is structured the way it is.

These pages are reference material, not a second source of truth. Current behavior belongs in the architecture, usage, configuration, and feature pages.

The records here intentionally avoid detailed implementation task lists. They capture context, decision, and consequences.

Initial System Design

Status: Accepted

Date: 2026-04-02

Context

Talos needed to let a developer inspect and interact with a ROS 2 system from a terminal without installing ROS 2 on every client machine.

The core constraint was keeping ROS 2 isolated to the robot-side process while still giving clients enough typed structure to inspect messages and send basic commands.

Decision

The system was split into four crates:

  • talos-common for protocol, config, transport, and shared data types.
  • talos-agent for ROS 2 integration.
  • talos-cli for scriptable command-line workflows.
  • talos-tui for interactive terminal observation and control.

Messages are converted in the agent into DynValue, a generic tree that preserves enough structure for clients to render and inspect data without ROS 2 message definitions.

The initial transport was UDS with length-prefixed bincode frames. Configuration uses TOML.

Consequences

Only the agent depends on ROS 2. The CLI, TUI, and common library can be built and tested separately from the ROS 2 runtime.

The agent must contain explicit conversion support for each ROS 2 message type Talos wants to bridge. That keeps clients simple but limits dynamic coverage until generic message support is added.

The terminal UI can focus on rendering current protocol data instead of talking directly to ROS 2.

QUIC Transport

Status: Accepted

Date: 2026-04-10

Context

UDS works well for local workflows but does not handle the common robotics setup where the robot and developer workstation are different machines.

Talos needed a remote transport that could support observation and control across a local network while preserving UDS for low-overhead local use.

Decision

QUIC was added as a feature-gated transport using quinn.

The protocol gained an explicit subscription model. Clients subscribe to topics before receiving topic data, and the agent routes each topic only to subscribed clients.

The session layer moved above raw transport details. Application code talks to ProtocolClient; UDS and QUIC implement the same client behavior with different stream layouts.

QUIC uses:

  • A client-opened bidirectional stream for control requests and responses.
  • Server-opened unidirectional streams for subscribed topic data.
  • A StreamHeader once per topic stream.
  • Repeated TopicFrame values after the header.

Consequences

Remote clients can use --remote <addr:port> when built with the quic feature. UDS remains the default path for local clients.

Per-topic streams give QUIC independent flow control for different topics and avoid repeating topic metadata on every data frame.

The initial QUIC security model is intentionally local-network only: the agent can generate a self-signed certificate and clients skip certificate verification. Authentication and verified TLS remain future work.

The agent configuration changed to separate [transport.uds] and [transport.quic] sections.

Roadmap

This page tracks likely future work. It is intentionally higher level than an issue tracker.

Near Term

  • Keep this mdBook as the canonical project documentation.
  • Improve examples for agent configuration and common ROS 2 setups.
  • Add more integration coverage for UDS and QUIC client behavior.
  • Publish the mdBook from main with GitHub Pages.

Protocol And Transport

  • Add authenticated QUIC connections for untrusted or shared networks.
  • Document and tune QUIC stream limits for large topic sets.
  • Improve reconnect behavior and error reporting for remote clients.

ROS 2 Coverage

  • Add support for more common ROS 2 message types.
  • Explore generic message conversion instead of compiled-in conversions only.
  • Consider service and action proxying once topic observation and control are stable.

User Experience

  • Improve TUI ergonomics for filtering, selection, and high-rate streams.
  • Add examples for scripting with the CLI.
  • Make joint control behavior clearer and safer around limits and command publishing.

Documentation

  • Link important Rust API items from this book where they clarify concepts.
  • Optionally publish Rustdoc separately from the mdBook.
  • Keep design history concise and focused on accepted decisions.

Open Questions

Security

What is the right authentication model for remote access? Current QUIC support is suitable for trusted local networks only.

Dynamic Message Support

Should Talos continue adding compiled-in conversions for common message types, or should it support generic ROS 2 message introspection?

Compiled-in conversions are simple and predictable. Generic conversion would cover more systems but adds complexity around type discovery, field traversal, and compatibility.

Services And Actions

Topic observation is the first priority. Service and action proxying could make Talos more capable, but they would expand the protocol and UI model significantly.

Documentation Versioning

The current plan is main/latest documentation only. If Talos starts shipping stable releases with incompatible behavior, versioned docs may become useful.

Rustdoc Publishing

Rustdoc should remain separate from this book. The open question is whether CI should also publish Rustdoc under a stable path, such as /api/, next to the mdBook output.

Development

Branching And Releases

main is the stable release branch. Use dev for ongoing integration work. Create feature branches from dev and open pull requests back into dev.

When dev is ready to release, open a pull request from dev to main. Merging that pull request runs the version bump workflow, promotes CHANGELOG.md entries from [Unreleased], and creates the GitHub release. Add version:minor or version:major to the dev -> main pull request when the release should be larger than a patch bump.

Workspace Checks

Without ROS 2:

cargo check -p talos-common -p talos-cli -p talos-tui

With the ROS 2/rclrs environment:

source rclrs_ws/install/setup.bash
cargo check --workspace

With QUIC:

cargo check --workspace --features quic

Tests

cargo test --workspace
cargo test -p talos-common
cargo test -p talos-agent --test integration
cargo test -p talos-agent --test integration --features quic

Rustdoc

Rustdoc is API reference and stays separate from this book:

cargo doc --workspace --no-deps

Use this mdBook for concepts, workflows, architecture, and contributor guidance. Use Rustdoc for item-level API details.

Changelog

User-facing code, behavior, documentation, CI, or configuration changes should be recorded under [Unreleased] in CHANGELOG.md.

Documentation

The docs/ mdBook is the canonical documentation source.

Local Preview

mdbook serve docs

By default, mdBook serves at http://localhost:3000 and rebuilds when files change.

Build

mdbook build docs

The generated site is written to docs/book/.

Style

Write current behavior as prose. Avoid preserving formal requirement language unless it makes the behavior clearer.

Use design history pages for context on accepted decisions. Do not duplicate current behavior there.

Keep future plans in the future/ section so readers can distinguish planned work from implemented behavior.

When documenting Rust APIs, link or name the relevant type, trait, or module, but keep full API reference in Rustdoc.