CallScreen is open source and welcomes contributions. This guide covers the development workflow.
- Fork the repository and clone your fork
- Install Python 3.12+ and set up the backend:
cd backend
pip install -e ".[dev,messaging]"- Copy the environment template:
cp docker/.env.example docker/.env- Run the test suite to verify your setup:
cd backend
python -m pytest tests/ -v- Create a branch from
mainfor your change - Write tests for new functionality
- Run the full test suite before submitting
- Open a pull request with a clear description
- Python 3.12+ with type hints throughout
- Pydantic v2 for all request/response schemas
- SQLAlchemy 2.0 async patterns for database access
- pytest with
@pytest.mark.unit/@pytest.mark.integrationmarkers - All TwiML output is sanitized via
sanitize_for_twiml()to prevent injection - Phone numbers use E.164 format (
+15551234567) - SIP URIs use the
sip:scheme prefix
Calls follow a strict state machine (core/call_state.py) with transitions enforced in Redis. New states or transitions require updating ALLOWED_TRANSITIONS.
Forwarding destinations resolve in priority order:
- Per-user
UserSettings(database) - App-level environment variables (
CALLSCREEN_FORWARD_*) TWILIO_PHONE_NUMBER(backward-compatible fallback)
Emergency callbacks always use PSTN (never SIP) for reliability.
All Twilio webhook endpoints validate request signatures using X-Twilio-Signature. The fallback endpoint (/voice/fallback) intentionally skips validation so it always works even if the application is partially down.
cd docker
docker compose up -dAfter code changes to the backend, rebuild:
docker compose build backend
docker compose up -d backendOpen a GitHub issue with:
- Steps to reproduce
- Expected vs actual behavior
- Relevant logs (redact any credentials)