OpenRAG is an open, self-hosted platform for building secure AI assistants over private business knowledge. It brings document ingestion, hybrid retrieval, model choice, citations, access control, and administration into one system that can run in the cloud, on private infrastructure, or fully on-premises.
OpenRAG is under active development. The repository currently includes a working FastAPI backend, React frontend, authentication and invitations, multi-tenant workspaces, asynchronous document ingestion, hybrid retrieval, streamed cited chat, and model/user administration.
Track: Work & Productivity
Repository: https://github.com/marketcalls/openrag Supported judge platform: Docker Desktop or Docker Engine with Compose v2 on macOS or Linux (Windows through WSL2)
OpenRAG turns private company documents into a governed, agentic knowledge assistant. The submitted build uses GPT-5.6 through the in-process LiteLLM Python library and was built collaboratively with Codex during the July 13–21, 2026 submission period. It demonstrates streamed answers, follow-up context, hybrid retrieval, OCR ingestion, page-level citations, safe analytical tables and charts, configurable completion and embedding models, RBAC, token budgets, and RAG operations/evaluation views.
A live instance is running for judging and testing, with no local setup required:
- URL: https://ragdemo.openalgo.in
- Email:
demo@openalgo.in - Password:
DemoOpen1234#
This is a shared demo account, not an isolated sandbox per judge — please
avoid deleting other judges' workspaces or documents. A tested LiteLLM model
is already configured, so no API key is required. Once signed in, create a
workspace, upload
frontend/e2e/fixtures/sample.pdf, wait
for Awaiting approval, approve it, and ask: “What is the internal launch
codename for the OpenRAG payroll project?” The grounded answer is
ZEBRA-COMET-7 with a page-level citation. You can also explore an existing
demo workspace instead of uploading another copy.
The instance stays available, free of charge and without restriction, through
the end of the Judging Period.
The instance is deployed with install/install.sh,
which stands up the same Docker Compose stack described below behind nginx
and Let's Encrypt on a single Ubuntu host. Run it from a clone of this
repository to reproduce the deployment on another domain:
sudo ./install/install.sh \
--domain ragdemo.openalgo.in \
--admin-email demo@openalgo.in \
--admin-password 'DemoOpen1234#'These intentionally public credentials are only for the hackathon VPS demo. Use a unique administrator email and a long randomly generated password for any private or production deployment, and rotate the demo password after judging.
It installs Docker if missing, starts the stack with the semantic tei
embedding profile, writes an nginx site for the given domain, and requests a
TLS certificate with certbot. Run ./install/install.sh --help for all
options (including --skip-nginx / --skip-tls for environments that
already terminate TLS elsewhere).
This is the shortest clean-machine path. It does not require Python, Node, or a locally installed database—only Git, Docker, and an OpenAI API key with access to the GPT-5.6 model used for judging.
git clone https://github.com/marketcalls/openrag.git
cd openrag
cp .env.example .env
install -d -m 700 data
openssl rand -hex -out data/event_redis_password 32
chmod 600 data/event_redis_password
docker compose -f deploy/compose.yaml up -d --build
docker compose -f deploy/compose.yaml ps
curl --fail http://localhost:8000/readyzOn macOS, if install is unavailable, use mkdir -p data, create the password
file with openssl rand -hex 32 > data/event_redis_password, and then run
chmod 600 data/event_redis_password.
Open http://localhost:5173 and sign in with the development judge account:
- Email:
root@openrag.internal - Password:
changeme123
Then complete this one-time setup in the UI:
- Open Models, choose Add model, select OpenAI via LiteLLM, enter a
display name, the GPT-5.6 model ID available to the judge account (the demo
build uses
gpt-5.6-luna), and the API key. The key is write-only and envelope-encrypted. Wait for the live capability probe to pass. - Open the workspace switcher, choose New workspace, then use the adjacent settings button to select the model as the workspace default.
- Open Documents and upload
frontend/e2e/fixtures/sample.pdf. Wait for Awaiting approval, choose Approve, and wait for Indexed. - Open Chat and ask:
What is the internal launch codename?The answer should stream and cite the uploaded PDF. AskPut that in a tableto show follow-up context and safe structured presentation. - Open Users → Token budget to set organization and per-user monthly token allocations; the chat header now reports real prompt + completion usage.
If any service is not healthy, the fastest diagnosis is:
docker compose -f deploy/compose.yaml logs --tail=200 \
migrate bootstrap api run-worker ingestion-worker event-worker webNo provider secret is bundled in the repository or image. Judges may remove the
stack with docker compose -f deploy/compose.yaml down; add -v only if all
local evaluation data may be deleted.
The product direction and final decisions came from the project owner: rename the product to OpenRAG, use only the LiteLLM library for model access, enforce grounded citations and enterprise permissions, and prioritize a polished, testable self-hosted workflow. Codex accelerated implementation by:
- comparing local RAGFlow, AnythingLLM, OpenUI, and earlier RAGHub patterns;
- building the async ingestion, durable streaming, follow-up memory, retrieval, model catalog/probing, evaluation, analytics, RBAC, and quota slices;
- tracing live PostgreSQL, Redis, Qdrant, worker, and browser failures to root causes and adding regression tests before each fix; and
- continuously running focused backend/frontend tests, type checks, lint, migrations, and live health/smoke checks before reviewed commits were pushed.
GPT-5.6 is both the featured completion model in the demo and the model used
with Codex for the core build session. Dated commits on July 18–21 distinguish
the hackathon work. The Devpost submission must also include the /feedback
Codex Session ID from that primary build thread, plus a public YouTube demo under
three minutes with audio explaining both Codex and GPT-5.6 usage.
Businesses want to use generative AI with internal documents, but production deployments must solve more than document search. They need to protect sensitive data, respect user permissions, avoid dependence on one model provider, operate at large corpus sizes, and produce answers that people can verify.
OpenRAG is designed around those needs:
- Self-hosted and privacy-first: Run every component inside your own infrastructure, including language models, embeddings, reranking, storage, and observability.
- Model-agnostic: Use hosted providers or local models through the in-process LiteLLM Python library, with support for OpenAI-compatible endpoints and no proxy control plane.
- Grounded answers: Combine dense and sparse retrieval, stream responses, and attach citations that resolve to the original document and page.
- Enterprise access controls: Isolate organizations and workspaces, enforce document permissions during retrieval, and maintain append-only audit records.
- Built for scale: Process large document collections asynchronously and search them through Qdrant with tenant-aware filters.
- Operationally transparent: Expose ingestion status, usage, model health, retrieval traces, and administrative controls through a professional web interface.
OpenRAG is planned to provide:
- Email/password authentication, invitations, SSO, MFA, and role-based access control
- Multi-tenant organizations, workspaces, groups, and document-level permissions
- Upload and ingestion for PDF, DOCX, XLSX, PPTX, CSV, text, Markdown, HTML, and images
- OCR, semantic chunking, metadata extraction, deduplication, and document versioning
- Hybrid dense and sparse retrieval with optional reranking and no-answer safeguards
- Streaming chat with conversation history, source citations, and document previews
- Agentic retrieval for multi-step questions using read-only search tools
- Hosted and local model registration, capability probing, fallback chains, and BYOK
- Fail-closed, asynchronous LiteLLM probes measure streaming, structured output, tool calling, vision, context metadata, and verifier eligibility before use
- Encrypted secret storage, quotas, budgets, usage reporting, and audit logs
- Versioned golden datasets with deterministic metrics, optional verifier judging, and budgeted on-demand or recurring evaluation runs
- Connectors for object storage, shared drives, knowledge systems, and websites
- Docker Compose, Kubernetes, and air-gapped deployment options
- An administrator creates an organization and one or more workspaces.
- Users upload documents or synchronize them from connected sources.
- Background workers parse, chunk, embed, and index the content.
- A user asks a question in a workspace.
- OpenRAG retrieves only the content that the user is authorized to access.
- The selected language model generates a streamed, grounded answer with citations.
- Usage, retrieval activity, administrative changes, and feedback feed operational and quality reporting.
OpenRAG keeps authorization and answer release deterministic, while Agno controls the bounded retrieval plan for weak-evidence, metadata-sensitive, analytical, and multi-part questions. The planner sees the user question plus prior search observations and can perform up to four novel read-only calls: global hybrid search, filename/file-type/page/section filtering, search within one document, surrounding-chunk retrieval, source inspection, and cross-document comparison. Every tool call is tenant pinned and current-version filtered. OpenRAG then revalidates the gathered evidence in PostgreSQL and refuses answers that cannot produce filename, version, section, and page citations.
Embedding models are never hardcoded into ingestion. Administrators select a
versioned LiteLLM embedding profile and generation; text-embedding-3-large is
one supported hosted profile among the curated choices. Changing a populated
workspace requires background reindexing, evaluation, atomic cutover, and a
rollback-capable previous generation.
The batch operator streams supported files through the same authenticated upload API used by the UI. It discovers PDF, DOCX, XLSX, PPTX, CSV, TXT, and Markdown recursively, requires at least 100 MB of configured batch capacity, bounds parallelism, retries transient failures, and emits only sanitized per-file receipts. Docling parsing/OCR, chunking, embedding, Qdrant indexing, deduplication, updates, deletion, and stage failure records remain in the durable background pipeline.
export OPENRAG_BATCH_TOKEN='<short-lived access token>'
cd backend
uv run python -m openrag.tools.batch_ingest \
--base-url https://ragdemo.openalgo.in \
--workspace-id '<workspace UUID>' \
--max-total-mb 500 \
--concurrency 4 \
/path/to/document-batchThe versioned 54-question benchmark is
backend/benchmarks/agentic_rag_v1.json.
It covers direct facts, multi-document and multi-search questions, ambiguity,
correct refusal, follow-ups, scanned OCR, tables, and combined digital/OCR
evidence. Capture Simple RAG and Agentic RAG observations with identical case
IDs, then generate a like-for-like JSON comparison; incomplete runs fail closed.
cd backend
uv run python -m openrag.modules.evaluations.comparison \
--dataset benchmarks/agentic_rag_v1.json \
--simple /path/to/simple-observations.json \
--agentic /path/to/agentic-observations.json \
--output /path/to/comparison.jsonWhen a request explicitly asks for analysis, comparison, metrics, a chart, or a
table, OpenRAG first produces the same citation-validated grounded Markdown
answer used by normal RAG. Only after that answer passes the evidence and
citation contract may a model with a passed structured JSON capability probe
perform one bounded, non-streaming presentation call. The presentation call is
supplemental: it can never add evidence, convert an insufficient answer into a
successful answer, or replace the authoritative Markdown response.
The only accepted contract is analytics.v1. It allows:
- up to 8 source-bound KPI cards;
- up to 12 total bar charts, line charts, semantic tables, and Markdown explainers;
- up to 50 chart categories, 8 series, 200 table rows, 12 columns, and 5 suggested follow-ups; and
- a maximum serialized size of 49,152 UTF-8 bytes.
Every KPI and block must cite one or more markers from the persisted citation snapshot. Unknown fields or component kinds, invalid markers, non-finite numbers, malformed table/chart shapes, HTML, scripts, URLs, executable expressions, control characters, and oversized values fail closed. Composition failure leaves the grounded answer intact and simply omits the analytical view.
Artifacts are content-addressed, immutable, tenant scoped, persisted atomically
with their assistant message, replayed through the durable event stream, and
returned with historical chats. The browser reparses the contract before every
render and uses a closed React component registry—never generated code. Charts
include a screen-reader data table. Table CSV exports use RFC 4180 quoting and
neutralize spreadsheet formulas; JSON export contains only the validated
analytics.v1 object. Export files are created locally in the browser.
The extra model call is capped at 4,096 output tokens and 45 seconds, uses no tools or history, and is available only when the selected LiteLLM model has a passed structured-output probe. Operational telemetry records bounded timing, usage, state, and safe error codes; prompts, evidence text, artifact contents, credentials, and provider errors are excluded from logs and traces.
OpenRAG authorizes every protected request from current PostgreSQL state. A signed access token identifies the user and carries UI hints, but the API reloads active role bindings, workspace membership, and platform status on every request. Role names are labels only; they never grant authority by string comparison.
| Template | Intended use | Capabilities |
|---|---|---|
| Administrator | Organization administration and knowledge governance | All organization capabilities listed below |
| HSE Manager | Manage and approve HSE knowledge in assigned workspaces | chat.use, document.read, document.upload, document.approve |
| Engineer | Use chat and contribute knowledge in assigned workspaces | chat.use, document.read, document.upload |
| User | Use grounded chat and read assigned knowledge | chat.use, document.read |
The built-in templates are protected system roles. An organization role manager may create custom roles from the same closed capability catalog, update a custom role, and delete an unbound custom role. Custom roles cannot add unknown capabilities, cannot become platform superadmin, cannot cross organization boundaries, and cannot bypass workspace membership. The last active Administrator binding cannot be removed.
Workspace membership and role assignment are independent:
- A role answers what actions a user may perform.
- Membership answers which workspaces the user may reach.
- An organization capability does not grant workspace access without membership,
except the explicit
workspace.read_allgovernance capability. - A workspace-scoped role binding applies only to that workspace, even if the user is a member of other workspaces.
| Permission | Meaning |
|---|---|
chat.use |
Ask grounded questions in authorized workspaces |
document.read |
View authorized documents and cited evidence |
document.upload |
Add documents for background extraction and indexing |
document.approve |
Approve governed document versions for retrieval |
workspace.manage |
Create workspaces and manage membership |
workspace.read_all |
Read every workspace in the current organization |
user.manage |
Invite, activate, and deactivate organization users |
role.manage |
Create roles and replace organization role bindings |
model.configure |
Configure organization model and retrieval profiles |
rag.evaluate |
Run and review grounded-answer quality evaluations |
audit.read |
Review immutable security and administration events |
Platform superadmin is not a permission and is not an organization role. It is a non-assignable platform flag created only by the serialized bootstrap command. Organization administrators cannot view, create, invite, bind, or promote a platform superadmin. Platform model and secret administration remains behind the separate platform boundary.
The platform uses a modular monolith with independently scalable API and worker processes plus dedicated infrastructure services:
| Area | Technology |
|---|---|
| API | FastAPI, Python, Pydantic, SQLAlchemy |
| Web application | React, TypeScript, Vite, Tailwind CSS, shadcn/ui |
| Relational data | PostgreSQL |
| Vector search | Qdrant |
| Object storage | MinIO or S3-compatible storage |
| Background jobs | Celery and Redis |
| Model runtime | Agno orchestration with the in-process LiteLLM Python library |
| Embeddings | Text Embeddings Inference with BGE-M3 |
| Document parsing and OCR | Docling with local RapidOCR |
| Observability | OpenTelemetry, Prometheus, and Grafana |
The design follows five foundational rules: tenant filtering has one enforced path per data store, document permissions are applied inside retrieval, secrets have one controlled decryption path, authorization is declared at API boundaries, and all document content and model output are treated as untrusted data.
See the high-level architecture for service boundaries and ingestion/query flows.
Docker Compose is the supported single-node evaluation and development deployment. It starts PostgreSQL, isolated broker and durable event Redis services, Qdrant, MinIO, database migrations, bootstrap, the FastAPI service, independently scalable ingestion, run, summary, evaluation, model-probe, event, and enrichment workers, the event scheduler, and the React web application. Completion and hosted-embedding calls run through the LiteLLM Python library inside bounded application workers; no LiteLLM Proxy service or master key is required.
Uploads are streamed through an owner-only quarantine and validated by extension,
declared MIME, file signature, and bounded Office archive expansion. PDF parsing
enforces byte, page, rendered-pixel, extracted-block, text-output, worker-memory,
and wall-time budgets. Scanned and mixed PDFs use local per-page OCR by default;
set OPENRAG_OCR_MODE to auto, force, or disabled and configure comma-separated
RapidOCR languages with OPENRAG_OCR_LANGUAGES.
Install Git and Docker with the Compose v2 plugin, then clone the public repository:
git clone https://github.com/marketcalls/openrag.git
cd openrag
cp .env.example .envBefore the first startup, edit .env and replace at least:
OPENRAG_BOOTSTRAP_EMAIL=admin@example.com
OPENRAG_BOOTSTRAP_PASSWORD=replace-with-a-long-random-passwordCreate the local event-transport credential as an ignored, owner-readable file. It is mounted only into the dedicated event Redis and event worker, not placed in Compose environment variables or exposed to the API and ingestion worker.
install -d -m 700 data
openssl rand -hex -out data/event_redis_password 32
chmod 600 data/event_redis_passwordOPENRAG_EVENT_REDIS_SECRET_FILE may point to a different secret-managed file
for nonlocal deployments. Never commit that file.
The bootstrap credentials create the first platform superadmin only when one does not already exist. Bootstrap is the only application path that can set platform superadmin, concurrent bootstrap attempts are serialized, and changing the variables later does not change an existing account password.
docker compose -f deploy/compose.yaml up -d --buildThe first build downloads base images and document-processing dependencies, so it can take several minutes. Compose waits for the infrastructure, runs Alembic migrations, prepares the encryption key, creates the first superadmin, and then starts the application services.
Check the deployment:
docker compose -f deploy/compose.yaml ps
curl --fail http://localhost:8000/readyzEvery listed service should be running or successfully completed, and readiness should return {"status":"ready"}. If startup fails, inspect the application services:
docker compose -f deploy/compose.yaml logs --tail=200 \
api worker ingestion-worker run-worker summary-worker enrichment-worker model-worker \
event-worker event-scheduler migrate bootstrap webOpen http://localhost:5173 and use the bootstrap email and password from .env. With the unchanged development defaults, they are:
- Email:
root@openrag.internal - Password:
changeme123
Go to Superadmin → Models, register a hosted or local completion model and its write-only credential, and wait for its measured probe to pass. Designate one measured model as the utility model for bounded background AI work. Then create a workspace, select its default model, and optionally enable Enrich approved documents in workspace settings. Enrichment runs asynchronously and never holds ingestion in Processing. Upload a document, wait until its status is Indexed, and start a chat.
Credentials are write-only and stored separately for each model. A
provider_authentication_failed probe means that model record has an invalid
credential; edit it, enter a valid provider key, save, and probe again. A
passing model with a different key fingerprint does not automatically share
its encrypted credential with other model records.
The default hash embedder avoids a model download and is intended only for installation smoke tests. It is lexical rather than semantic, so generic questions such as “tell me about the invoice” may not match invoice text reliably.
For real document question answering, start the optional local ML profile with Text Embeddings Inference and BGE-M3:
OPENRAG_EMBEDDING_BACKEND=tei \
docker compose -f deploy/compose.yaml --profile ml up -d --buildThe first start downloads model images and weights. For governed changes, use Superadmin → Embeddings to register an immutable embedding profile, test it, build a new versioned generation, and activate it only after the complete approved corpus is indexed. Do not switch a populated production workspace by changing only an environment variable. Activation is an atomic cutover; background enrichment automatically backfills the newly active generation.
The same ml profile starts Ollama. Its host port defaults to 11434 and can be changed with OPENRAG_OLLAMA_PORT.
Before upgrading an installation created before capability RBAC, take a tested
PostgreSQL backup. Revision 6c4a2f8b9d10 locks the affected legacy tables,
fails closed if it finds an unknown legacy role, seeds the four protected role
templates for every organization, and performs this backfill:
- legacy
superadminbecomes the bootstrap-only platform flag; - legacy
adminreceives an organization-wide Administrator binding; - legacy
userreceives an organization-wide User binding; - pending invitations receive the corresponding role ID; and
- workspace membership receives an explicit organization scope and no longer stores a role string.
Run and inspect the migration separately when operating a controlled upgrade:
docker compose -f deploy/compose.yaml run --rm migrate
docker compose -f deploy/compose.yaml run --rm bootstrap
docker compose -f deploy/compose.yaml up -d api worker webFor the revision-fenced ingestion upgrade, keep
OPENRAG_INGEST_REVISION_PROTOCOL_V2_ENABLED=false and use this order:
- stop new uploads, drain both Celery queues, and stop every old worker;
- deploy the new API and worker images and run the database migration;
- start only new workers and verify no old worker remains connected;
- set
OPENRAG_INGEST_REVISION_PROTOCOL_V2_ENABLED=true, then restart the API and workers before accepting uploads again.
While the flag is false, revision-1 uploads use rolling-compatible one-argument
tasks; retries and stale-attempt recovery remain disabled. New workers can also
consume a residual one-argument legacy task as revision 1.
The database rejects lifecycle writes from an accidentally retained old worker,
and retrieval excludes its non-approved vectors. After cutover, retrying an
exact-Legacy processing item is allowed only after all unfinished work is older
than OPENRAG_STALE_INGEST_RECOVERY_SECONDS (default 900). Recovery locks the
jobs, advances the revision fence, terminalizes the stale jobs, and dispatches
a fresh v2 attempt. A recent attempt fails with a conflict and is not stolen.
Rollback warning: downgrading to 4f2e1c9a7b30 is intentionally lossy. Custom
roles, multiple role bindings, workspace-scoped bindings, and capability detail
cannot be represented by the legacy three-role schema. The downgrade maps a
platform superadmin to superadmin, an organization-wide Administrator to
admin, and every other user to least-privileged user. Never downgrade a
production database without a restore point and an explicit data-loss decision.
docker compose -f deploy/compose.yaml run --rm migrate \
/app/.venv/bin/alembic downgrade 4f2e1c9a7b30After migration, use Users to manage accounts and Roles to manage capabilities. The demo-friendly user flow does not require an email provider:
- A superadmin opens Users → Invite, enters an email, and selects a role.
- OpenRAG displays a one-time acceptance link. Copy it immediately and share it with the intended user through a secure channel.
- The user opens the link, chooses a password, and signs in.
- Use Users → Roles to change the user's effective organization roles and Users → Tokens to set a monthly token quota.
- A platform superadmin can permanently remove access with Delete. OpenRAG retains audit references, revokes refresh tokens, removes personal email from the deleted account, and permits the address to be invited again.
The raw invitation token is returned only once to the authorized administrator
over a no-store response, expires after 72 hours, and is stored in PostgreSQL
only as a SHA-256 hash. Creating another link for the same email immediately
revokes its older pending links. Treat the copied link like a temporary password. A
production deployment can replace this manual handoff with a secure delivery
adapter without changing invitation acceptance semantics.
Follow application logs:
docker compose -f deploy/compose.yaml logs -f api worker event-worker event-scheduler webRestart only the application processes without deleting stored data:
docker compose -f deploy/compose.yaml restart api worker event-worker event-scheduler webUpgrade from the public main branch:
git pull --ff-only
docker compose -f deploy/compose.yaml up -d --buildStop the stack while retaining PostgreSQL, Qdrant, MinIO, and key volumes:
docker compose -f deploy/compose.yaml downBack up the openrag_kekdata volume together with PostgreSQL. Provider credentials are encrypted with that key-encryption key; losing it, or restoring a database with a different KEK volume, makes the stored credentials intentionally undecryptable. Never use docker compose down -v on an installation whose data must be retained.
Application ports bind to loopback by default. Set OPENRAG_WEB_PORT and OPENRAG_API_PORT in .env to change host ports. Put a TLS reverse proxy or ingress in front of OpenRAG before exposing it outside the host.
The Compose topology is not a production proof for a 500 GB corpus. A large enterprise deployment requires external or highly available PostgreSQL and object storage, a distributed Qdrant cluster with planned sharding and replication, multiple ingestion workers, monitored Redis, backups and restore drills, TLS, metrics, traces, capacity tests, and an explicit embedding migration strategy. Those production artifacts will be documented separately under docs/superpowers/gaps after the enterprise architecture is approved.
Prerequisites: Docker, Python 3.12+, uv, Node.js 20+, and Corepack.
Start only the infrastructure:
docker compose -f deploy/compose.yaml -f deploy/compose.local.yaml up -d \
postgres redis qdrant minio event-redisPrepare the backend, then export one shared local runtime profile for the API and every worker. Do not run the API with the TEI default while running workers with the hash embedder; query and document vectors must come from the same immutable embedding profile.
cd backend
uv sync
uv run alembic upgrade head
OPENRAG_BOOTSTRAP_EMAIL=root@openrag.internal \
OPENRAG_BOOTSTRAP_PASSWORD=changeme123 \
uv run python -m openrag.bootstrap
export OPENRAG_ENVIRONMENT=dev
export OPENRAG_EMBEDDING_BACKEND=hash
export OPENRAG_EMBEDDING_MODEL_ID=openrag-hash-v1
export OPENRAG_EMBEDDING_DIM=1024
export OPENRAG_EVENT_REDIS_URL=redis://openrag@127.0.0.1:56380/0
export OPENRAG_EVENT_REDIS_PASSWORD_FILE=../data/event_redis_password
uv run uvicorn --factory openrag.api.app:create_app --port 8000From backend/, start the durable event, run, and ingestion workers in three
additional terminals. The solo pool is deliberate for the 4 GB Docker Desktop
development profile and for macOS document-parser safety.
uv run celery -A openrag.worker.celery_app:celery_app worker \
-Q events -l warning --pool=solo --concurrency=1 \
--hostname=event-local@%h --without-gossip --without-mingle
uv run celery -A openrag.worker.celery_app:celery_app worker \
-Q runs -l warning --pool=solo --concurrency=1 \
--hostname=runs-local@%h --without-gossip --without-mingle
uv run celery -A openrag.worker.celery_app:celery_app worker \
-Q ingestion -l warning --pool=solo --concurrency=1 \
--hostname=ingestion-local@%h --without-gossip --without-mingleUse one memory-efficient threaded worker for the remaining local queues, then start the scheduler in another terminal:
uv run celery -A openrag.worker.celery_app:celery_app worker \
-Q models,evaluations,enrichment,summaries,interactive,default \
-l warning --pool=threads --concurrency=8 \
--hostname=aux-local@%h --without-gossip --without-mingle
uv run celery -A openrag.worker.celery_app:celery_app beat -l warningIf run-worker is absent, a new chat can persist the user question but remain
in a pending state indefinitely. If the ingestion worker or scheduler is
absent, uploads remain queued. For a source checkout, keep the scheduler and
workers on the host together; mixing a host scheduler with Docker workers can
introduce clock skew and expired Celery ticks. Before building images, keep at
least 10 GiB of free host disk; do not solve a space issue with
docker compose down -v, because that deletes application data.
New or reconfigured models remain unavailable until their measured LiteLLM probe passes. The provider key is decrypted only inside the probe worker and is never returned by the API or stored in probe results.
Start the frontend in another terminal:
cd frontend
corepack pnpm install
corepack pnpm generate:api
corepack pnpm devOpen http://localhost:5173. During local development, sign in with:
- Email:
root@openrag.internal - Password:
changeme123
These are development-only bootstrap credentials. Change them for any shared or internet-accessible deployment.
Useful service URLs:
| Service | URL |
|---|---|
| OpenRAG web app | http://localhost:5173 |
| API documentation | http://localhost:8000/api/docs |
| API liveness / readiness | http://localhost:8000/healthz / http://localhost:8000/readyz |
| MinIO console | http://localhost:59001 |
# Backend
cd backend
uv run pytest -q
OPENRAG_RUN_LOAD_TESTS=1 uv run pytest tests/load -q
uv run ruff check src tests
uv run mypy src/openrag
uv run lint-imports
uv run alembic check
# Frontend
cd frontend
corepack pnpm lint
corepack pnpm typecheck
corepack pnpm test -- --run
corepack pnpm build
corepack pnpm e2e # RBAC cases always run; the live RAG journey needs E2E=1The RBAC browser suite starts an isolated Vite server when E2E_BASE_URL is not
set. frontend/e2e/rbac.spec.ts deliberately intercepts /api with deterministic
fixtures. It verifies frontend navigation, route guards, and presentation for an
organization Administrator, Engineer, workspace-scoped HSE Manager, and platform
superadmin. It does not prove live login, catalog enforcement, API denial,
workspace isolation, or logout. Frontend guards are a convenience, not a
security boundary.
The authoritative live RBAC smoke is the credential-safe backend script. Start
the standard Compose stack first, then run it from backend/:
docker compose -f deploy/compose.yaml up -d
cd backend
uv run python scripts/rbac_compose_smoke.pyThe script defaults to http://127.0.0.1:8000. For a custom loopback API port,
set OPENRAG_SMOKE_API_URL; an explicitly remote target must use HTTPS:
OPENRAG_SMOKE_API_URL="http://127.0.0.1:${OPENRAG_API_PORT}" \
uv run python scripts/rbac_compose_smoke.pyIt obtains the existing bootstrap credentials from the standard
openrag-bootstrap-1 container without printing them, sends bearer tokens only
in authorization headers, and reports fixed PASS/status labels. In one
PostgreSQL transaction it creates a random temporary Engineer, two random
workspaces, and membership in exactly one of them. It then proves health,
readiness, the non-assignable platform boundary, exact 403 administration
denials, workspace isolation, and logout/refresh behavior against the real API.
The finally cleanup locks and validates the immutable fixture user plus both
exact organization/workspace ID/name records before deleting anything. A
mismatch fails closed and rolls the transaction back; cleanup never infers
ownership from a name. The script never requires a model provider or spends
model tokens.
The deterministic durable-stream load gate is opt-in so the normal unit suite stays fast. It drives 100 streams concurrently, reconnects half from a real event cursor, cancels ten midstream, and verifies ordering, deduplication, retention bounds, and workspace envelope isolation:
cd backend
OPENRAG_RUN_LOAD_TESTS=1 uv run pytest tests/load/test_100_run_streams.py -qAfter the full Compose stack is ready, run the live run-event smoke with credentials supplied only through the process environment. It validates readiness, login, workspace/chat creation, idempotent acceptance, Redis-backed SSE ordering, worker cancellation, and—when a second user is supplied—tenant denial. It prints fixed stage names and never prints tokens, passwords, or response bodies:
cd backend
OPENRAG_SMOKE_EMAIL="$OPENRAG_BOOTSTRAP_EMAIL" \
OPENRAG_SMOKE_PASSWORD="$OPENRAG_BOOTSTRAP_PASSWORD" \
uv run python scripts/smoke_run_events.pyFor the optional tenant-denial assertion, also set
OPENRAG_SMOKE_SECOND_EMAIL and OPENRAG_SMOKE_SECOND_PASSWORD. A remote
OPENRAG_SMOKE_API_URL must use HTTPS; plain HTTP is accepted only for
loopback development.
The automated API and isolation selections used for the RBAC handoff are:
cd backend
uv run pytest -q \
tests/api/test_roles.py \
tests/api/test_users.py \
tests/api/test_auth_routes.py \
tests/api/test_workspaces.py \
tests/isolation/test_rbac_isolation.pyFor the real-stack browser journey, configure a completion model or provide E2E_OPENAI_API_KEY, keep the API, worker, and frontend running, then run:
E2E=1 \
E2E_EMAIL=root@openrag.internal \
E2E_PASSWORD=changeme123 \
E2E_OPENAI_API_KEY=sk-... \
corepack pnpm e2e- Phase 1 — Foundation: Authentication, organizations, workspaces, document ingestion, hybrid retrieval, streaming chat with citations, model registration, and core administration.
- Phase 2 — Enterprise controls: SSO, document ACLs, model capability checks, budgets, audit views, and usage dashboards.
- Phase 3 — Agentic retrieval and polish: Multi-step retrieval, reranking, attachments, richer output, exports, and quality safeguards.
- Phase 4 — Scale and ecosystem: Connectors, evaluation tooling, deployment bundles, integrations, document viewing, and white-label support.