Voice mode
Talk to the current Studio agent while keeping the same chat and preview
Voice mode replaces the web chat’s messages and composer with a speaking orb. An adjacent page or site preview stays open. The selected agent, model, page context, tools, permissions, and message queue remain the same for delegated work. A realtime conversation, provided by ElevenLabs or OpenAI, handles speech while the selected Studio agent performs that work in the background. You can keep talking, ask about progress, or submit another request while a coding task runs.
Coding agents keep running Claude Code in their existing sandbox. Voice mode does not change the chat’s pinned runtime, checkout, preview, or Claude session. The voice response style travels with each turn because Claude Code restores the original system prompt when resuming a session. Text turns explicitly restore normal response style. Decopilot chats use the same speech transport.
Choose Start voice mode beside the composer and allow microphone access. Back to chat stops the microphone and playback. It preserves the chat and any running work. Stop agent work is a separate control. Speaking while a reply plays interrupts the audio. Complete work requests join the chat’s normal queue; pauses and greetings do not start coding turns. Both companions answer progress questions about this call’s requests and the tasks they created from Studio’s work status, without starting a turn. Approvals, questions, errors, and queued requests remain visible in voice mode.
The companion acknowledges accepted work without claiming it has finished. When the Studio agent finishes, its final text part is sent back to the companion, which announces the result during a quiet gap. A per-turn instruction asks the working agent for a short, natural answer. Switching back to text restores normal response style for subsequent messages.
Organization conversations
Voice mode also works with the Super Agent. It can delegate questions about connected services, analytics, and task management through the same tools and permissions as text chat. For example, ask it to inspect analytics, start two independent tasks, and then ask about their progress while discussing another topic. The Super Agent must have access to the relevant integrations. GA4 can answer analytics questions; fulfillment or order status requires a connected order system.
Studio keeps a work status for the call and supplies it to the companion as context. It lists each spoken request as queued, running, running in the background, or finished, and each board task created during the call with its current lane. If the agent creates tasks 1, 2, and 3 during this call, the browser follows them through the existing task-board push events and announces each lane change. Other tasks in the organization stay silent; a question about one is another request to the Super Agent.
Requests in one chat run one turn at a time. In voice turns, the working agent is
asked to start research or analysis as a background subtask so its turn ends
quickly and the next spoken request does not wait. The companion waits for that
subtask’s result turn before announcing the answer; the turn that only started it
is reported as background work. Separate pieces of work the user asks for become
board tasks when the agent has task-board tools. Claude Code chats have no
subtask tool, so their requests still queue.
Shared conversation interface
Both browser adapters implement publishUpdate , microphone controls, volume,
and session close, and report requests through onDelegate . Updates distinguish
quiet context from spoken announcements and can carry a delegation ID. This lets
Studio deliver several tasks’ progress or results independently and out of order.
OpenAI maps these to Live thinking/commentary appends; ElevenLabs maps them to
contextual updates and explicitly labeled background messages. Provider tool names
and event schemas stay inside the adapters.
The subscription scope is tasks created in this call. The browser reads their IDs
from TASK_BOARD_ITEM_CREATE results in the call’s turns, including background
result turns, and filters task-board push events to that set. An unrelated task
finishing elsewhere remains silent. A task-creation turn finishing does not
establish that the created tasks finished. Known gaps: re-entering voice starts
with an empty task set, and a lane change during a push-stream reconnect is
reported only by the next change.
Deployment setup
Provider selection is server-only, with no provider or model picker in the product. ElevenLabs remains the default. Set these variables on every API replica:
ELEVENLABS_API_KEY=<elevenlabs-api-key>
The key needs ElevenAgents read and write access ( convai_read , convai_write ),
plus Text to Speech and Speech to Text access for older browser sessions. Keep it
on the server. Studio creates a private ElevenLabs agent for its voice configuration
and reuses it across sessions. Browsers receive a conversation token and a signed
Studio session token; they never receive the API key.
The web app needs HTTPS for microphone access, except on localhost. No inbound
provider callback or manual agent provisioning is required. API replicas must
share the same Studio authentication secret and NATS service.
To make OpenAI the deployment default, configure:
VOICE_CONVERSATION_PROVIDER=openai
OPENAI_LIVE_API_KEY=<openai-api-key>
The OpenAI adapter uses GPT-Live with client delegation and browser WebRTC. Studio negotiates the SDP offer on its authenticated API using a single-use session reservation. The browser receives an SDP answer, not an OpenAI credential. It does not require an ElevenLabs key. Keep the ElevenLabs key during a rolling deployment if older browsers still use the transcription/synthesis endpoints. The long-lived OpenAI key stays on the API server. Provider selection never falls back silently to the other provider when credentials are missing.
Then enable Settings → General → Voice mode for the organization. The
voice_mode organization flag defaults off. It is separate from authentication:
only the owning user can start a voice session for a writable, hosted chat.
Native terminal chats and read-only chats do not offer this mode.
Optional variables:
| Variable | Default | Purpose |
|---|---|---|
VOICE_CONVERSATION_PROVIDER | elevenlabs | elevenlabs or openai |
OPENAI_LIVE_MODEL | gpt-live-1 | OpenAI Live model |
OPENAI_LIVE_VOICE | marin | OpenAI Live voice |
ELEVENLABS_VOICE_MODEL | eleven_v4_turbo | Speech synthesis model |
ELEVENLABS_VOICE_ID | JBFqnCBsd6RMkjVDRZzb | ElevenLabs voice |
ELEVENLABS_CONVERSATION_MODEL | gemini-2.5-flash | Conversational LLM model ID supported by ElevenLabs |
Both providers’ credentials can be configured together. Environment variables set the deployment defaults; administrators can override the provider and conversational model per organization in the database. No provider or model selector is exposed in the product or organization settings tools.
After migration 228-org-voice-config , choose OpenAI for an organization:
INSERT INTO organization_settings
("organizationId", voice_provider, voice_model, "createdAt", "updatedAt")
SELECT id, 'openai', 'gpt-live-1', now(), now()
FROM organization WHERE slug = '<org-slug>'
ON CONFLICT ("organizationId") DO UPDATE
SET voice_provider = EXCLUDED.voice_provider,
voice_model = EXCLUDED.voice_model,
"updatedAt" = now();
Set voice_provider = 'elevenlabs' and voice_model = NULL to use ElevenLabs
with ELEVENLABS_CONVERSATION_MODEL . An explicit ElevenLabs voice_model selects
its conversational LLM, not its speech synthesis model. ELEVENLABS_VOICE_MODEL
and ELEVENLABS_VOICE_ID continue to control speech synthesis and voice.
A model override requires an explicit provider so changing the deployment default
cannot apply one provider’s model ID to another provider.
Set both columns to NULL to restore deployment defaults. Keep voice_mode
enabled separately. These columns contain no credentials; the selected provider’s
key must exist on every API replica, and a missing key returns an error without
switching providers. An invalid VOICE_CONVERSATION_PROVIDER does not prevent API
startup. Voice calls that inherit that invalid default return 503; an organization
with a valid provider override can still use voice. Ordinary text chat is unaffected.
The existing organization-settings read resolves overrides when a call starts. There is no additional database query or per-turn lookup. The resolved provider and model are stored in the session reservation and stay fixed for that call, even if the DB changes before WebRTC connects. DB edits apply to the next call without a restart. Environment changes still require restarting every replica. The first call with a new ElevenLabs configuration may provision a private agent; later calls reuse it. The working agent and its model are unaffected.
Session behavior and limits
The browser closes sessions after ten minutes, with one active session per user per organization. ElevenLabs also enforces that limit at the provider. For OpenAI, ten minutes is a Studio browser limit, not a provider-enforced session limit. Up to 40 work requests can be delegated in one session. An interrupted browser that cannot release its reservation may need to wait for that expiry before reconnecting. The selected voice provider bills the conversation to the deployment’s account. ElevenLabs defaults to Gemini 2.5 Flash for conversation, with no separate model key. OpenAI uses its configured Live model for speech-to-speech conversation. Studio’s model usage accounting continues to cover the working agent’s model calls.
Microphone audio and streamed replies travel directly between the browser and
the selected provider over WebRTC. ElevenLabs uses Scribe transcription and its
configured speech synthesis model. GPT-Live handles simultaneous listening and
speaking, and emits transcript fragments and delegation IDs. Its adapter submits
the new speech as the chat message through the same chat API. Earlier spoken turns
travel beside it as voiceTranscript and reach the working agent as per-turn context
that the chat does not display. A delegation event is required; transcript fragments alone never
start work. A short settling window allows delayed fragments to arrive, but provider
transcripts have no completed-turn marker, so this needs evaluation with real audio.
ElevenLabs client tools submit requests, read current-chat status, and request cancellation.
GPT-Live answers status from the supplied work status and delegates cancellation
requests to the working agent, so those requests can wait behind active work. The visible Stop agent work control remains
available to cancel the current run immediately. Neither provider waits for long
coding tasks before continuing the spoken conversation.
Results arrive through Studio’s existing chat stream and are supplied to the
companion as context. The browser requests a spoken announcement when the user
is quiet. Permission and approval checks stay in the normal Studio path.
Delegated requests and agent answers remain in the normal Studio chat history. Conversational remarks and progress questions stay in the voice session. Recent chat text and the current page context are supplied to the companion when voice starts. Studio does not store audio. The provisioned ElevenLabs agent disables audio recording and requests one-day transcript retention. Those ElevenLabs settings do not apply to OpenAI; OpenAI data handling follows the deployment’s OpenAI account and API data controls.
During a rolling deployment, older browsers can continue using the original Scribe/TTS endpoints. Their signed speech grants retain the ten-minute limit, 120 synthesis requests, and 24,000-character allowance.
Leaving the chat, changing organizations, or disconnecting stops the voice session. Transport failures show an error with a path back to text. They do not automatically resend a request whose acceptance is uncertain. Check the chat before repeating it. Stopping playback leaves the agent’s work running.
Verification
The regular voice-mode.spec.ts browser suite checks access gates, the default
flag, and switching back to a preserved draft. Its optional live case requires
an API server configured with either voice provider and a synthetic WAV input:
E2E_VOICE_LIVE=1 E2E_VOICE_WAV=/tmp/synthetic-utterance.wav \
bun run --cwd=packages/e2e test:e2e -- tests/voice-mode.spec.ts
The live case uses the real speech service and an HTTP model stand-in, and
checks that the companion responds while the working model is delayed, announces
its result, and returns to text in the same chat. For ElevenLabs, with E2E_VOICE_FOLLOWUP=1 , use
a WAV containing a work request followed by a progress question; the test also
checks that the second spoken answer arrives before work completes without
submitting another coding turn. GPT-Live also answers from the supplied work
status, but this optional assertion has only been run against ElevenLabs.
The daemon suite also exercises the real Claude Code executable and SDK against an HTTP model stand-in. It starts in text, changes a file in voice mode, and returns to text while checking the same Claude session and conversation history:
DAEMON_E2E_CLAUDE_VOICE=1 \
bun test packages/sandbox/daemon-e2e/daemon.voice-claude.e2e.test.ts
Build the Go daemon first, as described in the sandbox package README. Set
DAEMON_E2E_CMD to use a daemon binary at another path.
Found an error or want to improve this page?
Edit this page