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
/rosoutlog 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
- The agent starts and loads configuration.
- The ROS 2 bridge subscribes to configured topics.
- Each ROS 2 message is converted to a transport-neutral
DynValue. - Client tools connect to the agent and explicitly subscribe to topics.
- 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:
ListTopicsListNodesListPosesSubscribe { topics }Unsubscribe { topics }SetJointPosition { joint, position }ExecutePose { name }
Responses
The agent replies with Response values:
TopicListNodeListPoseListSubscribedUnsubscribedTopicDataOkError
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.
f32andf64.- Strings.
- Byte arrays.
- Arrays of other
DynValuevalues. - 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:
- Loads configuration.
- Starts configured transport listeners.
- Creates the ROS 2 bridge node.
- Subscribes to configured topics with supported message types.
- 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/Odometrygeometry_msgs/msg/Twiststd_msgs/msg/Stringsensor_msgs/msg/JointStatercl_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-commonfor protocol, config, transport, and shared data types.talos-agentfor ROS 2 integration.talos-clifor scriptable command-line workflows.talos-tuifor 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
StreamHeaderonce per topic stream. - Repeated
TopicFramevalues 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
mainwith 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.