deco Studio

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