Local Development
RAG is driven by mise tasks (which load the env) and dependencies are managed
with uv. It builds on Railway with Railpack (railpack.json) and starts
with python -m app.temporal.worker.
Prerequisites
Section titled “Prerequisites”- mise — provisions Python 3.12, goose, the Railway CLI, and more.
- Docker — for the local
pgvectorPostgres. - Railway access —
mise run envpulls config from Railway. - A
GITHUB_TOKEN— thehuddlesurety-apiSDK is git-installed from a private repo; the build rewriteshttps://github.com/to use the token.
-
Install tools + dependencies:
Terminal window mise install # provisions the toolchain; uv resolves Python deps -
Pull environment variables from Railway:
Terminal window mise run env # writes .env.json (gitignored); mise auto-loads it -
Start local Postgres (pgvector):
Terminal window docker compose -f docker-compose-pgvector.yaml up -
Migrate:
Terminal window mise run db:migrate # goose up, against app/db/ -
Run the worker:
Terminal window mise run run # python -m app.temporal.worker
| Task | What it does |
|---|---|
mise run run |
Run the Temporal worker |
mise run db:migrate |
goose up (schema document) |
mise run db:status |
goose migration status |
mise run db:nuke |
goose reset |
mise run db:ui |
Postgres TUI (rainfrog) |
mise run env |
Pull env vars from Railway → .env.json |
mise run log |
Tail Railway logs |
Environment
Section titled “Environment”Runtime config comes from Railway via mise run env → .env.json (gitignored);
.env.local holds dev overrides. Key variables:
- API:
BASE_URL(Go API),KEY_AUTH_SECRET(service-key auth) - DB:
DATABASE_URL - Temporal:
TEMPORAL_SERVER_URL,TEMPORAL_TASK_QUEUE_RAG,DEPLOYMENT_ENVIRONMENT - LLM gateway:
LITELLM_PROXY_API_BASE,LITELLM_PROXY_API_KEY— both required (the worker holds no provider key; the gateway does). See LLM Gateway. - Models:
VERTEX_MODEL(the extraction model — the name is legacy; it now names a LiteLLMgemini/…model),EMBEDDING_MODEL,EMBEDDING_DIMENSION,RERANK_MODEL(avoyage/…gateway alias),RERANK_ENABLED - Tuning:
RAG_*,CHUNK_*,FUZZY_MATCH_THRESHOLD - OTel:
OTEL_EXPORTER_OTLP_ENDPOINT,OTEL_EXPORTER_OTLP_PROTOCOL
Conventions
Section titled “Conventions”- Python 3.12, type hints throughout. Dataclasses for Temporal activity I/O (must serialize across the boundary); pydantic models for domain types and LLM structured-output schemas.
- Lazy imports inside activities to keep the workflow sandbox light.
- Per-call LLM timeouts + retry — every
litellm.completioncall sets an explicittimeout(LLM_TIMEOUT_MS30s for the extractor,FILL_LLM_TIMEOUT_MS36s for the filler,FIND_LLM_TIMEOUT_MS/FINAL_FIND_LLM_TIMEOUT_MS30s for the finders). This is load-bearing: LiteLLM’s own defaultrequest_timeoutis 6000s, so an un-timed call can hang for ~27 min. The finder calls route through a sharedservices/llm_retry.pycompletion_with_retry(timeout_s, …)— 429s honor the server delay (capped at 15s), 5xx/transport errors back off exponentially, and a client-sideTimeoutis not retried. The filler additionally downshifts reasoning effort on a timeout/truncation (medium → low) rather than failing outright. No explicittemperatureis passed anymore — LiteLLM applies Gemini 3’s default of 1.0 (structure stays pinned by the strictjson_schema). - Memory hygiene — activities free memory (
gc+malloc_trim) infinally, and never pass images across activity boundaries (they re-download/re-render). - Settings via pydantic-settings with an env-var fallback for unlisted keys.
There are no committed tests (the tests/ and benchmark/ dirs are gitignored),
and the repo has no in-repo CI.