A minimal on-device voice agent loop
65
stars
19
commits
Python
primary language
Jun 20, 2026
updated
A minimal on-device voice agent loop. Runs entirely on Mac M4 / Apple Silicon.
Now with even snappier audio responses — TTS starts on the first sentence while the LLM is still generating the rest, so you hear the reply almost immediately.
Need a custom voice model or production voice agent? See Trelis Voice AI Services.
SOUL.md controls the agent's style, live-reloaded each turn--memory; the agent learns durable facts about you in MEMORY.md and consolidates every 5 turnsbrew install portaudio espeak-ng uv
git clone https://github.com/TrelisResearch/voice-loop.git
cd voice-loop
uv sync
First run downloads Gemma 4 E4B (~3GB), Moonshine (~250MB), Kokoro (~300MB).
# Recommended defaults (TTS + smart turn + voice interrupt all on)
uv run voice_loop_mac.py
# + chime on utterance + soft ticks while generating
uv run voice_loop_mac.py --chime
# + persistent memory (reads/writes MEMORY.md)
uv run voice_loop_mac.py --memory
# Text-only mode (no TTS)
uv run voice_loop_mac.py --no-tts
# Disable voice interruption (keypress only)
uv run voice_loop_mac.py --no-aec
# Different voice (see below)
uv run voice_loop_mac.py --voice bf_emma
# Use the smaller E2B model (faster, slightly lower quality)
uv run voice_loop_mac.py --model mlx-community/gemma-4-E2B-it-4bit
# Custom silence timeout
uv run voice_loop_mac.py --silence-ms 500
# Debug: record mic stream to a WAV
uv run voice_loop_mac.py --record
Only the higher-quality voices are listed here:
| Voice | Accent | Gender | Notes |
|---|---|---|---|
af_heart | US | Female | Top pick — Grade A (default) |
af_bella | US | Female | Grade A-, HH training |
bf_emma | UK | Female | Grade B-, HH training |
am_fenrir | US | Male | Grade C+, H training |
am_puck | US | Male | Grade C+, H training |
am_michael | US | Male | Grade C+, H training |
bm_fable | UK | Male | Grade C, MM training |
bm_george | UK | Male | Grade C, MM training |
Mic (16kHz) ──► Silero VAD ──► Smart Turn ──► Moonshine ──► Gemma 4 E4B ──► Kokoro ──► Speakers
▲ │
SOUL.md + MEMORY.md │
▼
Mic during TTS ──► WebRTC AEC3 (LiveKit APM) ──► Silero VAD ──► voice interrupt ◄──────────┘
--memory) as system promptPress any key during TTS to interrupt.
SOUL.md — persona / style (always loaded, live-reloaded each turn)MEMORY.md — long-term facts. Only read/written when --memory is passed. When enabled, the agent extracts new durable facts after each turn and consolidates every 5 turns.Both files are re-read at the start of every turn, so edits take effect immediately.
~3.5 GB total. Fits easily in 16GB.
Built with:
See docs/raspberry-pi.md for a full feasibility analysis. Short version: Pi 4 is too slow; Pi 5 + LiteRT-LM is the best current option but still borderline for natural-feeling voice.
Apache 2.0.
18 commits
1 commits
Python
100.0%
A minimal on-device voice agent loop
65
stars
19
commits
Python
primary language
Jun 20, 2026
updated
A minimal on-device voice agent loop. Runs entirely on Mac M4 / Apple Silicon.
Now with even snappier audio responses — TTS starts on the first sentence while the LLM is still generating the rest, so you hear the reply almost immediately.
Need a custom voice model or production voice agent? See Trelis Voice AI Services.
SOUL.md controls the agent's style, live-reloaded each turn--memory; the agent learns durable facts about you in MEMORY.md and consolidates every 5 turnsbrew install portaudio espeak-ng uv
git clone https://github.com/TrelisResearch/voice-loop.git
cd voice-loop
uv sync
First run downloads Gemma 4 E4B (~3GB), Moonshine (~250MB), Kokoro (~300MB).
# Recommended defaults (TTS + smart turn + voice interrupt all on)
uv run voice_loop_mac.py
# + chime on utterance + soft ticks while generating
uv run voice_loop_mac.py --chime
# + persistent memory (reads/writes MEMORY.md)
uv run voice_loop_mac.py --memory
# Text-only mode (no TTS)
uv run voice_loop_mac.py --no-tts
# Disable voice interruption (keypress only)
uv run voice_loop_mac.py --no-aec
# Different voice (see below)
uv run voice_loop_mac.py --voice bf_emma
# Use the smaller E2B model (faster, slightly lower quality)
uv run voice_loop_mac.py --model mlx-community/gemma-4-E2B-it-4bit
# Custom silence timeout
uv run voice_loop_mac.py --silence-ms 500
# Debug: record mic stream to a WAV
uv run voice_loop_mac.py --record
Only the higher-quality voices are listed here:
| Voice | Accent | Gender | Notes |
|---|---|---|---|
af_heart | US | Female | Top pick — Grade A (default) |
af_bella | US | Female | Grade A-, HH training |
bf_emma | UK | Female | Grade B-, HH training |
am_fenrir | US | Male | Grade C+, H training |
am_puck | US | Male | Grade C+, H training |
am_michael | US | Male | Grade C+, H training |
bm_fable | UK | Male | Grade C, MM training |
bm_george | UK | Male | Grade C, MM training |
Mic (16kHz) ──► Silero VAD ──► Smart Turn ──► Moonshine ──► Gemma 4 E4B ──► Kokoro ──► Speakers
▲ │
SOUL.md + MEMORY.md │
▼
Mic during TTS ──► WebRTC AEC3 (LiveKit APM) ──► Silero VAD ──► voice interrupt ◄──────────┘
--memory) as system promptPress any key during TTS to interrupt.
SOUL.md — persona / style (always loaded, live-reloaded each turn)MEMORY.md — long-term facts. Only read/written when --memory is passed. When enabled, the agent extracts new durable facts after each turn and consolidates every 5 turns.Both files are re-read at the start of every turn, so edits take effect immediately.
~3.5 GB total. Fits easily in 16GB.
Built with:
See docs/raspberry-pi.md for a full feasibility analysis. Short version: Pi 4 is too slow; Pi 5 + LiteRT-LM is the best current option but still borderline for natural-feeling voice.
Apache 2.0.
18 commits
1 commits
Python
100.0%