# Shuna config. Copy to .env and fill in. Commit THIS file, not .env. DATABASE_URL=postgresql+psycopg://shuna:CHANGEME@db:5432/shuna POSTGRES_USER=shuna POSTGRES_PASSWORD=CHANGEME POSTGRES_DB=shuna TZ=America/New_York # Ollama endpoint (used when AI features are enabled; see F6 opt-out). OLLAMA_URL=http://localhost:11434 OLLAMA_MODEL=qwen2.5:7b OLLAMA_VISION_MODEL=qwen2.5vl:7b OLLAMA_AGENT_MODEL=hermes3:8b # Remix diff model chain (first success wins): fast cloud -> capable cloud -> local # fallback (OLLAMA_AGENT_MODEL) so remix still works offline. Ollama cloud = free tier. OLLAMA_REMIX_MODEL=gemma4:31b-cloud OLLAMA_REMIX_FALLBACK=gpt-oss:120b-cloud # Global cap on in-flight AI requests across all users (protects the shared GPUs). # Excess requests wait AI_ACQUIRE_TIMEOUT_S then get a 503. 2 = OLLAMA_MAX_LOADED_MODELS. AI_MAX_CONCURRENCY=2 AI_ACQUIRE_TIMEOUT_S=30 KROGER_CLIENT_ID= KROGER_CLIENT_SECRET= KROGER_LOCATION_ID= KROGER_ZIP= # Home Assistant shopping-list export (F4). HA_TOKEN is a long-lived access token. HA_BASE_URL=http://homeassistant.local:8123 HA_TOKEN= HA_TODO_ENTITY=todo.shopping_list # SSRF control for the household-set HA export URL. Leave true for self-hosting: your Home # Assistant is on a private LAN address, so the export must be allowed to reach it. Set to # false ONLY on a public multi-tenant instance, where an authenticated user's HA URL must # resolve to a public address (otherwise they could make the server hit your internal network). ALLOW_PRIVATE_EXPORT_TARGETS=true # --- App-native login (app/auth.py) --- # Auth is ENABLED when AUTH_SECRET *or* AUTH_PASSWORD is set. For a self-host, set only # AUTH_SECRET (a random signing key) and leave AUTH_PASSWORD blank: the FIRST person to # sign up in the web UI becomes the admin, no env account needed. Leave BOTH blank for an # open, login-less LAN. AUTH_PASSWORD is a recovery fallback (env-bootstrap admin) only. # Generate a secret with: # python3 -c "import secrets; print(secrets.token_hex(32))" AUTH_USERNAME=admin AUTH_PASSWORD= AUTH_SECRET= AUTH_TOKEN_DAYS=30 # HOSTED_MODE gates public-instance-only surfaces (waitlist, AI-access request/approval, # gated self-serve signups). Self-hosters leave this false. the operator's shunaapp.com sets true. HOSTED_MODE=false # Registration mode. false (default) = invite-only: signup requires a household join # code. Set true only to allow public self-serve signup (do this once PRIVACY.md + # TERMS.md are live and you intend to accept data from the general public). SIGNUP_OPEN=false # Comma-separated allowed CORS origins (empty -> '*'). Same-origin in prod makes this # mostly moot; lock to your real origins. CORS_ORIGINS=http://localhost:8771 # --- Email (Resend via SMTP; app/email.py). Unset = email off (signups auto-verify, # links logged not sent). Get an API key at resend.com + add the DNS records it shows. --- APP_BASE_URL=https://shuna.example.com SMTP_HOST=smtp.resend.com SMTP_PORT=587 SMTP_USER=resend SMTP_PASSWORD= EMAIL_FROM=Shuna # Operator inbox for contact-form / waitlist notices. Empty -> those are logged, not sent. CONTACT_EMAIL= # Postal address for the CAN-SPAM email footer. Empty -> the footer omits the line. # Recommended if you send real mail to the public; not needed for a private LAN install. EMAIL_POSTAL_ADDRESS=