# ⚖️ Astraea — Self-Hosted AI Family-Law Assistant for Washington State > **Eight specialist AI agents. Grounded in verified Washington law. Your documents never leave your network.** Astraea is a self-hosted, multi-agent legal information assistant focused on Washington State family law: divorce, custody, child support, maintenance, property division, protection orders, and mediation. It combines retrieval-augmented generation (RAG) over a curated library of state-specific legal references with tool-calling LLM agents, PDF form auto-fill, per-user document vaults, and optional Twilio/SMTP communications — all running on your own hardware with your own models. **Live instance:** https://astraea.thetempleofdoom.com --- ## Why Astraea People going through divorce or custody battles face three problems: lawyers are expensive, court forms are intimidating, and generic chatbots hallucinate the law. Astraea attacks all three: 1. **Grounded answers, not vibes.** Every agent answers from a curated book library (185KB of verified WA-law reference material citing RCW chapters, controlling case law like *In re Marriage of Littlefield*, and WashingtonLawHelp.org). Responses carry citations back to the source chunks. 2. **Specialists, not one generic bot.** Eight agents, each with its own system prompt, book subset, and focus — from the intake Navigator to the Protection Orders specialist with built-in DV-safety guardrails. 3. **Self-hosted and private.** Runs on a Proxmox LXC container, talks to a LAN Ollama server, and stores everything in a local SQLite database. No cloud APIs, no data leaving your network. > ⚠️ **Not legal advice.** Astraea is an educational and organizational tool. It does not replace a licensed Washington attorney. This notice is embedded in the product, the agents' system prompts, and every source book. ## The Eight Specialists | Agent | Focus | |---|---| | 🧭 **Navigator** | Intake — where to start, which specialist next, the overall WA process | | ⚖️ **Divorce & Dissolution** | No-fault dissolution, legal separation, the 90-day wait, decrees | | 🧒 **Child Custody & Parenting** | Parenting plans, best-interest factors, relocation, nonparental custody | | 💰 **Child Support** | Washington's economic table, imputation, deviations | | 🤝 **Spousal Maintenance** | Alimony factors, duration, modification | | 🏠 **Property & Debt** | Characterization, fair-and-equitable division, QDROs | | 🛡️ **Protection** | Protection orders, no-contact orders, DV safety planning | | 🕊️ **Mediation & ADR** | Mediation, arbitration, collaborative law, settlement strategy | ## Feature Highlights - **Multi-agent RAG chat** — stdlib-only vector engine (embeddings via Ollama, cosine retrieval, cached disk index, incremental rebuild when a book changes) - **Per-user document vault** — upload filings/correspondence/evidence; text extracted (PDF/DOCX/TXT), chunked, embedded, and retrieved as `[USER DOC]` context in chats - **PDF form auto-fill** — 10+ Washington court form packets (FL All-Cases series) with field detection (`detect_fields.py` + `pymupdf` overlay) and LLM-assisted mapping from your case facts - **Document generation** — declarations, letters, timelines generated from your case context - **Comms missions with DV safety guard** — Twilio SMS/voice + SMTP email with a hard block on contacting anyone protected by a no-contact/protection order, plus formal message templates - **No-KYC auth** — username/password only, per-user profiles with an "About Me" context system, 12 professional avatars - **Text-to-speech** — every answer speakable via edge-tts - **Conversation memory** — per-agent persisted history in SQLite - **Zero cloud dependencies** — Flask + SQLite + Ollama; the RAG engine is pure stdlib (urllib + json + math) ## Architecture ``` ┌─────────────────────────────────────────┐ Browser ──HTTPS──▶│ nginx (TLS termination, fleet tunnel) │ └───────────────┬─────────────────────────┘ │ :5000 ┌───────────────▼───────────────┐ │ Astraea (Flask + gunicorn) │ │ ├─ agents.py 8 specialists │ │ ├─ rag.py vector engine │ │ ├─ store.py SQLite DAL │ │ ├─ userdocs.py doc vault │ │ ├─ forms.py PDF autofill │ │ ├─ comms.py Twilio/SMTP │ │ └─ tts.py edge-tts │ └───────────────┬───────────────┘ │ LAN ┌───────────────▼───────────────┐ │ Ollama host (GPU) │ │ ├─ qwen3.8fast orchestrator │ │ ├─ ornith-1.5:9b fallback │ │ └─ nomic-embed embeddings │ └───────────────────────────────┘ ``` **Repo layout** ``` ├── app.py # Flask app: routes, chat orchestration, uploads (757 lines) ├── agents.py # The 8 specialist definitions (system prompts, book subsets) ├── rag.py # Stdlib-only RAG: chunk → embed → cosine retrieve → cite ├── store.py # SQLite: users, sessions, profiles, settings, messages, files ├── documents.py # Generated-document engine ├── detect_fields.py # PDF form field detection (pymupdf) ├── forms.py # Court-form fill + overlay endpoints ├── comms.py # Twilio SMS/voice + SMTP, no-contact safety guard ├── tts.py # edge-tts speech synthesis ├── userdocs.py # Per-user document vault ingestion ├── books/ # 16 curated WA family-law reference books (the RAG corpus) ├── templates/ # Landing page + app SPA (vanilla JS, no build step) ├── static/ # Assets ├── astraea.service # systemd unit (gunicorn, 2 workers × 4 threads) ├── astraea-nginx.conf # nginx site config └── benchmark_models.py # Model-selection benchmark harness ``` ## Quick Start ### Requirements - Python 3.11+ (3.9 works with minor tweaks — stdlib-only core) - An [Ollama](https://ollama.com) server reachable on your LAN with: - `qwen3.8fast` (or any tool-calling model) — orchestrator - `ornith-1.5:9b` (or any reliable instruct model) — fallback - `nomic-embed-text-v2-moe` — embeddings - Optional: `pymupdf` for PDF form filling, `edge-tts` for speech ### Install ```bash git clone http://10.30.20.149:3000/drjones/astraea.git cd astraea python3 -m venv venv && source venv/bin/activate pip install -r requirements.txt pip install pymupdf edge-tts # optional features ``` ### Configure Point the agents at your Ollama host in `agents.py`: ```python OLLAMA_URL = "http://your-ollama-host:11434" RAG_MODEL = "qwen3.8fast" # tool-calling orchestrator GENERAL_MODEL = "ornith-1.5:9b" # fallback EMBED_MODEL = "nomic-embed-text-v2-moe" ``` The vector index builds on first boot (background thread) and caches to `index.json`. ### Run ```bash python app.py # dev, port 5000 # or production: gunicorn --workers 2 --threads 4 --bind 0.0.0.0:5000 --timeout 240 app:app ``` Register a user, answer the About-Me prompts (this becomes silent context for every agent), and start with the **Navigator**. ### Deploy on Proxmox LXC (how we run it) ```bash pct create 150 local:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst \ --hostname astraea --memory 2048 --cores 2 \ --net0 name=eth0,bridge=vmbr0,ip=10.30.20.160/24,gw=10.30.20.1 \ --rootfs poolmaster:8 --unprivileged 1 pct start 150 # then: install python3-venv, clone, pip install, cp astraea.service /etc/systemd/system/ systemctl enable --now astraea ``` nginx TLS termination + Cloudflare Tunnel gives the public URL. See `astraea-nginx.conf`. ## The RAG Corpus `books/` contains 16 reference books (~185KB) written as structured Markdown, each with inline citations to RCW statutes, Washington case law, and WashingtonLawHelp.org: - `divorce-dissolution.md` + 3 case-law companions (characterization, division, maintenance) - `custody-parenting.md`, `parentage.md`, `guardianship.md` - `child-support.md`, `spousal-maintenance.md`, `property-debt.md` - `protection-orders.md`, `mediation-adr.md`, `modification-enforcement.md` - `overview-intake.md`, `committed-relationships.md`, `adoption.md` The index is chunked at ~1200 chars, embedded once, and rebuilt incrementally per-book on change. Retrieval returns top-k chunks as `[SOURCE n]` blocks the agent must cite. ## Safety Design - **Not-legal-advice notice** in the product UI, agent system prompts, and every book header - **No-contact safety guard** (`comms.py`): if a user's profile indicates a protection/no-contact order is in effect, outbound Twilio/SMTP actions toward the protected party are hard-blocked with a safety message - **No-KYC by design**: no emails, no phone numbers required at signup; users stay anonymous - **Local-only data**: uploads, chats, and profiles live in one SQLite file on your container ## Known Limitations & Roadmap - [ ] **Password hashing is unsalted SHA-256** — needs bcrypt/argon2 with a transparent re-hash-on-login migration (next security release) - [ ] Session tokens don't expire — add TTL + refresh - [ ] No rate limiting on auth/chat endpoints - [ ] Single-node SQLite — Postgres adapter for multi-user scale - [ ] Books cover WA only — contributions for other states welcome (keep the citation format!) - [ ] Streaming responses (currently full-answer) ## Operations ```bash systemctl status astraea # service health curl localhost:5000/api/health # app health + index status curl -X POST localhost:5000/api/reindex # force full RAG rebuild ``` Database backup: `cp astraea.db astraea.db.bak-$(date +%F)` — everything (users, chats, vault metadata) is in that one file. Uploads live in `uploads/`. ## Credits Built by [drjones](https://github.com/drjonesxxx1) on a Proxmox homelab with local Ollama models — no cloud APIs were harmed. --- *Licensed under MIT — see [LICENSE](LICENSE). Legal reference material is educational, cites public sources, and is not legal advice.*