Listening & Wake Word
The Intern listens continuously by default: whenever the voice-activity detector (VAD) hears speech, it opens a turn, streams it to STT, and closes the turn after a short silence. Everything on this page tunes that loop.
Most knobs here are HAL environment variables in /opt/hal/.env. They're read
once at start:
sudo nano /opt/hal/.env
sudo systemctl restart hal
sudo journalctl -u hal -f # watch the effect
A device-profile OTA update replaces /opt/hal/.env with the shipped copy.
Keep your changes in a file and re-apply them after updates, or disable the
bootstrap service while you tune.
Wake word
Off by default — the Intern responds to any speech it hears. Turn it on to make it wait for a wake phrase.
Web UI: http://<device-ip>/setting#general → General → Require an
attention trigger before handling speech. The panel also lists the current
wake phrases.
API:
curl -s -X PUT $DEVICE/api/device/config \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"wakeword":true}'
Saving restarts HAL.
Wake phrases are generated from the agent's name, not typed in: hello,
hey, hi, alo, okay, ok, wake up + the agent name (e.g. "hey Nova"). The same
prefixes + "autonomous" and + the device type always work too. To change the
phrases, rename the agent: edit the - **Name:** … line in
/root/.openclaw/workspace/IDENTITY.md (or rename the device from the
Autonomous app). os-server re-reads the file every 5 seconds and pushes the new
phrases to HAL — no restart needed.
After a wake phrase, follow-up questions don't need the phrase again for a while:
| HAL env | Default | Effect |
|---|---|---|
HAL_WAKEWORD_FOLLOWUP_TIMEOUT_S | 20 | Seconds after a reply during which you can keep talking without the phrase. 0 = phrase required every time. |
A single press of the button also wakes it (see Button).
Sensitivity and turn-taking
| HAL env | Code default | Intern v2 ships | What it does |
|---|---|---|---|
HAL_VAD_THRESHOLD | 3500 | 500 | RMS energy that counts as "someone is speaking". Lower = more sensitive. |
HAL_SPEECH_HOLDOFF | 0.2 | 0.05 | Seconds speech must last before a turn opens (filters clicks and bumps). |
HAL_PRE_ROLL_FRAMES | 8 | — | 64 ms frames kept from before the trigger, so the first syllable isn't clipped. |
HAL_SILENCE_TIMEOUT | 2.5 | 1.2 | Seconds of silence that end a turn when STT hasn't produced a final transcript (fallback clock). |
HAL_ENDPOINT_SILENCE_S | 0.8 | — | Seconds of silence that end a turn once STT has a final transcript. Raise it if the Intern cuts you off mid-sentence; 0 disables. |
HAL_MAX_SESSION_DURATION_S | 30 | — | Hard cap on one listening session. |
HAL_SESSION_COOLDOWN_S | 0.3 | — | Pause before a new session can open. |
HAL_STT_KEEPALIVE | false | true | Keep the STT connection warm — lower latency, more idle STT usage. |
Noise filters
| HAL env | Default | Intern v2 ships | What it does |
|---|---|---|---|
HAL_WEBRTCVAD_ENABLED | false | true | Fast speech/non-speech pre-filter |
HAL_WEBRTCVAD_AGGRESSIVENESS | 2 | — | 0–3; higher rejects more noise. 0 lets room noise open sessions. |
HAL_SILERO_ENABLED | false | false | Neural VAD that rejects TV, music and background chatter |
HAL_SILERO_THRESHOLD | 0.3 | — | Silero speech probability needed (presets use 0.15–0.18) |
HAL_SILENCE_VAD_ENABLED | true | — | Silero also confirms silence at end of turn — without it, a noisy room can keep a turn open forever |
Echo handling (so it doesn't hear itself)
| HAL env | Default | What it does |
|---|---|---|
HAL_AEC_ENABLED | true | WebRTC acoustic echo cancellation |
HAL_AEC_DELAY_MS | 205 | Speaker→mic delay the AEC assumes |
HAL_AEC_NS | true | Noise suppression in the AEC |
HAL_ECHO_RMS_FLOOR | 200 | Minimum level that counts as speech right after TTS |
HAL_ECHO_GATE_MAX_WAIT_S | 1.5 | Max wait for the speaker tail to clear |
HAL_ECHO_SIMILARITY_THRESHOLD | 0.55 | Transcripts this similar to what it just said are dropped as echo |
HAL_WARM_MIC | true | Keep the mic open between turns for faster pick-up |
Recipes
Noisy room / it wakes up on the TV:
HAL_VAD_THRESHOLD=650
HAL_SILERO_ENABLED=true
HAL_SILERO_THRESHOLD=0.18
HAL_WEBRTCVAD_ENABLED=true
HAL_WEBRTCVAD_AGGRESSIVENESS=2
HAL_SILENCE_VAD_ENABLED=true
HAL_STT_KEEPALIVE=false
…and consider turning on the wake word.
It cuts me off while I'm thinking:
HAL_ENDPOINT_SILENCE_S=1.5
HAL_SILENCE_TIMEOUT=2.5
It doesn't hear me from across the room: lower HAL_VAD_THRESHOLD
(e.g. 400) and HAL_SPEECH_HOLDOFF; keep Silero on to stay filtered.
Ready-made presets
The repo ships three tested presets in
hal/env-presets/.
Copy the HAL_* lines into /opt/hal/.env (keep your audio device and key
lines) and restart HAL. Try them in order:
| Preset | Use it when |
|---|---|
01-balanced-cost-safe.env | First choice. VAD 650, Silero 0.18, WebRTC VAD 2, STT keep-alive off, echo floor 300, realtime cost guards on. |
02-sensitive-filtered.env | 01 misses quiet speech. VAD 500, holdoff 0.05, silence 3.0 s, Silero 0.15. |
03-max-sensitive-debug.env | Short debugging only — Silero and WebRTC VAD off, keep-alive on. Picks up everything, including noise. |
Button
The top button is a physical control for the voice loop:
| Gesture | Action |
|---|---|
| Single press | Stop speech and music, cancel the current reply, unmute the mic and start listening (also works as the wake trigger) |
| Triple press | Reboot |
| Hold 2 s | Sleep |
| Hold 5 s | Shut down |
| Hold 10 s | Factory reset |
There is no voice barge-in in the default turn-based mode — press the button
(or POST /tts/stop) to interrupt. Experimental voice interruption is
available in Realtime Voice → Live mode.
Mic mute
The slide switch on top mutes the mic: HAL stops feeding audio to VAD/STT. To mute from code, see HAL API → Mic.
Audio devices and volume
| HAL env | Intern v2 ships | What it does |
|---|---|---|
HAL_AUDIO_INPUT_ALSA | plug:device_micro2 | Mic ALSA device |
HAL_AUDIO_OUTPUT_ALSA | plug:device_speaker | Speaker ALSA device |
HAL_AUDIO_SENSING_DEVICE | — | Optional separate mic for ambient sound sensing |
List devices with arecord -l / aplay -l over SSH.
Volume persists across reboots — the last value you set wins; a fresh device starts at 100 %. To read or set it from code, see HAL API → Speaker.