- macOS: local Voice Wake enable/disable toggle. Requires macOS 26+; see Voice wake (macOS) for runtime/PTT details.
- iOS: local Voice Wake enable/disable toggle in Settings.
- Android: local Voice Wake enable/disable toggle and wake-word editor in Settings → Voice. Requires Android on-device speech recognition.
Storage
Wake words and routing rules live in the Gateway state database,~/.openclaw/state/openclaw.sqlite by default (override with OPENCLAW_STATE_DIR), tables voicewake_triggers, voicewake_routing_config, voicewake_routing_routes. Legacy settings/voicewake.json and settings/voicewake-routing.json are openclaw doctor --fix migration inputs only — runtime never reads them.
Protocol
Trigger list
voicewake.set normalizes input: trims whitespace, drops empty entries, keeps at most 32 triggers, and truncates each to 64 UTF-16 code units without splitting surrogate pairs. An empty result falls back to the built-in defaults (openclaw, claude, computer).
Routing (trigger to target)
target supports exactly one of:
{ "mode": "current" }{ "agentId": "main" }{ "sessionKey": "agent:main:main" }
"Hey, Bot!!" and "hey bot" match and count as duplicates) — this is a stricter normalization than the plain trim used for the global trigger list above.
Events
Both broadcast to every WebSocket client with read scope (macOS app, WebChat, and similar) and to every connected node. A node also gets both as an initial snapshot push right after it connects.
Client behavior
- macOS: calls
voicewake.set/voicewake.getand listens forvoicewake.changedto stay in sync with other clients. - iOS: calls
voicewake.set/voicewake.getand listens forvoicewake.changedto keep local wake-word detection responsive. - Android: calls
voicewake.set/voicewake.get, listens forvoicewake.changed, and advertisesvoiceWakewhile enabled. Recognition stays on-device and foreground-only; it pauses while Talk, manual dictation, voice-note capture, or message speech owns audio.