{"id":44616325,"url":"https://github.com/dnacenta/morpheus-line","last_synced_at":"2026-02-14T13:05:47.750Z","repository":{"id":338091803,"uuid":"1156545640","full_name":"dnacenta/morpheus-line","owner":"dnacenta","description":"Voice interface for Claude Code over the phone via Twilio","archived":false,"fork":false,"pushed_at":"2026-02-12T19:35:16.000Z","size":48,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"development","last_synced_at":"2026-02-13T03:20:47.553Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dnacenta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-12T19:15:16.000Z","updated_at":"2026-02-12T19:35:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dnacenta/morpheus-line","commit_stats":null,"previous_names":["dnacenta/morpheus-line"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/dnacenta/morpheus-line","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnacenta%2Fmorpheus-line","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnacenta%2Fmorpheus-line/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnacenta%2Fmorpheus-line/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnacenta%2Fmorpheus-line/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dnacenta","download_url":"https://codeload.github.com/dnacenta/morpheus-line/tar.gz/refs/heads/development","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnacenta%2Fmorpheus-line/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29444108,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T12:43:28.304Z","status":"ssl_error","status_checked_at":"2026-02-14T12:43:14.160Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-14T13:05:47.304Z","updated_at":"2026-02-14T13:05:47.738Z","avatar_url":"https://github.com/dnacenta.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# morpheus-line\n\n[![CI](https://github.com/dnacenta/morpheus-line/actions/workflows/ci.yml/badge.svg?branch=development)](https://github.com/dnacenta/morpheus-line/actions/workflows/ci.yml)\n[![License: GPL-3.0](https://img.shields.io/github/license/dnacenta/morpheus-line)](LICENSE)\n[![Version](https://img.shields.io/github/v/tag/dnacenta/morpheus-line?label=version\u0026color=green)](https://github.com/dnacenta/morpheus-line/tags)\n[![Rust](https://img.shields.io/badge/rust-1.75%2B-orange)](https://rustup.rs/)\n\nVoice interface for Claude Code over the phone. Call in and talk to Claude, or trigger outbound calls from n8n / automation workflows.\n\nBuilt in Rust. Uses Twilio for telephony, Groq Whisper for speech-to-text, ElevenLabs for text-to-speech, and the Claude Code CLI for reasoning.\n\n## Architecture\n\n```\n                         ┌─────────────────────────────────────┐\n                         │          morpheus-line (axum)        │\n                         │                                     │\n  Phone ◄──► Twilio ◄──►│  WebSocket ◄──► VAD ──► STT (Groq)  │\n                         │                         │           │\n                         │                    Claude CLI        │\n                         │                         │           │\n                         │                    TTS (ElevenLabs)  │\n                         │                         │           │\n                         │                    mu-law encode     │\n                         └─────────────────────────────────────┘\n                                        ▲\n                                        │ POST /api/call\n                                   n8n / curl\n```\n\n## How It Works\n\n### Inbound calls\n\n1. Someone calls your Twilio number\n2. Twilio POSTs to `/twilio/voice` -- responds with TwiML that opens a media stream\n3. Twilio connects a WebSocket to `/twilio/media`\n4. Audio arrives as base64 mu-law chunks\n5. VAD (voice activity detection) buffers audio until it detects silence after speech\n6. Complete utterance is converted: mu-law -\u003e PCM -\u003e WAV -\u003e Groq Whisper (STT)\n7. Transcript is sent to `claude -p` (Claude Code CLI)\n8. Response goes through ElevenLabs TTS -\u003e PCM -\u003e mu-law -\u003e back through the WebSocket\n9. Caller hears Claude's response\n\n### Outbound calls\n\n1. POST to `/api/call` with a phone number and optional initial message\n2. morpheus-line calls Twilio REST API to initiate the call\n3. When the recipient picks up, Twilio hits `/twilio/voice/outbound`\n4. Same media stream pipeline kicks in -- full duplex conversation with Claude\n\n## Prerequisites\n\n- [Rust](https://rustup.rs/) (1.75+)\n- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated\n- [Twilio](https://www.twilio.com/) account with a phone number\n- [Groq](https://console.groq.com/) API key (free tier works)\n- [ElevenLabs](https://elevenlabs.io/) API key (free tier: ~10k chars/month)\n- A server with a public HTTPS URL (for Twilio webhooks)\n- nginx (recommended, for TLS termination and WebSocket proxying)\n\n## Installation\n\n### 1. Clone and build\n\n```bash\ngit clone https://github.com/dnacenta/morpheus-line.git\ncd morpheus-line\ncargo build --release\n```\n\nThe binary will be at `target/release/morpheus-line`.\n\n### 2. Configure\n\nCopy the example files to `~/.morpheus-line/`:\n\n```bash\nmkdir -p ~/.morpheus-line\ncp config.example.toml ~/.morpheus-line/config.toml\ncp .env.example ~/.morpheus-line/.env\n```\n\nEdit `~/.morpheus-line/.env` with your API keys:\n\n```bash\nTWILIO_ACCOUNT_SID=AC...\nTWILIO_AUTH_TOKEN=your_token\nGROQ_API_KEY=gsk_...\nELEVENLABS_API_KEY=your_key\nMORPHEUS_API_TOKEN=$(openssl rand -hex 32)\nSERVER_EXTERNAL_URL=https://your-server.example.com\n```\n\nEdit `~/.morpheus-line/config.toml` -- set your Twilio phone number and adjust defaults as needed. Secrets are loaded from `.env`, so leave them empty in the TOML.\n\nYou can override the config directory with `MORPHEUS_LINE_CONFIG=/path/to/config.toml`.\n\n### 3. nginx\n\nCopy `deploy/nginx.conf` and replace `your-server.example.com` with your domain:\n\n```bash\nsudo cp deploy/nginx.conf /etc/nginx/sites-available/morpheus-line\nsudo ln -s /etc/nginx/sites-available/morpheus-line /etc/nginx/sites-enabled/\n# Edit server_name and SSL cert paths\nsudo nginx -t \u0026\u0026 sudo systemctl reload nginx\n```\n\nTLS is required -- Twilio only sends webhooks over HTTPS. Use certbot or similar.\n\n### 4. systemd\n\n```bash\nsudo cp target/release/morpheus-line /usr/local/bin/\nsudo cp deploy/morpheus-line.service /etc/systemd/system/\nsudo systemctl daemon-reload\nsudo systemctl enable --now morpheus-line\n```\n\n### 5. Twilio webhook\n\nIn the [Twilio Console](https://console.twilio.com/), set your phone number's voice webhook to:\n\n```\nPOST https://your-server.example.com/twilio/voice\n```\n\n## Configuration Reference\n\n### config.toml\n\n| Section       | Field                  | Default                   | Description                                      |\n|---------------|------------------------|---------------------------|--------------------------------------------------|\n| `server`      | `host`                 | --                        | Bind address (e.g. `0.0.0.0`)                    |\n| `server`      | `port`                 | --                        | Bind port (e.g. `8443`)                          |\n| `server`      | `external_url`         | --                        | Public HTTPS URL (overridden by `SERVER_EXTERNAL_URL` env var) |\n| `twilio`      | `account_sid`          | --                        | Twilio Account SID (overridden by env var)       |\n| `twilio`      | `auth_token`           | --                        | Twilio Auth Token (overridden by env var)        |\n| `twilio`      | `phone_number`         | --                        | Your Twilio phone number (E.164)                 |\n| `groq`        | `api_key`              | --                        | Groq API key (overridden by env var)             |\n| `groq`        | `model`                | `whisper-large-v3-turbo`  | Whisper model to use                             |\n| `elevenlabs`  | `api_key`              | --                        | ElevenLabs API key (overridden by env var)       |\n| `elevenlabs`  | `voice_id`             | `JAgnJveGGUh4qy4kh6dF`   | ElevenLabs voice ID                              |\n| `claude`      | `session_timeout_secs` | `300`                     | Conversation session timeout                     |\n| `api`         | `token`                | --                        | Bearer token for `/api/*` (overridden by env var)|\n| `vad`         | `silence_threshold_ms` | `1500`                    | Silence duration before utterance ends           |\n| `vad`         | `energy_threshold`     | `50`                      | Minimum RMS energy to detect speech              |\n\n### Environment variables\n\nAll secrets can be set via env vars (recommended) instead of config.toml:\n\n| Variable               | Overrides                  |\n|------------------------|----------------------------|\n| `TWILIO_ACCOUNT_SID`   | `twilio.account_sid`       |\n| `TWILIO_AUTH_TOKEN`    | `twilio.auth_token`        |\n| `GROQ_API_KEY`         | `groq.api_key`             |\n| `ELEVENLABS_API_KEY`   | `elevenlabs.api_key`       |\n| `MORPHEUS_API_TOKEN`   | `api.token`                |\n| `SERVER_EXTERNAL_URL`  | `server.external_url`      |\n| `MORPHEUS_LINE_CONFIG` | Config file path            |\n| `RUST_LOG`             | Log level filter            |\n\n## Usage\n\n### Call in\n\nJust call your Twilio number. You'll hear \"Connected to Claude. Go ahead and speak.\" then talk normally.\n\n### Trigger an outbound call\n\n```bash\ncurl -X POST https://your-server.example.com/api/call \\\n  -H \"Authorization: Bearer YOUR_API_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"to\": \"+34612345678\", \"message\": \"Server CPU at 95 percent\"}'\n```\n\nThe recipient picks up, hears the initial message (if provided), then can talk to Claude.\n\n### n8n integration\n\nUse an HTTP Request node in n8n to POST to `/api/call`. Set the bearer token in the header. Useful for alerting workflows -- Claude can explain what's happening when the call connects.\n\n## Costs\n\n| Service      | Free tier                     | Paid                             |\n|--------------|-------------------------------|----------------------------------|\n| Twilio       | Trial credit (~$15)           | ~$1.15/mo number + per-minute    |\n| Groq         | Free (rate-limited)           | Usage-based                      |\n| ElevenLabs   | ~10k chars/month              | From $5/month                    |\n| Claude Code  | Included with Max plan        | Or API usage                     |\n\nFor personal use with a few calls a day, the running cost is minimal beyond the Twilio number.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for branch naming, commit conventions, and workflow.\n\n## License\n\n[GPL-3.0](LICENSE)\n\n## Acknowledgments\n\n*Inspired by [NetworkChuck's claude-phone](https://github.com/networkchuck/claude-phone). Rewritten from scratch in Rust with a different architecture -- no intermediate Node.js server, direct WebSocket pipeline, energy-based VAD, and an outbound call API for automation.*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdnacenta%2Fmorpheus-line","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdnacenta%2Fmorpheus-line","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdnacenta%2Fmorpheus-line/lists"}