Astraea v1.0 — multi-agent WA family-law assistant

Eight specialist agents over a 16-book verified WA law corpus (RAG with citations),
per-user document vault, WA court-form PDF auto-fill, comms missions with DV
safety guard, no-KYC auth, TTS. Self-hosted: Flask + SQLite + Ollama, stdlib-only RAG.

Includes README, LICENSE (MIT + not-legal-advice notice), DEPLOY runbook, .gitignore.
This commit is contained in:
drjones
2026-09-07 18:49:32 -07:00
commit 9f9d812320
37 changed files with 4934 additions and 0 deletions

194
README.md Normal file
View File

@@ -0,0 +1,194 @@
# ⚖️ 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.*