# ===================================================================== # ECHODO — Environment Variables # ===================================================================== # Local dev: copy this file to .env and adjust values. # Coolify (CT 107): paste these into the resource's "Environment Variables" # tab. Coolify also accepts a .env file uploaded via the UI. # # See AGENT-DEPLOY.md for shared CT 102 service credentials and the # CT 100 Traefik routing pattern. # ===================================================================== # ----- Database (CT 102 shared Postgres) ----- # The database name is `echodo` everywhere — local dev, Coolify, and the # drizzle migration ledger all assume it. Do NOT use `tasks` (an early # pre-rename name); see commit 93565cd and the 2026-06 drift incident for # why a parallel `tasks` DB caused production OAuth to look broken when # it was really just connected to an empty schema. # # Local dev (Docker compose): postgresql://postgres:postgres@localhost:5432/echodo # Production (Coolify, CT 102): dedicated `echodo` user/db on shared Postgres DATABASE_URL="postgresql://echodo:CHANGE_ME@192.168.68.102:5432/echodo" # UUID of the workspace that owns imported `plans/` rows (slug or UUID from Settings). # For dogfooding this repo, use the `convoys-tasks` workspace id. # Required by `pnpm --filter @tasks/database import:markdown-backlog` and # `watch:markdown-backlog` (not loaded automatically — set in `.env`). MARKDOWN_BACKLOG_WORKSPACE_ID="00000000-0000-0000-0000-000000000000" # ----- Redis (CT 102 shared Redis) ----- # Use a dedicated DB index per AGENT-DEPLOY.md (ECHODO uses /11) # Local dev: redis://localhost:6379 REDIS_URL="redis://:CHANGE_ME@192.168.68.102:6379/11" # ----- Orchestrator (apps/orchestrator) ----- # ORCHESTRATOR_DRY_RUN=1 logs dispatch/transition without Redis enqueue # ORCHESTRATOR_POLL_MS=5000 # ORCHESTRATOR_STALL_MINUTES=120 # ORCHESTRATOR_MAX_IMPLEMENTERS=2 # ----- Worker (apps/worker) ----- # WORKER_DRY_RUN=1 skips Redis dequeue loop # WORKER_BLPOP_TIMEOUT_S=5 # WORKER_MAX_TOOL_STEPS=12 # WORKER_REPO_ROOT= # defaults to monorepo root (pnpm-workspace.yaml walk-up) # WORKER_WORKTREE_BASE=/tmp/echodo-worker-worktrees # ----- Auth (NextAuth v5) ----- # Local: http://localhost:3000 • Prod: https://echodo.stillwell.cloud NEXTAUTH_URL="http://localhost:3000" # Generate with: openssl rand -base64 32 NEXTAUTH_SECRET="CHANGE_ME_RUN_openssl_rand_base64_32" AUTH_SECRET="CHANGE_ME_RUN_openssl_rand_base64_32" # Optional dev-only credentials provider (looks up users by email, # accepts this single password for everyone). Leave blank in prod. AUTH_DEV_PASSWORD="" # ----- OAuth Providers (all optional) ----- AUTH_GITHUB_ID="" AUTH_GITHUB_SECRET="" AUTH_GOOGLE_ID="" AUTH_GOOGLE_SECRET="" # Authentik SSO (CT 100 — auth.stillwell.cloud) # In Authentik admin → Applications → Create OAuth2/OpenID Provider. # Slug "echodo", redirect URI: /api/auth/callback/authentik AUTH_AUTHENTIK_ID="" AUTH_AUTHENTIK_SECRET="" AUTH_AUTHENTIK_ISSUER="https://auth.stillwell.cloud/application/o/echodo/" # ----- Realtime collab server (Hocuspocus / Yjs) ----- # Server-side reference (used by Next.js server actions, if any) COLLAB_SERVER_URL="ws://localhost:1234" # Browser-facing — must be wss:// in production because the page is https NEXT_PUBLIC_COLLAB_SERVER_URL="ws://localhost:1234" # ----- Umami Analytics (CT 107 — analytics.stillwell.cloud) ----- # In Umami: Settings → Websites → Add website. Copy the website UUID. NEXT_PUBLIC_UMAMI_SCRIPT="https://analytics.stillwell.cloud/script.js" NEXT_PUBLIC_UMAMI_WEBSITE_ID="" # ----- Libredesk Support Widget (CT 105 — support.stillwell.cloud) ----- NEXT_PUBLIC_LIBREDESK_URL="https://support.stillwell.cloud" NEXT_PUBLIC_LIBREDESK_WIDGET_ID="" # ----- Directus Feedback (CT 107 — directus.stillwell.cloud) ----- # Static token scoped write-only on the `feedback` collection NEXT_PUBLIC_DIRECTUS_URL="https://directus.stillwell.cloud" DIRECTUS_FEEDBACK_TOKEN="" # ----- AI Providers ----- # Registry aliases (Epic 1) read these env var NAMES from the DB — values # live here on the server/worker host, never in Postgres. # # Local Ollama on Mac: # OPENAI_BASE_URL=http://:11434/v1 # OPENAI_API_KEY=ollama # OPENAI_MODEL=qwen2.5-coder:32b # # Local MLX (mlx-openai-server on Mac — preferred for parallel implementers): # MLX_SERVER_URL=http://:8000/v1 # MLX_API_KEY=local # (Register as openai_compatible alias qwen-coder-mlx in Settings when Epic 1 ships) # # Cloud / free-tier (see docs/adr-model-routing.md): OPENAI_API_KEY="" OPENAI_BASE_URL="" ANTHROPIC_API_KEY="" GOOGLE_GENERATIVE_AI_API_KEY="" NVIDIA_API_KEY="" # ----- MCP Server ----- MCP_SERVER_PORT=3001 # ===================================================================== # Coolify Docker Compose build (8 GB hosts) # ===================================================================== # Serialize image builds to avoid kernel OOM (exit 255) during export. # Coolify (8 GB host): set Custom Build Command to `bash scripts/build-coolify.sh` # so compose builds collab → mcp → orchestrator → worker → web sequentially. # COMPOSE_PARALLEL_LIMIT is documented for reference but the script is required. # ===================================================================== # Local Docker Compose only (docker/docker-compose.yml) # Not needed for Coolify (Coolify uses CT 102's shared Postgres/Redis). # ===================================================================== POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres # Keep this aligned with the database name in DATABASE_URL above. The # docker-compose files default to `tasks` (the old name) — override here. POSTGRES_DB=echodo POSTGRES_PORT=5432 REDIS_PORT=6379 WEB_PORT=3000 COLLAB_PORT=1234