Quickstart
Get a fully working CRTX instance — backend API, background worker, and frontend — running locally in about 15 minutes.
Want to run this for real users or inside a customer's infrastructure instead of on your laptop? See Self-hosting & deploying in your environment.
#Prerequisites
- Python 3.13+
- Node.js 20+ and Bun
- A running Redis instance (
redis://localhost:6379by default) - Accounts with:
#1. Clone
git clone https://github.com/YOUR_USERNAME/crtx.git
cd crtx
#2. Provision the external services
Pinecone. Create a serverless index (name it e.g. crtx-documents) with
dimension 1024 and metric cosine (matching text-embedding-3-small at
1024 dims). Note the index name and API key.
Supabase. Create a project, then:
- Copy the project URL, the service role key (server-side secret), the
anon key (client-side), and the JWKS URL
(
https://<project>.supabase.co/auth/v1/.well-known/jwks.json). - Create two Storage buckets:
documents(private — original files, served via time-limited signed URLs) andimages(public — extracted PDF figures, whose public URLs are stored in vector metadata). - Enable email/password auth.
- Create the application tables. CRTX reads/writes:
collections,collection_members,collection_shares,collection_documents,document_chunks,chat_sessions,chat_messages,ingest_jobs,rag_evals, plus thequery_logs/ingest_logsobservability tables. (Apply your project's migration/SQL for these; the columns each endpoint expects are documented in the API reference.)
OpenAI. Create an API key.
#3. Backend
cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
Create backend/app/.env (this project loads env from backend/app/.env, which
overrides the defaults in config.py):
# Supabase
SUPABASE_URL=https://<your-project>.supabase.co
SUPABASE_SECRET_KEY=<service role key>
SUPABASE_JWKS_URL=https://<your-project>.supabase.co/auth/v1/.well-known/jwks.json
# OpenAI
OPENAI_API_KEY=sk-...
# Pinecone
PINECONE_API_KEY=...
PINECONE_INDEX=crtx-documents
# Redis (required for ingestion + async eval scoring)
REDIS_URL=redis://localhost:6379
# CORS — the frontend origin(s), comma-separated
ALLOWED_ORIGINS=http://localhost:3000
Every tunable (chunk size, Top-K, retrieval defaults, vision model, reranking) has a sensible default and is documented in Configuration.
Now start both processes — the API and the worker. The worker is not optional: ingestion and async eval scoring run through it.
# Terminal 1 — API
uvicorn app.main:app --reload --port 8000
# Terminal 2 — background worker
arq app.worker.WorkerSettings
Sanity check: open http://localhost:8000/docs for FastAPI's auto-generated
Swagger UI.
#4. Frontend
cd frontend
bun install
Create frontend/.env.local:
NEXT_PUBLIC_API_URL=http://localhost:8000
NEXT_PUBLIC_SUPABASE_URL=https://<your-project>.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon key>
bun dev
Open http://localhost:3000.
#5. First run: from zero to a cited answer
- Sign up at
/login(email/password, via Supabase). - Create a collection — this becomes an isolated Pinecone namespace.
- Upload a document (PDF, DOCX, PPTX, XLSX, CSV, TXT, or MD — up to 50 MB) or
paste a URL. Ingestion runs in the background; watch the job progress
(
chunks_processed / chunks_total). - Ask a question. The answer streams in with its sources listed above it. Figure sources render inline.
- Open the Evaluation dashboard to see faithfulness and context-relevance scores accumulate.
#Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
503 Redis unavailable — set REDIS_URL to enable ingestion on upload | Worker/Redis not reachable | Start Redis and the arq worker; verify REDIS_URL. |
Uploads accepted but never finish (queued forever) | Worker process not running | Ingestion is enqueued but nothing consumes it — start arq app.worker.WorkerSettings. |
401 Invalid token on every call | JWKS/audience mismatch | Confirm SUPABASE_JWKS_URL matches your project; tokens are validated with audience="authenticated". |
| CORS errors in the browser | Frontend origin not allowed | Add the exact origin to ALLOWED_ORIGINS. |
| Chats work but scores never appear | Worker down (eval scoring is async) | Scoring runs in the worker via persist_query_result; if Redis is down it falls back inline but degraded. |
415 Unsupported file type | Extension/MIME not recognized | Use one of PDF, DOCX, PPTX, XLSX, CSV, TXT, MD. |
Next: Ingesting documents →