Files
hold-slayer/docs/configuration.md
Robert Helewka 4a3c14d4af
All checks were successful
CVE Scan & Docker Build / security-scan (push) Successful in 45s
CVE Scan & Docker Build / build-and-push (push) Successful in 1m53s
docs: add Claude AI assistant rules and configuration
Add comprehensive rule documentation for AI-assisted development covering
authentication surfaces, outbound-call safety invariants, and other project
conventions to guide Claude's understanding of critical system behaviors.
2026-07-28 19:01:38 -04:00

6.2 KiB

Configuration

All configuration is via environment variables, loaded through Pydantic Settings. Copy .env.example to .env and edit.

Environment Variables

Auth (Casdoor SSO + owner)

The gateway is owner-only: the browser signs in via Casdoor (JWT), MCP/CLI clients use owner-minted PATs, and only OWNER_NAME may use any surface. With CASDOOR_ENABLED=false the gateway runs in dev-owner mode — permitted only on a loopback HOST. Startup refuses SSO-enabled-with-missing-config and SSO-disabled-off-loopback.

Variable Description Default Required
CASDOOR_ENABLED Enable Casdoor SSO false No
CASDOOR_ENDPOINT Casdoor base URL https://id.ouranos.helu.ca If SSO on
CASDOOR_CLIENT_ID Casdoor application client ID If SSO on
CASDOOR_CLIENT_SECRET Casdoor application client secret If SSO on
CASDOOR_ORG_NAME Casdoor organization heluca No
CASDOOR_APP_NAME Casdoor application name No
OWNER_NAME Casdoor username of the single operator If SSO on
PUBLIC_BASE_URL Public base URL for OAuth discovery (else derived) No

SIP Trunk

Variable Description Default Required
SIP_TRUNK_HOST Your SIP provider hostname Yes
SIP_TRUNK_PORT SIP signaling port 5060 No
SIP_TRUNK_USERNAME SIP auth username Yes
SIP_TRUNK_PASSWORD SIP auth password Yes
SIP_TRUNK_DID Your phone number (E.164) Yes
SIP_TRUNK_TRANSPORT Transport protocol (udp, tcp, tls) udp No

Gateway

Variable Description Default Required
GATEWAY_SIP_PORT Port for device SIP registration 5080 No
GATEWAY_RTP_PORT_MIN Minimum RTP port 10000 No
GATEWAY_RTP_PORT_MAX Maximum RTP port 20000 No
GATEWAY_HOST Bind address 0.0.0.0 No

LLM

Variable Description Default Required
LLM_BASE_URL OpenAI-compatible API endpoint http://localhost:11434/v1 No
LLM_MODEL Model name for IVR analysis llama3 No
LLM_API_KEY API key (if required) not-needed No
LLM_TIMEOUT Request timeout in seconds 30.0 No
LLM_MAX_TOKENS Max tokens per response 1024 No
LLM_TEMPERATURE Sampling temperature 0.3 No

Speech-to-Text

Variable Description Default Required
SPEACHES_URL Speaches/Whisper STT endpoint http://localhost:22070 No
SPEACHES_MODEL Whisper model name whisper-large-v3 No

Database

Variable Description Default Required
DATABASE_URL PostgreSQL or SQLite connection string sqlite+aiosqlite:///./hold_slayer.db No

Notifications

Variable Description Default Required
NOTIFY_SMS_NUMBER Phone number for SMS alerts (E.164) No

Audio Classifier

Variable Description Default Required
CLASSIFIER_WINDOW_SECONDS Audio window size for classification 3.0 No
CLASSIFIER_SILENCE_THRESHOLD RMS below this = silence 0.85 No
CLASSIFIER_MUSIC_THRESHOLD Spectral flatness below this = music 0.7 No
CLASSIFIER_SPEECH_THRESHOLD Spectral flatness above this = speech 0.6 No

Hold Slayer

Variable Description Default Required
MAX_HOLD_TIME Maximum seconds to wait on hold 7200 No
HOLD_CHECK_INTERVAL Seconds between audio checks 2.0 No
DEFAULT_TRANSFER_DEVICE Device to transfer to sip_phone No

Recording

Variable Description Default Required
RECORDING_DIR Directory for WAV recordings recordings No
RECORDING_MAX_SECONDS Maximum recording duration 7200 No
RECORDING_SAMPLE_RATE Audio sample rate 16000 No

Settings Architecture

Configuration is managed by Pydantic Settings in config.py:

from config import get_settings

settings = get_settings()
settings.sip_trunk_host      # "sip.provider.com"
settings.llm.base_url        # "http://localhost:11434/v1"
settings.llm.model           # "llama3"
settings.speaches_url        # "http://localhost:22070"
settings.database_url        # "sqlite+aiosqlite:///./hold_slayer.db"

LLM settings are nested under settings.llm as a LLMSettings sub-model.

Deployment

Development

# 1. Clone and install
git clone <repo-url>
cd hold-slayer
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

# 2. Configure
cp .env.example .env
# Edit .env

# 3. Start Ollama (for LLM)
ollama serve
ollama pull llama3

# 4. Start Speaches (for STT)
docker run -p 22070:8000 ghcr.io/speaches-ai/speaches

# 5. Run
uvicorn main:app --host 0.0.0.0 --port 8000 --reload

Production

# PostgreSQL is required (no SQLite fallback)
DATABASE_URL=postgresql+asyncpg://user:pass@localhost/hold_slayer

# Use vLLM for faster inference
LLM_BASE_URL=http://localhost:8000/v1
LLM_MODEL=meta-llama/Llama-3-8B-Instruct

# Run with multiple workers (note: each worker is independent)
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 1

Note: Hold Slayer is designed as a single-process application. Multiple workers would each have their own SIP engine and call state. For high availability, run behind a load balancer with sticky sessions.

Docker

FROM python:3.13-slim

# Install system dependencies for PJSUA2 and Sippy
RUN apt-get update && apt-get install -y \
    build-essential \
    libpjproject-dev \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY . .
RUN pip install -e .

EXPOSE 8000 5080/udp 10000-20000/udp

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Port mapping:

  • 8000 — HTTP API + WebSocket + MCP
  • 5080/udp — SIP device registration
  • 10000-20000/udp — RTP media ports