← index2026-05-12 12:53 (Beirut)HeyBrian unsolicited-speech fix — DND, auto-meeting silence, wake-word pause, robot-voice removed

HeyBrian unsolicited-speech fix (2026-05-12)

HeyBrian unsolicited-speech fix — shipped 2026-05-12

What you reported

"many many times during the day, the orb speaks out without me addressing it. it happened today while i was on a meeting. also, the voice sounded like the male robot again."

Root causes (diagnosed)

Three independent paths to unprompted speech in HeyBrian. I traced each one:

# Path Trigger Where
1 Proactive /notify Hetzner POSTs to http://100.79.172.24:9100/notify {"message":"...", "speak":true} → HB shows orb + speaks HTTPServer.swift:210AppDelegate.onNotify (L598) → self.speak(message) (L608)
2 Wake-word false positive during meeting Mic picks up other speakers (Zoom/Teams audio bleed) → wakeword_daemon fires above 0.65 threshold → SFSpeechRecognizer transcribes the OTHER speaker → routed to Brian API → Brian replies + speaks wakeword_daemon.py (threshold 0.65, cooldown 4s) → AppDelegate.wakeWordDetected() (L161) → _actuallyStartListening()commandRouter.route(text:fromVoice:true)speak(response.spoken)
3 Male-robot TTS fallback Puck (Gemini Live) request fails / times out → TTSManager.speakLocal() falls through to NSSpeechSynthesizer (the macOS robot voice) TTSManager.swift:104"remote Puck failed, falling back to local AVSpeech"

What shipped, server-side (live NOW, no Mac rebuild needed)

1. Do Not Disturb (DND) — kill-switch for path #1

New endpoints on the agent-api:
- GET /api/mac/heybrian/dnd — read current state + inbox count
- POST /api/mac/heybrian/dnd {"enabled": true|false, "reason": "..."} — toggle
- GET /api/mac/heybrian/dnd/inbox?limit=50 — read suppressed notifications
- POST /api/mac/heybrian/dnd/inbox/clear — wipe inbox

Modified POST /api/mac/heybrian/notify — when DND on, request is logged to inbox + 200 returned but NEVER forwarded to Mac. The orb stays silent.

2. Auto-DND during meetings

When /api/meetings/active/ returns count > 0 (a real recording session is live), DND auto-engages even with manual toggle off. Meeting ends → auto-DND clears. You never have to remember to flip it.

3. Wake-word pause/resume verb on the panel

G02 (Wake-word daemon) now has pause and resume verbs. Pause kills the wakeword_daemon Python process on your Mac — HB stays running but won't react to anything resembling "Hey Brian" until you resume. This completely eliminates path #2 during meetings, no false positives possible. Resume → opens HB which respawns the daemon within 2 seconds.

4. DND tile in the Mac App group

New function DND in the mac_app group with verbs enable / disable / inbox / clear-inbox. Click into Mac App tile → focused sheet → DND row → toggle. Inbox verb opens the inline log viewer showing every suppressed notification with timestamp, source, priority, and the 🔊 flag if it would have spoken.

The panel also auto-engages DND visually when a meeting is recording — status pill turns amber with "AUTO (meeting) · N suppressed".

What's queued for the next HB rebuild

Patches written to source — will take effect on next revive of HeyBrian.app:

wakeword_daemon.py

TTSManager.swift — robot-voice fix (path #3)

Removed the AVSpeech fallback by default. When Puck fails, HB now stays silent instead of falling through to the male-robot voice. The text still surfaces in HB's log (and we can route it to the panel conversation log too).

Legacy behavior preserved via BRIAN_ALLOW_ROBOT_FALLBACK=1 env var if you ever want the robot back temporarily.

How to use right now

Before a meeting:
- Open mac.jonahtebaa.com → Mac App tile → DND row → click enable
- Optionally: Wake-word row → click pause

When the meeting ends:
- DND row → click disable
- Wake-word row → click resume

Or do nothing. If you start a meeting via the Meetings tile (click Meetings → start), auto-DND engages and clears itself. The wake-word pause still requires a manual click because killing the daemon during a meeting auto-started elsewhere (Cmd-M from menubar) isn't a server-known event.

To pick up the Mac-side patches

When you're ready to rebuild HeyBrian.app with the threshold + TTS fixes:
- Click Mac App tile → HeyBrian.app row → restart (hard restart) — this rebuilds + relaunches HB picking up the new wakeword threshold + the silence-over-robot TTS behavior

Or wait — the changes are in the source tree, the next planned HB rebuild will pick them up automatically.

Verified end-to-end (server-side fixes)

Test Result
POST /heybrian/dnd {enabled:true} state.enabled=true, set_by=J0n@h ✓
POST /heybrian/notify while DND on All 3 return suppressed_by_dnd:true reason:manual
Inbox via panel verb All 3 entries logged with ts, source, message, 🔊 flag ✓
POST /heybrian/dnd {enabled:false} effective_enabled=false ✓
Auto-meeting DND When /api/meetings/active/ count>0 → effective_enabled=true ✓
Wake-word G02 verbs pause, resume, logs, configure ✓
Panel groups total 46 functions (was 45) across 6 tiles ✓