{"_id":"@afterrealism/opencode-voice","name":"@afterrealism/opencode-voice","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@afterrealism/opencode-voice","version":"1.0.0","description":"Local voice dictation for OpenCode on Linux using whisper.cpp and Ollama","type":"module","main":"dist/src/index.js","types":"dist/src/index.d.ts","exports":{".":{"types":"./dist/src/index.d.ts","import":"./dist/src/index.js"},"./tui":{"types":"./dist/src/index.d.ts","import":"./dist/src/index.js"}},"bin":{"opencode-voice":"dist/src/doctor.js"},"engines":{"node":">=22"},"scripts":{"build":"tsc -p tsconfig.json","test":"npm run build && node --test dist/test/*.test.js","pack:check":"npm pack --dry-run"},"repository":{"type":"git","url":"git+https://github.com/afterrealism/opencode-voice.git"},"bugs":{"url":"https://github.com/afterrealism/opencode-voice/issues"},"homepage":"https://github.com/afterrealism/opencode-voice#readme","keywords":["opencode-plugin","voice","dictation","whisper","speech-to-text","linux","privacy"],"author":{"name":"After Realism"},"license":"MIT","publishConfig":{"access":"public"},"devDependencies":{"@opencode-ai/plugin":"1.18.1","@types/node":"24.12.2","typescript":"5.8.2"},"_id":"@afterrealism/opencode-voice@1.0.0","gitHead":"ca47b780497b5ca985f34094819b106a88daec3d","_nodeVersion":"22.22.0","_npmVersion":"10.9.4","dist":{"integrity":"sha512-/Rdm+Lm0IlxgohGajeeZZlDJGPdgCZjauNCG534IatcIHIbJwdij3+3zH0rruq3j99rz65Bi004gmpDOz3UJuA==","shasum":"2e038abf31a172a7d334db3c2390e2e488d9620a","tarball":"https://registry.npmjs.org/@afterrealism/opencode-voice/-/opencode-voice-1.0.0.tgz","fileCount":17,"unpackedSize":69417,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDttClL1tyoNCQb1ugKIgGJSOwZBwTgzeL/wW/Mh3NN/AIgTtUv7kzgmCOeez1sCo3UIvVO0XsL8ILKgdPxJakpU4M="}]},"_npmUser":{"name":"afterrealism","email":"contact@afterrealism.com"},"directories":{},"maintainers":[{"name":"afterrealism","email":"contact@afterrealism.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/opencode-voice_1.0.0_1784124157161_0.5737269220270391"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-15T14:02:36.970Z","1.0.0":"2026-07-15T14:02:37.342Z","modified":"2026-07-15T14:02:37.509Z"},"maintainers":[{"name":"afterrealism","email":"contact@afterrealism.com"}],"description":"Local voice dictation for OpenCode on Linux using whisper.cpp and Ollama","homepage":"https://github.com/afterrealism/opencode-voice#readme","keywords":["opencode-plugin","voice","dictation","whisper","speech-to-text","linux","privacy"],"repository":{"type":"git","url":"git+https://github.com/afterrealism/opencode-voice.git"},"author":{"name":"After Realism"},"bugs":{"url":"https://github.com/afterrealism/opencode-voice/issues"},"license":"MIT","readme":"# @afterrealism/opencode-voice\n\nLocal, private voice dictation for [OpenCode](https://opencode.ai) on Linux.\nIt records from your microphone with ALSA, transcribes on-device with\n[whisper.cpp](https://github.com/ggml-org/whisper.cpp), optionally cleans up the\ntranscript with a loopback [Ollama](https://ollama.com) model, and appends the\nresult to your OpenCode prompt. It **never submits** the prompt for you and it\nnever sends audio or transcripts to the cloud.\n\n## Features\n\n- Push-to-toggle dictation from the OpenCode TUI (`Ctrl+O` by default).\n- `/voice` and `/voice-cancel` slash commands.\n- On-device transcription with whisper.cpp (`whisper-cli`).\n- Optional local transcript cleanup via a loopback Ollama endpoint.\n- Raw-transcript fallback when Ollama is unavailable or returns bad output.\n- Appends to the prompt only — you review and submit.\n- No runtime dependencies, no telemetry, no cloud calls, no install hooks.\n- `opencode-voice doctor` prerequisite checker that changes nothing.\n\n## Requirements\n\n- **Linux with ALSA.** This version supports Linux only; recording uses\n  `arecord` from `alsa-utils`. macOS and Windows are not supported.\n- **Node.js >= 22** (OpenCode already provides a compatible runtime; Node is\n  only needed directly for the `opencode-voice doctor` CLI).\n- **whisper.cpp** providing the `whisper-cli` binary on your `PATH`.\n- **A Whisper model file** (see below); the large v3 Q5 model is recommended.\n- **Ollama** (optional) running on loopback for transcript cleanup.\n\n## Install\n\nInstall the plugin from npm:\n\n```bash\nnpm install -g @afterrealism/opencode-voice\n```\n\nInstalling globally puts the `opencode-voice` doctor CLI on your `PATH`. You may\nalso let OpenCode manage the plugin from `tui.json` (see\n[Configure OpenCode](#configure-opencode)); OpenCode installs the package into\nits own plugin store. The package ships no install, build, or postinstall\nscripts and pulls in no runtime dependencies.\n\nInstall the ALSA recording utility for your distribution:\n\n```bash\n# Debian / Ubuntu\nsudo apt-get install -y alsa-utils\n\n# Fedora\nsudo dnf install -y alsa-utils\n```\n\n`arecord` (from `alsa-utils`) must be on your `PATH`.\n\n## Install whisper.cpp\n\nThis plugin calls the `whisper-cli` binary from whisper.cpp. Your distribution\nmay or may not package it, so build it from source. These instructions target\nwhisper.cpp **v1.9.1**.\n\n```bash\ngit clone --branch v1.9.1 --depth 1 https://github.com/ggml-org/whisper.cpp\ncd whisper.cpp\n```\n\nPick the CPU build or the NVIDIA CUDA build below, then put the resulting\n`build/bin/whisper-cli` on your `PATH` (for example, copy or symlink it into a\ndirectory such as `~/.local/bin`).\n\n### CPU\n\nA CPU build works everywhere and needs no GPU drivers:\n\n```bash\ncmake -B build\ncmake --build build -j --config Release\n# result: build/bin/whisper-cli\n```\n\n### NVIDIA CUDA\n\nA CUDA build is faster if you have an NVIDIA GPU and the CUDA toolkit installed.\nEnable CUDA and let the toolchain detect your GPU architecture rather than\nhardcoding one:\n\n```bash\ncmake -B build -DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=native\ncmake --build build -j --config Release\n# result: build/bin/whisper-cli\n```\n\n`native` asks the CUDA compiler to target the architecture of the GPU in the\nbuild machine. If your CUDA toolkit is too old to support `native`, look up your\nGPU's compute capability (for example, `89` for an RTX 40-series Ada card) and\npass it explicitly, e.g. `-DCMAKE_CUDA_ARCHITECTURES=89`. Do not copy another\nmachine's architecture number blindly — it must match your card.\n\n## Download the Whisper model\n\nThe model file is user-supplied and referenced by an **absolute** path. The\nrecommended model is large v3 Q5 (`ggml-large-v3-q5_0.bin`). Download it from\nthe whisper.cpp model repository on Hugging Face:\n\n```bash\nmkdir -p ~/.local/share/whisper-models\ncurl -L -o ~/.local/share/whisper-models/ggml-large-v3-q5_0.bin \\\n  https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-q5_0.bin\n```\n\nConfirm the file is present and readable — the plugin and the doctor both check\nreadability at the configured absolute path:\n\n```bash\ntest -r ~/.local/share/whisper-models/ggml-large-v3-q5_0.bin && echo readable\n```\n\nSmaller models (for example `ggml-base.en.bin`) also work and are faster but\nless accurate; point `whisperModelPath` at whichever `.bin` you downloaded.\n\n## Configure Ollama\n\nOllama is optional. When it is running on loopback, the raw transcript is passed\nthrough a local model for light cleanup (punctuation, capitalization, obvious\nrecognition fixes). Install Ollama from <https://ollama.com>, then pull the\ndefault model:\n\n```bash\nollama pull qwen2.5:7b\n```\n\nOllama serves an OpenAI-compatible API on `http://127.0.0.1:11434` by default,\nwhich matches the plugin's default endpoint. If Ollama is not running, dictation\nstill works and the plugin uses the **raw transcript** instead.\n\n## Run the doctor\n\n`opencode-voice doctor` is a read-only prerequisite check. It records nothing,\ncalls no cloud endpoint, and installs, downloads, or starts nothing.\n\n```bash\nopencode-voice doctor --model /absolute/path/to/ggml-large-v3-q5_0.bin\n```\n\nIt checks, in order: Linux platform, `arecord`, `whisper-cli`, the model file's\nreadability, the OpenCode version (if `opencode` is on `PATH`), and Ollama\nreachability plus the configured model.\n\nExit semantics:\n\n- Exit code **0** when no required check fails.\n- Exit code **1** when a required check fails (wrong platform, missing\n  `arecord`/`whisper-cli`, or an unreadable model), or when the arguments are\n  invalid.\n- A missing OpenCode binary and an unreachable or unconfigured Ollama are\n  **warnings**, not failures: the plugin still transcribes, and an Ollama\n  warning simply means normalization is skipped and the **raw transcript** is\n  used.\n\nAdd `--json` to emit the machine-readable result. Run `opencode-voice --help`\nfor all flags (`--model`, `--ollama-model`, `--ollama-endpoint`, `--language`,\n`--shortcut`, `--json`).\n\n## Configure OpenCode\n\nRegister the plugin in your OpenCode TUI config at\n`~/.config/opencode/tui.json`. Use the npm tuple form — a `[name, options]`\npair — with an **absolute** model path:\n\n```json\n{\n  \"$schema\": \"https://opencode.ai/tui.json\",\n  \"plugin\": [\n    [\n      \"@afterrealism/opencode-voice\",\n      {\n        \"whisperModelPath\": \"/home/you/.local/share/whisper-models/ggml-large-v3-q5_0.bin\"\n      }\n    ]\n  ]\n}\n```\n\n**Restart OpenCode** after editing `tui.json` so it loads the plugin. On a\nsuccessful load the plugin registers its commands and the toggle shortcut; on\ninvalid options it shows one error toast and stays inactive.\n\n## Usage\n\n- **Toggle recording:** press `Ctrl+O` (or your configured `shortcut`), or run\n  `/voice`. Press again to stop; transcription and optional cleanup run, then\n  the text is appended to your prompt.\n- **Cancel:** run `/voice-cancel` to stop and discard the current dictation\n  without inserting anything.\n- **Review and submit:** the plugin **never submits** the prompt. It only\n  appends text; you press Enter yourself.\n- Recording stops automatically after 120 seconds.\n\nStatus toasts report each phase (Recording, Transcribing, Normalizing,\nTranscript added). If normalization fails, you get a warning and the **raw\ntranscript** is inserted instead — your words are never lost.\n\n## Configuration\n\nOptions go in the second element of the plugin tuple in `tui.json`.\n\n| Option            | Required | Default                                      | Notes |\n| ----------------- | -------- | -------------------------------------------- | ----- |\n| `whisperModelPath`| yes      | —                                            | Absolute path to a whisper.cpp `.bin` model. |\n| `ollamaModel`     | no       | `qwen2.5:7b`                                 | Local Ollama model used for cleanup. |\n| `ollamaEndpoint`  | no       | `http://127.0.0.1:11434/v1/chat/completions` | Must be loopback (`127.0.0.1`, `localhost`, or `::1`), HTTP/HTTPS, no credentials/query/fragment, path exactly `/v1/chat/completions`. |\n| `language`        | no       | `en`                                         | `auto` or a 2–3 letter lowercase code passed to whisper.cpp. |\n| `shortcut`        | no       | `ctrl+o`                                     | OpenCode key expression for the toggle. |\n\nUnknown options are rejected to catch typos.\n\nNotes:\n\n- **Normalization is best-effort.** If Ollama is unreachable, times out, or\n  returns malformed output, the plugin falls back to the raw transcript and\n  **no prompt is submitted**.\n- **Shortcut conflicts.** `ctrl+o` may collide with an existing OpenCode\n  keybinding or a terminal/emulator binding. If the toggle does nothing, pick a\n  free key via `shortcut` and avoid keys your terminal already intercepts.\n- **Cloud endpoints are rejected.** Only loopback Ollama hosts are accepted;\n  there is no API-key or remote-endpoint support by design.\n\n## Privacy and security\n\n- Audio and transcripts stay on your machine. Nothing is sent to any cloud\n  service. The only network call is to your configured loopback Ollama endpoint.\n- No telemetry, analytics, or crash reporting.\n- Recordings are written to a unique, mode-`0700` temporary directory and\n  deleted after the pipeline finishes or on cancel/shutdown.\n- Child processes (`arecord`, `whisper-cli`) are spawned with argument arrays,\n  never a shell string, and only the exact spawned process is ever signalled —\n  no process-name matching or `pkill`.\n- Logs contain state names and error categories only — never transcript text,\n  model responses, audio, or secrets.\n- Output buffers and operation timeouts are bounded so a runaway process cannot\n  exhaust memory or hang the plugin.\n\n## Troubleshooting\n\n- **`/voice` or the shortcut does nothing.** Confirm OpenCode was restarted\n  after editing `tui.json`, then check for a shortcut conflict and set a\n  different `shortcut`.\n- **\"Voice unavailable\" preflight error.** `arecord` or `whisper-cli` is not on\n  `PATH`, or the model is not readable. Run `opencode-voice doctor --model ...`\n  to see which check fails.\n- **No speech detected.** Recording was silent or too quiet; check your ALSA\n  input device and microphone levels.\n- **Transcription failed.** Verify the model path is correct and the file is a\n  valid whisper.cpp `.bin`, and that your `whisper-cli` version can read it.\n- **Cleanup unavailable; using the raw transcript.** Ollama is down or the model\n  is not pulled. Start Ollama and run `ollama pull qwen2.5:7b`, or ignore it and\n  keep using raw transcripts.\n- **Plugin inactive after config change.** An option is invalid (for example a\n  relative `whisperModelPath` or a non-loopback endpoint). The error toast names\n  the offending option.\n\n## Upgrade\n\n```bash\nnpm install -g @afterrealism/opencode-voice@latest\n```\n\nIf OpenCode manages the plugin from `tui.json`, update the version constraint\nthere (or let it re-resolve) and restart OpenCode. Review the changelog for any\noption changes before upgrading across a major version.\n\n## Uninstall\n\n```bash\nnpm uninstall -g @afterrealism/opencode-voice\n```\n\nThen remove the plugin tuple from `~/.config/opencode/tui.json` and restart\nOpenCode. Whisper models, whisper.cpp, and Ollama are separate installs; remove\nthem yourself if you no longer need them. The plugin leaves no temporary audio\nbehind — recordings are deleted after each use.\n\n## Development\n\n```bash\ngit clone https://github.com/afterrealism/opencode-voice\ncd opencode-voice\nnpm install --ignore-scripts\nnpm test\nnpm run build\nnpm pack --dry-run\n```\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for the full contributor workflow and\n[SECURITY.md](SECURITY.md) for vulnerability reporting.\n\n## License\n\n[MIT](LICENSE) © 2026 After Realism\n","readmeFilename":"README.md","_rev":"1-917c47a9a414911226143c996ae5ed01"}