Claude-code-minoan sms
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.
git clone https://github.com/tdimino/claude-code-minoan
T=$(mktemp -d) && git clone --depth=1 https://github.com/tdimino/claude-code-minoan "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/integration-automation/sms" ~/.claude/skills/tdimino-claude-code-minoan-sms && rm -rf "$T"
skills/integration-automation/sms/SKILL.mdSMS 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:
env var, or falls back toTELNYX_API_KEY
(already configured)~/.claude.json - Twilio:
+TWILIO_ACCOUNT_SID
env vars, or falls back to hardcoded defaultsTWILIO_AUTH_TOKEN
Quick Start
# Send a text python3 ~/.claude/skills/sms/scripts/sms_send.py "+19175551234" "Hello from Claude" # Read recent messages python3 ~/.claude/skills/sms/scripts/sms_read.py -n 10 # View conversation with someone python3 ~/.claude/skills/sms/scripts/sms_conversation.py "+19175551234" # List all available numbers python3 ~/.claude/skills/sms/scripts/sms_numbers.py # Start real-time listener (background) python3 ~/.claude/skills/sms/scripts/sms_listen.py --bg # Check inbound messages 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 |
|---|---|
| Send from a specific number (auto-detects provider) |
| Force a specific provider |
| Attach media for MMS |
Examples:
# Send via Telnyx (default) python3 ~/.claude/skills/sms/scripts/sms_send.py "+19175551234" "Meeting at 3pm" # Send from a Twilio number python3 ~/.claude/skills/sms/scripts/sms_send.py "+19175551234" "Hello" --from "+18508058037" # Send MMS with image 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 |
|---|---|
| Messages to a specific number |
| Messages from a specific sender |
| Filter by direction |
| Number of messages (default: 10) |
| Query specific provider |
| Query both providers |
Examples:
# Read last 10 messages (Twilio recommended for reads) python3 ~/.claude/skills/sms/scripts/sms_read.py -n 10 --provider twilio # Messages to a specific number python3 ~/.claude/skills/sms/scripts/sms_read.py --to "+18508058037" --provider twilio # Only inbound messages python3 ~/.claude/skills/sms/scripts/sms_read.py --direction inbound --provider twilio # Query both providers 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 |
|---|---|
| Max messages per direction (default: 20) |
| Filter to a specific one of our numbers |
| Query specific provider |
| Query both providers |
Examples:
# View conversation with a number python3 ~/.claude/skills/sms/scripts/sms_conversation.py "+19175551234" --provider twilio # Limit to last 10 messages per direction python3 ~/.claude/skills/sms/scripts/sms_conversation.py "+19175551234" -n 10 --provider twilio # Filter to a specific one of our numbers 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 |
|---|---|
| Filter by provider |
| Query APIs for live status (slower) |
Examples:
# List all 8 numbers python3 ~/.claude/skills/sms/scripts/sms_numbers.py # Twilio numbers only python3 ~/.claude/skills/sms/scripts/sms_numbers.py --provider twilio # Live API status check 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 |
|---|---|
| Run in background (daemonize) |
| Stop running listener |
| Check if listener is running |
| Twilio poll interval in seconds (default: 10) |
| Twilio numbers to monitor (default: all 6) |
| Telnyx webhook port (default: 9147) |
| Disable Telnyx webhook server |
| Disable Twilio polling |
Examples:
# Start listener in background python3 ~/.claude/skills/sms/scripts/sms_listen.py --bg # Check status python3 ~/.claude/skills/sms/scripts/sms_listen.py --status # Stop listener python3 ~/.claude/skills/sms/scripts/sms_listen.py --stop # Monitor only the Aldea production number, poll every 5s python3 ~/.claude/skills/sms/scripts/sms_listen.py --bg --numbers +18557066006 --interval 5 # Telnyx webhook only (no Twilio polling) 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)
/sms-respondProcess 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)
sms_respond.pyStandalone 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 |
|---|---|
| Loop continuously, polling inbox |
| Run daemon in background (requires ) |
| Check if responder daemon is running |
| Stop running responder daemon |
| Poll interval in seconds (default: 5) |
| Override LLM model (default: claude-sonnet-4-5-20250514) |
| Disable soul context (plain responses) |
| Process messages without sending replies |
Examples:
# Start auto-reply daemon in background (Mac Mini) python3 ~/.claude/skills/sms/scripts/sms_respond.py --daemon --bg # Check daemon status python3 ~/.claude/skills/sms/scripts/sms_respond.py --status # Stop daemon 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 |
|---|---|
| Poll interval in seconds (default: 5) |
| 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:
# Start watcher (run as background task in Claude Code) python3 ~/.claude/skills/sms/scripts/sms_watch.py # Enriched mode — pre-loads memory context for faster processing python3 ~/.claude/skills/sms/scripts/sms_watch.py --enrich # Faster polling 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 |
|---|---|
| Sender's E.164 number (required) |
| Our number they texted (required) |
| Inbox message ID (required) |
| Original inbound message text (required) |
| External dialogue text to send (required) |
| Internal monologue text (required) |
| Monologue verb (default: thought) |
| Dialogue verb (default: said) |
| Whether user model was updated (default: false) |
| Updated user model markdown (if check was true) |
| JSON dict of soul state updates |
| Read all args from stdin as JSON (avoids shell quoting) |
| Skip sending SMS, do memory operations only |
Examples:
# Basic reply with memory update 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 # With soul state update 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 |
|---|---|
| Show all messages (including handled) |
| Number of messages to show |
| Filter by sender number |
| Filter by provider |
| Mark a specific message as handled |
| Mark all messages as handled |
Examples:
# Show unhandled messages python3 ~/.claude/skills/sms/scripts/sms_inbox.py # Show last 5 messages from a specific sender python3 ~/.claude/skills/sms/scripts/sms_inbox.py --from "+17327595647" -n 5 # Mark all as read 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 | |
| Default Twilio from | (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
endpoint — message receiving is webhook-based only. Sent messages are tracked via the local log. For full read/conversation capability, useGET /v2/messages
or--provider twilio
.--all-providers
Phone Number Reference
Telnyx
| Number | Type | Label | Reserved |
|---|---|---|---|
| Longcode | Primary (default) | Aldea / Dr. Shefali |
| Toll-free | Secondary | Aldea (dev/backup) |
Twilio (9 numbers — verified live 2026-03-03)
| Number | Type | Label | Reserved |
|---|---|---|---|
| Local | Claudius 320 | Claudius (broken—needs 10DLC registration) |
| Toll-free | Claudius 855 | Claudius (2-way) |
| Toll-free | 855 number | Available |
| Local | 877 number | Available |
| Local | 866 number | Available |
| Local | 877-837 number | Available |
| Local | 866-565 number | Available |
| Local | 866-705 number | Available |
| Local | 844 number | Available |