Democracy Dies in Silence
See a demo of it in action here.
The first thing you need to know is that in the 90's, there was a board game called Dream Phone. This is a real thing that exists.
With that whimsy in mind, American Dream Phone is a Pipecat AI Voice Agent to help you call your political representatives. Some may call it 'revenge of the robo-calls', I call it civic engagement.
cp env.example .envAdd API keys as needed. See services.
# Backend
uv sync
# Frontend
cd frontend && npm installYou need two terminals:
# Terminal 1 — API server
uv run python server.py# Terminal 2 — Frontend dev server
cd frontend && npm run devOpen http://localhost:5173 in your browser. The frontend proxies API requests to the backend at localhost:7860.
If you don't need the frontend, you can still run the bot directly:
uv run python bot.py -t dailycurl -X POST http://localhost:7860/start \
-H "Content-Type: application/json" \
-d '{"createDailyRoom": true, "body": {"testInPrebuilt": true}}'The response includes a dailyRoom URL. Open it in your browser to talk to and test the bot.
curl -X POST http://localhost:7860/start \
-H "Content-Type: application/json" \
-d '{"createDailyRoom": true, "dailyRoomProperties": {"enable_dialout": true}, "body": {"dialout_settings": [{"phoneNumber": "+15551234567"}]}}'This actually calls the phone number. (Debug pro tip — open the dailyRoom URL and listen in on the conversation.)
cd frontend && npm run buildThis outputs static files to frontend/dist/. Serve them however you like (nginx, Cloudflare Pages, etc.) and point API requests (/start, /preview, /upload-voice, /clone-voice, /representatives) at the backend.
uv run python server.py --host 0.0.0.0 --port 7860All API keys go in .env. See env.example for the full list. Required:
| Variable | Service |
|---|---|
DAILY_API_KEY |
Daily (transport + dialout) |
ANTHROPIC_API_KEY |
Claude (LLM) |
DEEPGRAM_API_KEY |
Deepgram (STT) |
CARTESIA_API_KEY |
Cartesia (TTS + voice cloning) |
| Route | Method | Description |
|---|---|---|
/start |
POST | Create Daily room, launch bot, start call |
/preview |
POST | LLM-generated preview of what the bot will say |
/upload-voice |
POST | Save voice recording for cloning |
/clone-voice |
POST | Clone voice via Cartesia API |
/representatives |
GET | Look up reps by address (placeholder) |
bot.py — Bot logic (IVR navigation, voicemail, human conversation)
server.py — FastAPI server (all HTTP endpoints)
prompts/ — System prompts and message templates
frontend/ — Vite + vanilla JS web UI
test_calls.sh — CLI test harness
By using pipecat, all services (transport, LLM, STT, and TTS) are all changeable. These are just the ones I started with.
- "Orchestration"
Pipecat- Python framework; the glue that makes it all possible.
- Transport
- LLM
- STT
- TTS
With the bot server running (uv run python server.py), use the test harness:
# Browser test — talk to the bot directly, verify IVR detection + conversation
./test_calls.sh webrtc
# Phone test — calls TEST_PHONE_NUMBER, verify IVR nav + voicemail/human routing
TEST_PHONE_NUMBER=+15551234567 ./test_calls.sh dialout
# Run both
TEST_PHONE_NUMBER=+15551234567 ./test_calls.sh allEach test starts a session and returns a Daily room URL. Open it in your browser to watch both the bot and telephony participant in real time.
- use some API to auto get representative phone numbers like https://5calls.org/representatives-api/ (maybe an MCP around this?)
- huge shout out to this pipecat example
- E l e c t r o n i c Dream Phone


