Introduction
CRTX is a multi-user Retrieval-Augmented Generation (RAG) platform. Teams upload their own documents, ask questions in natural language, and get answers that are grounded in — and cite — that content. Every answer is automatically scored for quality, so you can trust it and watch trends over time.
Most AI chat tools are black boxes: you can't see where an answer came from, and you can't tell when retrieval quietly failed. CRTX is built around the opposite principle — every response carries its sources, and every interaction is measured.
#What you can do with it
- Chat with your documents. Ask anything about the files or web pages you've uploaded. Answers stream token-by-token, and the sources appear before the first token so you see grounding immediately.
- Ingest almost anything. PDF, Word (
.docx), PowerPoint (.pptx), Excel (.xlsx), CSV, plain text (.txt), Markdown (.md), and public URLs. - Understand multimodal PDFs. Embedded images are described by GPT-4o vision and become searchable; tables are extracted as structured Markdown; scanned PDFs fall back to page-level vision OCR.
- See exactly where answers come from. Each answer cites the specific chunks it used, including inline rendering of figure/image sources.
- Collaborate. Share a collection with a link and control whether recipients can only query it or also upload to it. Share individual chat transcripts with collection members.
- Measure quality. Faithfulness and context-relevance scores are computed on every query by an LLM judge, and surfaced on an evaluation dashboard with daily trends and a "worst queries" view.
- Tune retrieval. Swap retrieval strategies per collection, adjust chunk size, and (optionally) add a Cohere reranking layer.
#The mental model
Collection ── owns ──► Documents ── produce ──► Chunks ── embedded into ──► Vectors
│ │
│ ▼
│ Pinecone namespace
│ (== collection id)
│
├── has ──► Chat sessions ── contain ──► Messages (with cited sources)
├── has ──► Config (retrieval strategy, chunk size)
├── has ──► Shares (links) ── grant ──► Members (query or ingest permission)
└── accrues ──► Evals (faithfulness + relevance per query)
A collection is the central unit. Everything — documents, chat history, retrieval config, sharing, and evaluation metrics — hangs off a collection. Under the hood, each collection maps to a dedicated Pinecone namespace (the namespace is the collection id), which keeps every tenant's vectors isolated.
#How a query works, end to end
- You send a question (optionally within a chat session and collection).
- For follow-up questions, the last couple of user turns are prepended so the question embeds with its context (a bare "what about its pricing?" otherwise retrieves the wrong chunks).
- The question is embedded (
text-embedding-3-small, 1024-dim) and used to search the collection's Pinecone namespace with the configured strategy (similarity / MMR / threshold), optionally reranked by Cohere. - Retrieved chunks are stitched with their neighbours to restore context lost at chunk boundaries, then formatted into a numbered, source-labelled context block.
- GPT-4o generates an answer grounded in that context, streamed back over SSE.
Image-derived chunks are marked
[Figure/Image]so the model knows their origin. - The exchange is saved to the chat session, logged (latency, tokens), and scored asynchronously for faithfulness and context relevance.
Full detail: Querying & chat and Retrieval tuning.
#Architecture at a glance
| Layer | Technology |
|---|---|
| Frontend | Next.js 16, React 19, TypeScript 5, Tailwind CSS v4 |
| Backend | FastAPI, Python 3.13, Uvicorn |
| Auth | Supabase JWT (ES256, JWKS-validated); Next.js middleware for edge auth |
| Database | Supabase PostgreSQL |
| Storage | Supabase Storage (documents + images buckets) |
| Vector store | Pinecone (per-collection namespace; chunk_type + image_url metadata) |
| LLM / Vision | OpenAI GPT-4o (answers, image description, scanned-PDF OCR) |
| Judge | OpenAI GPT-4o-mini (faithfulness + relevance scoring) |
| Embeddings | OpenAI text-embedding-3-small (1024-dim) |
| Reranking (opt-in) | Cohere rerank-english-v3.0 |
| Background jobs | Arq + Redis (batched upserts, tenacity retries) |
| RAG framework | LangChain |
The backend exposes five routers — /collections, /ingest, /query,
/chat, /evals — behind JWT auth. Heavy work (document parsing, embedding,
eval scoring) runs asynchronously in an Arq worker backed by Redis, keeping the
API responsive. See Operations & scaling.
#Glossary
| Term | Meaning |
|---|---|
| Collection | The top-level container for documents, chats, config, and sharing. Maps 1:1 to a Pinecone namespace. |
| Document | A single ingested file or URL within a collection. |
| Chunk | A slice of a document (text, table, or image description) that is embedded and stored as one vector. |
| Chunk type | text or image_description. Image-description chunks are GPT-4o vision output for embedded figures/scanned pages. |
| Vector ID | Deterministic SHA-256 of (collection_id, source, chunk_index) — re-ingesting the same document upserts identical IDs, so Pinecone deduplicates naturally. |
| Retrieval strategy | How candidate chunks are selected: similarity, mmr, or threshold. |
| Top-K | The number of chunks retrieved and fed to the model as context. |
| Reranking | Optional Cohere cross-encoder pass that reorders over-fetched candidates before trimming to Top-K. |
| Neighbour window | Number of adjacent chunks stitched around each retrieved chunk to restore boundary context. |
| Faithfulness | 0.0–1.0 score: is every claim in the answer supported by the retrieved context? |
| Context relevance | 0.0–1.0 score: were the retrieved chunks actually useful for the question? |
| Session | A saved chat conversation within a collection. |
| Share / Member | A share is a link granting query or ingest access; a member is a user who accepted one. |
| Job | A background ingestion task tracked in ingest_jobs with queued → processing → succeeded/partial/failed. |
Next: Quickstart →