Local macOS voice-control integration for OpenClaw. Use when setting up, deploying, troubleshooting, or operating wakeword-triggered voice access to a local...
---
name: openclaw-voice-control
description: Local macOS voice-control integration for OpenClaw. Use when setting up, deploying, troubleshooting, or operating wakeword-triggered voice access to a local OpenClaw agent with ASR, TTS, overlay UI, and launchd background support.
homepage: https://github.com/CarrotYuan/openclaw-voice-control
metadata: {"openclaw":{"os":["darwin"],"homepage":"https://github.com/CarrotYuan/openclaw-voice-control","requires":{"bins":["python3","git","launchctl"],"env":["OPENCLAW_BASE_URL","OPENCLAW_TOKEN","SENSEVOICE_MODEL_PATH","SENSEVOICE_VAD_MODEL_PATH"]},"primaryEnv":"OPENCLAW_TOKEN"}}
---
# OpenClaw Voice Control
OpenClaw Voice Control is a local macOS voice-control integration for OpenClaw.
Repository source:
- GitHub: [CarrotYuan/openclaw-voice-control](https://github.com/CarrotYuan/openclaw-voice-control)
It provides:
- wakeword activation
- local microphone capture
- local ASR with FunASR / SenseVoice
- forwarding recognized text to a local OpenClaw agent
- macOS TTS playback
- optional overlay UI
- launchd-based background resident behavior
- auto-start after user login
## Platform
- macOS only
## Safety Warning
This skill adds a voice entrypoint, and that entrypoint is not identity-bound.
That means:
- anyone near the microphone may be able to trigger it
- any capability exposed through the connected OpenClaw agent may become reachable by voice
Recommended safety practice:
- add explicit safety constraints to the connected agent prompt
- require confirmation for high-risk actions
- avoid broad autonomous permissions for the voice-facing agent
- use least privilege for tools and connected systems
## Main Path
Treat this as a local deployment skill, not as a prompt-only helper.
When this skill is installed into OpenClaw:
- work inside the current installed skill directory for the current conversation agent
- use the declared GitHub repository as the source of truth
- do not silently switch to another local clone or an already-prepared environment
- do not continue until the workspace contains the real repository files, not just `SKILL.md`
The main installation guide is the repository `README.md`.
`README.zh-CN.md` is the Chinese companion guide.
Use this as the standard install path:
1. sync the full repository into the current installed skill workspace
2. create and activate `.venv`
3. run `pip install -e .`
4. download or populate the SenseVoice model directory
5. download or populate the VAD model directory
6. copy `.env.example` to `.env`
7. fill the required values in `.env`
8. use the default openWakeWord route
9. run direct-run validation with both the voice service and overlay process
10. ask whether the user wants background resident behavior and auto-start
11. if yes, run `./scripts/deploy_macos.sh`
12. if no, stop after direct-run validation
Before running any system-changing step in that path, explicitly tell the user
what you are about to do and get confirmation for:
- fetching and checking out the repository into the skill workspace
- running `pip install -e .` from the repository
- downloading large local models or wakeword assets
- enabling background resident behavior or launchd auto-start
Minimum command path:
```bash
# from the current conversation agent's installed skill directory
git init
git remote add origin https://github.com/CarrotYuan/openclaw-voice-control.git
git fetch --depth 1 origin main
git checkout -B main FETCH_HEAD
# do not continue until the workspace contains scripts/, src/, config/,
# launchagents/, and README.md
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
./.venv/bin/modelscope download --model iic/SenseVoiceSmall --local_dir models/SenseVoiceSmall
./.venv/bin/python - <<'PY'
from funasr import AutoModel
AutoModel(model='fsmn-vad', disable_update=True)
PY
cp .env.example .env
# terminal 1, from the current installed skill workspace
python -m openclaw_voice_control --config config/default.yaml --env-file .env
# terminal 2, from the same workspace
python -m openclaw_voice_control.overlay_app --config config/default.yaml --env-file .env
```
Direct-run validation is not complete unless both commands above are running at
the same time from the same installed skill workspace.
Before any next step after direct-run validation, stop that test
first.
This includes:
- background resident deployment
- auto-start validation
- starting another direct-run test
If an old direct-run service and overlay are left running, two active voice
runtimes can respond to the same wakeword and produce duplicate replies.
## What Must Exist Before Setup
Before setup begins, make sure these prerequisites exist or can be provided:
- Python 3.11 or newer
- a running local OpenClaw service
- `OPENCLAW_TOKEN`
- macOS microphone permission
- a way to download the local SenseVoice and VAD model directories
For the default route, the remaining setup can usually be handled by the AI or
operator:
- copy `.env.example` to `.env`
- download the SenseVoice model directory
- download or populate the VAD model directory
- let openWakeWord download the selected pretrained wakeword model on first run
## Recommended Defaults
The default public route is:
- `WAKEWORD_PROVIDER=openwakeword`
- `OPENWAKEWORD_MODEL_NAME=hey jarvis`
- `OPENCLAW_AGENT_ID=main`
- `OPENCLAW_MODEL=openclaw:main`
- `OPENCLAW_USER=openclaw-voice-control`
Prefer that route unless the user explicitly asks for something else.
## Default Route Variables
These are the main values for the default route:
- required in `.env`
- `OPENCLAW_BASE_URL`
- `OPENCLAW_TOKEN`
- `SENSEVOICE_MODEL_PATH`
- `SENSEVOICE_VAD_MODEL_PATH`
- usually left at their documented defaults unless the user wants customization
- `WAKEWORD_PROVIDER=openwakeword`
- `OPENWAKEWORD_MODEL_NAME=hey jarvis`
- `OPENCLAW_AGENT_ID=main`
- `OPENCLAW_MODEL=openclaw:main`
- `OPENCLAW_USER=openclaw-voice-control`
If the user changes the macOS TTS voice, first make sure that voice has been
downloaded in:
- System Settings
- Accessibility
- Spoken Content
- the `i` button next to System Voice
- Language
- Voice
## Optional Porcupine Route
Picovoice / Porcupine is an optional fallback route, not the default path.
Only switch to it when the user explicitly wants to use a local `.ppn` wakeword
model.
If that route is chosen, set:
- `WAKEWORD_PROVIDER=porcupine`
- `PICOVOICE_ACCESS_KEY`
- `WAKEWORD_FILE`
Only ask for those Porcupine-specific values when the user explicitly chooses
that route.
## Switching openWakeWord Models
To switch the default openWakeWord wakeword, change:
- `OPENWAKEWORD_MODEL_NAME`
Common official pretrained examples include:
- `hey jarvis`
- `hey mycroft`
- `hey rhasspy`
- `alexa`
Those pretrained wakeword models are downloaded automatically on first use.
The code path already supports changing `OPENWAKEWORD_MODEL_NAME`, but only the
default `hey jarvis` route has been smoke-tested in this repository so far.
## Execution Rules
When using this skill, follow these rules:
1. Use the declared GitHub repository first.
- Start from `https://github.com/CarrotYuan/openclaw-voice-control.git`
- Do not substitute another repository just because it looks similar.
2. Keep deployment work in the current installed skill workspace.
- Do not silently switch to another local clone.
- If GitHub access fails and a local clone exists, ask before using it.
3. Do not silently reuse an old environment.
- Do not assume an existing `.venv`, local model cache, previous `.env`, or private runtime should be reused.
- If reusing cached assets might save time, explain that and ask first.
4. Do not invent missing values.
- When writing `.env`, use the exact variable names required by the project, especially `OPENCLAW_TOKEN`.
- If required values or local assets are missing, stop and point to the documented source of truth.
5. Handle secrets conservatively.
- Do not print real tokens or keys back into the conversation unless the user explicitly asks to see them.
- For this project, use the OpenClaw token from `~/.openclaw/openclaw.json`, specifically the `gateway` configuration.
- Do not use `~/.openclaw/identity/device-auth.json` as the token source for this project.
6. Ask before any system-changing action.
- Do not assume you should fetch the repository, run `pip install -e .`, download models, or enable launchd behavior without user approval.
- Explain the action first, then continue only after the user confirms.
7. Ask before enabling background resident behavior.
- Foreground validation comes first.
- Direct-run validation means starting both `python -m openclaw_voice_control --config config/default.yaml --env-file .env` and `python -m openclaw_voice_control.overlay_app --config config/default.yaml --env-file .env` from the same installed skill workspace.
- Only run `./scripts/deploy_macos.sh` when the user explicitly wants background resident behavior or auto-start.
## Daily Maintenance
Primary scripts:
- deploy background runtime: `./scripts/deploy_macos.sh`
- restart installed background services: `./scripts/restart_service.sh`
- uninstall installed background services: `./scripts/uninstall_macos.sh`
- inspect local installation and environment issues: `./scripts/doctor.sh`
Double-click `.command` wrappers are also available in `scripts/` for macOS users who prefer Finder-based execution.
## Shutdown Intents
Treat shutdown requests as one of these two user intents:
- temporarily disable voice functionality
- stop the running direct-run process, or stop the deployed background runtime
- do not delete the skill folder
- delete the skill completely
- remove the skill folder itself
- only do this when the user explicitly asks for full removal
If the user says something ambiguous like "turn it off" or "stop voice", ask one short clarification question before acting.
## Background Architecture
The canonical background startup path is:
- `launchd -> host app -> shell script -> python`
`./scripts/deploy_macos.sh` builds the required host apps automatically.
## Configuration Surface
Default-route required values:
- `OPENCLAW_BASE_URL`
- `OPENCLAW_TOKEN`
- `SENSEVOICE_MODEL_PATH`
- `SENSEVOICE_VAD_MODEL_PATH`
Default-route configurable values:
- `OPENCLAW_AGENT_ID`
- `OPENCLAW_MODEL`
- `OPENCLAW_USER`
- `WAKEWORD_PROVIDER`
- `OPENWAKEWORD_MODEL_NAME`
- `OPENWAKEWORD_MODEL_PATH`
If the user explicitly switches to the optional Porcupine route, also configure:
- `PICOVOICE_ACCESS_KEY`
- `WAKEWORD_FILE`
Interpreter override variables still exist:
- `VOICE_CONTROL_PYTHON_BIN`
- `VOICE_CONTROL_OVERLAY_PYTHON_BIN`
They are troubleshooting knobs only, not the main deployment model.
`OPENWAKEWORD_THRESHOLD` still exists as a tuning variable, but it is a
troubleshooting adjustment rather than a first-run requirement.
As a rule, machine-specific secrets and paths belong in `.env`, while wakeword
timing and threshold tuning should normally be adjusted in `config/default.yaml`.
## Where To Get Missing Requirements
After syncing the repository into the current installed skill workspace, read these sections in `README.md`:
- `What Must Exist Before Setup`
- `Required Variables`
- `Where To Get Each Requirement`
Practical source notes:
- `OPENCLAW_BASE_URL`: use the full OpenClaw chat completions endpoint, not only the host and port root. For the default local setup, use `http://127.0.0.1:18789/v1/chat/completions`
- `OPENCLAW_TOKEN`: obtain it from the local OpenClaw gateway configuration in `~/.openclaw/openclaw.json`, under `gateway`
- default wakeword route: use openWakeWord with the built-in English `hey jarvis` model
- optional Porcupine route: obtain `PICOVOICE_ACCESS_KEY` and the local `.ppn` file from [Picovoice](https://picovoice.ai/)
- if GitHub clone fails, report that first rather than switching to an unrelated local directory
## Related Files
- `README.md` in the cloned repository
- `README.zh-CN.md` in the cloned repository
- `docs/macos-install.md` in the cloned repository
don't have the plugin yet? install it then click "run inline in claude" again.
set up local macOS voice control for OpenClaw agents using wakeword activation, local ASR (FunASR / SenseVoice), TTS playback, and optional background runtime with launchd auto-start. use this skill when deploying voice input to a running local OpenClaw service, troubleshooting voice entrypoints, or managing background voice daemons. this is a local deployment skill, not a prompt-only helper.
OpenClaw service
OPENCLAW_BASE_URL (e.g., http://127.0.0.1:18789/v1/chat/completions)OPENCLAW_TOKEN (obtain from ~/.openclaw/openclaw.json under gateway key, not from ~/.openclaw/identity/device-auth.json)SENSEVOICE_MODEL_PATH env var. download via modelscope or provide local pathSENSEVOICE_VAD_MODEL_PATH env var. auto-cached by FunASR on first runrequired in .env
OPENCLAW_BASE_URLOPENCLAW_TOKENSENSEVOICE_MODEL_PATHSENSEVOICE_VAD_MODEL_PATHdefault-route optional in .env
WAKEWORD_PROVIDER (default: openwakeword)OPENWAKEWORD_MODEL_NAME (default: hey jarvis)OPENCLAW_AGENT_ID (default: main)OPENCLAW_MODEL (default: openclaw:main)OPENCLAW_USER (default: openclaw-voice-control)OPENWAKEWORD_THRESHOLD (tuning only, optional)VOICE_CONTROL_PYTHON_BIN (interpreter override, troubleshooting only)VOICE_CONTROL_OVERLAY_PYTHON_BIN (interpreter override, troubleshooting only)porcupine-route optional (only if user explicitly chooses porcupine)
PICOVOICE_ACCESS_KEYWAKEWORD_FILE (local .ppn file path)https://github.com/CarrotYuan/openclaw-voice-control.giti button next to System Voice > Language > Voiceask for confirmation to fetch the repository into the current installed skill workspace. explain that this will run git init, git remote add, and git fetch --depth 1.
input: user confirmation
output: proceed to step 2 or stop
sync the repository from https://github.com/CarrotYuan/openclaw-voice-control.git into the current workspace using:
git init
git remote add origin https://github.com/CarrotYuan/openclaw-voice-control.git
git fetch --depth 1 origin main
git checkout -B main FETCH_HEAD
input: network access, git credentials if needed
output: workspace now contains scripts/, src/, config/, launchagents/, and README.md
edge case: if git fails, stop and report the error; do not substitute an unrelated local directory
verify repository structure. confirm the workspace contains:
scripts/src/config/launchagents/README.mdinput: filesystem check
output: if any file is missing, fail and tell user to re-sync; if all present, proceed
create and activate virtual environment. ask for confirmation before running pip install -e ..
input: user confirmation
output: proceed to step 5 or stop
set up python venv:
python3 -m venv .venv
source .venv/bin/activate
input: python3 available, disk space for venv
output: .venv/ directory created, shell prompt shows (.venv) indicator
edge case: if python3 is missing or not python 3.11+, stop and tell user to upgrade
install the project in editable mode:
pip install -e .
input: active venv, network access for pip
output: openclaw-voice-control and dependencies installed
edge case: if install fails due to missing system headers or binary dependencies, report error and suggest brew install for common missing deps
download SenseVoice ASR model. ask for confirmation before downloading (large download, may take minutes). explain what will be downloaded and where.
input: user confirmation, network access, ~10GB disk space
output: proceed to step 8 or stop
download SenseVoice model:
./.venv/bin/modelscope download --model iic/SenseVoiceSmall --local_dir models/SenseVoiceSmall
input: modelscope CLI, network access
output: models/SenseVoiceSmall/ directory populated
edge case: if download stalls or times out, user can resume by running the same command again; if disk is full, stop and free space
download VAD model. explain this will cache the FunASR VAD model locally.
input: user confirmation, network access, ~500MB disk space
output: proceed to step 10 or stop
download VAD model:
./.venv/bin/python - <<'PY'
from funasr import AutoModel
AutoModel(model='fsmn-vad', disable_update=True)
PY
input: active venv, network access
output: VAD model cached in FunASR cache directory
edge case: if network is offline, this will fail; inform user to retry when online
create .env file from template:
cp .env.example .env
input: .env.example must exist in repository
output: .env file created in workspace root
populate required .env values. guide user through filling:
OPENCLAW_BASE_URL: get from running OpenClaw service (e.g., http://127.0.0.1:18789/v1/chat/completions)OPENCLAW_TOKEN: get from ~/.openclaw/openclaw.json under gateway keySENSEVOICE_MODEL_PATH: set to models/SenseVoiceSmall (relative path from workspace)SENSEVOICE_VAD_MODEL_PATH: set to a valid VAD model path (FunASR will auto-cache if not specified, or user can provide explicit path)input: user provides real values
output: .env contains all 4 required values
edge case: if OPENCLAW_TOKEN is missing or wrong, test will fail at runtime; if SENSEVOICE_MODEL_PATH does not exist, ASR will fail
explain direct-run validation. tell user this tests voice control in foreground before enabling background mode. two processes must run simultaneously in separate terminals.
input: user acknowledgment
output: proceed to step 14 or stop
start voice service in terminal 1:
python -m openclaw_voice_control --config config/default.yaml --env-file .env
input: active venv, .env populated, OpenClaw service running
output: voice service starts listening for wakeword, logs to stdout
edge case: if OpenClaw is unreachable, service will error; if SENSEVOICE_MODEL_PATH is wrong, ASR will fail to load
start overlay UI in terminal 2 (same workspace, same time as step 14):
python -m openclaw_voice_control.overlay_app --config config/default.yaml --env-file .env
input: active venv, same .env and config/, both terminals in the same workspace
output: overlay UI appears on screen, logs to stdout
edge case: if both processes try to bind to the same port, second will fail; if microphone permission is denied by macOS, ASR will not record
test voice interaction. user speaks the wakeword (default: "hey jarvis") and gives a command. verify:
input: microphone, audio output, wakeword utterance
output: voice interaction completes, reply is heard and displayed
stop direct-run services before proceeding. kill both terminal processes (ctrl-c).
input: user kills both processes or you kill them
output: both services stopped, no orphaned processes
edge case: if user does not stop these before starting background mode, duplicate voice runtimes will respond to same wakeword
ask whether user wants background resident behavior and auto-start. explain:
input: user chooses "yes" or "no"
output: proceed to step 19 (yes) or step 20 (no)
deploy background runtime. ask for confirmation before running ./scripts/deploy_macos.sh (this modifies launchd and creates host apps).
input: user confirmation
output: proceed to step 20a or stop
20a. run deployment script:
bash ./scripts/deploy_macos.sh
input: workspace contains `scripts/deploy_macos.sh`, sudo may be needed
output: launchd plist files installed, host shell apps created, background service now auto-starts
edge case: if sudo is required but user does not have admin, deployment will fail; if launchd is broken, service will not start
21a. validate background service is running:
bash ./scripts/doctor.sh
input: workspace contains `scripts/doctor.sh`
output: diagnostic output shows whether launchd service is active, voice process is running, env vars are correct
edge case: if service failed to start, `doctor.sh` will indicate which env var or file is missing
22a. test voice control in background mode. user speaks wakeword without any terminal running. verify interaction works.
input: wakeword utterance
output: voice control responds without manual process start
23a. explain daily maintenance. provide user with these scripts:
- ./scripts/restart_service.sh to restart the background service
- ./scripts/uninstall_macos.sh to remove background service and auto-start
- ./scripts/doctor.sh to diagnose issues
input: none (informational)
output: user knows how to manage background service
20b. end setup. voice control is ready to use in foreground mode only.
input: none
output: user can start voice service and overlay UI manually whenever needed (repeat steps 14-16)
if direct-run services are already running from a previous attempt:
ask user whether to kill old processes first. if yes, kill them. if no, stop and tell user to stop old processes manually before retrying.
if OpenClaw service is unreachable:
voice control will fail at runtime when trying to forward recognized text. stop and ask user to verify OpenClaw service is running and OPENCLAW_BASE_URL is correct.
if OPENCLAW_TOKEN is missing or invalid:
authentication will fail at first interaction. stop and ask user to retrieve the correct token from ~/.openclaw/openclaw.json (gateway key, not identity key).
if SenseVoice model path does not exist:
ASR will fail to load. stop and ask user to either download the model (step 8) or provide the correct path to an existing model directory.
if user wants to switch from openWakeWord (default) to Porcupine wakeword:
only ask for PICOVOICE_ACCESS_KEY and WAKEWORD_FILE if user explicitly requests this. do not offer Porcupine as a default option. set WAKEWORD_PROVIDER=porcupine only when user chooses it.
if user wants to change the wakeword phrase (staying with openWakeWord):
only change OPENWAKEWORD_MODEL_NAME in .env. do not download extra models unless user explicitly asks. common examples: hey jarvis (default), hey mycroft, hey rhasspy, alexa. warn that only hey jarvis has been smoke-tested.
if user says "turn it off" or "stop voice" (ambiguous intent):
ask one short clarification: "do you want to temporarily stop voice (and restart later), or completely remove it?" if temporarily stop, kill the direct-run process or run ./scripts/uninstall_macos.sh then ask if they want to reinstall. if completely remove, delete the skill folder.
if user wants to use a custom TTS voice on macOS:
that voice must be pre-downloaded in System Settings > Accessibility > Spoken Content > the i button > Language > Voice. if not, voice will default to system voice or fail. ask user to download the desired voice first, then test in direct-run mode.
if a direct-run test completed successfully but background service fails to start:
run ./scripts/doctor.sh to diagnose. common causes: launchd plist syntax error (check launchagents/), missing env var in .env or in the plist, python path mismatch (check VOICE_CONTROL_PYTHON_BIN if needed).
if network connection is offline during model download:
model download will fail and stall. inform user that step 8 or 10 failed and ask them to retry when online.
successful setup produces the following artifacts in the installed skill workspace:
.venv/ directory with active python environmentmodels/SenseVoiceSmall/ directory containing ASR model weights.env file in workspace root containing all 4 required values and any optional overridesconfig/default.yaml unchanged from repository (user configures via .env)~/Library/LaunchAgents/ if background mode was enabled (step 19)~/.openclaw_voice/ if background mode was enableddirect-run processes (steps 14-15):
background service (step 20a):
./scripts/doctor.sh reports healthy status./scripts/restart_service.sh can restart service without manual launchd management./scripts/uninstall_macos.sh can fully remove service and host appssuccessful setup is confirmed when all of the following are true:
.env file exists with all 4 required values populated (test by reading back, do not print secrets)./scripts/doctor.sh reports service healthy and voice works without manual terminal process startuser will say something like: "okay, voice is working" or "i can talk to it and it understands" or "the reply came back" to confirm outcome signal.
if any artifact is missing, test fails, or service does not auto-start, offer troubleshooting: run ./scripts/doctor.sh, check .env for missing values, verify OpenClaw service is re