# ============================================================================ # JAK Swarm -- Environment Variables # ============================================================================ # Copy this file to .env and fill in your values: # cp .env.example .env # # NEVER commit .env to version control. # # Legend: # [REQUIRED] -- The system will not start without this variable # [OPTIONAL] -- Enables additional features; system works without it # [DEV-ONLY] -- Only needed for local development # # Quick start (minimum viable config): # DATABASE_URL, AUTH_SECRET, OPENAI_API_KEY # ============================================================================ # ── Database [REQUIRED] ───────────────────────────────────────────────────── # PostgreSQL connection string. # Format: postgresql://USER:PASSWORD@HOST:PORT/DATABASE # The database must exist before running migrations. # For Docker: docker run -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres # Production: use a connection pool URL (e.g., PgBouncer) and SSL. DATABASE_URL="postgresql://jakswarm:jakswarm@localhost:5432/jakswarm" # Redis connection string. [OPTIONAL] # Used for: cron scheduling, voice session storage, future pub/sub. # Format: redis://[:PASSWORD@]HOST:PORT[/DB_NUMBER] # Without Redis: schedules use polling, voice sessions are unavailable. REDIS_URL="redis://localhost:6379" # ── Authentication [REQUIRED] ─────────────────────────────────────────────── # Secret used to sign JWTs and derive AES-256-GCM encryption keys. # MUST be at least 32 characters. Use cryptographically random bytes. # Generate with: openssl rand -base64 32 # WARNING: Changing this invalidates all existing JWTs and encrypted API keys. # Production: use a strong, unique value. Never reuse across environments. AUTH_SECRET="change-me-to-a-random-32-char-secret" # Base URL for auth callbacks (used by the frontend). # Development: http://localhost:3000 # Production: https://your-domain.com AUTH_URL="http://localhost:3000" # ── LLM Providers ─────────────────────────────────────────────────────────── # JAK Swarm supports OpenAI and Gemini as LLM execution providers. # Set LLM_PROVIDER to select the active provider (default: existing = OpenAI). # Provider selection: 'existing' (OpenAI, default) or 'gemini' # LLM_PROVIDER="existing" # OpenAI [REQUIRED] -- default LLM provider for orchestrators, workers, and vision # Get your key at: https://platform.openai.com/api-keys # Format: sk-... (starts with "sk-") OPENAI_API_KEY="sk-..." # Company Brain vector retrieval (C3). OFF by default (lexical+graph). Set to 1 to enable # real OpenAI embeddings (requires OPENAI_API_KEY), or "deterministic" for a no-key # bag-of-words stand-in used in tests/dev. # COMPANY_BRAIN_EMBEDDINGS=1 # Gemini [OPTIONAL] -- required when LLM_PROVIDER=gemini # Get your key at: https://aistudio.google.com/apikey # Format: AIza... (starts with "AIza") # GEMINI_API_KEY="AIza..." # GEMINI_MODEL="gemini-2.5-flash" # GEMINI_REQUEST_TIMEOUT_MS=60000 # OpenAI default model. [OPTIONAL] # Defaults in code: GPT-5.5 for tier-3 orchestration, GPT-5.4 for tier-1/2 workers. # Override only when intentionally testing a newer OpenAI model. OPENAI_MODEL="gpt-5.4" # OpenAI Organization ID. [OPTIONAL] # Only needed if your key belongs to multiple orgs. OPENAI_ORG_ID="" # ── Google ADK Orchestration + Grounding ───────────────────────────────── # These flags control the Google Agents Challenge integration. # All are optional — the system works without them using the default LangGraph path. # Google ADK orchestration mode. When set to "1", workflows route through # @google/adk's SequentialAgent + ParallelAgent pipeline instead of LangGraph. # Falls back to LangGraph on ADK error or when not set. # JAK_ADK_MODE="1" # Google Search Grounding for Gemini. When set to "1" and LLM_PROVIDER=gemini, # injects { googleSearch: {} } into the Gemini API tools array for real-time, # citation-backed web search. Free — no Serper/Tavily keys needed. # GEMINI_GOOGLE_SEARCH_GROUNDING="1" # Vertex AI Search datastore path. When set and LLM_PROVIDER=gemini, injects # { vertex_ai_search: { datastore } } into the Gemini API tools array for # enterprise RAG over your own data. Format: projects/PROJECT/locations/LOCATION/dataStores/STORE # GEMINI_VERTEX_AI_SEARCH_DATASTORE="" # OpenAI web_search_preview hosted tool. When set to "1" and LLM_PROVIDER=openai, # enables the native web_search_preview tool for real-time web search. Free — no # external search API keys needed. # OPENAI_WEB_SEARCH="1" # ── Voice Pipeline [OPTIONAL] ────────────────────────────────────────────── # Enables real-time voice interaction. Requires Redis for session storage. # OpenAI Realtime API model for WebRTC voice sessions. # Only change if OpenAI releases a newer realtime model. OPENAI_REALTIME_MODEL="gpt-4o-realtime-preview" # Deepgram -- speech-to-text adapter [OPTIONAL] # Get your key at: https://console.deepgram.com/ # Used as an alternative STT backend to OpenAI's built-in transcription. DEEPGRAM_API_KEY="" # ElevenLabs -- text-to-speech adapter [OPTIONAL] # Get your key at: https://elevenlabs.io/api # Voice ID: find available voices in your ElevenLabs dashboard. ELEVENLABS_API_KEY="" ELEVENLABS_VOICE_ID="" # ── Email -- Gmail IMAP/SMTP [OPTIONAL] ──────────────────────────────────── # Without these, the email agent uses mock adapters (no real emails sent). # To enable real Gmail: # 1. Enable 2FA on your Google account # 2. Go to https://myaccount.google.com/apppasswords # 3. Generate an app password for "Mail" # 4. Paste the 16-character app password below (spaces are fine) # # IMPORTANT: This is NOT your Gmail login password. It's the app-specific # password generated in step 3. Your regular password will NOT work. GMAIL_EMAIL="" GMAIL_APP_PASSWORD="" # ── Calendar -- CalDAV [OPTIONAL] ────────────────────────────────────────── # Without these, the calendar agent uses mock adapters. # For Google Calendar via CalDAV: # URL: https://apidata.googleusercontent.com/caldav/v2 # Username: your Gmail address # Password: same app password as Gmail IMAP (or a separate one) CALDAV_URL="" CALDAV_USERNAME="" CALDAV_PASSWORD="" # ── Billing -- Paddle [OPTIONAL] ─────────────────────────────────────────── # Paddle handles payments, tax, and acts as merchant of record. # Create account at: https://vendors.paddle.com # Webhook secret: Paddle dashboard > Developer Tools > Notifications > Secret key PADDLE_WEBHOOK_SECRET="" PADDLE_PRICE_PRO="" # Price ID for Pro plan (pri_xxxxx) PADDLE_PRICE_TEAM="" # Price ID for Team plan PADDLE_PRICE_ENTERPRISE="" # Price ID for Enterprise plan # Frontend Paddle checkout links (set these in Vercel env vars too) NEXT_PUBLIC_PADDLE_PRO_LINK="" # Paddle checkout URL for Pro NEXT_PUBLIC_PADDLE_TEAM_LINK="" # Paddle checkout URL for Team # ── Application ──────────────────────────────────────────────────────────── # Environment. [OPTIONAL] # development: verbose logging, mock adapter fallbacks # production: optimized logging, stricter validation NODE_ENV="development" # API server port. [OPTIONAL] # The Fastify API server listens on this port. API_PORT=4000 # Frontend API URL. [OPTIONAL] # The Next.js dashboard calls this URL for all API requests. # Must match the API server's actual address. # Production: https://api.jakswarm.com NEXT_PUBLIC_API_URL="http://localhost:4000" # Frontend app URL. [OPTIONAL] # Used for CORS and auth callback URLs. # Production: https://jakswarm.com NEXT_PUBLIC_APP_URL="http://localhost:3000" # Logging level. [OPTIONAL] # Options: trace, debug, info, warn, error, fatal # Development: info or debug # Production: warn or error LOG_LEVEL="info" # Approval policy. [OPTIONAL] # When true, WRITE-level and above tool executions require human approval. # When false, only DESTRUCTIVE and EXTERNAL_SIDE_EFFECT require approval. # Production recommendation: true (safer default) DEFAULT_APPROVAL_REQUIRED=true # ── WhatsApp Control (QR-based, no Twilio) [OPTIONAL] ───────────────────── # Uses a local WhatsApp Web client (Baileys) that you pair via QR code. # Start the client with: # pnpm --filter @jak-swarm/whatsapp-client dev # API base URL the WhatsApp client calls for command execution. WHATSAPP_API_URL="http://localhost:4000" # Auto-start the WhatsApp client when the API boots. [OPTIONAL] # In production, keep this off unless you run the API and client on the same host. WHATSAPP_AUTO_START=1 # Port for the WhatsApp client's QR/status HTTP server. WHATSAPP_CLIENT_PORT=47891 # Host for the WhatsApp client's QR/status HTTP server. # Default: 127.0.0.1 (local-only) WHATSAPP_CLIENT_HOST=127.0.0.1 # Directory to persist WhatsApp auth (keep this private). WHATSAPP_AUTH_DIR="./.whatsapp-auth" # Shared bearer token for WhatsApp bridge auth (REQUIRED to accept commands). WHATSAPP_BRIDGE_TOKEN="change-me-to-a-random-secret" # Per-number tenant mapping (required for command execution). # Format: "+14155551234:tenantId:userId,+442071838750:tenantId:userId" # If empty, users can register their WhatsApp number from the dashboard and verify via challenge code. WHATSAPP_NUMBER_MAP="" # Comma-separated E.164 numbers allowed to control workflows. # If empty, defaults to the numbers in WHATSAPP_NUMBER_MAP. WHATSAPP_ALLOWED_NUMBERS="" # ── Supabase [REQUIRED for production] ──────────────────────────────────── # Supabase provides authentication and PostgreSQL database. # Create a project at https://supabase.com/dashboard # Find these values in Settings > API Keys and Settings > Database # Supabase project URL and publishable (anon) key — used by the frontend NEXT_PUBLIC_SUPABASE_URL= # https://yourproject.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY= # your publishable/anon key (sb_publishable_...) # Database connection strings (from Supabase > Connect > ORM > Prisma) # DATABASE_URL uses connection pooling (for application queries) # DIRECT_URL is for Prisma migrations (bypasses pooler) # Replace [YOUR-PASSWORD] with the database password you set when creating the project # DATABASE_URL="postgresql://postgres.YOURREF:[YOUR-PASSWORD]@aws-0-REGION.pooler.supabase.com:6543/postgres?pgbouncer=true" # DIRECT_URL="postgresql://postgres.YOURREF:[YOUR-PASSWORD]@aws-0-REGION.pooler.supabase.com:5432/postgres"