|
|
5 months ago | |
|---|---|---|
| cli | 5 months ago | |
| tests | 5 months ago | |
| .gitignore | 5 months ago | |
| README.md | 5 months ago | |
| app.py | 5 months ago | |
| crypto_utils.py | 5 months ago | |
| letta_executor.py | 5 months ago | |
| models.py | 5 months ago | |
| pytest.ini | 5 months ago | |
| requirements-test.txt | 5 months ago | |
| requirements.txt | 5 months ago | |
| scheduler.py | 5 months ago | |
| setup_encryption.sh | 5 months ago | |
| test-lines.bash | 5 months ago | |
| test_api.py | 5 months ago | |
| test_api.sh | 5 months ago |
Free hosted message routing service for Letta agents.
Send messages to your Letta agents immediately or scheduled for later. Supports natural language scheduling ("in 5 minutes", "every weekday at 9am") and secure cross-agent communication.
๐ Hosted Service: https://letta--switchboard-api.modal.run
๐ป CLI: letta-switchboard
๐ Security: End-to-end encryption, API key isolation
๐ Docs: CLI Guide | API Reference
Send a message right now with just cURL:
curl -X POST https://letta--switchboard-api.modal.run/schedules/one-time \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_LETTA_API_KEY" \
-d '{
"agent_id": "agent-xxx",
"execute_at": "2025-11-12T20:00:00Z",
"message": "Hello from Switchboard!",
"role": "user"
}'
Or create a recurring schedule:
curl -X POST https://letta--switchboard-api.modal.run/schedules/recurring \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_LETTA_API_KEY" \
-d '{
"agent_id": "agent-xxx",
"cron": "0 9 * * 1-5",
"message": "Daily standup reminder",
"role": "user"
}'
Check your schedules:
# List all one-time schedules
curl https://letta--switchboard-api.modal.run/schedules/one-time \
-H "Authorization: Bearer YOUR_LETTA_API_KEY"
# List all recurring schedules
curl https://letta--switchboard-api.modal.run/schedules/recurring \
-H "Authorization: Bearer YOUR_LETTA_API_KEY"
# View execution results
curl https://letta--switchboard-api.modal.run/results \
-H "Authorization: Bearer YOUR_LETTA_API_KEY"
Note:
YOUR_LETTA_API_KEY with your actual Letta API keyagent-xxx with your agent IDPro tip: Use the CLI for natural language scheduling - it's much easier than writing ISO timestamps and cron expressions!
The CLI makes natural language scheduling much easier:
# Download the CLI (or build from source)
cd cli
go build -o letta-switchboard
# Configure with your Letta API key
./letta-switchboard config set-api-key sk-your-letta-key
Send messages with natural language:
# Send immediately
letta-switchboard send \
--agent-id agent-xxx \
--message "Hello from Switchboard!"
# Send later (natural language!)
letta-switchboard send \
--agent-id agent-xxx \
--message "Reminder to check in" \
--execute-at "tomorrow at 9am"
# Create recurring schedule (plain English!)
letta-switchboard recurring create \
--agent-id agent-xxx \
--message "Daily standup" \
--cron "every weekday at 10am"
That's it! The hosted service handles everything - scheduling, execution, and delivery.
โ
Free hosted service - No deployment needed
โ
Natural language scheduling - "in 5 minutes", "tomorrow at 9am", "every weekday"
โ
Secure by default - API key isolation, encrypted storage
โ
Recurring schedules - Cron expressions or plain English
โ
Instant delivery - Messages execute within 1 minute
โ
Execution tracking - Get run IDs for every message
โ
Self-hostable - Deploy your own instance if needed
No Infrastructure Setup
Just use the hosted service at https://letta--switchboard-api.modal.run. No deployment, no servers, no configuration.
Natural Language Scheduling
Forget cron syntax. Use plain English like "every weekday at 9am" or "in 5 minutes".
Secure by Design
Always Available
Security Model:
# Relative time
--execute-at "in 5 minutes"
--execute-at "in 2 hours"
--execute-at "in 3 days"
# Tomorrow
--execute-at "tomorrow at 9am"
--execute-at "tomorrow at 14:30"
# Next weekday
--execute-at "next monday at 3pm"
--execute-at "next friday at 10:00"
# ISO 8601 (still works)
--execute-at "2025-11-12T19:30:00Z"
# Minutes
--cron "every 5 minutes"
--cron "every 30 minutes"
# Hourly/Daily
--cron "every hour"
--cron "daily at 9am"
--cron "daily at 14:30"
# Weekdays
--cron "every monday"
--cron "every friday at 3pm"
--cron "every weekday" # Mon-Fri at 9am
# Traditional cron (still works)
--cron "*/5 * * * *" # Every 5 minutes
This will test all endpoints (create, list, get, delete) for both recurring and one-time schedules.
**Features:**
- Validates API key before running
- Shows configuration at startup
- Tests create, list, get, and delete operations
- Pretty prints all responses
### Bash Test Script
```bash
./test_api.sh
Same functionality using curl commands.
Example with inline variables:
LETTA_API_KEY=sk-xxx LETTA_AGENT_ID=agent-yyy python test_api.py
The easiest way to interact with letta-switchboard is via the CLI:
# Send a message immediately
letta-switchboard send --agent-id agent-xxx --message "Hello!"
# Send a message later
letta-switchboard send --agent-id agent-xxx --message "Reminder" --execute-at "tomorrow at 9am"
# Create recurring schedule
letta-switchboard recurring create --agent-id agent-xxx --message "Daily standup" --cron "every weekday at 9am"
# List schedules
letta-switchboard onetime list
letta-switchboard recurring list
# View results
letta-switchboard results list
See CLI Documentation for installation and full usage guide.
Base URL: https://letta--schedules-api.modal.run
All endpoints require Bearer token authentication using your Letta API key:
curl -H "Authorization: Bearer your-letta-api-key" https://your-modal-app.modal.run/schedules/recurring
Security Model:
list agents call with limit=1)Error Codes:
401 Unauthorized: Invalid or expired Letta API key403 Forbidden: Valid API key, but trying to access someone else's schedule404 Not Found: Schedule doesn't existSchedule a message to be sent on a cron schedule:
curl -X POST https://your-modal-app.modal.run/schedules/recurring \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agent-123",
"api_key": "your-letta-api-key",
"cron": "0 9 * * *",
"message": "Good morning! Time for your daily check-in.",
"role": "user"
}'
Cron Format: minute hour day month day_of_week
0 9 * * * - Every day at 9:00 AM*/15 * * * * - Every 15 minutes0 */2 * * * - Every 2 hours0 0 * * 0 - Every Sunday at midnightSchedule a message for a specific time:
curl -X POST https://your-modal-app.modal.run/schedules/one-time \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agent-123",
"api_key": "your-letta-api-key",
"execute_at": "2025-11-07T14:30:00-05:00",
"message": "Reminder: Meeting in 30 minutes",
"role": "user"
}'
Timestamp Format: ISO 8601 with timezone
2025-11-07T14:30:00-05:00 (EST)2025-11-07T14:30:00Z (UTC)# List your recurring schedules
curl -H "Authorization: Bearer your-letta-api-key" \
https://your-modal-app.modal.run/schedules/recurring
# List your one-time schedules
curl -H "Authorization: Bearer your-letta-api-key" \
https://your-modal-app.modal.run/schedules/one-time
# Get recurring schedule
curl -H "Authorization: Bearer your-letta-api-key" \
https://your-modal-app.modal.run/schedules/recurring/{schedule_id}
# Get one-time schedule
curl -H "Authorization: Bearer your-letta-api-key" \
https://your-modal-app.modal.run/schedules/one-time/{schedule_id}
# Delete recurring schedule
curl -X DELETE -H "Authorization: Bearer your-letta-api-key" \
https://your-modal-app.modal.run/schedules/recurring/{schedule_id}
# Delete one-time schedule
curl -X DELETE -H "Authorization: Bearer your-letta-api-key" \
https://your-modal-app.modal.run/schedules/one-time/{schedule_id}
# List all execution results
curl -H "Authorization: Bearer your-letta-api-key" \
https://your-modal-app.modal.run/results
# Get result for specific schedule
curl -H "Authorization: Bearer your-letta-api-key" \
https://your-modal-app.modal.run/results/{schedule_id}
Result Format:
{
"schedule_id": "uuid",
"schedule_type": "recurring",
"run_id": "run_abc123",
"agent_id": "agent-123",
"message": "The scheduled message",
"executed_at": "2025-11-07T00:15:00"
}
Note: Results are stored when the message is queued to Letta. To check the actual run status, use the Letta API:
# Get the run_id from results
RESULT=$(curl -H "Authorization: Bearer your-letta-api-key" \
https://your-modal-app.modal.run/results/{schedule_id})
RUN_ID=$(echo $RESULT | jq -r '.run_id')
# Check run status with Letta
curl -H "Authorization: Bearer your-letta-api-key" \
https://api.letta.com/v1/runs/$RUN_ID
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"agent_id": "agent-123",
"cron": "0 9 * * *",
"message": "Good morning!",
"role": "user",
"created_at": "2025-11-06T10:00:00",
"last_run": "2025-11-06T09:00:00"
}
Note: API keys are stored securely and never returned in responses.
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"agent_id": "agent-123",
"execute_at": "2025-11-07T14:30:00-05:00",
"message": "Reminder!",
"role": "user",
"created_at": "2025-11-06T10:00:00"
}
Note:
/results endpoint for execution history)last_run timestamp in schedule fileRace Condition Prevention:
Schedules and execution results are stored in a hash-based directory structure:
/data/
โโโ schedules/
โ โโโ recurring/
โ โ โโโ {api_key_hash}/ # SHA256 hash of API key (first 16 chars)
โ โ โ โโโ {uuid-1}.json.enc # Encrypted schedule files
โ โ โ โโโ {uuid-2}.json.enc
โ โ โโโ {another_hash}/
โ โ โโโ {uuid-3}.json.enc
โ โโโ one-time/
โ โโโ 2025-11-06/ # Date bucket
โ โ โโโ 14/ # Hour bucket (00-23)
โ โ โ โโโ {api_key_hash}/
โ โ โ โ โโโ {uuid}.json.enc
โ โ โ โโโ {another_hash}/
โ โ โ โโโ {uuid}.json.enc
โ โ โโโ 15/
โ โโโ 2025-11-07/
โโโ results/
โโโ {api_key_hash}/
โ โโโ {schedule_uuid}.json.enc # Execution results with run_id
โ โโโ {schedule_uuid}.json.enc
โโโ {another_hash}/
Security Features:
Performance Benefits:
View logs in Modal dashboard:
modal app logs letta-switchboard
Or watch logs in real-time:
modal app logs letta-switchboard --follow
Modal pricing (as of 2024):
Free tier: 30 credits/month (~$30 value)
Want to run your own instance? Switchboard is fully self-hostable on Modal.
Clone the repository:
git clone https://github.com/cpfiffer/letta-switchboard.git
cd letta-switchboard
Install Modal CLI:
pip install modal
modal setup
1. Set up encryption (required):
# Automated setup
./setup_encryption.sh
# Or manually
ENCRYPTION_KEY=$(python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())")
echo "Save this key: $ENCRYPTION_KEY"
modal secret create letta-switchboard-encryption \
LETTA_SWITCHBOARD_ENCRYPTION_KEY="$ENCRYPTION_KEY"
2. Deploy to Modal:
modal deploy app.py
3. Get your API URL:
modal app list
# Look for 'switchboard' and note the URL
4. Configure CLI to use your instance:
letta-switchboard config set-url https://your-instance.modal.run
Run locally with hot reloading:
# Enable dev mode (no encryption)
export LETTA_SWITCHBOARD_DEV_MODE=true
# Start local server
modal serve app.py
Dev Mode Features:
View files in dev mode:
# View a schedule
cat /tmp/letta-switchboard-volume/schedules/recurring/abc123/uuid.json | jq
# List all schedules
ls -la /tmp/letta-switchboard-volume/schedules/
Set environment variables:
export LETTA_API_KEY="sk-..."
export LETTA_AGENT_ID="agent-xxx"
export LETTA_SWITCHBOARD_URL="https://your-instance.modal.run"
Run tests:
# Python test suite
python test_api.py
# Bash test script
./test_api.sh
# Unit tests
pytest -m "not e2e"
# Full E2E tests (requires modal serve running)
pytest
Running your own instance on Modal:
The hosted service at letta--switchboard-api.modal.run is free to use!
MIT