openclaw-speak is a command-line Rust application for Linux that listens for OpenClaw assistant replies and voices them through the local sound device using ElevenLabs text-to-speech.
- Run as a local CLI daemon on Linux.
- Intercept assistant replies from an OpenClaw Gateway session.
- Convert visible assistant text into speech with ElevenLabs.
- Play audio on the local output device.
- Support cross-compilation for Raspberry Pi 5.
This repository currently contains a compile-first scaffold:
- CLI entry points
- config loading from file and environment
- module boundaries for OpenClaw Gateway, ElevenLabs, and audio output
- Raspberry Pi 5 oriented cross-build settings
The live OpenClaw event subscription and ElevenLabs audio playback pipeline are the next implementation steps.
Configuration is loaded from:
--config <path>if provided$XDG_CONFIG_HOME/openclaw-speak/config.toml~/.config/openclaw-speak/config.toml.envin the current working directory, if present- environment variables
Environment variables:
OPENCLAW_GATEWAY_URLOPENCLAW_GATEWAY_TOKENOPENCLAW_SESSION_FILTERELEVENLABS_API_KEYELEVENLABS_VOICE_IDELEVENLABS_MODEL_IDELEVENLABS_OUTPUT_FORMATELEVENLABS_LANGUAGE_CODEAUDIO_OUTPUT_DEVICERUST_LOG
See config.example.toml.
For secret values, see .env.example.
Recommended split:
- keep stable non-secret settings in
config.toml - keep secrets such as
OPENCLAW_GATEWAY_TOKENandELEVENLABS_API_KEYin.env - use real exported shell env vars only when you want to override
.env
Example .env:
OPENCLAW_GATEWAY_TOKEN=replace-me
ELEVENLABS_API_KEY=replace-meRunning openclaw-speak on a different machine from the Gateway is fine.
- Preferred secure default: keep the Gateway loopback-only and reach it through SSH, VPN, or Tailscale.
- LAN option: bind the Gateway for LAN access and require token or password auth.
- This project is already set up to send a Gateway token using
openclaw.gateway_tokenorOPENCLAW_GATEWAY_TOKEN.
Example LAN client config:
[openclaw]
gateway_url = "ws://192.168.1.50:18789"
gateway_token = "replace-me"If a .local hostname resolves only to a link-local IPv6 address, use either:
- an IPv4 LAN address such as
ws://192.168.1.50:18789, or - a scoped IPv6 literal such as
ws://[fe80::1234:5678:abcd:ef01%eth0]:18789
Plain ws://ada.local:18789 can fail in that case because link-local IPv6 needs an interface scope.
cargo run -- devices
cargo run -- test --text "Hello from openclaw-speak"
cargo run -- daemonTo enable real Linux audio device access through CPAL and ALSA:
cargo run --features audio-cpal -- devices
cargo run --features audio-cpal -- test --text "Hello from openclaw-speak"
cargo run --features audio-cpal -- daemonOn Debian or Ubuntu style systems, that feature typically needs:
sudo apt install pkg-config libasound2-devWith audio-cpal enabled, the app will:
- decode ElevenLabs PCM output
- resample it to the selected device configuration when needed
- play speech through the chosen output device
This repo includes a system-level unit for running the daemon in the background.
Build the release binary and install the bundled service:
./scripts/install-systemd-service.shEnable and start it:
sudo systemctl enable --now openclaw-speak.serviceUseful commands:
sudo systemctl status openclaw-speak.service
journalctl -u openclaw-speak.service -f
sudo systemctl restart openclaw-speak.serviceNotes:
- the installer renders the unit for the current
$USER, checkout path, and user runtime directory - the unit runs with
WorkingDirectoryset to this repo root, so the local.envfile continues to load - the unit sets the user audio runtime variables needed to reach PipeWire/Pulse from a system service
The default target for a 64-bit Raspberry Pi 5 image is:
rustup target add aarch64-unknown-linux-gnu
cargo build --release --target aarch64-unknown-linux-gnuYou will also need an ARM64 cross linker installed on the build machine, for example aarch64-linux-gnu-gcc.
For audio playback on the Pi, system libraries for ALSA are expected to be present on the target system.
If you build with --features audio-cpal, make sure your cross toolchain also exposes the target ALSA development files.