- Node.js 22+ (CI runs on 22; 20+ works locally)
- Expo CLI (
npm install -g expo-cli) - Supabase CLI (
npm install -g supabase) - A Supabase project with pgvector enabled
- OpenAI API key (for embeddings + Whisper voice transcription)
- Google AI (Gemini) API key
npm install
cd scripts && npm install && cd ..Copy the example files and fill in your credentials:
cp .env.example .env
cp scripts/.env.example scripts/.envEdit .env (client environment):
EXPO_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
EXPO_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
EXPO_PUBLIC_OPENAI_KEY=your-openai-key # Required for voice-to-text on iOS/Android
EXPO_PUBLIC_DEV_BYPASS=your-dev-secret # Remove for production builds
Edit scripts/.env (server/ingestion environment):
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
OPENAI_API_KEY=your-openai-key
See ENVIRONMENT.md for a full description of every variable.
Apply all migrations in order via supabase db push or your Supabase SQL Editor:
supabase/migrations/20260402080000_initial_schema.sql— Tables, indexes, RLS, hybrid search functionsupabase/migrations/20260402081000_rate_limits.sql— Rate limiting, response cache, global usagesupabase/migrations/20260403010000_user_verse_data.sql— Highlights, bookmarks, and notes tablessupabase/migrations/20260524000000_backend_hardening.sql— Security hardening, FK constraints, triggerssupabase/migrations/20260524000001_optimize_embeddings.sql— halfvec migration, IVFFlat index rebuild
Enable Anonymous Sign-Ins in Supabase Dashboard > Authentication > Providers.
Set your backend secrets via the Supabase CLI:
supabase secrets set \
OPENAI_API_KEY="your-key" \
GEMINI_API_KEY="your-key" \
DEV_BYPASS_SECRET="your-secret"supabase functions deploy chat --no-verify-jwtThis fetches the entire BSB Bible from bible.helloao.org, generates embeddings via OpenAI, and upserts to Supabase. Takes ~20 minutes, costs ~$0.02. Result: 31,086 verses across all 66 books.
cd scripts
npx tsx ingest.tsIf some books are missing verses (e.g. after an interrupted run), use the targeted fix script:
cd scripts
npx tsx fix-incomplete.ts# Mobile (iOS/Android via Expo Go)
npx expo start
# Web browser
npx expo start --web
# Desktop (requires Rust installed)
npm run desktop