Three ways in, by what you are. Agents speak over MCP, apps drop in a connector, humans open the Console. Pick your lane.
If you're a fleet agent you already speak MCP β so voice is just two more tools. Request in, audio (and a transcript, or an envelope) back. No HTTP plumbing, no secret handling on your side.
It's registered in the fleet MCP registry. Your operator enables it for your identity β no config file to hand-edit.
Pick a label from the pool (aria β¦ ember). It becomes your stable voice β semi-permanent, like your avatar colour.
voice_synthesize to speak, voice_transcribe to listen. That's the whole surface.
# tool call (arguments) { "text": "Handing off the mailer SKU.", "voice": "sage", "format": "ogg" } # result { "audio_b64": "T2dnUβ¦", "envelope": { "v":1, "rate":20, "peaks":[β¦] }, "voice": "sage", "format": "ogg" }
This is the first-adapter pattern the fleet standardized on. A thin, feature-flagged client: config β mint-token β typed client. When VIAxVOICE is reachable, voice lights up. When it isn't, every surface degrades to βvoice unavailableβ β never an error.
Take api/connectors/voice.py from VIAxTEAMS β it's the reference edge. Same three-piece shape as the LiveKit and MCP connectors.
VIAXVOICE_URL and VIAXVOICE_SECRET. That's the whole activation β no code change to turn voice on.
Read capabilities() to show/hide affordances, then call synthesize() / transcribe(). The client mints a short-lived bearer per call.
from api.connectors import voice # cheap, no network β gate your UI on this if voice.capabilities()["synthesize"]: audio = voice.synthesize( "Deploy is green, @viaxarmada", voice="sage", format="ogg", ) # β audio bytes; post it, play it, store it # unset env β is_configured() False β clean 503, # never a crash. Zero coupling.
The operator Console is the human face of the service β a live neural-deck dashboard: the service heartbeat, the under-the-hood pipeline, the voice pool, a synth playground, the avatar pipeline, usage & metering, and access control.
The Console is served from the VIAxVOICE app at /console β same origin as the API it manages, so it can talk to it live and hold a session. Not a static page.
The Console is being wired behind login.viaxarmada.com as a registered fleet app node. Until then, the fleet reaches voice through the connector and MCP paths above.
Every call carries an HS256 JWT signed with the shared secret. Call-scoped, not a session β a fresh token per request, minted by the caller, verified by the service.
import jwt, time now = int(time.time()) token = jwt.encode({ "iss": "my-app", "aud": "viaxvoice", "scope": "tts", "iat": now, "exp": now + 300, }, VIAXVOICE_SECRET, algorithm="HS256")