Architecture — Lawyer Assistant
1. Big picture
┌─────────────────────────────────────────────────────────────────────┐
│ ELECTRON SHELL (frontend/electron/) │
│ • Creates the BrowserWindow │
│ • Starts Python backend (auto .venv, port 8765) │
│ • Starts Vite dev server (port 5173, dev mode only) │
│ • Kills stale processes on 8765/5173 at startup │
│ • IPC: window controls, python:port, python:health │
└───────────────┬─────────────────────────────────────────────────────┘
│ loads
┌───────────────▼─────────────────────────────────────────────────────┐
│ FRONTEND (frontend/, Vite+React+TS) │
│ • ChatArea, InputBar, SourcesPanel, ScanPanel, PipelineEditor │
│ • Zustand stores (chat, persist 'freebuff-chat-storage') │
│ • Services layer → HTTP + SSE to backend (http://localhost:8765) │
└───────────────┬─────────────────────────────────────────────────────┘
│ HTTP + SSE (text/event-stream)
┌───────────────▼─────────────────────────────────────────────────────┐
│ BACKEND (backend/main.py, FastAPI) │
│ • /api/chat/stream (SSE), /api/upload, /api/chat/resume │
│ • /api/playbooks, /api/scan[/stream|/upload], /api/flags │
│ • Warmup: preloads BGE-M3, BGE-Reranker, Ollama LLM on startup │
└───────────────┬─────────────────────────────────────────────────────┘
│
┌───────────────▼─────────────────────────────────────────────────────┐
│ LEGAL RETRIEVAL ENGINE (backend/legal_retrieval/) │
│ • router_intent.py / router.py (AI orchestration) │
│ • tools.py: search_documents, verify_relevance, scan_document, │
│ ingest_file │
│ • retrieval.py: dense (ChromaDB) + sparse (BM25) + rerank │
│ • playbook/: compliance scanner (classifier → rules → flags) │
│ • llm.py → Ollama (localhost:11434) │
└─────────────────────────────────────────────────────────────────────┘
Local-first: models (BGE-M3 embeddings, BGE-Reranker-v2-M3) live in models/; the vector store lives in data/chroma_db; LLM inference is Ollama running locally on http://localhost:11434. No cloud dependency.
2. Ports & processes
| Port | Owner | Purpose |
|---|---|---|
| 8765 | backend/main.py (uvicorn) | FastAPI "Lawyer Assistant API" — the frontend's only backend |
| 5173 | Vite dev server | Serves the React app in development (npm run dev) |
| 11434 | Ollama | Local LLM inference (ChatOllama / OllamaLLM) |
The Electron main process kills anything listening on 8765/5173 at startup to avoid EADDRINUSE, then starts the Python backend (auto-creating/using .venv) and, in dev mode, the Vite server.
3. Runtime modes
| Mode | Dev | Production |
|---|---|---|
| Electron load | mainWindow.loadURL(viteUrl) (Vite dev server) | mainWindow.loadFile(frontend/dist/index.html) |
| Backend | spawned by Electron (python main.py) | bundled into extraResources (backend/**/*.py + requirements) |
| Run command | npm run dev (root → runs Electron, which boots backend + Vite itself) | npm run build then npm run package:win/mac/linux |
4. The three AI flows
4a. Chat / RAG (search → answer)
/api/chat/stream → intent router → tools (search_documents, verify_relevance) → retrieval (dense+sparse+rerank) → LLM answer with citations → SSE events streamed to the UI. Details: BACKEND.md.
4b. Compliance scan (document → flags)
/api/scan/stream (or /api/scan/upload for new files) → chunk → classify clause type (embedding classifier) → check playbook rules → emit flags → persist to SQLite. Details: BACKEND.md → "Playbook scan".
4c. Pipeline editor (visual config → backend reconfiguration)
A ReactFlow canvas that visualizes the pipeline as nodes (intent, planner, dense, sparse, rerank, ingest, scan, answer) with removable/toggleable sub-nodes, localStorage persistence, and JSON export/import. Since the /api/pipeline/config endpoint, the exported layout also reconfigures the Python backend at runtime (rerank on/off, search mode + dense/sparse fusion weights, top_k overrides) via backend/legal_retrieval/pipeline_config.py; RetrievalPipeline reads the active config on construction. Details: PIPELINE_EDITOR.md, PIPELINE_JSON.md §10.
5. Key architectural decisions
- Single FastAPI process owns both chat and scan; models warm up in a background thread at startup so the first query is fast.
- SSE everywhere for real-time UX: chat tokens, thinking, tool calls, node status, scan progress, and flags all stream as Server-Sent Events.
- Two router generations: the default
ragmode uses the intent router (router_intent.py, plan-based, intent classification); the legacy agentic router (router.py) is a LangGraph ReAct agent with human-in-the-loop approval and is used forretrieval_only/directmodes (and by resume). - Human-in-the-loop: LangGraph
interrupt()pauses before tool execution; the UI shows an ApprovalBar;/api/chat/resumecontinues the thread. - Persistence split: conversations persist in the browser (Zustand
localStorage); pipeline layout persists inlocalStorage['pipeline-layout-v1']; scan flags persist in backend SQLite; LangGraph thread state persists indata/conversations.db(AsyncSqliteSaver). - Theme: light parchment mode is the default; the whole UI is driven by CSS variables (
--bg-primary,--text-primary,--accent, …) with anhtml.lightbridge that remaps Tailwind utilities for contrast.