A Linux, macOS, and Windows web client for operating a running Robonix deployment. It provides
text tasks, voice turns, hands-free control, explicit Stop/steer behavior,
audio-device routing, live Pilot/RTDL execution events, and a Vitals workspace
for robot hardware and software health.
Install Guide
Requirements:
Linux, macOS, or Windows
Python 3.11 or newer
network access to the machine running Robonix Atlas
a running Robonix deployment with Atlas, Liaison, Pilot, and Executor
On Windows sounddevice ships its own PortAudio DLL and works
out of the box. If the audio server still cannot find any devices,
install a pre-built PyAudio wheel (which includes PortAudio) from
elibroftw/pyaudio_portaudio
— wheels are available for Python 3.10–3.14 (win_amd64):
# Pick the wheel matching your Python version, e.g. cp312 for 3.12:
pip install https://github.com/elibroftw/pyaudio_portaudio/releases/download/0.2.15/pyaudio-0.2.15-cp312-cp312-win_amd64.whl
pip install -e ".[audio]"
Quick Start
Assume Robonix Atlas is running on 100.87.172.93:50051:
The client starts its local audio service automatically. On Linux it uses the
desktop’s PipeWire, PulseAudio, or ALSA devices through PortAudio. In the UI:
Confirm Robot Host is 100.87.172.93 and Atlas Port is 50051.
Click Connect. The status should become online.
Enter a small text task and click Send.
While a task is active, Send becomes Steer and Stop appears.
Open Audio to select and test microphone/speaker providers and devices.
Open Vitals to inspect the Soma-derived robot model, hardware signals,
module reports, and Atlas providers.
--host and --robot-host are different:
--host 127.0.0.1 controls where this Web UI listens.
--robot-host 100.87.172.93 selects the remote Robonix machine.
Most users only need --robot-host.
Connecting to a Robonix Machine
Which IP should I enter?
Enter the IP or hostname of the machine that runs Robonix Atlas. It is not
the Mac client IP and not an unrelated development PC.
Good choices are:
the robot’s Tailscale IP when both machines use Tailscale;
the robot’s LAN IP when both machines are on the same trusted LAN;
127.0.0.1 only when Robonix and this client run on the same machine.
The required fields are:
Field
Value
Robot Host
Atlas machine IP or hostname, for example 100.87.172.93
Atlas Port
50051 unless the deployment changed it
Liaison Endpoint
Leave empty; the client discovers Liaison through Atlas
User ID
Optional identity used by the deployment’s access policy
Liaison normally listens on port 50081, but clients should discover it
through Atlas instead of hard-coding that port.
Audio routing
For a Mac microphone/speaker, the Robonix deployment must include the
audio_client_bridge provider in client-initiated mode:
The word reverse only describes connection ownership: the Mac connects to
the robot. The deployment does not store the Mac IP. The client discovers the
bridge endpoint through Atlas, opens one outbound WebSocket, and carries both
microphone and speaker PCM over that connection.
In Audio, select audio_client_bridge for input and/or output, choose the
client machine’s devices, click Apply Route, then run Test microphone and Test
speaker. Hands-free mode is disabled until explicitly enabled in the UI.
Testing with the Robonix Webots Example
This flow runs Webots and Robonix on a Linux machine and the client on Linux or macOS.
The same-host case also works by using 127.0.0.1 as Robot Host.
1. Prepare Robonix
On the Linux/Webots machine:
git clone --recursive https://github.com/syswonder/robonix.git
cd robonix
cd rust && make install && cd ..
export VLM_BASE_URL=https://api.openai.com/v1
export VLM_API_KEY=<your-key>
export VLM_MODEL=<your-model>
cd examples/webots
rbnx build
Use the reverse audio_client_bridge manifest block shown above if voice from
the Mac is part of the test. Text, planning, execution, and Stop tests do not
require client audio.
2. Start Webots
In terminal 1, from the Robonix repository root:
bash examples/webots/sim/start.sh
office.wbt is the default. To select another built-in world:
Send a harmless text request such as Use Bash to print WEBOTS_CLIENT_OK.
Send a longer Bash task, then send a Steer update while it runs.
Start another long Bash task and click Stop; verify the task becomes
interrupted and its child process exits.
Inspect the RTDL tree and execution history for one plan/call per request.
Open Vitals and confirm the TIAGo body, hardware components, module
health, and Atlas providers update without refreshing the page.
If audio bridge is enabled, apply the route and test microphone, speaker,
one Voice turn, then hands-free wake detection.
Only after those checks, test simulated camera/navigation capabilities.
Stop the environment with:
cd examples/webots
rbnx shutdown
bash sim/stop.sh
Core Design
Control path
Browser UI
-> local robonix-client FastAPI/WebSocket adapter
-> Atlas discovery
-> Liaison task/voice API
-> Pilot planning harness
-> Executor and registered capabilities
-> structured Pilot/RTDL events back to the UI
The client does not embed a planner and does not call robot drivers directly.
Atlas is the source of provider endpoints; Liaison is the interaction gateway;
Pilot owns task/steer/abort semantics; Executor owns running capability calls.
Vitals path
The browser opens /ws/vitals on the local FastAPI process. That adapter
discovers and combines these robot-local contracts through Atlas:
robonix/system/soma/get_yaml and robonix/system/soma/get_urdf describe
the body and its components;
robonix/system/vitals/stream supplies hardware health and power state;
the Atlas provider snapshot supplies provider lifecycle state.
The 3D view uses a model URL when the Soma description provides one, then a
URDF with browser-renderable visual geometry, and finally a procedural renderer
selected from robot family and component types. The current dev-nextget_urdf contract returns only robot_id and urdf_xml; it does not attach
mesh or texture files. A URDF whose relative resources are unavailable therefore
falls back to the procedural renderer. The same-origin resource route remains
available for a future contract that explicitly supplies those assets.
Actuators that report torque_enabled=0 remain healthy but are presented as
yellow idle components. This readiness state propagates to their parent robot
for rendering and does not create a warning incident.
Vitals persists hardware, module, and provider incidents in
~/.local/share/robonix-client/vitals-alerts.sqlite3. Set
ROBONIX_CLIENT_VITALS_DB to use another database path. A reported anomaly is
active; after the source becomes healthy it remains recovered in the alert
center until an operator confirms it as resolved. Active incidents cannot be
cleared manually, and resolved incidents remain available in alert history.
The compiled browser bundle is committed under src/robonix_client/static, so
Node.js is not required to run the Python package. To rebuild or test the
Vitals frontend after changing frontend/src/vitals.js:
cd frontend
npm install
npm run build
npm run test:visual
Turn behavior
Send starts a new task when the session is idle.
Steer targets the active turn using its expected turn ID. Stale steer is
rejected rather than applied to a newer task.
Stop sends an abort control event. Pilot interrupts the active turn and
Executor cancels running work, including Bash child processes. If an F2
session is recording, recognizing, or speaking, Stop also cancels that voice
stream and releases its audio devices.
Pressing F2 while TTS is active performs barge-in: the old reply is
interrupted, then a fresh voice capture starts. TTS is never recorded back
into the new turn.
Voice steer ASR text is shown as a voice steer user message and is fenced to
the active turn ID.
Capture ends after speech plus 1.2 seconds of silence. If no speech is
detected, it exits with a visible error after 5 seconds instead of occupying
the microphone for the full record limit.
Planning and node state are structured events. Only a completed answer or a
real user-input boundary becomes an assistant reply.
New Session is disabled while a task is active, so it cannot hide an
execution that is still running.
Audio path
Linux audio or macOS CoreAudio
<-> local audio service
<-> outbound WebSocket to audio_client_bridge on the robot
<-> standard Robonix mic/speaker contracts
<-> Liaison + Speech
The bridge-specific endpoint is discovered through the optional
robonix/primitive/audio/bridge_info capability. Normal robot-local audio
drivers do not need that capability.
Troubleshooting
Client page does not open: check that robonix-client is running on
127.0.0.1:7860.
Robot stays offline: verify the entered host is the Atlas machine and that
<robot-host>:50051 is reachable from the client machine.
Vitals stays unknown: confirm Soma and Vitals are active in Atlas and
expose the contracts listed in the Vitals path section.
Liaison unavailable: leave the endpoint empty and confirm Liaison is
registered in Atlas.
Audio bridge unavailable: confirm the deployment uses
audio_client_bridge, port 60002 is reachable, and the provider exposes
bridge_info.
Microphone test reports digital silence: every PCM sample was zero. Check
hardware mute and Linux/macOS audio routing, or select audio_client_bridge
and a real input device. Quiet nonzero background audio is accepted.
Linux audio service is offline: install libportaudio2 and the audio
extra, then run python -m sounddevice to confirm that input and output
devices are visible in the same desktop session that runs the client.
Stop does not end a task: inspect the RTDL event history and Executor log;
a successful Stop must produce an interrupted turn and a cancelled running
plan.
Robonix Client
A Linux, macOS, and Windows web client for operating a running Robonix deployment. It provides text tasks, voice turns, hands-free control, explicit Stop/steer behavior, audio-device routing, live Pilot/RTDL execution events, and a Vitals workspace for robot hardware and software health.
Install Guide
Requirements:
Install from source:
The
audioextra installs the PortAudio adapter used for microphone and speaker access. Install the system library first when needed.Ubuntu/Debian:
macOS:
Windows:
On Windows
sounddeviceships its own PortAudio DLL and works out of the box. If the audio server still cannot find any devices, install a pre-built PyAudio wheel (which includes PortAudio) from elibroftw/pyaudio_portaudio — wheels are available for Python 3.10–3.14 (win_amd64):Quick Start
Assume Robonix Atlas is running on
100.87.172.93:50051:Open http://127.0.0.1:7860/.
The client starts its local audio service automatically. On Linux it uses the desktop’s PipeWire, PulseAudio, or ALSA devices through PortAudio. In the UI:
100.87.172.93and Atlas Port is50051.--hostand--robot-hostare different:--host 127.0.0.1controls where this Web UI listens.--robot-host 100.87.172.93selects the remote Robonix machine.Most users only need
--robot-host.Connecting to a Robonix Machine
Which IP should I enter?
Enter the IP or hostname of the machine that runs Robonix Atlas. It is not the Mac client IP and not an unrelated development PC.
Good choices are:
127.0.0.1only when Robonix and this client run on the same machine.The required fields are:
100.87.172.9350051unless the deployment changed itLiaison normally listens on port
50081, but clients should discover it through Atlas instead of hard-coding that port.Audio routing
For a Mac microphone/speaker, the Robonix deployment must include the
audio_client_bridgeprovider in client-initiated mode:The word
reverseonly describes connection ownership: the Mac connects to the robot. The deployment does not store the Mac IP. The client discovers the bridge endpoint through Atlas, opens one outbound WebSocket, and carries both microphone and speaker PCM over that connection.In Audio, select
audio_client_bridgefor input and/or output, choose the client machine’s devices, click Apply Route, then run Test microphone and Test speaker. Hands-free mode is disabled until explicitly enabled in the UI.Testing with the Robonix Webots Example
This flow runs Webots and Robonix on a Linux machine and the client on Linux or macOS. The same-host case also works by using
127.0.0.1as Robot Host.1. Prepare Robonix
On the Linux/Webots machine:
Use the reverse
audio_client_bridgemanifest block shown above if voice from the Mac is part of the test. Text, planning, execution, and Stop tests do not require client audio.2. Start Webots
In terminal 1, from the Robonix repository root:
office.wbtis the default. To select another built-in world:Wait until the simulator and Tiago controller are ready.
3. Start the Robonix stack
In terminal 2:
Wait for Atlas, Liaison, Pilot, Executor, and the manifest providers to report ready.
rbnx capscan be used to confirm capability registration.4. Start the client
On the client machine:
Open http://127.0.0.1:7860/, click Connect, and run the checks in this order:
Use Bash to print WEBOTS_CLIENT_OK.Stop the environment with:
Core Design
Control path
The client does not embed a planner and does not call robot drivers directly. Atlas is the source of provider endpoints; Liaison is the interaction gateway; Pilot owns task/steer/abort semantics; Executor owns running capability calls.
Vitals path
The browser opens
/ws/vitalson the local FastAPI process. That adapter discovers and combines these robot-local contracts through Atlas:robonix/system/soma/get_yamlandrobonix/system/soma/get_urdfdescribe the body and its components;robonix/system/vitals/streamsupplies hardware health and power state;robonix/system/vitals/modules/getsupplies software module health;The 3D view uses a model URL when the Soma description provides one, then a URDF with browser-renderable visual geometry, and finally a procedural renderer selected from robot family and component types. The current
dev-nextget_urdfcontract returns onlyrobot_idandurdf_xml; it does not attach mesh or texture files. A URDF whose relative resources are unavailable therefore falls back to the procedural renderer. The same-origin resource route remains available for a future contract that explicitly supplies those assets.Actuators that report
torque_enabled=0remain healthy but are presented as yellowidlecomponents. This readiness state propagates to their parent robot for rendering and does not create a warning incident.Vitals persists hardware, module, and provider incidents in
~/.local/share/robonix-client/vitals-alerts.sqlite3. SetROBONIX_CLIENT_VITALS_DBto use another database path. A reported anomaly isactive; after the source becomes healthy it remainsrecoveredin the alert center until an operator confirms it as resolved. Active incidents cannot be cleared manually, and resolved incidents remain available in alert history.The compiled browser bundle is committed under
src/robonix_client/static, so Node.js is not required to run the Python package. To rebuild or test the Vitals frontend after changingfrontend/src/vitals.js:Turn behavior
voice steeruser message and is fenced to the active turn ID.Audio path
The bridge-specific endpoint is discovered through the optional
robonix/primitive/audio/bridge_infocapability. Normal robot-local audio drivers do not need that capability.Troubleshooting
robonix-clientis running on127.0.0.1:7860.<robot-host>:50051is reachable from the client machine.audio_client_bridge, port60002is reachable, and the provider exposesbridge_info.audio_client_bridgeand a real input device. Quiet nonzero background audio is accepted.libportaudio2and theaudioextra, then runpython -m sounddeviceto confirm that input and output devices are visible in the same desktop session that runs the client.Related