| name | sms |
| description | Send, read, listen, respond, and manage SMS conversations via Telnyx and Twilio. Supports 8 phone numbers across both providers with auto-detection, conversation threading, MMS, real-time inbound listening, background watcher, batch reply processor, and soul-aware auto-reply. 10 Python scripts for SMS operations. |
SMS Skill
Send SMS/MMS, read inboxes, auto-reply as Claudius, and view conversation threads via Telnyx (2 numbers) and Twilio (6 numbers).
When to Use This Skill
- Sending a text message to any phone number
- Reading recent SMS messages (inbox)
- Listening for real-time inbound messages (two-way SMS)
- Auto-replying to inbound SMS as Claudius (soul-aware responses)
- Viewing a conversation thread with a specific number
- Listing available phone numbers across providers
- Sending MMS with image attachments
Prerequisites
Requires requests (uv pip install --system requests).
Credentials are loaded automatically:
- Telnyx:
TELNYX_API_KEY env var, or falls back to ~/.claude.json (already configured)
- Twilio:
TWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN env vars, or falls back to hardcoded defaults
Quick Start
python3 ~/.claude/skills/sms/scripts/sms_send.py "+19175551234" "Hello from Claude"
python3 ~/.claude/skills/sms/scripts/sms_read.py -n 10
python3 ~/.claude/skills/sms/scripts/sms_conversation.py "+19175551234"
python3 ~/.claude/skills/sms/scripts/sms_numbers.py
python3 ~/.claude/skills/sms/scripts/sms_listen.py --bg
python3 ~/.claude/skills/sms/scripts/sms_inbox.py
Available Scripts
1. sms_send.py — Send SMS/MMS
python3 ~/.claude/skills/sms/scripts/sms_send.py TO "MESSAGE" [OPTIONS]
| Flag | Description |
|---|
--from NUMBER | Send from a specific number (auto-detects provider) |
--provider telnyx|twilio | Force a specific provider |
--media URL | Attach media for MMS |
Examples:
python3 ~/.claude/skills/sms/scripts/sms_send.py "+19175551234" "Meeting at 3pm"
python3 ~/.claude/skills/sms/scripts/sms_send.py "+19175551234" "Hello" --from "+18508058037"
python3 ~/.claude/skills/sms/scripts/sms_send.py "+19175551234" "Check this" --media "https://example.com/photo.jpg"
2. sms_read.py — Read Inbox
python3 ~/.claude/skills/sms/scripts/sms_read.py [OPTIONS]
| Flag | Description |
|---|
--to NUMBER | Messages to a specific number |
--from-number NUMBER | Messages from a specific sender |
--direction inbound|outbound | Filter by direction |
-n/--limit NUM | Number of messages (default: 10) |
--provider telnyx|twilio | Query specific provider |
--all-providers | Query both providers |
Examples:
python3 ~/.claude/skills/sms/scripts/sms_read.py -n 10 --provider twilio
python3 ~/.claude/skills/sms/scripts/sms_read.py --to "+18508058037" --provider twilio
python3 ~/.claude/skills/sms/scripts/sms_read.py --direction inbound --provider twilio
python3 ~/.claude/skills/sms/scripts/sms_read.py --all-providers -n 20
3. sms_conversation.py — View Conversation Thread
python3 ~/.claude/skills/sms/scripts/sms_conversation.py NUMBER [OPTIONS]
| Flag | Description |
|---|
-n/--limit NUM | Max messages per direction (default: 20) |
--our-number NUMBER | Filter to a specific one of our numbers |
--provider telnyx|twilio | Query specific provider |
--all-providers | Query both providers |
Examples:
python3 ~/.claude/skills/sms/scripts/sms_conversation.py "+19175551234" --provider twilio
python3 ~/.claude/skills/sms/scripts/sms_conversation.py "+19175551234" -n 10 --provider twilio
python3 ~/.claude/skills/sms/scripts/sms_conversation.py "+19175551234" --our-number "+18508058037"
4. sms_numbers.py — List Available Numbers
python3 ~/.claude/skills/sms/scripts/sms_numbers.py [OPTIONS]
| Flag | Description |
|---|
--provider telnyx|twilio | Filter by provider |
--live | Query APIs for live status (slower) |
Examples:
python3 ~/.claude/skills/sms/scripts/sms_numbers.py
python3 ~/.claude/skills/sms/scripts/sms_numbers.py --provider twilio
python3 ~/.claude/skills/sms/scripts/sms_numbers.py --live
5. sms_listen.py — Real-Time Inbound Listener
Background daemon that polls Twilio for new inbound messages and runs a webhook server for Telnyx inbound. Messages are written to data/inbox.jsonl.
python3 ~/.claude/skills/sms/scripts/sms_listen.py [OPTIONS]
| Flag | Description |
|---|
--bg | Run in background (daemonize) |
--stop | Stop running listener |
--status | Check if listener is running |
--interval N | Twilio poll interval in seconds (default: 10) |
--numbers +1... +1... | Twilio numbers to monitor (default: all 6) |
--webhook-port N | Telnyx webhook port (default: 9147) |
--no-telnyx | Disable Telnyx webhook server |
--no-twilio | Disable Twilio polling |
Examples:
python3 ~/.claude/skills/sms/scripts/sms_listen.py --bg
python3 ~/.claude/skills/sms/scripts/sms_listen.py --status
python3 ~/.claude/skills/sms/scripts/sms_listen.py --stop
python3 ~/.claude/skills/sms/scripts/sms_listen.py --bg --numbers +18557066006 --interval 5
python3 ~/.claude/skills/sms/scripts/sms_listen.py --bg --no-twilio
Telnyx webhook setup: Point your Telnyx Messaging Profile webhook URL to http://localhost:9147/telnyx. For remote access, use ngrok or similar tunnel.
6. Auto-Reply — Two Modes
Mode A: /sms-respond Slash Command (Interactive)
Process unhandled SMS using the current Claude Code session as the LLM. No subprocess needed—follows the same pattern as /slack-respond.
/sms-respond # Process all unhandled messages
/sms-respond 2 # Process only message #2 from inbox
The slash command loads inbox, soul.md, and memory context dynamically, then walks through a 6-step cognitive pipeline (internal monologue → external dialogue → user model check → user model update → soul state check → soul state update). Replies are sent via sms_send.py and all memory layers are updated.
The command also starts a background watcher (sms_watch.py) after processing, which polls for new inbound messages every 5 seconds and notifies the session when one arrives—creating a continuous two-way SMS loop.
Use this when: You're in an active Claude Code session and want to reply to SMS.
Mode B: sms_respond.py Daemon (Standalone)
Standalone daemon for Mac Mini or headless deployment. Uses claude -p subprocess to generate responses. Does not work from within a running Claude Code session (subprocess nesting conflict).
python3 ~/.claude/skills/sms/scripts/sms_respond.py [OPTIONS]
| Flag | Description |
|---|
--daemon | Loop continuously, polling inbox |
--bg | Run daemon in background (requires --daemon) |
--status | Check if responder daemon is running |
--stop | Stop running responder daemon |
--interval N | Poll interval in seconds (default: 5) |
--model MODEL | Override LLM model (default: claude-sonnet-4-5-20250514) |
--no-soul | Disable soul context (plain responses) |
--dry-run | Process messages without sending replies |
Examples:
python3 ~/.claude/skills/sms/scripts/sms_respond.py --daemon --bg
python3 ~/.claude/skills/sms/scripts/sms_respond.py --status
python3 ~/.claude/skills/sms/scripts/sms_respond.py --stop
Use this when: Running headless on Mac Mini or outside Claude Code.
Shared Infrastructure
Both modes require sms_listen.py running to feed inbox.jsonl.
Memory: 3-tier SQLite at data/sms_memory.db:
- Working memory — per-conversation message history + cognitive outputs
- User models — per-phone-number personality profiles
- Soul memory — cross-conversation soul state
7. sms_watch.py — Background Watcher for Claude Code
Polls inbox.jsonl for new unhandled messages. Designed as a run_in_background bash task—exits when a new message is detected, printing a structured line for Claude Code to parse.
python3 ~/.claude/skills/sms/scripts/sms_watch.py [OPTIONS]
| Flag | Description |
|---|
--interval N | Poll interval in seconds (default: 5) |
--enrich | On detect, also print sender's memory context (user model, soul state, recent conversation) |
Output on detect: {"event": "NEW_SMS", "id": "...", "from": "...", "to": "...", "body": "..."}
Output on detect with --enrich: Same JSON line, followed by ---MEMORY_CONTEXT--- and the sender's user model, soul state, and recent conversation history.
Output on timeout/kill: NO_NEW_SMS
Examples:
python3 ~/.claude/skills/sms/scripts/sms_watch.py
python3 ~/.claude/skills/sms/scripts/sms_watch.py --enrich
python3 ~/.claude/skills/sms/scripts/sms_watch.py --interval 3
8. sms_process_reply.py — Batch Reply Processor
Sends SMS reply and performs all 9 memory operations in a single call. Replaces the 9 separate python3 -c invocations from the /sms-respond pipeline.
python3 ~/.claude/skills/sms/scripts/sms_process_reply.py [OPTIONS]
| Flag | Description |
|---|
--phone NUMBER | Sender's E.164 number (required) |
--our-number NUMBER | Our number they texted (required) |
--message-id ID | Inbox message ID (required) |
--message-text TEXT | Original inbound message text (required) |
--reply-text TEXT | External dialogue text to send (required) |
--monologue-text TEXT | Internal monologue text (required) |
--monologue-verb VERB | Monologue verb (default: thought) |
--dialogue-verb VERB | Dialogue verb (default: said) |
--user-model-check BOOL | Whether user model was updated (default: false) |
--user-model-md MD | Updated user model markdown (if check was true) |
--soul-updates JSON | JSON dict of soul state updates |
--stdin-json | Read all args from stdin as JSON (avoids shell quoting) |
--dry-run | Skip sending SMS, do memory operations only |
Examples:
python3 ~/.claude/skills/sms/scripts/sms_process_reply.py \
--phone "+17327595647" \
--our-number "+18557066006" \
--message-id "SM0334c637c6017dbf84eae2a7fd824abd" \
--message-text "Hello there" \
--reply-text "Hello! Good to hear from you." \
--monologue-text "A friendly greeting." \
--monologue-verb "noticed" \
--dialogue-verb "replied" \
--user-model-check false
python3 ~/.claude/skills/sms/scripts/sms_process_reply.py \
--phone "+17327595647" \
--our-number "+18557066006" \
--message-id "SM..." \
--message-text "text" \
--reply-text "reply" \
--monologue-text "monologue" \
--dialogue-verb "said" \
--user-model-check true \
--user-model-md "# Updated model" \
--soul-updates '{"currentTopic": "testing", "emotionalState": "engaged"}'
9. sms_inbox.py — Read Inbound Inbox
Read messages collected by sms_listen.py.
python3 ~/.claude/skills/sms/scripts/sms_inbox.py [OPTIONS]
| Flag | Description |
|---|
--all | Show all messages (including handled) |
-n/--limit NUM | Number of messages to show |
--from NUMBER | Filter by sender number |
--provider telnyx|twilio | Filter by provider |
--mark-read ID | Mark a specific message as handled |
--mark-all-read | Mark all messages as handled |
Examples:
python3 ~/.claude/skills/sms/scripts/sms_inbox.py
python3 ~/.claude/skills/sms/scripts/sms_inbox.py --from "+17327595647" -n 5
python3 ~/.claude/skills/sms/scripts/sms_inbox.py --mark-all-read
Configuration
Provider Auto-Detection
When you use --from, the skill detects the provider by matching against known numbers:
- Telnyx numbers:
+18628026208, +18334843851
- Twilio numbers:
+13205950420, +18557066006, +18559149834, +18776882519, +18665517616, +18778377603, +18665650327, +18667056747, +18445491928
Defaults
| Setting | Value |
|---|
| Default provider | Telnyx |
| Default Telnyx from | +18628026208 |
| Default Twilio from | +18557066006 (Claudius 855) |
Edit _sms_utils.py to change defaults.
Local Message Log
All sent messages are automatically logged to ~/.claude/skills/sms/data/messages.jsonl (JSONL format). This enables:
- Telnyx conversation history: Since Telnyx is send-only (no REST API for reading messages), the local log provides the only record of Telnyx messages.
- Offline message browsing: Read/conversation scripts automatically fall back to the local log when Telnyx API returns 404.
- Per-number history: Filter by any phone number to see all correspondences.
The log grows with each sent message. To reset, delete data/messages.jsonl.
Known Limitations
- Telnyx is send-only: Telnyx has no
GET /v2/messages endpoint — message receiving is webhook-based only. Sent messages are tracked via the local log. For full read/conversation capability, use --provider twilio or --all-providers.
Phone Number Reference
Telnyx
| Number | Type | Label | Reserved |
|---|
+18628026208 | Longcode | Primary (default) | Aldea / Dr. Shefali |
+18334843851 | Toll-free | Secondary | Aldea (dev/backup) |
Twilio (9 numbers — verified live 2026-03-03)
| Number | Type | Label | Reserved |
|---|
+13205950420 | Local | Claudius 320 | Claudius (broken—needs 10DLC registration) |
+18557066006 | Toll-free | Claudius 855 | Claudius (2-way) |
+18559149834 | Toll-free | 855 number | Available |
+18776882519 | Local | 877 number | Available |
+18665517616 | Local | 866 number | Available |
+18778377603 | Local | 877-837 number | Available |
+18665650327 | Local | 866-565 number | Available |
+18667056747 | Local | 866-705 number | Available |
+18445491928 | Local | 844 number | Available |