Cross-checked 75 docs pages under user-guide/messaging/, developer-guide/,
guides/, and integrations/ against the live registries and gateway code.
messaging/
- index.md: API Server toolset is hermes-api-server (was 'hermes (default)');
Google Chat slug is hermes-google_chat (underscore — plugin name uses _).
- google_chat.md: drop bogus 'pip install hermes-agent[google_chat]' (no such
extra); list the actual deps (google-cloud-pubsub, google-api-python-client,
google-auth, google-auth-oauthlib).
- qqbot.md: config namespace is platforms.qqbot (was platforms.qq, which is
silently ignored by the adapter); QQ_STT_BASE_URL is not read directly —
baseUrl lives under platforms.qqbot.extra.stt.
- teams-meetings.md: 'hermes teams-pipeline' is plugin-gated (teams_pipeline
plugin must be enabled), not a built-in subcommand.
- sms.md: example log line 0.0.0.0:8080 -> 127.0.0.1:8080 (default
SMS_WEBHOOK_HOST).
- open-webui.md: API_SERVER_* are env vars, not YAML keys — write them to
per-profile .env, not 'hermes config set' (same pattern fixed in
api-server.md last round). Also bumped example ports to 8650+ to dodge the
default webhook (8644)/wecom-callback (8645)/msgraph-webhook (8646)
collision.
developer-guide/
- architecture.md: tool/toolset counts (61/52 -> 70+/~28); LOC stamps for
run_agent.py, cli.py, hermes_cli/main.py, setup.py, mcp_tool.py,
gateway/run.py replaced with 'large file' to stop drifting.
- agent-loop.md: same LOC drift (~13,700 -> 'a large file (15k+ lines)').
- gateway-internals.md: '14+ external messaging platforms' -> '20+'; gateway
platform tree updated (qqbot is a sub-package, not qqbot.py; added
yuanbao.py, feishu_comment.py, msgraph_webhook.py); 'gateway/builtin_hooks/
(always active)' was wrong — it's an empty extension point and
_register_builtin_hooks() is a no-op stub.
- acp-internals.md: drop fictional 'message_callback' from the bridged-
callbacks list; clarify thinking_callback is currently set to None.
- provider-runtime.md: provider list was missing AWS Bedrock, Azure Foundry,
NVIDIA NIM, xAI, Arcee, GMI Cloud, StepFun, Qwen OAuth, Xiaomi, Ollama
Cloud, LM Studio, Tencent TokenHub. Fallback section described only the
legacy single-pair model — corrected to the canonical list-form
fallback_providers chain.
- environments.md: parsers list missing llama4_json and the deepseek_v31
alias; both register via @register_parser.
- browser-supervisor.md: drop reference to scripts/browser_supervisor_e2e.py
which doesn't exist in-repo.
- contributing.md: tinker-atropos is a git submodule — note that
'git submodule update --init' is required if cloning without
--recurse-submodules.
guides/
- operate-teams-meeting-pipeline.md: cron flags were all wrong — schedule is
positional (not --schedule), the script-only flag is --no-agent (not
--script-only), and there's no --command flag. Replaced with a real example
that creates the script under ~/.hermes/scripts/ and uses the actual flags.
Also replaced fictional 'hermes cron show <name>' with 'hermes cron status'.
- automation-templates.md: 'cron create --skills "a,b"' doesn't work —
the flag is --skill (singular, repeatable). Fixed all 5 occurrences via AST
rewrite.
- minimax-oauth.md: 'hermes auth add minimax-oauth --region cn' silently
fails because --region isn't registered on the auth-add argparse spec.
Pointed users at the minimax-cn provider (or MINIMAX_CN_API_KEY env) for
China-region access.
- cron-script-only.md: 'hermes send' is fictional — replaced the comparison-
table mention with a webhook-subscription pointer; also fixed the dead link
to /guides/pipe-script-output (page doesn't exist).
- cron-troubleshooting.md: 'hermes serve' isn't a real subcommand. Pointed
at 'hermes gateway' (foreground) / 'hermes gateway start' (service).
- local-ollama-setup.md: 'agent.api_timeout' is not a config key. The right
knob is the HERMES_API_TIMEOUT env var.
- python-library.md: run_conversation() return dict has only final_response
and messages — task_id is stored on the agent instance, not echoed back.
- use-mcp-with-hermes.md: '--args /c "npx -y …"' wraps the npx command in
one quoted string, so cmd.exe gets a single arg instead of the multi-token
command line it needs. Removed the surrounding quotes — argparse nargs='*'
collects each token correctly.
integrations/
- providers.md: Bedrock guardrail YAML keys were 'id'/'version' (don't exist);
actual keys are guardrail_identifier/guardrail_version (matches DEFAULT_CONFIG
and the run_agent.py reader). GMI default base URL (api.gmi.ai/v1 ->
api.gmi-serving.com/v1) and portal URL (inference.gmi.ai -> www.gmicloud.ai)
refreshed. Fallback section rewritten to lead with the canonical
fallback_providers list form (was leading with the legacy fallback_model
single dict); supported-providers list extended to include azure-foundry,
alibaba-coding-plan, lmstudio.
index.md
- '68 built-in tools' -> '70+'; '15+ platforms' was both inconsistent with
integrations/index.md ('19+') and undercounted — bumped to 20+ and added
Weixin/QQ Bot/Yuanbao/Google Chat to the list.
Validation: 'npm run build' clean (exit 0); broken-link count unchanged at
155 (same as round-1 post-skill-regen baseline). 24 files, +132/-89.
6.4 KiB
| sidebar_position | sidebar_label | title | description |
|---|---|---|---|
| 8 | SMS (Twilio) | SMS (Twilio) | Set up Hermes Agent as an SMS chatbot via Twilio |
SMS Setup (Twilio)
Hermes connects to SMS through the Twilio API. People text your Twilio phone number and get AI responses back — same conversational experience as Telegram or Discord, but over standard text messages.
:::info Shared Credentials
The SMS gateway shares credentials with the optional telephony skill. If you've already set up Twilio for voice calls or one-off SMS, the gateway works with the same TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, and TWILIO_PHONE_NUMBER.
:::
Prerequisites
- Twilio account — Sign up at twilio.com (free trial available)
- A Twilio phone number with SMS capability
- A publicly accessible server — Twilio sends webhooks to your server when SMS arrives
- aiohttp —
pip install 'hermes-agent[sms]'
Step 1: Get Your Twilio Credentials
- Go to the Twilio Console
- Copy your Account SID and Auth Token from the dashboard
- Go to Phone Numbers → Manage → Active Numbers — note your phone number in E.164 format (e.g.,
+15551234567)
Step 2: Configure Hermes
Interactive setup (recommended)
hermes gateway setup
Select SMS (Twilio) from the platform list. The wizard will prompt for your credentials.
Manual setup
Add to ~/.hermes/.env:
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=your_auth_token_here
TWILIO_PHONE_NUMBER=+15551234567
# Security: restrict to specific phone numbers (recommended)
SMS_ALLOWED_USERS=+15559876543,+15551112222
# Optional: set a home channel for cron job delivery
SMS_HOME_CHANNEL=+15559876543
Step 3: Configure Twilio Webhook
Twilio needs to know where to send incoming messages. In the Twilio Console:
- Go to Phone Numbers → Manage → Active Numbers
- Click your phone number
- Under Messaging → A MESSAGE COMES IN, set:
- Webhook:
https://your-server:8080/webhooks/twilio - HTTP Method:
POST
- Webhook:
:::tip Exposing Your Webhook If you're running Hermes locally, use a tunnel to expose the webhook:
# Using cloudflared
cloudflared tunnel --url http://localhost:8080
# Using ngrok
ngrok http 8080
Set the resulting public URL as your Twilio webhook. :::
Set SMS_WEBHOOK_URL to the same URL you configured in Twilio. This is required for Twilio signature validation — the adapter will refuse to start without it:
# Must match the webhook URL in your Twilio Console
SMS_WEBHOOK_URL=https://your-server:8080/webhooks/twilio
The webhook port defaults to 8080. Override with:
SMS_WEBHOOK_PORT=3000
Step 4: Start the Gateway
hermes gateway
You should see:
[sms] Twilio webhook server listening on 127.0.0.1:8080, from: +1555***4567
If you see Refusing to start: SMS_WEBHOOK_URL is required, set SMS_WEBHOOK_URL to the public URL configured in your Twilio Console (see Step 3).
Text your Twilio number — Hermes will respond via SMS.
Environment Variables
| Variable | Required | Description |
|---|---|---|
TWILIO_ACCOUNT_SID |
Yes | Twilio Account SID (starts with AC) |
TWILIO_AUTH_TOKEN |
Yes | Twilio Auth Token (also used for webhook signature validation) |
TWILIO_PHONE_NUMBER |
Yes | Your Twilio phone number (E.164 format) |
SMS_WEBHOOK_URL |
Yes | Public URL for Twilio signature validation — must match the webhook URL in your Twilio Console |
SMS_WEBHOOK_PORT |
No | Webhook listener port (default: 8080) |
SMS_WEBHOOK_HOST |
No | Webhook bind address (default: 0.0.0.0) |
SMS_INSECURE_NO_SIGNATURE |
No | Set to true to disable signature validation (local dev only — not for production) |
SMS_ALLOWED_USERS |
No | Comma-separated E.164 phone numbers allowed to chat |
SMS_ALLOW_ALL_USERS |
No | Set to true to allow anyone (not recommended) |
SMS_HOME_CHANNEL |
No | Phone number for cron job / notification delivery |
SMS_HOME_CHANNEL_NAME |
No | Display name for the home channel (default: Home) |
SMS-Specific Behavior
- Plain text only — Markdown is automatically stripped since SMS renders it as literal characters
- 1600 character limit — Longer responses are split across multiple messages at natural boundaries (newlines, then spaces)
- Echo prevention — Messages from your own Twilio number are ignored to prevent loops
- Phone number redaction — Phone numbers are redacted in logs for privacy
Security
Webhook signature validation
Hermes validates that inbound webhooks genuinely originate from Twilio by verifying the X-Twilio-Signature header (HMAC-SHA1). This prevents attackers from injecting forged messages.
SMS_WEBHOOK_URL is required. Set it to the public URL configured in your Twilio Console. The adapter will refuse to start without it.
For local development without a public URL, you can disable validation:
# Local dev only — NOT for production
SMS_INSECURE_NO_SIGNATURE=true
User allowlists
The gateway denies all users by default. Configure an allowlist:
# Recommended: restrict to specific phone numbers
SMS_ALLOWED_USERS=+15559876543,+15551112222
# Or allow all (NOT recommended for bots with terminal access)
SMS_ALLOW_ALL_USERS=true
:::warning SMS has no built-in encryption. Don't use SMS for sensitive operations unless you understand the security implications. For sensitive use cases, prefer Signal or Telegram. :::
Troubleshooting
Messages not arriving
- Check your Twilio webhook URL is correct and publicly accessible
- Verify
TWILIO_ACCOUNT_SIDandTWILIO_AUTH_TOKENare correct - Check the Twilio Console → Monitor → Logs → Messaging for delivery errors
- Ensure your phone number is in
SMS_ALLOWED_USERS(orSMS_ALLOW_ALL_USERS=true)
Replies not sending
- Check
TWILIO_PHONE_NUMBERis set correctly (E.164 format with+) - Verify your Twilio account has SMS-capable numbers
- Check Hermes gateway logs for Twilio API errors
Webhook port conflicts
If port 8080 is already in use, change it:
SMS_WEBHOOK_PORT=3001
Update the webhook URL in Twilio Console to match.