Skip to content

Repository files navigation

AverVOX integrations

Thin, host-native adapters that let external agent environments use AverVOX (OSS or Pro) as their local speech engine.

These packages ship separately from AverVOX itself so that host-plugin churn never touches the AppImage or the PyPI package, and so each one can be published to the registry its ecosystem actually uses.

Why run speech locally

A hosted agent that speaks sends every reply — and with STT, every word the user says — to a speech vendor, and is billed per character for the privilege. Routing that through AverVOX changes three things:

  • Nothing leaves the machine. Synthesis and transcription run on the same box as the agent. There is no speech vendor in the path, so conversation text is not subject to anyone else's retention policy, and audio of the user's voice is never uploaded.
  • No per-character billing. Speech cost stops scaling with how much the agent talks. A verbose agent and a terse one cost the same.
  • It works offline. No API key to expire, no quota to exhaust, no outage to wait out. An agent on a laptop on a plane still speaks.

The tradeoff is honest: cloud voices still sound better than Piper, and the machine does the work. Pro's Kokoro voices narrow the quality gap — judge for yourself from the samples — and the latency numbers below cover the rest.

AverVOX-Integrations/
  hermes/      # Hermes Agent TTS/STT plugin + config snippets  (PyPI)
  openclaw/    # OpenClaw speech provider                       (npm)
  odysseus/    # Docs only until the Odysseus plugin ABI settles
Repository Contents
AverVOX-OSS The free edition and the avrvx CLI these adapters call
AverVOX Pro Commercial edition, distributed per licence from avervoxpro.com
This repo Host adapters only — no speech code lives here

Architecture

AverVOX remains the local voice engine. Hosts call its CLI bridge; they do not embed Piper/Kokoro/faster-whisper themselves.

Direction Mechanism
AverVOX → host (Converse) LLM profile pointing at the host’s OpenAI-compatible /v1
Host → AverVOX (TTS/STT) avrvx --synthesize / avrvx --transcribe / avrvx --capabilities

CLI bridge contract

Requires AverVOX 0.5.0 or newer (OSS or Pro):

# Capability probe (OSS vs Pro, engines, features)
avrvx --capabilities

# Text → WAV file (no playback)
avrvx --synthesize --text-file /tmp/in.txt --output /tmp/out.wav
avrvx --synthesize --text "Hello" -o /tmp/out.wav
echo "Hello" | avrvx --synthesize --text - -o /tmp/out.wav

# Pick a voice and rate for one request
avrvx --synthesize --text - -o /tmp/out.wav --voice af_heart --speed 1.2

# Audio file → transcript on stdout
avrvx --transcribe /tmp/message.ogg

Details that matter when wiring a host:

  • --capabilities writes JSON to stdout and diagnostics to stderr, so parsing stdout is always safe. Treat edition, licensed, and features as a stable contract.
  • --synthesize writes mono PCM16 WAV mode 0600 and prints the path. The output directory must already exist.
  • Pass text via --text-file or --text - (stdin) rather than --text "…": arguments are visible to other local users in the process list.
  • Failures print a message on stderr and exit non-zero. Genuine runtime failures during synthesis/transcription are prefixed avrvx --<command> failed: …; upfront argument-validation errors are not (e.g. --synthesize requires --output PATH or --speed must be between 0.1 and 4.0 both exit 2 with a bare message, no prefix).
  • --voice, --engine, and --speed are per-request overrides that leave the user's saved settings alone. They arrived in 0.5.0, so detect them by checking for tts.voices in the probe; both plugins do this and simply fall back to the configured voice on an older install.

OSS and Pro share the same commands. Pro unlocks Kokoro, wake word, session memory, and avrvx --serve — probed via --capabilities, not separate adapters.

Warm bridge (optional)

Every avrvx call pays for a Python start plus a model load before it produces a sample, which a host speaking every agent reply pays on every turn. avrvx --daemon pays it once and serves requests over a Unix socket at $XDG_RUNTIME_DIR/avervox/bridge.sock, created mode 0600 inside a 0700 directory. It roughly quarters the time to a finished reply; see Latency.

avrvx --daemon &                        # or the systemd unit in systemd/
avrvx --capabilities | grep -A3 daemon  # reports the socket and whether it is up

The protocol is newline-delimited JSON, one request object per line and one response per line, on a connection a host may keep open across turns:

{"method": "synthesize", "text": "Hello", "output": "/tmp/out.wav", "voice": "af_heart", "speed": 1.1}
{"ok": true, "path": "/tmp/out.wav"}

Methods are capabilities, synthesize, transcribe, cancel, and ping. Failures come back as {"ok": false, "code": "...", "error": "..."}.

