Consumer-side AI that helps end users contest the institutional loops they're trapped in — insurance denials, surprise medical bills, parity violations. Recourse reads the letter, anchors your claim to actual statute, and runs a cadence engine that never lets the clock slip.
React 19 + TypeScript + Tailwind v4 · single canonical case (out-of-network mental health denial) · all data mocked, all statutes real.
Companion piece to Sentinel. Sentinel is oversight of AI by experts; Recourse is oversight of institutions by AI, on behalf of the person they're squeezing.
Live demo → · MCP server → · How it works → · Parity-law context → · Architecture → · Legal & compliance →
Not legal advice. Recourse identifies patterns and surfaces statutes; it does not interpret the law for your specific situation. For anything time-critical, high-dollar, or involving a court deadline, get a licensed attorney to review what the tool produced before you act. See docs/LEGAL.md for the full posture (UPL, HIPAA, state variance, B2B compliance gaps).
Recourse ships in three forms:
- Web app, canonical mode — two hand-authored cases (mental-health denial, surprise ER bill). Mocked end-to-end. Instant. The portfolio path.
- Web app, upload mode — two real tasks against a local Ollama vision model:
- Read a denial letter — single page in, structured fields out.
- Decode your insurance policy — multi-page SPD in, annotated map out (covered / excluded / vague (loopholes) / silent (gaps) / procedural requirements). Real vision call, no cloud, no API keys, no data leaving your machine. Setup below.
- MCP server (
mcp/) — same Ollama-backed extractors as the web app, exposed as tools any Model Context Protocol client (Claude Desktop, Claude Code, future agents) can call. Means the policy decoder becomes part of whatever AI workflow you already use, instead of a separate destination.
Every AI-for-legal product today is built for the lawyer or the in-house compliance team. The patient holding a $3,876 mental health denial gets nothing. Meanwhile the loop the institution runs against them is mechanical: vague denial code, 90-day clock, complex appeal, second denial, externally-reviewed appeal, statute of limitations. The institution wins by exhaustion. Recourse's win condition is being unexhaustible.
The product is not a chatbot. It is a document-first workflow:
EOB / denial letter → vision extraction → loop classifier
↓ ↓
the user reads ← plain-language claims ← statute-anchored strategy
↓
draft letter → cadence engine (3 deadlines, not 1) → certified mail
The visible artifact in this repo is a single canonical case — an out-of-network mental health denial with a parity-law attack surface — staged across four screens. A real product runs the same pipeline against any uploaded document.
This canonical case isn't arbitrary. It's picked because:
- Recent regulatory tailwind. The 2024 tri-agency MHPAEA Final Rule (DOL / HHS / Treasury) tightened NQTL (Non-Quantitative Treatment Limitation) parity requirements and named "ghost networks" as an enforcement priority. Plans now have to prove their mental-health review processes are comparable to medical/surgical.
- Clear procedural attack. A blanket CO-50 denial across 14 sessions with no documented medical-necessity review is a textbook NQTL flag. The leverage move — requesting the plan's parity comparative analysis under 29 CFR § 2590.712(d) — usually breaks the loop, because most plans haven't done the homework.
- Sympathetic story most reviewers recognize. Therapist waitlists are months long; patients pay out-of-network because the in-network directory is fiction; the claim gets denied for "non-medical necessity" with no review on record.
- Three real deadlines, not one. Internal appeal (90 days). Parity disclosure request (separate window). External review (opens after the internal denial). The cadence engine is the product.
Every statute citation in the demo (29 U.S.C. § 1185a, 29 CFR § 2590.712(d), 45 CFR § 146.136(c)(4), the 2024 final rule) is real. The patient, provider, plan numbers, and dollar amounts are fictional.
- Landing — the pitch + one "Run the example case" button.
- Scan — a believable EOB renders as paper; a scan-line sweep simulates the vision model reading it. Takes ~2 seconds. The point is to make the document recognizable, not to actually OCR.
- Extract — bounding boxes appear over the EOB; the right rail shows what the AI pulled (deadline, amount, denial code, plan type, network status). Hovering a row lights up its region on the page. This bidirectional anchor is the credibility moment.
- Strategy — four AI-generated claims about the case, each:
- prefaced with a plain-language gloss ("They have to show their work…") so a non-expert understands the move,
- labelled
Settled/You verify/Ask a lawyer(the calibrated-confidence layer, flipped for non-experts), - anchored to one or more real statutes with the operative excerpt and a "verified on" date,
- tagged with what the user still has to verify themselves (your plan type, your call logs, your state),
- sitting above three deadlines surfaced as the cadence engine.
- Draft — the actual appeal letter, every word visible before send. Statutes cited in-line. A "Send via certified mail" CTA closes the loop.
The two projects share primitives (calibrated confidence, evidence anchors, cross-hatch pattern for fabricated content) because the underlying problem is the same: AI claims become trustworthy only when their uncertainty is legible and their basis is checkable. What differs is the audience and the inversion of who's checking whom:
| Dimension | Sentinel | Recourse |
|---|---|---|
| Reader | Expert (clinician, lawyer, analyst) | End user (patient, tenant, debtor) |
| Confidence vocabulary | High / Likely / Unsure / Low — bands experts already use |
Settled / You verify / Ask a lawyer — action verbs, not percentages |
| Verdict model | Reader judges AI's claims (Accept / Edit / Reject) | AI explains itself; reader's role is to understand and verify, then send |
| Provenance | Evidence link to clinical/legal source the expert can read | Statute chip with excerpt, verified date, and a "verified on" stamp |
| Audit object | Per-claim verdict log for compliance | Deadline ledger + certified-mail receipts for the user |
Sentinel proves "every AI tool needs an oversight layer." Recourse proves "every adversarial institution needs an oversight layer the user controls."
- Not a chatbot. Conversational interfaces hide the structure. A document-first workflow lets the user see what the AI saw.
- Not a lawyer. The "Ask a lawyer" confidence band is intentional — the AI's job is to win procedurally, surface the disclosure ask, and run the clock, not to provide jurisdiction-specific legal advice.
- Not a generic "legal AI." Picking one loop hard makes the product sharp; market-fit research lives in the broader portfolio. Medical billing + insurance denial is the strongest target (proven monetization via GoodBill / Resolve, ~17% in-network denial rate, ~50% appeal win rate when filed).
npm install
npm run devOpen the printed URL.
npm run build # typecheck + production build
npm run preview # preview the built appA GitHub Pages deploy workflow lives alongside Sentinel's — this repo will get its own when there's a stable public URL to point at.
The "Upload your own" button on the landing switches into a mode where Recourse calls a local Ollama daemon to read a document you upload. The vision call runs entirely on your machine. Nothing leaves your laptop.
# 1. Install Ollama
brew install ollama
# or download the .dmg from https://ollama.com
# 2. Pull a vision-capable model (pick one)
ollama pull llava # 7B, ~5 GB, fast
ollama pull llama3.2-vision # 11B, ~8 GB, better quality
ollama pull bakllava # 7B, ~5 GB, decent middle ground
# 3. Start Ollama with browser-CORS allowed (this is the step most
# people miss — without it, the browser can't talk to localhost:11434)
OLLAMA_ORIGINS="*" ollama serveLeave that terminal running. Verify with:
curl http://localhost:11434/api/tagsOnce Ollama is reachable, the upload screen offers two tasks against the same daemon:
1. Read a denial letter / bill (single-page).
- Drop an EOB, denial letter, or hospital bill (PDF, PNG, JPG, WebP).
- Renders page 1 to a canvas, runs one vision call, returns structured fields: insurer, claim ID, deadlines, denial code, plan type, amount, network status.
- ~10–15 seconds per document on M1/M2.
2. Decode your insurance policy (multi-page).
- Drop your Summary Plan Description (SPD), Evidence of Coverage (EOC), or Certificate of Insurance.
- Renders up to 25 pages as a vertical thumbnail stack on the left; each page goes through the vision model with a prompt that surfaces what's covered, what's excluded, what's deliberately vague, what's silent (gaps), and what procedural steps are required.
- Annotations stream into the right panel as each page finishes, filterable by kind.
- ~5–15 minutes for a 25-page policy on M1/M2. Cancel any time — partial results are kept.
Reading a denial letter is the reactive moment — the insurer already said no, you're fighting an existing decision. Decoding the policy is the proactive moment — you're learning what loopholes the insurer can use against you before they're used. The asymmetry the product targets is that the insurer's claims adjusters open your policy and find the exclusion to deny you under; you don't even know that exclusion exists. The decoder closes that gap on your side.
- No claim or appeal generation. A 7B–11B local model isn't reliable enough to cite real statute correctly. Both upload modes stop at extraction or annotation; the canonical cases retain hand-authored playbooks for the harder reasoning.
- No bounding-box anchoring on uploaded docs. Vision models don't return reliable pixel coordinates for arbitrary documents. The bbox bidirectional anchor is canonical-mode-only.
- No state-mandate cross-reference yet. The decoder flags vague language and silent gaps, but doesn't yet check those against state-mandate floors (which often override the policy). That's the next layer.
- Decoder caps at 25 pages. Most plan summaries fit; for 100+ page master agreements, the first 25 pages typically cover the load-bearing benefit structure.
- No API keys, no costs, fully private — case data never leaves the user's machine. For consumer-legal AI specifically, that's a meaningful posture, not just a tagline.
- Forkable. Anyone reading this README can clone, install Ollama, and have the whole pipeline running locally in ~3 minutes. The portfolio piece doubles as a runnable artifact.
- Forces honest UX. Local-only means the demo can't paper over model failures with a fallback to a more expensive API. The failure modes (parse error, no vision model, daemon down) all get first-class UI.
- Vite + React 19 + TypeScript (strict)
- Tailwind v4 with
@themedesign tokens (OKLCH palette, dark default + light mode) — shifted accent from Sentinel'sinfoblue to a warmeremberso it reads as a sibling, not a clone - Radix UI primitives for dialogs / popovers
- Lucide icons + Fraunces for display type
- pdfjs-dist for in-browser PDF rendering to a canvas (upload mode)
- Zod for validating model output against a strict extraction schema
- Ollama (local daemon, optional) for the upload-mode vision calls
A portfolio piece exploring AI Trust & Safety on the consumer side. Sentinel asks "how should the expert reviewing AI work?"; Recourse asks "what does the AI look like when the user is the one being run on a loop, and the AI is in their corner?" Same primitives, inverted oversight, different politics.