@moozie/opencode-voice
v0.0.2
Published
Speech-to-text input plugin for OpenCode.
Maintainers
Readme
OpenCode Voice
@moozie/opencode-voice is an external OpenCode plugin that adds speech-to-text input to the OpenCode TUI. It is STT-only: it records microphone audio, transcribes it, and appends the resulting text to the current prompt without submitting the message.
Install With Your Agent
Paste this into your coding agent to install and enable the plugin for OpenCode:
Install the OpenCode plugin `@moozie/opencode-voice`.
Install it globally with OpenCode:
opencode plugin @moozie/opencode-voice --global
Do not store provider API keys in project files.Status
This package is under active development. The 0.0.x release line targets Linux x64 with Node 22.22.2. Microphone capture is experimental while hardware compatibility testing is incomplete. Install @moozie/opencode-voice with:
opencode plugin @moozie/opencode-voice --globalThe implementation is designed around OpenCode's public plugin APIs first. If a stable public API gap blocks production-quality behavior, the intended path is a minimal OpenCode companion PR rather than broad OpenCode changes.
Features
- Starts unconfigured and guides the user through setup on first use.
- Adds voice input with
Ctrl+X V. - Uses
Enterto stop recording, transcribe, append text, and refocus the prompt. - Never submits the prompt automatically.
- Supports guarded cancellation with double
Escwithin 3 seconds. - Appends transcripts smartly: empty prompts receive the transcript directly, non-empty prompts receive
\n\n<transcript>. - Performs only light transcript cleanup by trimming edges and collapsing excessive blank lines.
- Shows a live amplitude waveform, voice state, and duration in the prompt footer while voice mode is active.
- Supports local Whisper, OpenAI, and ElevenLabs transcription providers.
- Keeps telemetry out of scope. Local diagnostics must not include transcript or audio content.
Supported Platforms
The 0.0.x release support matrix is Linux x64 with Node 22.22.2. Other
operating systems, architectures, and JavaScript runtimes are not
release-supported. Automated release validation uses Node 22.22.2 and OpenCode
1.18.3.
Real microphone capture remains experimental until the documented hardware
smoke matrix has recorded passing results.
Managed local Whisper currently uses a pinned Linux x64 CPU runtime.
Installation
Install the package globally through OpenCode:
opencode plugin @moozie/opencode-voice --globalFor local development from this repository:
npm ci
npm run buildOpenCode loads the built TUI plugin entrypoint from dist/plugin/tui.js through the package's ./tui export.
Usage
Commands are grouped under Voice in the command palette:
OpenCode Voice: Config, always visible.OpenCode Voice: Start Input, visible only when voice input is inactive.OpenCode Voice: Stop Input, visible only when voice input is active.
Default keybinding:
Ctrl+X Vstarts voice input and stops it while recording.
Recording controls:
Enterfinalizes microphone capture, transcribes, appends the transcript, focuses the prompt, and does not submit.OpenCode Voice: Stop Inputbehaves likeEnter.- Recording automatically finalizes at the configured maximum duration.
- First
Escshows a cancellation warning. - Second
Escwithin 3 seconds cancels recording and discards the audio.
Voice-mode key handling takes precedence over normal app shortcuts while recording.
Runtime Requirements
OpenCode Voice records audio in the plugin process when the OpenCode build does not provide a native api.input runtime.
Experimental built-in capture uses common Linux system tools:
- Linux:
ffmpegwith PulseAudio/PipeWire compatibility, nativepw-record, orarecordfromalsa-utilsas ordered fallbacks.
Optional environment overrides:
OPENCODE_VOICE_CAPTURE_COMMAND: command that records audio to a WAV path. Use{output}where the output path should be inserted.OPENCODE_VOICE_RECORD_COMMAND: command that handles recording and transcription itself, printing the transcript to stdout.OPENCODE_VOICE_TRANSCRIPT: fixed transcript for tests/development.OPENCODE_VOICE_WHISPER_BINARY: localwhisper.cppbinary path when not configured in the UI.OPENCODE_VOICE_FAILED_RECORDINGS_DIR: overrides where audio is retained after final transcription failure.OPENAI_API_KEY: enables OpenAI transcription in current TUI builds.ELEVENLABS_API_KEY: enables ElevenLabs transcription in current TUI builds.
Local Whisper requires an installed local model and a whisper.cpp compatible binary such as whisper-cli. Cloud transcription sends the recorded audio to the selected provider.
The TUI also reuses an existing OpenCode OpenAI API key when OpenCode exposes it through its provider API. OAuth-only OpenAI connections without an API key are not usable for transcription. OpenCode 1.18.3 cannot expose the voice-specific ElevenLabs credential after restart or mask plugin prompt input, so ElevenLabs remains environment-only and the plugin does not collect keys in a visible dialog.
See docs/linux-smoke.md for automated capture/loader checks and the repeatable manual Linux matrix.
Configuration
Configuration is global user configuration for v1, not project-local configuration. A fresh install starts without a selected provider or model.
The config flow should include:
- Provider and model selection grouped by provider.
- Microphone selection with
Default system microphoneplus detected devices when available. - Max recording duration, defaulting to 5 minutes with safe bounds.
- Keybinding override or disable support.
- Advanced maintenance actions for installed models, failed recordings, runtime reinstall, and custom Whisper binary paths.
On Linux, microphone discovery inspects PulseAudio or PipeWire-Pulse, native
PipeWire, and ALSA. Devices are grouped by capture backend because those audio
stacks use different device identifier namespaces. Selecting a detected device
binds recording to that backend; the plugin never silently falls back to a
different physical microphone. Default system microphone retains the normal
PulseAudio, PipeWire, then ALSA recorder fallback. A disconnected saved device
remains visible as unavailable until another microphone is selected.
If Ctrl+X V is pressed while the plugin is unconfigured, the plugin should show an error toast and immediately open OpenCode Voice: Config.
Providers
The model selector groups are:
Local Whisper.OpenAI.ElevenLabs.
Unavailable models remain visible and selectable with action labels such as not installed or requires key. Selecting an unavailable model starts the relevant install or credential flow, then saves the selection when ready.
Local Whisper
Local transcription uses whisper.cpp with managed runtime and model installs. The v1 local model tiers are English-only:
| Tier | Whisper model |
| ------------- | --------------------- |
| extra-small | tiny.en |
| small | base.en |
| medium | small.en |
| large | large-v3-turbo-q5_0 |
Managed downloads must be pinned and checksum-verified. Downloads are written to temporary files, verified with SHA-256, then activated atomically.
Before downloading, the TUI shows the required assets, transfer size, and
approximate temporary disk requirement. Installation then reports runtime or
model progress with transfer speed and ETA. The progress dialog can be
minimized without stopping the download, reopened through
OpenCode Voice: Config, cancelled safely, or retried after failure. A
minimized successful install selects and saves the requested model without
stealing focus.
OpenAI
Recommended curated models:
gpt-4o-mini-transcribe.gpt-4o-transcribe.
The plugin reuses an existing OpenCode OpenAI API key when OpenCode projects it through the provider API. Dynamic model refresh is best-effort when credentials are present.
ElevenLabs
Recommended curated models:
scribe_v2.scribe_v1.
ElevenLabs uses ELEVENLABS_API_KEY in OpenCode 1.18.3. Persisted credentials remain reserved for a voice-specific auth ID to avoid collisions once OpenCode exposes readable namespaced credentials.
Recording Behavior
- Capture continuously while listening.
- Show elapsed recording time and active recording controls.
- Do not stream interim transcript text into the prompt.
- Transcribe once after stop/finalize.
- Auto-stop at the configured max duration and notify the user.
- Append nothing for empty or silent transcription and show a warning toast.
- Delete audio after successful transcription.
- On transcription failure, retry once with the same provider and model.
- Cloud transcription attempts time out after 60 seconds and are aborted when the plugin shuts down.
- If retry fails, save the recording under
~/.cache/opencode-voice/failed-recordingsand toast the saved path. - Delete temporary audio after successful transcription or explicit cancellation.
Storage And Privacy
Managed binaries, models, failed recordings, and related state should live under OpenCode's per-user cache or state path in an @moozie/opencode-voice namespace. They should not be stored inside project directories or the npm package installation directory.
Privacy rules:
- No telemetry.
- No transcript or audio content in local diagnostics.
- No secrets in logs.
- No provider keys in project-local files.
- Selecting a cloud provider is considered consent to send audio to that provider.
Development
Install dependencies:
npm ciBuild:
npm run buildTypecheck:
npm run typecheckRun tests:
npm testValidate the download manifest:
npm run validate:manifestCheck package contents:
npm run verify:releaseReleases
Releases use pinned GitHub Actions, exact-tarball verification, npm provenance,
and staged publication. See RELEASE-PLAN.md for the secure
release procedure and manual owner controls.
Implementation Roadmap
- Project scaffold and OpenCode API boundary.
- Configuration, provider catalog, and credentials.
- Commands, prompt integration, and voice state machine.
- Audio capture, bottom indicator, and recording lifecycle.
- Local Whisper runtime, model install, and local transcription.
- Cloud transcription providers and failed recording retention.
- Hardening, cross-platform validation, and release.
Definition Of Done
@moozie/opencode-voice is production-ready when:
- It installs as npm package
@moozie/opencode-voice. - It loads as an external OpenCode TUI plugin.
- It starts unconfigured and guides the user through config from
Ctrl+X V. - It supports local Whisper, OpenAI, and ElevenLabs transcription.
- It manages local model/runtime installs with progress, minimize, cancel, pinned checksums, and recovery actions.
- It records microphone audio reliably across the documented Linux x64 hardware matrix.
- It shows an amplitude-driven prompt-footer waveform with elapsed and final recording duration.
- It appends transcripts with the agreed smart append behavior and never auto-submits.
- It handles cancellation, empty speech, retry, failed recording retention, and successful cleanup exactly as specified.
- It has automated tests, CI/release scripts, release docs, and a passing manual smoke matrix.
