# ════════════════════════════════════════════════════════════════════════════ # Bee — Workspace .env (canonical secrets) # ════════════════════════════════════════════════════════════════════════════ # # This file is the SINGLE SOURCE OF TRUTH for environment variables shared # between: # # • Python backend (`bee/*` — daemon, server, training, etc.) # • Next.js portal (`apps/portal/*` — pricing, billing, QNSP UI) # # How it's loaded # ─────────────── # • Python reads /Users/.../Bee/.env directly via dotenv. # • Portal reads /Users/.../Bee/.env via the symlink # `apps/portal/.env -> ../../.env`. # Next.js then layers `apps/portal/.env.local` on top # for any portal-only overrides (e.g. SMTP, dev flags). # # Precedence (highest first, per Next.js convention): # 1. process.env (Vercel / shell) # 2. apps/portal/.env.{NODE_ENV}.local # 3. apps/portal/.env.local ← portal overrides # 4. apps/portal/.env.{NODE_ENV} # 5. apps/portal/.env (symlink → THIS file) # # Local setup # ─────────── # 1. cp .env.example .env (this file → live secrets) # 2. Fill in every required value. # 3. ln -sf ../../.env apps/portal/.env (one-time symlink) # 4. cp apps/portal/.env.example apps/portal/.env.local (portal overrides) # 5. Fill in SMTP_* and any portal-only overrides. # # Production (Vercel) # ─────────────────── # Every key here belongs in Vercel → Project → Environment Variables, with # identical names. The symlink + .env.local pattern is local-dev only; # Vercel injects via process.env directly. # # Security # ──────── # • This file is in `.gitignore`. NEVER commit secrets. # • Every secret should have an "owner" comment indicating which team / # vault provides it (QNSP Ops, Stripe Dashboard, Supabase Dashboard, etc.) # • Rotate any secret on suspected compromise. The QNSP partner secret # and BEE_PARTNER_OUTBOUND_SIGNING_SECRET have a ROLLING-WINDOW caveat # documented in `docs/integrations/qnsp-partner.md`. # # Adding a new key # ──────────────── # 1. Add the placeholder line here in the right section. # 2. Add the real value to the live `.env` (this same file but with values). # 3. Mirror to Vercel → Project → Environment Variables. # 4. If the portal needs a different value in dev, set it in # `apps/portal/.env.local` (overrides this file). # ════════════════════════════════════════════════════════════════════════════ # 1. Workspace identity (public URLs) # ════════════════════════════════════════════════════════════════════════════ # Public site URL. Used by the portal for OG tags, password-reset links, # email canonicalisation. NEXT_PUBLIC_ → exposed to the browser. # Production: https://bee.cuilabs.io # Local dev: http://localhost:3000 NEXT_PUBLIC_SITE_URL=http://localhost:3000 # Bee Python backend URL. Server-side only — the portal proxies all client # traffic through internal /api routes; the backend URL is never exposed. # Production: https://cuilabs-bee.hf.space (HuggingFace Space, always-on) # Local dev: http://localhost:8000 (when running `python -m bee`) BEE_API_URL=https://cuilabs-bee.hf.space # ════════════════════════════════════════════════════════════════════════════ # 2. Supabase / Postgres # ════════════════════════════════════════════════════════════════════════════ # Source: Supabase Dashboard → Project Settings → API + Database # # IMPORTANT: the portal does NOT use the Supabase JS client for hot-path # queries. It uses a pg-shim (`apps/portal/src/lib/db.ts`) with a # Supabase-JS-compatible API surface, talking directly to the pg pooler. # This bypasses the egress-quota restriction on PostgREST. Auth is also # verified locally with SUPABASE_JWT_SECRET — never via GoTrue REST. # Public-facing (browser-readable): NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ... # anon role; safe in client # Server-side keys (never exposed to the browser): SUPABASE_SERVICE_ROLE_KEY=eyJ... # full DB access; pg-shim uses this SUPABASE_JWT_SECRET= # HS256 secret for local cookie verify (lib/auth-jwt.ts) SUPABASE_PUBLISHABLE_KEY= # alias / legacy SUPABASE_SECRET_KEY= # alias / legacy # Direct Postgres pooler connection (used by lib/db.ts): POSTGRES_HOST= POSTGRES_DATABASE= POSTGRES_USER= POSTGRES_PASSWORD= POSTGRES_URL= # pooled (pgbouncer transaction mode) POSTGRES_URL_NON_POOLING= # session pooler — used for migrations + lib/db.ts POSTGRES_PRISMA_URL= # alias # ════════════════════════════════════════════════════════════════════════════ # 3. Stripe (billing) # ════════════════════════════════════════════════════════════════════════════ # Source: https://dashboard.stripe.com → Developers → API keys + Webhooks # Test keys: sk_test_ / pk_test_ Live keys: sk_live_ / pk_live_ # # Webhook setup: # 1. Add endpoint: https://bee.cuilabs.io/api/webhooks/stripe # 2. Subscribe to: customer.subscription.{created,updated,deleted}, # invoice.payment_succeeded, checkout.session.completed # 3. Copy whsec_… into STRIPE_WEBHOOK_SECRET below. STRIPE_SECRET_KEY= # sk_test_… or sk_live_… STRIPE_WEBHOOK_SECRET= # whsec_… signs Stripe → Bee deliveries NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= # pk_test_… or pk_live_… # ════════════════════════════════════════════════════════════════════════════ # 4. QNSP Partner Integration (Bee ↔ QNSP) # ════════════════════════════════════════════════════════════════════════════ # Owner: QNSP Ops team (CUI Labs internal). Delivered out-of-band. # Wire contract: docs/integrations/qnsp-partner.md # Commercial model: Phase 1–3 — see same doc, "Commercial model" section. # # These credentials let the Bee portal: # • Mint Dilithium2-signed JWTs against QNSP's auth-service. # • POST /provision and /deprovision when a Bee plan with non-null # qnsp_plan_name changes state (catalog.v2.ts). # • Verify HMAC signatures on inbound webhooks from QNSP. # Outbound (Bee calls QNSP): QNSP_PARTNER_BASE_URL=https://api.qnsp.cuilabs.io # edge gateway; never the cloud frontend QNSP_PARTNER_CLIENT_ID=bee-partner # service-account name on QNSP side QNSP_PARTNER_CLIENT_SECRET= # 64-char URL-safe random; mints JWTs # Inbound (QNSP calls Bee, /api/webhooks/qnsp): BEE_PARTNER_OUTBOUND_SIGNING_SECRET= # shared HMAC key; QNSP signs deliveries # Customer-facing QNSP (legacy / portal-side KMS — independent of partner integration above): QNSP_API_KEY= # required to activate cloud KMS QNSP_TENANT_ID= # your QNSP tenant UUID QNSP_KMS_KEY_ID= # KMS key UUID for key wrapping # ════════════════════════════════════════════════════════════════════════════ # 5. Cron / scheduled jobs (Bee-side, self-managed) # ════════════════════════════════════════════════════════════════════════════ # Bearer token the cron caller (Vercel Cron, GitHub Actions, etc.) presents # at /api/cron/qnsp-reconcile. Constant-time-compared on the route. Rotate # freely — independent of QNSP-team-managed secrets above. # Generate: openssl rand -base64 48 CRON_SECRET= # ════════════════════════════════════════════════════════════════════════════ # 6. Bee runtime (Python backend — `python -m bee`) # ════════════════════════════════════════════════════════════════════════════ BEE_HOST=0.0.0.0 BEE_PORT=8000 BEE_DEVICE=auto # auto detects MPS on Apple Silicon BEE_CORS_ORIGINS=https://bee.cuilabs.io,http://localhost:3000 # Ignition: ON by default in daemon mode. For legacy `python -m bee.server`, # set BEE_IGNITE=1 explicitly. BEE_IGNITE=1 BEE_IGNITE_PRESET=360m # 360m (any) | 1.7b (8GB+) | 7b (16GB+) # BEE_BASE_MODEL=Qwen/Qwen2.5-3B-Instruct # recommended for M4 Max / 16GB+ RAM # Model + adapters BEE_MODEL_PATH=HuggingFaceTB/SmolLM2-360M-Instruct BEE_LORA_DIR=./lora_checkpoints # Persistence BEE_DATASETS_DIR=./datasets BEE_INTERACTIONS_DIR=./datasets BEE_RAG_DIR=./rag_index BEE_EVOLUTION_DIR=./evolution_state # API auth (Bee's own Python API; separate from Stripe/QNSP) BEE_API_KEYS= # ════════════════════════════════════════════════════════════════════════════ # 7. Bee external API keys (LLM teachers — distillation + evolution) # ════════════════════════════════════════════════════════════════════════════ # Setting at least one of these unlocks autonomous training-data generation. # Without them the daemon falls back to local-only evolution (slower). BEE_TEACHER_API_URL=https://api.anthropic.com/v1 BEE_TEACHER_API_KEY= BEE_TEACHER_MODEL=claude-sonnet-4-20250514 BEE_OPENAI_API_KEY= BEE_GOOGLE_API_KEY= BEE_DEEPSEEK_API_KEY= # ════════════════════════════════════════════════════════════════════════════ # 8. ML platforms / quantum # ════════════════════════════════════════════════════════════════════════════ # HuggingFace Hub (model + dataset uploads) HF_TOKEN= # IBM Quantum (real 156-qubit Heron r2 access; ~10 min/month free) # Without this, Bee uses local quantum simulator only. IBM_QUANTUM_API_KEY= # Kaggle (datasets only) KAGGLE_USERNAME= KAGGLE_KEY= KAGGLE_API_TOKEN= # ════════════════════════════════════════════════════════════════════════════ # 9. Email confirmation + transactional email (Bee-side, self-managed) # ════════════════════════════════════════════════════════════════════════════ # Used by /api/auth/signup → confirmation email → /auth/confirm flow. # Sends through the Bee SMTP (SMTP_* below) so the From: address is # bee-noreply@cuilabs.io rather than Supabase's free-tier sender. # HMAC secret for email-confirmation tokens. Independent of # SUPABASE_JWT_SECRET so we can rotate without invalidating sessions. # Generate: openssl rand -base64 4# Generate: openssl rand -base64 4# Generate: opens 1 / true → require email confirmation on every new signup (default in prod). # 0 / unset → auto-confirm immediately (legacy / local-dev only). AUTH_REQUIRE_EMAIL_CONFIRMATION=1 # Default token TTL in seconds (clamped 60s … 7 days). Default 86400 (24 h). # EMAIL_CONFIRM_TTL_SECONDS=86400 # ── Outbound SMTP (transactional + auth emails) ──────────────────────────── # Namecheap Private Email is the canonical setup; any RFC-5321 SMTP host # works. SMTP_FROM_ADDRESS must match the SMTP_USER's domain (server # rewriting is permitted within the authenticated domain). SMTP_HOST=premium41.web-hosting.com SMTP_PORT=465 SMTP_SECURE=true # true for port 465 (implicit TLS); false for 587 (STARTTLS) SMTP_USER=bee-noreply@cuilabs.io SMTP_PASSWORD= SMTP_FROM_NAME=Bee SMTP_FROM_ADDRESS=bee-noreply@cuilabs.io # ════════════════════════════════════════════════════════════════════════════ # 10. OAuth providers (Google / GitHub / Microsoft) # ════════════════════════════════════════════════════════════════════════════ # Implemented natively (no Supabase GoTrue dependency). Each provider is # enabled when its CLIENT_ID + CLIENT_SECRET are both set; otherwise the # corresponding "Continue with X" button is hidden client-side. # # Redirect URIs to register at each provider's developer console: # Google: {NEXT_PUBLIC_SITE_URL}/auth/oauth/google/callback # GitHub: {NEXT_PUBLIC_SITE_URL}/auth/oauth/github/callback # Microsoft: {NEXT_PUBLIC_SITE_URL}/auth/oauth/microsoft/callback # # Walkthrough: docs/operations/infrastructure.md → "OAuth providers". # Google — https://console.cloud.google.com/apis/credentials → Create OAuth # 2.0 Client ID → Web application → add the redirect URI above. GOOGLE_OAUTH_CLIENT_ID= GOOGLE_OAUTH_CLIENT_SECRET= # GitHub — https://github.com/settings/developers → New OAuth App. GITHUB_OAUTH_CLIENT_ID= GITHUB_OAUTH_CLIENT_SECRET= # Microsoft — https://portal.azure.com → Microsoft Entra ID → App # registrations → New registration. Supported account types: # "Accounts in any organizational directory and personal Microsoft accounts" # for the most permissive setup. Add the redirect URI under Authentication # → Platform configurations → Web. MICROSOFT_OAUTH_CLIENT_ID= MICROSOFT_OAUTH_CLIENT_SECRET= # Tenant ID. "common" = work/school + personal accounts; "consumers" = # personal only; "organizations" = work/school only; or a specific GUID # for single-tenant apps. Default: "common". MICROSOFT_OAUTH_TENANT=common # ── Sentry — error tracking (free tier, errors-only, no perf/replays) ── # Org: cuilabs (us.sentry.io). Auth tokens are server/build-time only; # DSNs are public and safe to ship to clients. Errors-only by config — # tracesSampleRate=0, no replays, no profiling. Stays inside the 5K/mo # free-tier event budget for the friends-and-family beta. SENTRY_ORG=cuilabs SENTRY_AUTH_TOKEN=sntrys_ SENTRY_USER_PAT=sntryu_ SENTRY_DSN_MOBILE=https://@us.sentry.io/ SENTRY_DSN_WEB=https://@us.sentry.io/ SENTRY_DSN_BACKEND=https://@us.sentry.io/ NEXT_PUBLIC_SENTRY_DSN=https://@us.sentry.io/ # ── Mobile APK distribution (Stage 1 friends/family/PH/LinkedIn) ────── # APK_UPLOAD_SECRET — Bearer token operator passes when uploading the # Bee Android release APK to /api/admin/upload-apk. Generate fresh # (e.g. `openssl rand -hex 32`) and mirror to Vercel Production envs. APK_UPLOAD_SECRET= # BLOB_READ_WRITE_TOKEN — Vercel Blob token. Auto-injected by Vercel for # deployed routes; needed locally for `vercel blob put` CLI in # scripts/upload_apk.sh and apps/mobile/scripts/release-android.sh. BLOB_READ_WRITE_TOKEN=