Running Locally
This guide covers every way to run Nyayrithm on your machine, from the full Docker stack down to a completely container-free, zero-cost setup.
Option A: Full Docker stack (simplest)
Requires: Docker Desktop (Mac/Windows) or Docker Engine + Compose plugin (Linux)
git clone https://github.com/Aayush-Joshi-01/nyayrithm.git
cd nyayrithm
# Create .env and fill in at least one LLM API key
make env
nano .env # or open in your editor
# Build and start all services
make dev
# Apply DB migrations
make migrate
What starts:
backend: FastAPI on port 8000celery_worker: ingestion + simulation task workercelery_beat: scheduled tasksfrontend: Next.js dev server on port 3000db: PostgreSQL 16 on port 5432redis: Redis 7 on port 6379qdrant: Qdrant vector DB on port 6333minio: S3-compatible local storage on ports 9000 / 9001keycloak: Keycloak 26 identity provider on port 8080
Keycloak note: On first start Keycloak takes ~30 seconds to import the realm. The
nyayrithmrealm andnyayrithm-appclient are auto-created frominfra/keycloak/realm-export.json. Admin UI: http://localhost:8080 (admin/admin).
Open http://localhost:3000.
Option B: Minimal Docker (no local Python/Node needed)
If you only want containers for infra services (DB, Redis, Qdrant) and run app code natively:
# Start only infrastructure
docker compose up db redis qdrant -d
# Backend
cd backend
uv pip install -e ".[dev]"
uv run uvicorn app.main:app --reload --port 8000
# Worker (new terminal)
cd backend
uv run celery -A app.tasks.celery_app worker --loglevel=info \
-Q evidence,simulation,default
# Frontend (new terminal)
cd frontend
bun install
bun dev
Option C: No Docker at all (fully local, zero cost)
The lightest possible setup. Uses SQLite, Chroma (in-process), local file storage, and Gemini free tier (or Ollama for fully offline).
Prerequisites
| Tool | Install |
|---|---|
| Python 3.12+ | https://python.org or pyenv install 3.12 |
uv (fast Python package manager) |
curl -LsSf https://astral.sh/uv/install.sh \| sh |
| Node.js 20+ | https://nodejs.org or nvm install 20 |
bun (JS runtime + package manager) |
curl -fsSL https://bun.sh/install \| bash |
| Redis | See below |
Redis without Docker:
# macOS
brew install redis && brew services start redis
# Ubuntu/Debian
sudo apt install redis-server && sudo systemctl start redis
# Windows (WSL2)
sudo apt install redis-server && redis-server --daemonize yes
Redis is needed for Celery. If you want truly zero dependencies, set
CELERY_BROKER_URL=memory://in.envto use an in-memory broker (single-worker, non-persistent, fine for local testing).
.env for Option C
# App
APP_ENV=development
DEBUG=true
SECRET_KEY=local-dev-secret-change-me
CORS_ORIGINS=["http://localhost:3000"]
# DB, SQLite (no container)
DB_BACKEND=sqlite
SQLITE_PATH=./nyayrithm.db
# Vector DB, Chroma (runs in-process)
VECTOR_DB_BACKEND=chroma
CHROMA_HOST=localhost
CHROMA_PORT=8001
# Storage, local filesystem
STORAGE_BACKEND=local
STORAGE_LOCAL_ROOT=./storage
# Task queue
CELERY_BROKER_URL=redis://localhost:6379/0
CELERY_RESULT_BACKEND=redis://localhost:6379/1
REDIS_URL=redis://localhost:6379/2
# LLM, Gemini free tier
LLM_DEFAULT_PROVIDER=gemini
GEMINI_API_KEY=AIza...your-key...
# Embedder, local sentence-transformers (no API key)
EMBEDDER_BACKEND=sentence-transformers
EMBEDDING_DIMENSION=384
# Auth
ACCESS_TOKEN_EXPIRE_MINUTES=1440
# Frontend
NEXT_PUBLIC_API_URL=http://localhost:8000
NEXT_PUBLIC_WS_URL=ws://localhost:8000
Start the app (Option C)
Open three terminals:
Terminal 1, API server
cd backend
uv pip install -e ".[dev]"
uv run uvicorn app.main:app --reload --port 8000
Terminal 2, Celery worker
cd backend
uv run celery -A app.tasks.celery_app worker --loglevel=info \
-Q evidence,simulation,default
Terminal 3, Frontend
cd frontend
bun install # first time only
bun dev
Note: For native dev (
bun devoutside Docker), you needfrontend/.env.localwith Keycloak vars. Runmake env, it creates both.envandfrontend/.env.localautomatically.
Open http://localhost:3000.
Option D: Fully offline with Ollama
No internet connection required after initial model download.
Install Ollama
# macOS
brew install ollama
# Linux
curl -fsSL https://ollama.com/install.sh | sh
# Windows, download installer from https://ollama.com/download
Download models (one-time, needs internet)
ollama pull llama3.1:8b # ~4.7 GB, recommended balance
ollama pull mistral-nemo # ~7.1 GB, alternative
Configure .env for offline mode
LLM_DEFAULT_PROVIDER=ollama
OLLAMA_BASE_URL=http://localhost:11434
EMBEDDER_BACKEND=sentence-transformers
EMBEDDING_DIMENSION=384
DB_BACKEND=sqlite
VECTOR_DB_BACKEND=chroma
STORAGE_BACKEND=local
Start Ollama + app
# Terminal 1, Ollama server
ollama serve
# Terminals 2-4, same as Option C (backend, worker, frontend)
Everything now runs locally. No API keys, no external services, no network calls during simulation.
First run walkthrough
Once the app is running:
1. Create a case
Open http://localhost:3000, click New Case, fill in:
- Title and description of the legal matter
- Country (e.g.
India,United States,United Kingdom) - Jurisdiction (e.g.
Maharashtra,California,England and Wales) - Legal system (
common_law,civil_law,sharia,hybrid)
2. Upload evidence
Go to the case → Evidence tab. Drag and drop any supported file:
- PDF (court documents, contracts, reports)
- DOCX (written statements, affidavits)
- MP3/WAV/M4A (audio recordings)
- MP4/MOV (video footage)
- JPG/PNG (photographs, exhibits)
- TXT (plain text statements)
The file is sent to Celery for ingestion. Status updates from pending → processing → indexed in real time. Once indexed, chunks are searchable by agents.
3. Create a simulation
Click New Simulation on the case page:
- Choose a mode: Courtroom, Deposition, or Strategy
- Set max turns (10-50 recommended for local testing)
- Add predefined agents: pick roles, names, personas, and optionally override the LLM provider/model per agent
4. Start the simulation
Click Start. A WebSocket connection opens and the TurnFeed begins streaming:
- Each agent’s turn appears as a role-colored bubble
- Tokens stream in real time as the agent “speaks”
- Evidence citations appear as hoverable chips
- The AgentGraph on the right updates when agents spawn sub-agents
5. Intervene (optional)
- Click any turn bubble → Edit to override an agent’s statement (sets
is_human_override=true) - Click Pause to pause after the current turn completes
- Click Resume to continue
Database migrations
# Apply all pending migrations
make migrate
# Create a new migration after model changes
make migrate-create
# > Migration name: add_case_verdict_field
# Roll back one migration
make migrate-down
Migrations only apply to SQL backends (PostgreSQL and SQLite). MongoDB and DynamoDB are schema-less, collections/tables are created automatically on first write.
Running tests
# Full test suite with coverage
make test
# Backend tests only
cd backend && uv run pytest -v
# Specific test file
cd backend && uv run pytest tests/test_agents.py -v
# Frontend linting + type check
cd frontend && bun run lint && bun run tsc --noEmit
Tests use an in-memory SQLite database and mock LLM/vector store responses, no real API calls are made.
Environment variables cheat sheet
# Switch to SQLite instantly
DB_BACKEND=sqlite
SQLITE_PATH=./nyayrithm.db
# Switch to Chroma for vector DB
VECTOR_DB_BACKEND=chroma
# Use Gemini for free
LLM_DEFAULT_PROVIDER=gemini
GEMINI_API_KEY=AIza...
# Use local sentence-transformers for embeddings
EMBEDDER_BACKEND=sentence-transformers
EMBEDDING_DIMENSION=384
# Use Ollama for fully offline LLM
LLM_DEFAULT_PROVIDER=ollama
OLLAMA_BASE_URL=http://localhost:11434
Troubleshooting
Backend fails to start: connection refused to Postgres
You’re using DB_BACKEND=postgres but PostgreSQL isn’t running. Either:
- Run
make devto start the Docker stack, or - Switch to
DB_BACKEND=sqlitein.envfor local dev
Celery worker not processing evidence
Check that the broker is reachable:
cd backend && uv run celery -A app.tasks.celery_app inspect active
If Redis is down: redis-cli ping should return PONG. Start Redis or use CELERY_BROKER_URL=memory://.
Evidence stuck at processing
The Celery worker handles ingestion. Make sure the worker is running (Terminal 2 in the walkthrough above). Check worker logs for errors:
make logs # if using Docker
# or check Terminal 2 output
Gemini API rate limit errors (429)
You’ve hit the free tier RPM (15 requests/min). Solutions:
- Reduce simulation speed (add
TURN_DELAY_SECONDS=5to.env) - Use
gemini-flash-lite-latestfor simple roles (higher daily request quota) - Spread agents across multiple providers
Qdrant collection already exists error
This can happen when restarting after a schema change. Drop and recreate:
# If using Docker
docker compose exec qdrant ash -c "rm -rf /qdrant/storage/collections/case_*"
docker compose restart qdrant
Or switch to VECTOR_DB_BACKEND=chroma for local dev.
sentence-transformers slow first run
The model is downloaded on first use (~90 MB). Subsequent runs use the cached model. If you’re behind a proxy, set HF_HUB_OFFLINE=1 after the initial download.
Frontend can’t connect to backend
Ensure NEXT_PUBLIC_API_URL=http://localhost:8000 is set in .env. The Next.js dev server reads this at build time, restart bun dev after changing it.
Login/register returns “Could not reach authentication server” (503)
This usually means Next.js API routes can’t reach Keycloak. Check:
- Docker setup:
KEYCLOAK_URLmust behttp://keycloak:8080(the Docker service name), notlocalhost:8080. This is set automatically indocker-compose.yml. - Native dev: Ensure
frontend/.env.localexists withKEYCLOAK_URL=http://localhost:8080. Runmake envto create it. - Keycloak not started: Wait ~30 seconds after
make devfor Keycloak to finish realm import. Check withdocker compose logs keycloak.