Local Development
This guide is for developers who want to work on Vedana itself — debug a single service, add a feature to vedana-core, run a custom pipeline locally — and need their own Python environment instead of the all-in-one Docker stack.
If you just want to try Vedana, follow the Quick Start — it brings the whole stack up via Docker Compose with the LIMIT demo dataset, and you don’t need any of the steps below.
If you’re deploying Vedana to production, see Operations → Deployment. It covers single-node and clustered topologies with managed Postgres, Memgraph, and Grist.
This page covers the middle ground: native Python on your machine, infrastructure (Postgres, Memgraph, Grist) in Docker.
System requirements
| Component | Version / requirement |
|---|---|
| Python | 3.12 (see .python-version) |
| Docker | 24+ with Compose v2 (for the infra services) |
uv | recent — astral.sh/uv |
| LLM provider key | OpenAI, OpenRouter, Google/VertexAI, or any provider compatible with LiteLLM |
The LLM-provider key is the only thing you need to obtain externally. Postgres, Memgraph, and Grist are brought up locally via Docker Compose in step 2.
1. Sync the workspace
The repository is a uv workspace — every libs/jims-* and libs/vedana-* package is editable in place.
git clone https://github.com/epoch8/vedana
cd vedana
uv sync
uv creates .venv/ at the repo root and installs all workspace packages. After this, edits to any libs/*/src/... are picked up immediately by every script — no reinstall needed.
2. Bring up the infrastructure only
You don’t want the full app / api / widget services running in Docker — those are what you’ll run natively. Bring up only the data services:
docker compose -f apps/vedana/docker-compose.yml up -d db memgraph memgraph-lab grist
This starts:
db— Postgres 15 withpgvectoron port5432memgraph— Memgraph on port7687(Bolt) and7444(HTTP monitoring)memgraph-lab— Web inspector on port3000grist— Grist on port8484
Wait ~30 seconds for healthchecks to settle, then check Postgres is up:
docker compose -f apps/vedana/docker-compose.yml exec db pg_isready -U postgres
3. Configure .env
cp apps/vedana/.env.example apps/vedana/.env
Open apps/vedana/.env and set at minimum:
# LLM provider — pick one
OPENAI_API_KEY="sk-..."
# OPENROUTER_API_KEY="sk-or-..."
# GOOGLE_APPLICATION_CREDENTIALS="path-to-creds.json"
# Postgres (already correct in .env.example for local Docker)
JIMS_DB_CONN_URI="postgresql://postgres:postgres@localhost:5432"
DB_CONN_URI="postgresql://postgres:postgres@localhost:5432"
# Memgraph
MEMGRAPH_URI="bolt://localhost:7687"
MEMGRAPH_USER="neo4j"
MEMGRAPH_PWD="modular-current-bonjour-senior-neptune-8618"
Note on hostnames.
.env.exampleships with Docker-network hostnames (db,memgraph,grist) because it’s optimised for the Docker Compose path. Running natively, replace them withlocalhost— bothJIMS_DB_CONN_URI/DB_CONN_URIandMEMGRAPH_URIneed that change.Grist credentials.
GRIST_API_KEY,GRIST_DATA_MODEL_DOC_ID,GRIST_DATA_DOC_ID, andGRIST_TEST_SET_DOC_IDare hardcoded inapps/vedana/docker-compose.yml(underx-app-common.environment) and point to a public Grist demo. When you run natively those env vars aren’t injected — copy them fromdocker-compose.ymlinto your.env, or replace them with your own Grist values.
The full list of environment variables is in the Configuration Reference; the Configuration guide explains them grouped by purpose.
4. Apply migrations
cd apps/vedana
uv run alembic upgrade head
The migration 2dfad73e5cce_move_emb_to_pgvector requires the pgvector extension. The local Docker db service is built on pgvector/pgvector:pg15 and supports it out of the box, so the default CREATE_PGVECTOR_EXTENSION=true in .env.example will create the extension automatically.
If you’ve pointed JIMS_DB_CONN_URI at a managed Postgres that handles extensions for you (Supabase, Neon, RDS with the extension pre-enabled), set CREATE_PGVECTOR_EXTENSION=false to skip the CREATE EXTENSION statement.
5. Run the service you’re working on
The repository defines several CLI scripts. Run the one you need; others can stay off, or you can run several in separate terminals.
| Command | What it runs |
|---|---|
uv run vedana-backoffice-with-caddy | Reflex backoffice + Caddy reverse proxy (chat, ETL runner, eval — port 9000) |
uv run python -m jims_api.main --app vedana_core.app:app --host 0.0.0.0 --port 8080 | HTTP API on FastAPI (port 8080) |
uv run python -m jims_widget.main --app vedana_core.app:app --host 0.0.0.0 --port 8090 | Web widget (port 8090) |
uv run jims-telegram --app vedana_core.app:app | Telegram bot |
uv run jims-tui --app vedana_core.app:app | Terminal UI for interactive debugging |
All scripts accept --app module:attr (default app); for Vedana use vedana_core.app:app. Each also accepts --metrics-port, --enable-sentry, and --verbose. See the API overview for the full CLI flag list per service.
Note on
vedana-backoffice-with-caddy. This script spawns Caddy as a subprocess to reverse-proxy WebSocket events on port 9000 to the Reflex backend on port 8000, so you need thecaddybinary onPATH(brew install caddyon macOS,apt install caddyon Debian). If you only want the Reflex part, runuv run reflex run --env dev --backend-onlyfromapps/vedana/and point your browser at port 8000.
6. Run the ETL
Without ETL the graph is empty. Open the backoffice (http://localhost:9000), go to the ETL page, click Run Selected on the main tab. Wait for every step to turn green.
Alternatively, from the command line:
cd apps/vedana
uv run python -m datapipe run --pipeline vedana_etl.app
7. Verify
curl http://localhost:8080/healthz
# {"status":"ok"}
Then ask a question via the chat at http://localhost:9000/chat. The first request will hit your local pipeline and your LLM provider — watch the terminal of the backoffice for traces.
If something fails, see Troubleshooting.
What’s next
- Architecture Overview — how the code is structured.
- Repository Structure — where every file lives.
- Testing — how to run tests, VCR cassettes, the
tests/layout per package. - Custom Tools and Custom ETL — extending Vedana.