WhatsApp¶
Families message the assistant from their phones over WhatsApp. We use Twilio WhatsApp Business with a single shared sender number for everyone — the trick is routing an inbound message to the right family's agent.
How a shared number serves many families¶
The mapping from a phone number to a family account is the public.family_members table.
sudo-api verifies Twilio's signature, looks up the sender, and forwards the verified
payload over the docker network to that account's hermes plugin.
First-class platform, not a prompt hack¶
The twilio_whatsapp adapter is a real hermes platform (bind-mounted plugin at
cloud/hermes/plugins/twilio_whatsapp/). That means:
- The agent can proactively message a member:
send_message(target="twilio_whatsapp", chat_id="whatsapp:+E164", …). - It can schedule messages:
cronjob(deliver="twilio_whatsapp", …). - Platform metadata (the sender's name from
MemberName, reply-to viaOriginalRepliedMessageSid) arrives as structured fields on theMessageEvent, not as text shoved into the prompt.
The one path that skips the agent¶
Manual admin sends from the /integrations UI go straight to Twilio:
POST /v1/me/whatsapp/send → Twilio REST. That's the only WhatsApp path that doesn't run
through the agent.
Not the old Baileys/QR pairing
Earlier versions used a Baileys-based, QR-paired whatsapp platform. That's gone
— upstream's Baileys platform is left disabled; Twilio Business is the path. A dead
Baileys pairing once crash-killed the whole gateway (see Runbooks).
Where to look¶
| Concern | File / table |
|---|---|
| Inbound webhook + routing | cloud/api/main.py (/v1/twilio/whatsapp/inbound) |
| The plugin adapter | cloud/hermes/plugins/twilio_whatsapp/ |
| Phone → account mapping | public.family_members |
| Twilio credentials | global_settings.twilio (admin-set) — see Secrets |
| Original engineering notes | docs/whatsapp-twilio.md |