Appearance
Local Development
For AI agents: a documentation index is available at the root level at /llms.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Server configuration
Custom host and port
| Language | Custom Host and Port |
|---|---|
| Python | agent.run(host="0.0.0.0", port=8080) |
| TypeScript | agent.run({ host: "0.0.0.0", port: 8080 }) |
Using serve() directly (Python)
For more control, use serve() instead of run():
# Development server
<Badge type="tip" text="Fresh" />
agent.serve(host="127.0.0.1", port=3000)
# Listen on all interfaces
agent.serve(host="0.0.0.0", port=3000)Development endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/ | GET/POST | SWML document |
/swaig | POST | SWAIG function calls |
/post_prompt | POST | Post-prompt handling |
/debug | GET/POST | Debug information |
/debug_events | POST | Real-time debug events (when enable_debug_events() is active) |
/health | GET | Health check ( AgentServer only) |
Testing your agent
View SWML output
# Get the SWML document (use credentials from agent startup output or env vars)
curl -u "$SWML_BASIC_AUTH_USER:$SWML_BASIC_AUTH_PASSWORD" http://localhost:3000/
# Pretty print with jq
curl -u "$SWML_BASIC_AUTH_USER:$SWML_BASIC_AUTH_PASSWORD" http://localhost:3000/ | jq .Using swaig-test CLI
# List available functions
swaig-test my_agent.py --list-tools
# Test a specific function
swaig-test my_agent.py --exec get_weather --city "Seattle"
# Dump SWML output
swaig-test my_agent.py --dump-swmlExposing local server
SignalWire needs to reach your agent via a public URL. Use ngrok or similar:
Connection Flow: SignalWire Cloud, > ngrok tunnel, > localhost:3000
Steps:
- Start your agent (see run command table above)
- Start ngrok:
ngrok http 3000 - Use ngrok URL in SignalWire:
https://abc123.ngrok.io
Using ngrok
# Start your agent (example with Python; substitute your language's run command)
python my_agent.py
# In another terminal, start ngrok
ngrok http 3000ngrok provides a public URL like https://abc123.ngrok.io that forwards to your local server.
Using localtunnel
# Install
npm install -g localtunnel
# Start tunnel
lt --port 3000Environment variables for development
These environment variables work across all SDK languages:
| Variable | Purpose | Default |
|---|---|---|
SWML_BASIC_AUTH_PASSWORD | Auth password | Auto-generated |
SWML_BASIC_AUTH_USER | Auth username | signalwire |
SWML_PROXY_URL_BASE | Public URL (behind proxy) | Auto-detected |
SWML_ALLOW_PRIVATE_URLS | Allow private IP requests | false |
# Authentication (username defaults to 'signalwire' when not set)
# Only the password is required; omit both to disable auth for local testing
export SWML_BASIC_AUTH_PASSWORD="test123"
# Or disable authentication entirely for local testing
export SWML_BASIC_AUTH_USER=""
export SWML_BASIC_AUTH_PASSWORD=""
# Override proxy URL if behind ngrok
export SWML_PROXY_URL_BASE="https://abc123.ngrok.io"
# APP_URL is also accepted as a fallback (useful for Dokku deployments)
# Allow DataMap/skill requests to private IPs (e.g., local backend services)
export SWML_ALLOW_PRIVATE_URLS=trueProxy URL configuration
When behind ngrok or another proxy, the SDK needs to know the public URL:
import os
# Option 1: Environment variable
os.environ['SWML_PROXY_URL_BASE'] = 'https://abc123.ngrok.io'
# Option 2: Auto-detection from X-Forwarded headers
# The SDK automatically detects proxy from request headersDevelopment workflow
1. Code
Write/modify your agent code.
2. Test Locally
swaig-test my_agent.py --dump-swmlswaig-test my_agent.py --exec function_name --param value
3. Run Server
python my_agent.py (or your language’s equivalent run command)
4. Expose Publicly
ngrok http 3000
5. Test with SignalWire
Point phone number to ngrok URL and make test call.
Debug mode
Enable debug logging:
import logging
logging.basicConfig(level=logging.DEBUG)
agent = MyAgent()
agent.run()Or via environment variable:
export SIGNALWIRE_LOG_MODE=default
python my_agent.pyHot reloading
For automatic reloading during development, use uvicorn directly:
# Install uvicorn with reload support
pip install "uvicorn[standard]"
# Run with auto-reload
uvicorn my_agent:agent._app --reload --host 0.0.0.0 --port 3000Or create a development script:
# dev.py
from my_agent import MyAgent
agent = MyAgent()
app = agent._app # Expose the ASGI app for uvicornThen run:
uvicorn dev:app --reload --port 3000Serving static files
Use AgentServer.serve_static_files() to serve static files alongside your agents. This is useful for web dashboards, documentation, or any static content:
from signalwire import AgentServer
from pathlib import Path
# Create your agents
from my_agents import SupportAgent, SalesAgent
HOST = "0.0.0.0"
PORT = 3000
server = AgentServer(host=HOST, port=PORT)
server.register(SupportAgent(), "/support")
server.register(SalesAgent(), "/sales")
# Serve static files from web directory
web_dir = Path(__file__).parent / "web"
if web_dir.exists():
server.serve_static_files(str(web_dir))
server.run()Directory Structure:
my_project/
server.py
my_agents.py
web/
index.html
styles.css
app.jsKey Points:
- Use
server.serve_static_files(directory)to serve static files - Agent routes always take priority over static files
- Requests to
/serveindex.htmlfrom the static directory - Both
/supportand/support/work correctly with agents
Route Priority:
| Route | Handler |
|---|---|
/support | SupportAgent |
/sales | SalesAgent |
/health | AgentServer health check |
/* | Static files (fallback) |
Common development issues
| Issue | Solution |
|---|---|
| Port already in use | Use different port: agent.run(port=8080) |
| 401 Unauthorized | Check SWML_BASIC_AUTH_* env vars |
| Functions not found | Verify function registration |
| SWML URL wrong | Set SWML_PROXY_URL_BASE for ngrok |
| Connection refused | Ensure agent is running on correct port |
| Static files not found | Check web_dir.exists() and path is correct |
