Skip to content

Voice

Push-to-talk voice input — Claude Code builds a complete voice channel from microphone to model input through native audio modules, STT streaming, and OAuth gating.

Core Question

Enabling voice input for a CLI tool is not about “how to record audio” but “how to reliably acquire audio streams across platforms, transcribe in real time, and integrate with the existing permission system.”

Subsystem Overview

MetricValue
Core service filevoice.ts (526 lines)
MaturityEmerging
Gate controlGrowthBook (tengu_amber_quartz_disabled) + Anthropic OAuth
Native dependencyvendor/audio-capture/ — cpal native module

Architecture

ComponentFileResponsibility
Recording servicesrc/services/voice.ts (526 lines)Wraps cpal native module (macOS/Linux/Windows), falls back to SoX rec / ALSA arecord
STT streamsrc/services/voiceStreamSTT.tsConnects to claude.ai voice_stream endpoint for real-time speech-to-text
Keywordssrc/services/voiceKeyterms.tsVoice command keyword matching
Gatesrc/voice/voiceModeEnabled.tsGrowthBook + OAuth dual check
Command entrysrc/commands/voice//voice command registration
UI integrationuseVoice.ts, useVoiceEnabled.ts, useVoiceIntegration.tsxReact-side state and rendering
    flowchart LR
    subgraph Gate ["Gate Layer"]
        GB["GrowthBook<br/>tengu_amber_quartz_disabled"]
        OAuth["Anthropic OAuth<br/>Strong binding"]
    end

    subgraph Capture ["Audio Capture"]
        Native["cpal Native Module<br/>audio-capture.node"]
        Fallback["Fallback<br/>SoX rec / ALSA arecord"]
    end

    subgraph STT ["Speech-to-Text"]
        Stream["voiceStreamSTT.ts<br/>voice_stream endpoint"]
        Keywords["voiceKeyterms.ts<br/>Keyword matching"]
    end

    subgraph UI ["Interaction Layer"]
        Hook["useVoice.ts<br/>Push-to-talk"]
        Cmd["/voice command"]
    end

    GB --> OAuth
    OAuth --> Native
    OAuth --> Fallback
    Native --> Stream
    Fallback --> Stream
    Stream --> Keywords
    Keywords --> UI
  

Key Design Decisions

Lazy Native Module Loading

audio-capture.node links CoreAudio.framework; synchronous dlopen blocking can reach ~8 seconds (cold start). Therefore it delays until the first voice keypress rather than preloading. This is a typical startup time vs first-use latency trade-off: sacrificing first-use responsiveness for zero overhead in all non-voice scenarios.

OAuth Strong Binding

The voice_stream endpoint is only available through claude.ai. This means API Key, Bedrock, Vertex, and Foundry users cannot use voice. Voice is strongly bound to Anthropic’s own authentication system — likely for STT service cost and compliance reasons.

Cross-Platform Audio

PlatformPrimaryFallback
macOScpal native module (CoreAudio)SoX rec
Linuxcpal native module (ALSA/PulseAudio)ALSA arecord
Windowscpal native module (WASAPI)—

Fallback ensures voice remains functional even when native module loading fails (permission issues, missing dependencies) — just with potentially slightly degraded audio quality.

Push-to-talk Mode

Voice input uses Push-to-talk (hold to record, release to send), not continuous listening. Silence detection threshold is 2.0 seconds / 3%. This design avoids the privacy and resource consumption concerns of “always listening.”

Gate Mechanism

Voice Surface has triple gating:

  1. GrowthBook remote switch: tengu_amber_quartz_disabled can be shut off server-side at any time
  2. OAuth check: Only Anthropic OAuth-authenticated users can use it
  3. Feature Flag: VOICE_MODE (46 references) gates voice-related code paths

If any layer check fails, voice doesn’t appear in the UI or command list.

Lessons for Agent Builders

PatternDescription
Layered fallbackNative module → system tool → degradation notice — each layer has a clear fallback path
Lazy-load heavy resourcesDon’t load potentially 8-second-blocking native dependencies at startup
Auth-bound capabilitiesBind high-cost capabilities (STT) to authentication to control server resource consumption
Push-to-talkMore energy-efficient, more private than continuous listening, and users feel more in control

Path Evidence

PathRole
src/services/voice.tsRecording service core (526 lines)
src/services/voiceStreamSTT.tsSpeech-to-text stream
src/services/voiceKeyterms.tsKeyword matching
src/voice/voiceModeEnabled.tsGate logic
src/commands/voice/Command entry
src/hooks/useVoice.tsReact Hook
vendor/audio-capture/Audio capture native binary

Further Reading

  1. Signals & Extensions — Voice maturity assessment
  2. Architecture Map — Voice in the six-layer structure
  3. Computer Use — Another native-module-dependent capability