Environment Variables
Complete reference for all environment variables used in the STELLA platform. Variables are organized by category and include default values, requirements, and detailed descriptions.
Quick Referenceβ
Jump to a specific category:
| Category | Description |
|---|---|
| Core Server | Node environment, ports |
| Database | PostgreSQL configuration |
| Security | JWT, encryption keys |
| LiveKit | WebRTC server configuration |
| AI APIs | OpenAI and other AI services |
| Speech-to-Text | STT provider configuration |
| Text-to-Speech | TTS provider configuration |
| GPU Acceleration | GPU/CUDA settings |
| Kubernetes | K8s namespace, DNS configuration |
| Agent Configuration | Agent images and directories |
| Agent SDK (Pod-Level) | TTS, turn management, debouncing inside agent pods |
| Public URLs | Frontend URLs and API endpoints |
| Storage | Temporary directories and paths |
Core Serverβ
Basic server configuration for the STELLA backend.
| Variable | Required | Default | Description |
|---|---|---|---|
NODE_ENV | No | local | Environment mode. Use local for development with localhost URLs, production for deployment with custom domains |
PORT | No | 3000 | HTTP server port for the backend API |
GRPC_PORT | No | 50051 | gRPC server port for internal service communication |
PRODUCTION_DOMAIN | No | - | Your domain for production deployment (e.g., yourdomain.com). Only used when NODE_ENV=production |
Databaseβ
PostgreSQL database connection settings.
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL | Yes | - | PostgreSQL connection string. Format: postgresql://user:password@host:port/database?schema=public |
POSTGRES_DB | No | session_management | Database name |
POSTGRES_USER | No | postgres | Database username |
POSTGRES_PASSWORD | Yes | - | Database password. Use a strong, unique password in production |
Example Configuration:
POSTGRES_DB=session_management
POSTGRES_USER=postgres
POSTGRES_PASSWORD=your-secure-db-password
DATABASE_URL="postgresql://postgres:your-secure-db-password@localhost:5432/session_management?schema=public"
Securityβ
Authentication and encryption settings.
| Variable | Required | Default | Description |
|---|---|---|---|
JWT_SECRET | Yes | - | Secret key for signing JWT tokens. Use 64+ characters in production |
ENV_VAR_ENCRYPTION_KEY | Yes (prod) | - | AES-256 encryption key for sensitive environment variables stored in database. Generate with: openssl rand -hex 32 |
The ENV_VAR_ENCRYPTION_KEY must be exactly 64 hex characters (32 bytes). Losing this key means losing access to all encrypted environment variables! Store it securely in a secrets manager.
LiveKitβ
WebRTC server configuration for real-time audio/video communication.
| Variable | Required | Default | Description |
|---|---|---|---|
LIVEKIT_URL | Yes | ws://localhost:7880 | Internal LiveKit URL for services running in K8s pods |
PUBLIC_LIVEKIT_URL | Yes | ws://localhost:7880 | Public LiveKit URL for browser clients |
LIVEKIT_API_KEY | Yes | devkey | LiveKit API key for authentication |
LIVEKIT_API_SECRET | Yes | secret | LiveKit API secret |
LIVEKIT_TURN_ENABLED | No | false | Enable TURN server for NAT traversal in production |
LIVEKIT_TURN_DOMAIN | No | - | Domain for TURN server (e.g., turn.yourdomain.com) |
URL Configuration:
- Local development: Both URLs typically point to
ws://localhost:7880 - Production:
LIVEKIT_URLuses internal addressing (e.g.,ws://host.minikube.internal:7880), whilePUBLIC_LIVEKIT_URLuses your public domain with TLS (e.g.,wss://livekit.yourdomain.com)
AI APIsβ
API keys for AI services used by agents.
| Variable | Required | Default | Description |
|---|---|---|---|
OPENAI_API_KEY | Yes | - | OpenAI API key for agent conversations. Format: sk-proj-xxxxx |
OPENAI_PLAN_GENERATOR_API_KEY | No | - | Separate OpenAI key for plan generation (cost isolation) |
Speech-to-Textβ
Configure the speech recognition provider and settings.
| Variable | Required | Default | Description |
|---|---|---|---|
STT_PROVIDER | No | sherpa | STT provider: sherpa (lightweight CPU) or whisper (GPU-accelerated, best accuracy) |
Whisper Configuration
These settings only apply when STT_PROVIDER=whisper:
| Variable | Required | Default | Description |
|---|---|---|---|
WHISPER_MODEL | No | large-v3 | Model size. Options: tiny.en, base.en, small.en, medium.en (English-only) or tiny, base, small, medium, large-v3 (multilingual) |
WHISPER_DEVICE | No | cpu | Compute device: cpu or cuda |
WHISPER_COMPUTE_TYPE | No | int8 | Quantization type: float16, int8, int8_float16 |
WHISPER_BEAM_SIZE | No | 5 | Beam search width. Higher = more accurate but slower |
WHISPER_LANGUAGE | No | (auto-detect) | Force specific language code (e.g., en, de, fr) for the whole STT service. Empty for auto-detection. To fix a single agent's language, set STELLA_LANGUAGE on that agent instead β it pins transcription per session without affecting other agents |
VAD (Voice Activity Detection) Configuration
Silero VAD settings for the whisper provider:
| Variable | Required | Default | Description |
|---|---|---|---|
VAD_THRESHOLD | No | 0.5 | Voice detection threshold (0.0-1.0). Higher = less sensitive |
VAD_MIN_SILENCE_MS | No | 500 | Minimum silence duration (ms) before considering speech ended |
PARTIAL_INTERVAL_MS | No | 1000 | Interval for partial transcription updates |
Interruption Threshold & Diagnostics
The STT service reads these from the platform configuration. It decides when the user's speech is long enough to count as an interruption, and it reports that to the agent. Whether an agent acts on it is set per deployment: see BARGE_IN_ENABLED under Agent SDK (Pod-Level).
| Variable | Required | Default | Description |
|---|---|---|---|
BARGE_IN_MIN_SPEECH_MS | No | 600 | Voiced audio (ms) before the user's speech counts as an interruption instead of a backchannel like "mhm". Below it the agent keeps talking; above it the agent stops and listens. Lower yields sooner but lets "mhm" cut it off |
STELLA_MODEL_KEEP_WARM | No | true | Keeps the speech-recognition and voice models warm in the background so the first sentence after an idle spell is not slow. Set to false to turn it off. Asked in the setup wizard |
STT_DECODE_DIAGNOSTICS | No | 0 | 1 logs per-turn decode metrics and fills the STT cards in the session metrics modal. Costs extra GPU work per turn, so leave it at 0 in normal use |
Text-to-Speechβ
Configure the speech synthesis provider and settings.
| Variable | Required | Default | Description |
|---|---|---|---|
TTS_PROVIDER | No | piper | TTS provider: piper (fast local CPU), kokoro (fast local GPU), chatterbox (multilingual), elevenlabs (best quality), or auto (fallback chain) |
Provider Comparison:
| Provider | Latency | Quality | Cost | Notes |
|---|---|---|---|---|
piper | 30-80ms | Good | Free | CPU-only, lowest latency |
kokoro | 50-100ms | Good | Free | GPU-accelerated |
chatterbox | 100-200ms | Good | Free | Multilingual |
elevenlabs | 200-300ms | Excellent | Paid | Best voice quality |
auto | Varies | Varies | Mixed | Fallback: piper β chatterbox β kokoro |
ElevenLabs Configuration
These settings only apply when TTS_PROVIDER=elevenlabs:
| Variable | Required | Default | Description |
|---|---|---|---|
ELEVENLABS_API_KEY | Yes | - | ElevenLabs API key |
ELEVENLABS_VOICE_ID | No | Xb7hH8MSUJpSbSDYk0k2 | Voice ID from ElevenLabs |
ELEVENLABS_MODEL_ID | No | eleven_turbo_v2_5 | Model ID. eleven_turbo_v2_5 offers best latency |
Kokoro Configuration
Kokoro is automatically configured based on GPU settings. When ENABLE_GPU=true, Kokoro uses CUDA acceleration for best performance.
GPU Accelerationβ
Configure GPU support for STT and TTS services.
| Variable | Required | Default | Description |
|---|---|---|---|
ENABLE_GPU | No | false | Enable GPU support. Set to true for CUDA-accelerated inference |
ONNX_PROVIDER | No | CUDAExecutionProvider,CPUExecutionProvider | ONNX Runtime execution providers for STT/TTS |
Requirements for GPU mode:
- Linux with NVIDIA GPU (Tesla T4, RTX 3000+, etc.)
- NVIDIA drivers installed (
nvidia-smishould work) - K3s with NVIDIA Container Toolkit
macOS automatically falls back to CPU mode as NVIDIA GPUs are not supported.
Kubernetesβ
Kubernetes cluster and DNS configuration.
| Variable | Required | Default | Description |
|---|---|---|---|
KUBERNETES_NAMESPACE | No | ai-agents | Namespace for agent pods |
CUSTOM_DNS_SERVERS | No | - | Custom DNS servers for CoreDNS (space-separated). Example: "8.8.8.8 8.8.4.4" |
AUTO_DETECT_K8S_DNS | No | false | Auto-detect CoreDNS IP in production |
KUBERNETES_DNS_NAMESERVER | No | 10.96.0.10 | Fallback DNS IP for pod DNS resolution |
DNS Configuration:
Custom DNS is useful for bypassing network DNS interception (e.g., corporate SSL inspection):
# Google DNS (recommended for production)
CUSTOM_DNS_SERVERS="8.8.8.8 8.8.4.4"
# Cloudflare DNS
CUSTOM_DNS_SERVERS="1.1.1.1 1.0.0.1"
# Use system default (local development)
CUSTOM_DNS_SERVERS=""
Agent Configurationβ
Settings for agent deployment and management.
| Variable | Required | Default | Description |
|---|---|---|---|
AGENT_IMAGE | No | conversational-ai-server:latest | Docker image for agent pods |
AGENTS_DIR | No | ./agents | Directory containing agent definitions |
Public URLsβ
URLs exposed to clients and frontend applications.
| Variable | Required | Default | Description |
|---|---|---|---|
PUBLIC_API_URL | No | http://localhost:3000 | Public URL for the backend API |
VITE_API_URL | No | http://localhost:3000 | API URL for Vite frontend build |
VITE_LIVEKIT_URL | No | ws://localhost:7880 | LiveKit URL for Vite frontend build |
Storageβ
File storage and temporary directory configuration.
| Variable | Required | Default | Description |
|---|---|---|---|
STELLA_AI_TEMP_DIR | No | /tmp | Temporary directory for build artifacts, logs, and Docker image exports |
Use Cases:
- Docker build logs
- K3s image import/export (can be several GB)
- Temporary K8s manifests
- PID files for daemon mode
For production with limited root filesystem space:
STELLA_AI_TEMP_DIR=/mnt/stella-ai-temp
Agent SDK (Pod-Level)β
These environment variables are read by the STELLA Agent SDK inside each agent pod. They control audio pipeline behavior, turn management, and TTS. For how the audio pipeline actually works and why the timing constants are what they are, see TTS & Audio Pipeline. Agents declare them in their agent.yaml manifest under x-stella-optional-env-vars so the frontend deploy modal can expose them.
| Variable | Required | Default | Description |
|---|---|---|---|
TTS_ENABLED | No | true | Enable text-to-speech audio output. Set to false for text-only mode (skips TTS connection entirely) |
INTERRUPT_MODE | No | none | Transcript interrupt behavior. none = strict turn-based gating (user speech suppressed while agent processes/narrates). smart = reserved for future barge-in with re-prompting |
BARGE_IN_ENABLED | No | (agent decides) | Unset: barge-in is on for any agent that declares support for it. true/false forces it on or off for this deployment |
TRANSCRIPT_DEBOUNCE_MS | No | 0 | Debounce window in milliseconds for aggregating rapid successive final transcripts. Off by default since 1.2.0: neither STT provider can emit a second final inside the window, so the old 300 ms only added delay |
STT_WARMUP_ENABLED | No | true | Warm up the STT model on agent start and when participants join. Set to false to skip warmup |
STELLA_TTS_PLAYBACK | No | auto | Agent setting, per deployment; a deployment that leaves it at auto follows the platform default a system admin sets in Settings β Platform Defaults (from the next session). auto (and unset) starts each session in stream and switches once to sentence β never back β after 3 consecutive sentences synthesize slower than real time. stream always starts each sentence as it is generated; sentence always generates it whole first and then plays it, as 1.1.0 did. See the TTS pipeline |
STELLA_TTS_PREROLL_MS | No | auto | Jitter buffer (ms) held before each sentence plays. Unset, the agent picks it from the measured speed of the voice on this hardware (200 ms up to 3 s); setting a value pins it. Watch the agent log for "Pre-roll A -> B", "bridged" silence or "Playout starved". See tuning guidance |
TTS_PROGRESS_TICK_MS | No | 200 | How often a teleprompter progress envelope is emitted during playback |
TTS_VOICE | No | provider default | Seed TTS voice, overridable per stream. Honored by voice-selecting providers, ignored by others |
TTS_LANGUAGE | No | detected | Seed language for TTS (ISO 639-1). Empty = follow the per-turn detected language |
STELLA_TELEPROMPTER_ENABLED | No | on | Stream the reply dimmed and light each word as it is spoken. Set false to disable |
The SDK also reads two timing settings that neither built-in agent declares in agent.yaml: BARGE_IN_DUCK_TIMEOUT_MS (default 1200), after which a duck that was never confirmed as an interruption lifts by itself, so background noise cannot keep the agent quiet; and STELLA_MUTE_SILENCE_MS (default 3000), the silence fed to speech recognition when a participant mutes the microphone, so the sentence in flight is finalized like any pause.
The SDK also reads BARGE_IN_DUCK_GAIN (default 0.25): the volume the agent drops to the moment the user makes a sound, where 1.0 disables ducking. Neither built-in agent declares it in agent.yaml yet, so it can't be set from the deploy form and every deployment runs the default.
Turn Managementβ
When TTS_ENABLED=true (the default), the SDK enforces strict turn-based flow:
User speaks β Final transcript β Gate CLOSES β Agent processes β TTS narrates β Gate OPENS
While the gate is closed:
- No partials published to LiveKit (user speech invisible in frontend)
- No finals queued for the agent (prevents stale/fragmented input)
- No barge-in callbacks fired (when
INTERRUPT_MODE=none) - STT stream stays alive (no reconnection cost when gate re-opens)
A short utterance that begins and ends while the gate is closed, without passing BARGE_IN_MIN_SPEECH_MS, is not taken as a turn, even when it was a real answer like "okay" spoken while the agent was still waiting for its reply. It still appears in the transcript, marked "not counted as a turn", and the agent log has a [GATE] Not taken as a turn line for it.
In the v2 agent the gate stays closed from the bridge until the reply has been spoken, so a slow reply call keeps it closed longer. The reply call gets 4 s to its first streamed token, then one retry with 2 s ([REPLY-TIMEOUT] and [REPLY-RETRY] in the agent log, with the turn). If the retry stalls too, the agent says a short fallback line, the gate opens and it listens again. A reply that has started streaming is never cut off for being long.
When TTS_ENABLED=false, the gate still discards finals during processing but allows partials through to LiveKit (lighter turn management since processing completes quickly without narration).
Manifest Declarationβ
Agents declare these in agent.yaml so the frontend deploy modal can display them:
configSchema:
# ...
x-stella-optional-env-vars:
- name: TTS_ENABLED
description: "Enable text-to-speech audio output. Set to 'false' for text-only mode."
default: "true"
- name: INTERRUPT_MODE
description: "Transcript interrupt behavior: 'none' (turn-based gating) or 'smart' (barge-in)"
default: "none"
- name: TRANSCRIPT_DEBOUNCE_MS
description: "Debounce window (ms) for aggregating rapid successive final transcripts."
default: "300"
Agent Environment Variable Injectionβ
STELLA provides a secure mechanism for injecting environment variables into agent pods. This allows users to configure API keys and secrets without exposing them in code.
Flow Diagramβ
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β Frontend UI β β STELLA Backend β β Kubernetes β
β β β β β β
β Create Env βββββΆβ Encrypt with βββββΆβ Store as β
β Template β β AES-256-GCM β β K8s Secret β
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β Agent Pod ββββββ Mount Secret ββββββ Pod Creation β
β β β as Env Vars β β β
β Access via β β β β Session Start β
β os.environ β β β β β
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
How It Worksβ
- Template Creation: Users create environment variable templates in the Frontend UI
- Encrypted Storage: Variables are encrypted with AES-256-GCM using
ENV_VAR_ENCRYPTION_KEY - Pod Creation: When a session starts, the backend creates a Kubernetes Secret
- Secret Mounting: The secret is mounted into the agent pod as environment variables
- Agent Access: Agents access variables via
os.environin Python
Required Agent Variablesβ
| Variable | Required | Description |
|---|---|---|
OPENAI_API_KEY | Yes | OpenAI API key for conversation |
ELEVENLABS_API_KEY | No | ElevenLabs API key (if using ElevenLabs TTS) |
SDK Usageβ
Agents using the STELLA SDK can access environment variables through the standard Python os.environ:
import os
from stella_agent import run_agent_from_env
# Access environment variables
openai_key = os.environ.get("OPENAI_API_KEY")
elevenlabs_key = os.environ.get("ELEVENLABS_API_KEY")
# Or use the SDK helper that configures everything
run_agent_from_env()
Security Featuresβ
- AES-256-GCM encryption: All sensitive variables encrypted at rest
- Per-session secrets: Each session gets its own Kubernetes Secret
- Automatic cleanup: Secrets are deleted when the session ends
- Namespace isolation: Agent pods run in isolated namespace
- No plaintext storage: Variables never stored in plaintext in database
Example Configurationsβ
Development Environmentβ
Minimal configuration for local development:
# .env (Development)
NODE_ENV=local
# Database
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/stella?schema=public"
# LiveKit (local)
LIVEKIT_URL=ws://localhost:7880
PUBLIC_LIVEKIT_URL=ws://localhost:7880
LIVEKIT_API_KEY=devkey
LIVEKIT_API_SECRET=secret
# AI
OPENAI_API_KEY=sk-your-openai-key
# Security (can be simple for local dev)
JWT_SECRET=local-dev-secret-change-in-production
Production Environmentβ
Full configuration for production deployment:
# .env (Production)
NODE_ENV=production
PRODUCTION_DOMAIN=stella.yourdomain.com
# Database
POSTGRES_DB=stella
POSTGRES_USER=stella_user
POSTGRES_PASSWORD=<strong-password>
DATABASE_URL="postgresql://stella_user:<strong-password>@postgres:5432/stella?schema=public"
# Security
JWT_SECRET=<64+-character-secret>
ENV_VAR_ENCRYPTION_KEY=<output-of-openssl-rand-hex-32>
# LiveKit (production with TLS)
LIVEKIT_URL=ws://host.minikube.internal:7880
PUBLIC_LIVEKIT_URL=wss://livekit.stella.yourdomain.com
LIVEKIT_API_KEY=<your-livekit-key>
LIVEKIT_API_SECRET=<your-livekit-secret>
LIVEKIT_TURN_ENABLED=true
LIVEKIT_TURN_DOMAIN=turn.stella.yourdomain.com
# AI
OPENAI_API_KEY=sk-proj-xxxxx
# GPU (if available)
ENABLE_GPU=true
STT_PROVIDER=whisper
WHISPER_MODEL=large-v3
WHISPER_DEVICE=cuda
TTS_PROVIDER=kokoro
# Kubernetes
KUBERNETES_NAMESPACE=ai-agents
CUSTOM_DNS_SERVERS="8.8.8.8 8.8.4.4"
# Storage
STELLA_AI_TEMP_DIR=/mnt/stella-ai-temp
Security Considerationsβ
- Never commit
.envfiles - The.envfile is gitignored by default - Use strong secrets - Generate cryptographic secrets with
openssl rand - Rotate keys periodically - Especially
JWT_SECRETandENV_VAR_ENCRYPTION_KEY - Use secrets managers - In production, consider HashiCorp Vault or cloud-native solutions
- Limit API key scope - Use API keys with minimal required permissions
- Separate keys per environment - Use different API keys for development and production