Files
rmon/CLAUDE.md
T
Martino Ferrari dca378b5ef initial commit
2026-04-11 16:30:18 +02:00

4.1 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

RMon is a real-time data monitor and plotter for distributed control systems accessed over SSH. The UI runs locally; data is acquired by a remote agent. See usecase.md for requirements and docs/ for full specs.

Language and Tech Stack

Rust throughout — single language for agent, UI, and shared types.

Crate Role Key deps
rmon-common Shared types, protocol message enums serde, bincode
rmon-agent Remote data acquisition server tokio, tracing, anyhow, toml, serde
rmon-ui Operator desktop application egui, eframe, egui_plot, tokio, tracing

Build Commands

# Build everything (debug)
cargo build

# Build the agent as a fully static binary (primary deployment target)
cargo build --release --target x86_64-unknown-linux-musl -p rmon-agent

# Build agent for ARM (e.g. remote Raspberry Pi)
cargo build --release --target aarch64-unknown-linux-musl -p rmon-agent

# Build the UI for the current platform
cargo build --release -p rmon-ui

# Run tests
cargo test

# Run tests for a single crate
cargo test -p rmon-common
cargo test -p rmon-agent

# Run a single test
cargo test -p rmon-agent sources::csv::tests::parse_timestamp

# Lint
cargo clippy --all-targets --all-features

# Format
cargo fmt

Architecture (short version)

Two executables communicate via a binary TCP protocol over an SSH tunnel:

  • rmon-agent: runs on the remote machine, acquires data from heterogeneous sources (CSV, UDP, EPICS…), stores it, streams it to connected clients. Built as a fully static musl binary — single file, zero runtime deps, scp + run.

  • rmon-ui: runs on the operator's local desktop. Manages the SSH tunnel automatically (uses the system ssh binary + user's ~/.ssh/config). Renders real-time plots with egui/egui_plot.

  • rmon-common: library crate shared by both. Contains all types (SignalId, SignalInfo, Sample, StorageMode) and the ClientMessage/AgentMessage protocol enums serialized with bincode.

Full architecture: docs/architecture.md
Wire protocol: docs/protocol.md
Data model: docs/data-model.md
Agent config and source trait: docs/agent-spec.md
UI layout and state machine: docs/ui-spec.md

Key Design Decisions

  • Protocol framing: [u32 LE length][bincode payload] — no gRPC/HTTP overhead. Both sides are Rust so bincode + shared enum types is simplest.
  • Agent portability: x86_64-unknown-linux-musl gives a fully static binary requiring only Linux kernel ≥ 3.2. The agent never has a GUI, so no X11/GL needed.
  • Remote access UX: The UI deploys the agent binary via SSH itself (like VSCode Remote). Users only need to enter their SSH host alias; existing ~/.ssh/config (including ProxyJump) handles multi-hop routing.
  • UI rendering: egui immediate-mode with glow (OpenGL 2.1) backend. For signals with more points than screen pixels, min-max downsampling runs on the CPU before drawing.
  • Timestamps: all source timestamps are normalized to i64 nanoseconds since Unix epoch inside the source adapter. The rest of the codebase only sees i64.
  • Concurrency (agent): one tokio task per data source → broadcast channel → dispatcher fans out to storage writers and per-client session tasks.
  • UI/async boundary: tokio runtime in a background thread; egui on main thread. std::sync::mpsc channels carry UiEvent (agent→UI) and Command (UI→agent).

Adding a New Data Source

  1. Create rmon-agent/src/sources/{name}.rs
  2. Implement the DataSource trait (name(), signals(), async fn run(self, tx))
  3. Add a new variant to SourceConfig in config.rs and construct it in sources/mod.rs
  4. Add config example to docs/agent-spec.md

Protocol Changes

All protocol types live in rmon-common/src/protocol.rs. Since bincode is not self-describing, any change to ClientMessage or AgentMessage requires a protocol version bump in the Handshake message and both sides must be rebuilt together.