{"slug": "show-hn-casecite-free-rag-caselaw-research-and-document-analysis-for-lawyers", "title": "Show HN: CaseCite – Free RAG caselaw research and document analysis for lawyers", "summary": "CaseCite launched as a source-available, self-hosted legal research platform that lets law firms run retrieval-augmented generation (RAG) over their own documents using their own API keys, under the Elastic License 2.0. The platform bundles eight tools behind one login — research chat with semantic retrieval plus BM25 rescoring and inline citations, document indexing with imports from Google Drive, OneDrive, Box, Dropbox, iManage, NetDocuments, Filevine and Clio, contract review and redlining, long-document drafting, CourtListener case chat, an authority map, judge analytics and legal tools. CaseCite stores documents, the vector index and chat history only on the user's deployment, but uploading a document sends its text to an embeddings provider (OpenAI by default, or Voyage or Cohere) and asking, analyzing or drafting sends text to an LLM provider (OpenAI, Anthropic or Gemini); running fully on-network requires setting both OPENAI_BASE_URL and EMBEDDING_BASE_URL to self-hosted OpenAI-compatible servers.", "body_md": "CaseCite is a **source-available, self-hosted** legal research platform. Upload your firm's documents, ask questions, and research cases & judges — on infrastructure you control. Documents, the search index and chat history are stored on your own servers. AI features send your questions and the relevant document text to the AI providers **you** configure, under your own API keys (BYOK); nothing is sent to the CaseCite maintainers, and there is no telemetry. See [What leaves your infrastructure](#what-leaves-your-infrastructure).\n\nEight tools behind one login, all reading from the same document corpus.\n\n| **Research** (`/research` ) | Chat over your firm's documents — semantic retrieval with keyword (BM25) rescoring of the candidates, and inline citations back to the source. | \n| **Documents** (`/documents` ) | Upload, index, and organize your corpus. Import from Google Drive, OneDrive, Box, Dropbox, iManage, NetDocuments, Filevine, or Clio — OAuth sync, or a file picker where OAuth verification isn't needed. | \n| **Contracts** (`/contracts` ) | Full contract review pipeline: analyze an indexed contract or pasted text, chat with a single contract, compare 2–4 contracts clause-by-clause against a baseline, and export a redline, a draft, or the analysis itself. | \n| **Drafting** (`/drafting` ) | Draft a document grounded in up to four documents you pick from the Knowledge Base, with server-side text extraction and PDF conversion. Set a target length for long documents (30-page agreements): you review a section plan first, then every section is drafted in its own context window against the full references and the whole is reconciled. Revisions to long drafts are scoped to the sections they touch. | \n| **Case view** (`/case/:id` ) | Open a CourtListener opinion and chat with it directly. | \n| **Authority map** (`/case-citations` ) | Map the authorities cited across documents you select. | \n| **Judge intel** (`/judge-intel` ) | Judge analytics from CourtListener. | \n| **Legal tools** (`/tools` ) | Case lookup, citation check (a scan of citing opinions for negative-treatment language — not a Shepard's/KeyCite substitute), precedents, dockets, oral arguments, and case-law trends. | \n\n**Practice profile.** Nothing about any practice area is baked into the product.\nYou state what you practice, CaseCite drafts a profile of what matters in that\npractice, and you edit and own it (saved via Settings). It then rides along with\nevery review, redline, and draft as standing context.\n\nEvery AI-generated answer, analysis and draft carries a notice to verify it against the source documents and current law before relying on it. CaseCite is a research aid, not a substitute for a lawyer's judgment or for a citator.\n\nDocuments, the vector index, chat history and analyses are **stored** only on\nyour deployment. Using the AI features **transmits** content to third parties\nyou choose:\n\n- **Uploading a document** sends its text to the embeddings provider (OpenAI\nby default; Voyage or Cohere if configured).\n- **Asking a question, analysing or drafting** sends the question and the\nrelevant document text to the LLM provider (OpenAI, Anthropic or Gemini).\n- **Case-law tools** send search queries and citations to CourtListener.\n\nTo keep document text entirely on your network, run both models yourself: set\n`OPENAI_BASE_URL` (chat) **and** `EMBEDDING_BASE_URL` (embeddings) to\nOpenAI-compatible servers you host. Setting only the first still sends\ndocument text to OpenAI for embedding. The full list of outbound data flows,\nand how to restrict them, is in [docs/subprocessors.md](https://github.com/thomasunise/casecite/blob/main/docs/subprocessors.md).\n\nCaseCite is licensed under the **Elastic License 2.0** ([LICENSE](https://github.com/thomasunise/casecite/blob/main/LICENSE)). In plain terms:\n\n- ✅ Free to **self-host** for your firm's internal use.\n- ✅ Free to **modify** for your own deployment.\n- ❌ Not permitted to offer CaseCite to third parties as a hosted/managed service.\n- ❌ Not permitted to alter or remove licensing or copyright notices.\n\nFor paid private installs, support contracts, or hosted-SaaS licensing, contact the maintainer, [@thomasunise](https://github.com/thomasunise), through GitHub. See [SUPPORT.md](https://github.com/thomasunise/casecite/blob/main/SUPPORT.md).\n\n\"Source-available,\" not OSI \"open source.\" See [LICENSE](https://github.com/thomasunise/casecite/blob/main/LICENSE) for the full terms.\n\n- Docker + Docker Compose\n- `openssl` (to generate secrets)\n- An AI provider API key (OpenAI is the simplest start: it covers both chat and embeddings). Optional at the server level — users can each save their own.\n\n```\ngit clone https://github.com/thomasunise/casecite.git && cd casecite\ncp .env.example .env\n\n# 1. Generate the three REQUIRED secrets (the .env.example placeholders\n#    intentionally refuse to boot). Copy each value into .env:\nopenssl rand -hex 32   # -> SECRET_KEY\nopenssl rand -hex 32   # -> AUDIT_HMAC_KEY\nopenssl rand -hex 16   # -> ENCRYPTION_SALT\n\n# 2. In .env also set OPENAI_API_KEY (or leave it empty and save a key under\n#    Settings after signing in), then uncomment and set DOMAIN,\n#    POSTGRES_PASSWORD and REDIS_PASSWORD in the \"Bundled production stack\"\n#    section (generation hints are in the file; use DOMAIN=localhost to try it\n#    on your machine). CORS_ORIGINS and ALLOWED_HOSTS default from DOMAIN.\n#    Set REGISTRATION_BOOTSTRAP_TOKEN too (openssl rand -hex 16) — you need it\n#    to create the first account.\n\n# 3. Set DISK_ENCRYPTION_ACKNOWLEDGED=true in .env (required to boot).\n#    What this acknowledges: the app encrypts BYOK keys and uploaded documents\n#    at the application layer (AES-256-GCM), but derived text (vector chunks,\n#    chat history, analyses) is stored in cleartext in the app, Postgres and\n#    Redis volumes — full-disk encryption of the host is YOUR responsibility.\n\n# 4. Start the full stack (bundled Postgres + Redis + Caddy):\ndocker compose -f docker-compose.prod.yml up -d\n```\n\n`python3 scripts/setup_production.py --create-env --domain <host>` does steps\n1–2 for you (it generates every secret and writes `.env` with mode 0600).\n\nThen open **https://$DOMAIN** (with `DOMAIN=localhost`: **[https://localhost](https://localhost)**).\nOn a localhost trial Caddy redirects HTTP to HTTPS and serves a certificate\nfrom its own self-signed local CA — the browser warning on first visit is\nexpected. See \"TLS on Internal Networks\" in [docs/deployment.md](https://github.com/thomasunise/casecite/blob/main/docs/deployment.md)\nto trust that CA or bring your own certificate.\n\nThe first account you register becomes the admin, and registering it requires\nthe `REGISTRATION_BOOTSTRAP_TOKEN` from `.env` — so nobody else who reaches a\nfresh instance can claim it. The exact command is under \"Create the admin\naccount\" in [docs/deployment.md](https://github.com/thomasunise/casecite/blob/main/docs/deployment.md). After that, invite\ncolleagues from Settings → Users; self-service registration is off by default.\n\nDeploying behind an existing reverse proxy (Coolify/Traefik)? Use the root\n`docker-compose.yml` instead (it expects an external Postgres and Redis and\ndeclares the persistent data volume), and read `deploy/COOLIFY-SETUP.md` —\nyou must also set `TRUSTED_PROXIES` to the proxy's subnet or client IPs\ncollapse to one.\n\nUsers provide AI provider keys via the Settings modal. What firm evaluators should know about custody:\n\n- Per-user keys are stored **server-side** , AES-256-GCM-encrypted (PBKDF2 key\nderivation, HKDF per-record separation), in a file store on the data volume.\n- Keys are displayed masked-only and are **never sent to the browser** ; the\nbackend decrypts them on demand for each request.\n- Env-configured fallback keys (e.g. `OPENAI_API_KEY` in`.env` ) are shared by**all users** of the install — per-user cost attribution requires per-user\nBYOK keys.\n- `ENCRYPTION_SALT` can be rotated without losing stored keys: keep the old\nvalue in`ENCRYPTION_SALT_PREVIOUS` and run`python -m app.utils.reencrypt` inside the backend container — see`docs/secret-rotation.md` .`SECRET_KEY` cannot be rotated without making stored documents unreadable; keep it safe\nand backed up off the server.\n\nThe stack fails closed on startup if any of these are missing or left as placeholders.\n\n| Variable | Description | \n|---|---|\n| `SECRET_KEY` | JWT/CSRF signing key and root of at-rest encryption — `openssl rand -hex 32` (**never change after first run** ) | \n| `ENCRYPTION_SALT` | At-rest encryption salt — `openssl rand -hex 16` (**never change after first run** except via the rotation procedure) | \n| `AUDIT_HMAC_KEY` | Audit-log chain key — `openssl rand -hex 32` | \n| `POSTGRES_PASSWORD` | Password for the bundled Postgres | \n| `REDIS_PASSWORD` | Password for the bundled Redis | \n| `DOMAIN` | Public hostname (or `localhost` );`CORS_ORIGINS` +`ALLOWED_HOSTS` default from it | \n| `DISK_ENCRYPTION_ACKNOWLEDGED` | Set `true` to acknowledge that full-disk encryption of the host volumes is your responsibility (app-layer AES-256-GCM covers BYOK keys + document originals; derived text is cleartext) | \n| `REGISTRATION_BOOTSTRAP_TOKEN` | Needed to register the first (admin) account — `openssl rand -hex 16` | \n\nNot required to boot, but the product does little without them:\n\n| Variable | Description | \n|---|---|\n| `OPENAI_API_KEY`*(or another provider)* | Server-level provider key shared by all users. Without one, each user must save their own key under Settings before chat, analysis or indexing works. | \n| `COURTLISTENER_API_TOKEN` | CourtListener is the only case-law source in the app. Citation check requires a token; the other case-law tools work without one but are heavily rate-limited. Free token; see [CourtListener API token](#courtlistener-api-token) . | \n\nUsing the root `docker-compose.yml` (external DB/Redis) instead of the bundled\nstack? Then `DATABASE_URL`, `REDIS_URL`, `CORS_ORIGINS`, and `ALLOWED_HOSTS`\nare required directly, and set `DB_SSL=require` for a managed database.\n\n| Variable | Default | Description | \n|---|---|---|\n| `ANTHROPIC_API_KEY` | — | Claude access | \n| `VOYAGE_API_KEY` | — | Voyage AI legal embeddings | \n| `OPENAI_BASE_URL` | — | OpenAI-compatible endpoint for chat (self-hosted model or gateway) | \n| `EMBEDDING_BASE_URL` | — | OpenAI-compatible endpoint for embeddings; set with `OPENAI_BASE_URL` to keep document text on your network | \n| `VECTOR_DB` | `chroma` | `chroma` (local) or`pinecone` (stores document text with Pinecone) | \n| `TRUSTED_PROXIES` | `127.0.0.1` | Reverse-proxy IP/CIDR — **required behind a proxy** | \n| `REQUIRE_MFA` | `false` | Require every password account to enrol TOTP MFA | \n| `SESSION_ABSOLUTE_TIMEOUT_HOURS` /`SESSION_IDLE_TIMEOUT_MINUTES` | `8` /`120` | Session lifetime and idle timeout | \n| `ALLOW_REGISTRATION` | `false` | Allow self-service sign-up after the first account | \n| `SENDGRID_API_KEY` | — | Enables password-reset emails (change-password works without it) | \n\n`.env.example` documents every setting.\n\n- The sync API imports one folder (`folder_id` ) or, with an explicit`sync_all` , the whole account. The UI has no folder picker yet: \"Sync Now\"\nimports the whole connected account after a second confirmation that says so.\nTo bring in selected files, use the file pickers instead. Clio's listing is\naccount-wide, so Clio cannot sync a single folder.\n- Filevine uses one firm-wide API key, so it is off until\n`FILEVINE_ENABLED=true` and is then available to admins only.\n- The iManage and NetDocuments connectors are implemented against the vendors'\npublished APIs but have **not** been validated against a live tenant. Test\nthem in your environment before relying on them.\n- Microsoft and Google connections request read-only scopes. Connections made before this release keep their broader grant until reconnected.\n\nLegal tools, Judge intel, Case view, and the case-law side of the strategy\nengine all read from [CourtListener](https://www.courtlistener.com). CourtListener is the **only** case-law source in\nthe app. The app starts without a token, but the case-law half of the product\nis not usable without one:\n\n- **Citation check hard-fails without it** — the service raises`CourtListener API token required` (`backend/app/services/courtlistener.py` ).\n- Every other CourtListener call falls back to anonymous access, which is rate-limited hard enough that research features become unusable under any real load.\n\nGet a **free** token at\n[https://www.courtlistener.com/help/api/rest/#permissions](https://www.courtlistener.com/help/api/rest/#permissions), then either set\n`COURTLISTENER_API_TOKEN` in `.env`, or save it instance-wide as an admin\n(Settings → API Keys, or `POST /api/v1/admin/integrations/courtlistener`) —\nthe stored token overrides the `.env` value at runtime without a restart.\n\n```\nbackend/\n  app/\n    main.py              FastAPI app, middleware, health\n    config.py            Pydantic settings\n    routers/             API routers\n    services/\n      rag/               RAG pipeline (search, generation, citations, intent)\n      vectordb.py        ChromaDB/Pinecone abstraction\n      embeddings.py      Multi-provider embeddings\n      auth.py            JWT auth\n      strategy.py        Matter strategy briefs\n      courtlistener.py   CourtListener API\n      ...\n    middleware/          Security, CSRF\n  migrations/            Alembic migrations\nfrontend/\n  src/\n    App.tsx\n    api/                 Per-domain API clients\n    views/               Page views\n    stores/              Zustand stores\n    components/          Shared components + modals\n    layout/              App shell\nscripts/                 Backup/restore, production setup, key rotation, NOTICE generator\ndocs/                    Deployment, data flows, secret rotation, incident response, ADRs\nDockerfile               Unified image (frontend + backend)\ndocker-compose.prod.yml  Bundled stack: Caddy + Postgres + Redis + backend\ndocker-compose.yml       Behind an existing proxy (Coolify/Traefik); external Postgres + Redis\ndocker-compose.dev.yml   Local development\n```\n\nThese are implemented and reachable over the API, but the frontend does not expose them yet. Treat them as preview:\n\n- **Matters** (`/api/v1/matters` ) — matter records, membership, and sharing of\ndocuments and chats between members. Creating matters and changing\nmembership requires the`matters.manage` permission.\n- **Strategy briefs** (`/api/v1/strategy` ) — each proposition is searched on\nCourtListener, candidate opinions are read, and a citation is kept only when\na verbatim quote can be located in the real opinion text. Unsupported\ncitations are dropped rather than shown.\n- **Azure AD SSO** — backend token exchange only; there is no sign-in button.\nSAML, generic OIDC and SCIM are not supported.\n\nEverything else in the feature table above, plus user administration and the audit log (Settings, admins only), has a UI.\n\n- Password sign-in (PBKDF2-SHA256) with optional or mandatory TOTP MFA and recovery codes; password reset by email and change-password in the app\n- JWT access tokens with rotating refresh tokens in httpOnly cookies, JTI revocation in Redis (required in production), \"sign out everywhere\"\n- Sessions capped at 5 per user, with an 8-hour absolute lifetime and an idle timeout\n- Role-based permissions (`require_permission` ), adjustable per role by an admin\n- Per-user (and per-matter) scoping on every document, chat and analysis\n- CSRF double-submit cookies, HMAC-signed; per-IP rate limiting; account lockout\n- AES-256-GCM at-rest encryption for uploaded originals, API keys, connector tokens and MFA secrets. The vector index and database rely on disk encryption that you provide\n- CSP, HSTS, X-Frame-Options, Permissions-Policy headers\n- Audit log with HMAC-SHA256 chain hashing, verified at startup and on demand\n\nCaseCite holds no security certification (SOC 2, ISO 27001, HIPAA). What it\ndoes and does not do is described in [SECURITY.md](https://github.com/thomasunise/casecite/blob/main/SECURITY.md), which also\nexplains how to report a vulnerability; known gaps are listed in\n[ROADMAP.md](https://github.com/thomasunise/casecite/blob/main/ROADMAP.md).\n\nSee [CONTRIBUTING.md](https://github.com/thomasunise/casecite/blob/main/CONTRIBUTING.md). PRs welcome for the source-available product. Note that contributions are licensed under ELv2.", "url": "https://wpnews.pro/news/show-hn-casecite-free-rag-caselaw-research-and-document-analysis-for-lawyers", "canonical_source": "https://github.com/thomasunise/casecite", "published_at": "2026-10-25 20:47:26+00:00", "updated_at": "2026-10-25 21:12:28.002003+00:00", "lang": "en", "topics": ["artificial-intelligence", "generative-ai", "ai-products", "ai-tools", "large-language-models"], "entities": ["CaseCite", "CourtListener", "OpenAI", "Anthropic", "Gemini", "Voyage", "Cohere", "Elastic License 2.0"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/show-hn-casecite-free-rag-caselaw-research-and-document-analysis-for-lawyers", "markdown": "https://wpnews.pro/news/show-hn-casecite-free-rag-caselaw-research-and-document-analysis-for-lawyers.md", "text": "https://wpnews.pro/news/show-hn-casecite-free-rag-caselaw-research-and-document-analysis-for-lawyers.txt", "jsonld": "https://wpnews.pro/news/show-hn-casecite-free-rag-caselaw-research-and-document-analysis-for-lawyers.jsonld"}}