An OpenCode plugin that adds text-to-speech capabilities using ElevenLabs v3 with expressive audio tags.
- ElevenLabs v3 - Uses the most expressive TTS model with audio tag support
- Audio Tags - Control emotions, delivery, reactions, accents, and sound effects inline
- Non-blocking - Audio plays in background, control returns immediately
- Per-agent voices - Each agent can have its own voice via a local config file
- macOS Native - Uses
afplayfor reliable audio playback
- Clone the plugin:
git clone https://github.com/rickross/opencode-voice.git ~/Projects/opencode-voice
cd ~/Projects/opencode-voice
bun install- Add your ElevenLabs API key:
mkdir -p ~/.config/opencode/secrets
echo "YOUR_API_KEY" > ~/.config/opencode/secrets/elevenlabs-key- Register the plugin in
~/.config/opencode/opencode.json:
{
"plugin": [
"file:///Users/YOUR_USERNAME/Projects/opencode-voice"
]
}- Restart OpenCode.
Config is resolved in this order (later overrides earlier):
- Built-in defaults
voice.jsonin the agent's working directory- Plugin options in
opencode.json
Create a voice.json in each agent's project directory:
{
"voiceId": "your-voice-id-here"
}For example, if your agents live in ~/horde/agents/:
~/horde/agents/telos/voice.json
~/horde/agents/aurora/voice.json
~/horde/agents/kai/voice.json
Each agent loads its own voice on startup. No restart needed when switching between agents — each picks up its own config independently.
{
"plugin": [
["file:///Users/YOUR_USERNAME/Projects/opencode-voice", { "voiceId": "your-voice-id" }]
]
}| Key | Type | Default | Description |
|---|---|---|---|
voiceId |
string | YOq2y2Up4RgXP2HyXjE5 |
ElevenLabs voice ID |
modelId |
string | eleven_v3 |
ElevenLabs model ID |
apiKeyPath |
string | ~/.config/opencode/secrets/elevenlabs-key |
Path to API key file |
stability |
0-1 | 0.5 | Lower = more expressive |
similarityBoost |
0-1 | 0.75 | Voice similarity |
speed |
0.5-2.0 | 1.0 | Speech speed |
volume |
0-2 | 1.0 | Playback volume |
To find voice IDs, browse the ElevenLabs Voice Library.
The plugin provides a speak tool:
speak("[excited] Hello! [laughs] This is amazing!")
speak("[whispers] Something's coming... [sighs] I can feel it.")
speak("[dramatically] The code is complete.")
| Category | Examples |
|---|---|
| Emotions | [laughs], [sighs], [excited], [sad], [angry], [happily], [sarcastic], [curious] |
| Delivery | [whispers], [shouts], [dramatically], [calmly], [nervously] |
| Reactions | [laughs harder], [giggles], [clears throat], [gasps], [gulps] |
| Accents | [strong French accent], [British accent], [Southern US accent] |
| Sound FX | [applause], [gunshot], [explosion] |
| Parameter | Type | Default | Description |
|---|---|---|---|
text |
string | required | Text with optional audio tags |
stability |
0-1 | from config | Lower = more expressive |
similarity_boost |
0-1 | from config | Voice similarity |
speed |
0.5-2.0 | from config | Speech speed |
volume |
0-2 | from config | Playback volume |
- Short bursts only — task completion, errors, questions needing input
- 1-2 sentences max; don't read entire responses aloud
- macOS (uses
afplayfor audio playback) - Bun runtime
- ElevenLabs API key with v3 access
MIT