Both plugins try the socket first and fall back to spawning avrvx when it is absent or reports code: "busy", so the daemon is purely an optimisation and the CLI stays the authoritative contract. Set AVERVOX_BRIDGE=0 in a host's environment to make that host ignore the daemon.

Streaming

Waiting for a whole reply to finish rendering before the first word is heard is the remaining latency most users notice. Adding "stream": true to a synthesize request makes the daemon send audio as it is produced instead of a single reply at the end. No output path is needed — nothing touches the disk.

Each frame is a JSON header line followed by exactly bytes of raw little-endian PCM16, so a reader never has to guess where a frame ends:

{"ok": true, "frame": 0, "rate": 22050, "bytes": 8192}
<8192 bytes of PCM>
{"ok": true, "done": true, "frames": 12}

The shell equivalent is --output -, which writes the same headerless PCM to stdout and announces the format on stderr before the first sample:

avrvx --synthesize --text "Hello there." --output - | aplay -f S16_LE -r 22050 -c 1

Text is split into sentences before synthesis, which sets the frame size. Piper generates incrementally and will usually emit several frames per sentence; Kokoro returns one array per call, so its granularity is exactly one frame per sentence. Either way the first frame arrives after the first sentence rather than after the whole reply.

The OpenClaw plugin exposes this as streamSynthesize alongside synthesize, and the Hermes plugin registers a tools.tts_streaming provider; both fall back to avrvx --output - when the daemon is not running, and hosts that cannot play chunks keep using the file-based path.

One caveat on the fallback: it applies only to a daemon that fails before any audio arrives. If the daemon dies mid-stream the plugin raises rather than respawning, since restarting would replay words the user already heard.

Latency

Measured through each host's own provider interface — not by timing avrvx directly — on this project's reference machine, a 2017 laptop, with Piper en_US-lessac-high at 22.05 kHz. "First audio" is a three-sentence reply and counts the wait until the first chunk a host can play; "whole reply" is a one-sentence reply and counts the wait until a finished WAV.

Spawn per call Warm daemon
Hermes, first audio 2.6 s 0.32 s
Hermes, whole reply 3.3 s 0.77 s
OpenClaw, first audio 2.6 s 0.36 s
OpenClaw, whole reply 3.2 s 0.91 s

The two effects are separable and compose. The daemon removes the Python start and the model load, which is the bulk of it. Streaming then removes the wait for the rest of the reply to render, which is what takes a warm call under half a second — quicker than the audio it is producing, so playback never starves.

Both are opt-in and neither is required: with no daemon and no streaming, the numbers in the first column are what a host gets, and everything still works.

Packages

Directory Host Speech Install
hermes/ Hermes Agent 0.19.0 TTS + STT, streaming pip install avervox-hermes *
openclaw/ OpenClaw 2026.6.33 (npm) / 2026.7.2 (source, minGatewayVersion) TTS, streaming openclaw plugins install @avervox/openclaw-plugin
odysseus/ Odysseus Docs only: point AverVOX Converse at Odysseus /v1

* Install into the same Python environment as Hermes Agent. On Ubuntu 24.04, Debian 12+, and Linux Mint 22, a bare pip install outside a virtual environment fails with error: externally-managed-environment (PEP 668) — see hermes/README.md for the fix.

Each package README records the exact host versions it was tested against. OpenClaw is speech-output only because its transcription hook is realtime and duplex, which avrvx --transcribe cannot satisfy; Odysseus stays docs-only until its plugin ABI settles.

Design

Speech behavior belongs to AverVOX, not to a cross-host SDK. Anything a second host would also want — the voice list, cancellation, the daemon — goes into avrvx, and every adapter inherits it. That is what keeps these packages thin enough to follow host churn without any speech code moving.

Choosing AverVOX belongs to the host. There is no Hermes/OpenClaw/Odysseus switch in the AverVOX UI and there will not be one: a host selects AverVOX as its own TTS/STT provider in its own config, and AverVOX talks back through an ordinary LLM profile. One switch spanning every host would put the same decision in two places and make AverVOX responsible for tracking each host's plugin API.

Within a host, config-driven CLI wiring is preferred wherever it exists (Hermes command providers, OpenClaw tts-local-cli); a plugin ships only where richer UX or registry distribution needs one. Each package documents both paths and leads with the simpler one.

Contributing

git clone https://github.com/avrvx/AverVOX-Integrations.git
cd AverVOX-Integrations

# Python packages and the contract tests
python -m pip install -r requirements-dev.txt
pytest

# OpenClaw plugin
cd openclaw && npm install && npm run typecheck && npm test

The contract tests in tests/ run against a stub avrvx, so they need no models installed. Run them against a real install with AVRVX_BIN=$(command -v avrvx) pytest -m live.

About

Host adapters that let Hermes Agent, OpenClaw, and other agent environments use AverVOX as their local speech engine

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages