Point it at a log. It says what broke, why, and where the fix goes — as a file and a line in your own repository.
Python 3.10 or newer, nothing else. Tested on Ubuntu 24.04 with Python 3.12 in a clean virtualenv. One command, no repository to clone.
# Ubuntu ships ensurepip separately; skip if you already have it sudo apt install -y python3-venv python3 -m venv .venv && source .venv/bin/activate pip install https://trialone.wiki/trialone-0.1.0-py3-none-any.whl trialone --help # should list: diagnose, demo, watch, verify, fleet
A bundled recording with a real mid-run lidar dropout. It runs end to end and prints a finding, so you know the install is good before you point it at anything of yours.
trialone demo
ROS 2 keeps them under ~/.ros/log/, one directory per run, with
launch.log inside. A rosbag2 directory, an .mcap, a
dmesg dump or a GDB backtrace work just as well — the format is sniffed.
trialone diagnose ~/.ros/log/<run>/launch.log
This is the deterministic half: it decodes what the machine reported about itself. It will tell you, at the end, that you are seeing only that half — and the one line that turns on the other.
One key. The provider follows from whichever one is set, so there is nothing else to
configure. --project is your workspace, and it is what turns
“this topic looks wrong” into a file and a line in your own code.
export ANTHROPIC_API_KEY=... # or OPENROUTER_API_KEY, or GEMINI_API_KEY
trialone diagnose ~/.ros/log/<run>/launch.log \
--project ~/ws/src \
--symptom "the arm stops mid-cycle after a few minutes" \
--explain --json
--symptom is worth the ten seconds: it is what you observed, in one
sentence, and it steers the diagnosis toward the failure you actually care about rather
than the loudest thing in the log. Measured cost of a run with --explain:
about two cents.
output/diagnosis_<name>.txt # the full report, same as stdout output/diagnosis_<name>.json # one record per finding, nine fixed fields
The JSON is the handoff format: symptom, causal chain, the condition with its measured values, change class, affected files and lines, acceptance criterion, blast radius, effort. It is what you hand to a coding agent — Claude Code, Codex, Aider — rather than re-typing the finding yourself.
“how TrialONE integrates with ROS 2”
It reads what is already on disk — launch and console logs, rosbag2, MCAP. The format is
sniffed, so you never pick a parser. Add --project ~/ws/src and findings
resolve into your own code instead of stopping at a topic name; parameter files are found
structurally, so you do not list them either.
It does not attach to a running graph yet.
“what logs or data it needs”
One log file is enough to start. Also accepted: HDF5/CSV of repeated operations, ULog,
ArduPilot .BIN, dmesg and kernel oops, GDB backtraces, firmware
panic dumps. The workspace path is optional and it is what makes the output actionable.
“whether it can run locally”
Yes — that is the diagram below. Detection is deterministic and runs entirely on your machine. The interpretation layer calls a model, and you pick the provider, a local one included. Raw recordings never leave the machine.
Unedited, from a public ros2_control incident: a joint_state_broadcaster
that intermittently fails to configure with Resource temporarily unavailable, then a
segfault in the executor destructor. Two hours and a maintainer, in the original thread.
The fix
Code/Setting that owns it: the `lock_memory` parameter in
`ros2_control_node.cpp` (line 64) and the system's RLIMIT_MEMLOCK.
It defaults to `has_realtime`, which is true on a PREEMPT_RT kernel.
Option A — in the launch/params file:
controller_manager:
ros__parameters:
lock_memory: false
Option B — system configuration:
* soft memlock unlimited
* hard memlock unlimited
And in the same report — what it did not verify
the diagnosis names `mlockall`, `preempt_rt`, `rlimit_memlock` — these appear neither in the artifact, nor in the deterministic findings, nor in any tool result. NAMED BUT NEVER OPENED: `/etc/security/limits.conf`
That second block is the part we care most about. Those three terms genuinely are knowledge rather than measurement — they are nowhere in the log — and the report says so instead of letting them pass as findings. Every report carries the same accounting: which instruments were used, which were never touched, which paths do not exist in your tree, and which claim of absence was never actually searched for.