Voice
Two independent blocks: a transcriber for speech in and a synthesizer for speech out. Both are registry kinds, so the cloud and on-device options are the same shape.
moxxy plugins use transcriber local
moxxy plugins use synthesizer localSpeech in
| Name | Package | Runs |
|---|---|---|
whisper | @moxxy/plugin-stt-whisper | OpenAI Whisper, cloud |
whisper-codex | @moxxy/plugin-stt-whisper-codex | Whisper through a ChatGPT subscription |
local | @moxxy/plugin-stt-local | On-device, via sherpa-onnx |
Voice arrives from wherever the channel supports it: Telegram and WhatsApp voice notes, TUI push-to-talk, and raw audio posted to the HTTP channel.
Speech out
| Name | Package | Runs |
|---|---|---|
openai | @moxxy/plugin-tts-openai | Cloud |
elevenlabs | @moxxy/plugin-tts-elevenlabs | Cloud |
local | @moxxy/plugin-tts-local | On-device, Piper voices via sherpa-onnx |
/speak # read the last answer aloudFully on-device
The local transcriber and synthesizer run through sherpa-onnx with models downloaded once and cached. English and Polish ship configured. Nothing about the audio leaves the machine, which matters for the same reason the rest of moxxy runs locally — and it is the option to pick when a recording policy would otherwise make voice unusable.
Models are fetched on first use rather than bundled, so installing the plugin is cheap and the download is explicit.
Voice mode
Beyond one-shot transcription, voice mode holds a continuous call-style session: speech in, the loop runs, speech out, without touching the keyboard. Configure the voice, the language and the wake behaviour through the voice-admin plugin.
Writing one
import { defineTranscriber, definePlugin } from '@moxxy/sdk';
export const deepgram = defineTranscriber({
name: 'deepgram',
async transcribe(audio, ctx) {
return await send(audio);
},
});
export default definePlugin({
name: '@acme/plugin-stt-deepgram',
version: '1.0.0',
transcribers: [deepgram],
});defineSynthesizer mirrors it for the other direction.