# Bothy runtime configuration. Copy to `.env` and fill in. NEVER commit `.env` # (`.gitignore` + `scripts/check-secrets.sh` refuse it). # --- Database ---------------------------------------------------------------- # Default: a remote Postgres (Docker + PostGIS) reached over an SSH tunnel to # localhost:5433 (start with: scripts/db-tunnel.sh). The DB is NOT exposed # publicly - it binds to 127.0.0.1 on the server. DATABASE_URL=postgres://bothy:bothy@localhost:5433/bothy # For a fully local install instead: npm run db:local -> :5432 # DATABASE_URL=postgres://bothy:bothy@localhost:5432/bothy # --- LLM provider chain ------------------------------------------------------- # Providers are tried in order; the first that works wins (its result is # rate-limited and cached). If none respond, the agent falls back to its # deterministic scripted brain (no key needed). BOTHY_LLM_PROVIDERS=nebius,qwen-hf,venice,openrouter,openai,ollama BOTHY_LLM_MAX_TOKENS=1500 BOTHY_LLM_TIMEOUT=25000 # Nebius Token Factory (opt-in CONNECTED/cloud mode, not offline). # Copy the endpoint and verified NVIDIA model ID from the current catalogue. # All three values are required. No live/eligible integration is claimed yet. NEBIUS_API_KEY= NEBIUS_BASE_URL= NEBIUS_MODEL= NEBIUS_TIMEOUT=25000 # NEBIUS_RPM=20 # NEBIUS_BURST=4 # Nemotron-3 reasons before emitting content — keep "low" so claim/critique # prompts answer directly; a higher effort spends tokens on reasoning first. # NEBIUS_REASONING=low # To make Nebius the primary lane, prepend it to the provider order: # BOTHY_LLM_PROVIDERS=nebius,ollama # Fallback order stays Nebius → Ollama → scripted — the audited path is # identical regardless of which provider answers (citations never model-owned). # Venice AI (optional - set a dedicated VENICE_API_KEY; never commit it) VENICE_API_KEY= VENICE_BASE_URL=https://api.venice.ai/api/v1 VENICE_MODEL=venice-uncensored VENICE_TIMEOUT=60000 # VENICE_RPM=20 # VENICE_BURST=6 # Qwen3.8-27B - free public Hugging Face endpoint, OpenAI-compatible, no key. QWEN_HF_URL=https://g9hnto0u7lvbu837.us-east-2.aws.endpoints.huggingface.cloud/v1 QWEN_HF_MODEL=Qwen/Qwen3.8-27B QWEN_REASONING=low # none | low | medium | high | xhigh (dial thinking) # QWEN_HF_RPM=24 # QWEN_HF_BURST=12 # OpenRouter free tier (optional - set the key to enable) OPENROUTER_API_KEY= OPENROUTER_MODEL=meta-llama/llama-3.1-8b-instruct:free # Any OpenAI-compatible endpoint (vLLM, Groq, Together, local proxy, ...) OPENAI_BASE_URL= OPENAI_API_KEY= OPENAI_MODEL=gpt-4o-mini # Local Ollama (optional - set OLLAMA_BASE_URL to enable) OLLAMA_BASE_URL= OLLAMA_MODEL=qwen3:8b # --- Agent / web --------------------------------------------------------- PORT=8787 # Set 127.0.0.1 for local-only API smoke tests; containers use 0.0.0.0. AGENT_HOST=0.0.0.0 AGENT_URL=http://localhost:8787 # Browser origin permitted to call the agent directly; set this for deployment. WEB_ORIGIN=http://localhost:8477 # Public web origin used in digest links (case pages). Set for deployment. PUBLIC_WEB_URL=http://localhost:3000 # Agent URL for Next.js rewrite. Local: http://localhost:8787 # Fly.io/VPS internal network: http://bothy-agent.internal:8787 AGENT_URL=http://localhost:8787 # --- OIDC review adapter (all blank = approval/simulation disabled) ------------ # Use HTTPS issuer/JWKS URLs and a dedicated API access-token audience, not # the browser login client ID. RS256/ES256 only; exp/iat/sub are required. # Roles come from this server-side subject allowlist, never token/body roles. # Obtain API access tokens through an approved SSO client/session bridge. # Do not paste tokens into the UI, store them in localStorage, or log them. BOTHY_OIDC_ISSUER= BOTHY_OIDC_AUDIENCE= BOTHY_OIDC_JWKS_URL= BOTHY_OIDC_PRINCIPALS= # Optional disposable local rehearsal only; requires NODE_ENV=development and # loopback issuer/JWKS. Production always rejects HTTP. See scripts/demo-sso.mjs. # BOTHY_OIDC_ALLOW_LOCAL_DEMO=false # Example shape, fictitious subjects only: # BOTHY_OIDC_PRINCIPALS='{"analyst-sub":["analyst"],"reviewer-sub":["reviewer"],"owner-sub":["action-owner"]}' # --- Browser SSO session bridge (web app :3001) -------------------------------- # The web app is a backend-for-frontend: it performs authorization-code + PKCE # against your IdP, keeps the access token in an encrypted HttpOnly cookie, and # forwards it to the agent as `Authorization: Bearer`. The browser never holds a # token, and the agent never sees a cookie. # # PREREQUISITE: this requires a *confidential* OIDC client able to obtain a # token for a dedicated API audience. A browser-only (public/SPA) client # registration usually cannot mint one, and must not be copied here. # Blank values disable sign-in: /api/auth/login returns 503 and review stays off. # All endpoints must be HTTPS. Plain http://localhost is allowed only when # NODE_ENV is not production. BOTHY_SSO_AUTHORIZE_URL= BOTHY_SSO_TOKEN_URL= BOTHY_SSO_CLIENT_ID= BOTHY_SSO_CLIENT_SECRET= # The API access-token audience. This must match BOTHY_OIDC_AUDIENCE on the # agent. Never put the browser client id here. BOTHY_SSO_AUDIENCE= # Optional RFC 8707 resource indicator for providers that require it. # BOTHY_SSO_RESOURCE= # Optional; defaults to "openid profile email". # BOTHY_SSO_SCOPE= # Must match the registered redirect: /api/auth/callback BOTHY_SSO_REDIRECT_URI=http://localhost:3001/api/auth/callback # >= 32 random characters, server-only. Encrypts the session cookie. Rotating it # invalidates every signed-in session (fail-closed, by design). # node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))" BOTHY_SESSION_SECRET= # --- Digest (watch-my-road) ---------------------------------------------------- # Resend free tier (or leave blank for log-only queue mode in dev). RESEND_API_KEY= DIGEST_FROM=Bothy DIGEST_TOKEN= PUBLIC_APP_URL=http://localhost:3000 # --- Live weather context ---------------------------------------------------- # No key required for Open-Meteo's non-commercial public API. OPEN_METEO_BASE_URL=https://api.open-meteo.com/v1/forecast # --- Case memory (Meterless H-MEM, vendored engine) -------------------------- # Directory for memory state.json + ledger.jsonl; defaults to BOTHY_DATA_DIR/hmem. # BOTHY_HMEM_DIR= # LLM-backed memory mining through the provider chain ("llm") or the engine's # deterministic model-free path (default/unset). # BOTHY_HMEM_MINER=llm # Model-drafted claim text for captured federated rows via the provider chain # ("llm"). Citations stay deterministic; per-row failure falls back to # scripted text. Default/unset: fully deterministic briefs. # BOTHY_BRIEF_ASSIST=llm # --- Zetaris federation (defence path; inert until configured) --------------- # Instance origin (local :3000, AWS cluster host, or SSH tunnel to the VPS). ZETARIS_REST_URL= # API key created in the Zetaris GUI. Never commit a real key. ZETARIS_API_KEY= # Numeric organization id (usually 1 on a local install). ZETARIS_ORG_ID=1 # --- Self-hosted model lane (VPS Ollama, Nemotron) --------------------------- # Point the OpenAI-compatible provider at an SSH tunnel to snapflip-vultr: # ssh -L 11434:localhost:11434 snapflip-vultr # OLLAMA_BASE_URL=http://localhost:11434/v1 # OLLAMA_MODEL=nemotron-mini