# Project export: Medicaid Sherlock

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2026
- Tagline: Medicaid Sherlock is an open-source, multi-agent investigative copilot that scans 227M Medicaid claims to surface explainable high-risk billing patterns.
- Devpost: https://devpost.com/software/medicaid-sherlock
- GitHub: https://github.com/KrishDesai/medicaid-sherlock
- Video: https://www.youtube.com/embed/NpK-U383Yso?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — KrishDesai (3 commits)

## Devpost submission (written by the team)

### Inspiration

Medicaid helps serve 70 to 80 million people every year, which comes out to roughly 1 to 4 Americans. But due to the large number of people Medicaid is provided to, investigative capacity is limited. Parsing millions if not billions of data entries, and assessing billing patterns that look suspicious is slow, manual and full of false positives. Medicaid Sherlock is a open-source multi-agent AI system that helps investigators triage faster and help catch perpetrators in a more effective manner.

### What it does

Medicaid Sherlock is a multi-agent AI system that analyzes 227 million Medicaid claim rows between the years 2018 and 2024 and flags providers with unusual billing patterns using five anomaly detectors (spending outliers, cost-per-claim outliers, billing spikes, billing/service mismatch, and procedure concentration). It then uses a 5 agent workflow to turn any flagged provider into a nuanced case file that includes peer comparisons, time-series evidence, billing network relationships, HCPCS plain-English translation, and public context to separate explained structural patterns to unexplained signals that warrant review.

### How we built it

Data pipeline (DuckDB + Parquet): Pre-aggregated benchmarks (HCPCS×year medians/p95/p99), provider summaries, and monthly time series for fast analytics over a huge dataset. Anomaly detection layer: Implemented five complementary detectors and unified all flags into a single anomalies table with scores and categories. Cross-referencing engine: Intersected risk dimensions to surface high-signal leads (e.g., multi-flag providers, extreme cost outliers, new high spenders, flagged networks). Enrichment: NPPES NPI Registry API to classify providers (organization vs individual, specialty/taxonomy, location) for context-aware scoring. HCPCS lookup (official CMS file + common CPTs) to translate procedure codes. Perplexity Sonar to pull relevant public records and enforcement context. Multi-agent system (Claude Sonnet): Investigator orchestrates Analyst + Network Mapper + Researcher + Report Generator to produce structured reports with evidence and caveats. Frontend (demo): An interactive UI for exploring anomalies, drilling into providers, visualizing networks, and generating a report for screen-recorded demos.

### Challenges we ran into

Scale: Working with a massive dataset required careful pre-aggregation, indexing strategies, and avoiding “full table scans.” False positives / structural noise: Hospitals, FQHCs, and integrated systems naturally look anomalous; we had to design the system to avoid reckless conclusions and add context-aware interpretation. OSINT reliability: Web context can be messy; we structured outputs to separate confirmed enforcement actions from unverified allegations and to surface uncertainty clearly.

### Accomplishments we're proud of

Built a complete end-to-end investigation pipeline from raw claims to anomalies to cross-referenced leads to enriched case files. Created a system that’s explainable by design: every flag has a rationale, peer comparison, and a “legitimate explanation” section. Successfully integrated a multi-agent investigation workflow that produces structured, investigator-friendly reports on demand.

## README (from the GitHub repository)

# Medicaid Sherlock

Medicaid fraud detection and investigation system: a **DuckDB-powered pipeline** over HHS T-MSIS claims data and a **multi-agent framework** (Claude + Perplexity + NPPES) for provider-level intelligence.

---

## What it does

- **Scripts pipeline (batch):** Ingest 227M+ Medicaid claims, compute procedure benchmarks and provider summaries, run five anomaly-detection algorithms, enrich top-risk providers with NPPES and web research, and produce an executive briefing plus cross-referenced leads.
- **Multi-agent (conversational):** Investigate any provider on demand. The **Investigator** coordinates an **Analyst** (DuckDB + NPI + HCPCS), **Researcher** (Perplexity), **Network Mapper** (billing/servicing relationships), and **Report Generator** to produce structured investigation reports.

See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for data-flow diagrams and how scripts and agents connect.

---

## Requirements

- **Python 3.10+**
- **Data:** Place `medicaid-provider-spending.parquet` (or your T-MSIS-style spending file) in `data/`. Expected columns include `BILLING_PROVIDER_NPI_NUM`, `SERVICING_PROVIDER_NPI_NUM`, `HCPCS_CODE`, `CLAIM_FROM_MONTH`, `TOTAL_PAID`, `TOTAL_CLAIMS`, `TOTAL_UNIQUE_BENEFICIARIES`.
- **APIs (optional but recommended for full flow):**
  - [Anthropic](https://www.anthropic.com/) API key — for 05 deep analysis narrative, 06 executive briefing, and multi-agent (Claude).
  - [Perplexity](https://www.perplexity.ai/) API key — for web research in 05, 08, and the Researcher agent.
- **NPPES:** NPI lookups use the public [NPPES Registry API](https://npiregistry.cms.hhs.gov/) (no key required).

---

## Setup

### 1. Clone and virtualenv

```bash
git clone <repo-url>
cd medicaid-sherlock
python3 -m venv venv
source venv/bin/activate   # Windows: venv\Scripts\activate
```

### 2. Install Python dependencies

```bash
pip install -r requirements.txt
```

### 3. Environment variables

Copy the example env file and set your keys (do not commit `.env`):

```bash
cp .env.example .env
# Edit .env and set ANTHROPIC_API_KEY and PERPLEXITY_API_KEY
```

| Variable | Used by | Purpose |
|----------|---------|---------|
| `ANTHROPIC_API_KEY` | 05, 06, multi-agent | Claude (deep analysis, briefing, all agents) |
| `PERPLEXITY_API_KEY` | 05, 08, multi-agent | Perplexity Sonar (web research) |

### 4. Data

- Put your claims parquet in `data/medicaid-provider-spending.parquet`.
- HCPCS descriptions: the agent uses `agent/hcpcs_codes.json` (from CMS 2026 release). Populate or generate it if you need procedure lookups.

---

## Scripts pipeline (run in order)

Run from the project root. Later steps depend on earlier outputs in `data/`.

| Step | Script | Purpose |
|------|--------|---------|
| 1 | `python scripts/01_explore.py` | Schema and summary stats (row count, top providers, time range). |
| 2 | `python scripts/02_enrich_npi.py` | Extract unique NPIs to `data/unique_npis.parquet` (for bulk lookups if needed). |
| 3 | `python scripts/03_benchmarks.py` | Build `procedure_benchmarks`, `provider_summaries`, `provider_monthly` parquet files. |
| 4 | `python scripts/04_anomaly_detection.py` | Run 5 anomaly algorithms → `data/all_anomalies.parquet`. |
| 5 | `python scripts/05_deep_analysis.py` | Top-20 risk providers + NPPES + Perplexity → `data/intelligence_report.json`. |
| 6 | `python scripts/06_generate_report.py` | Claude turns `intelligence_report.json` into `data/executive_briefing.md`. |
| 7 | `python scripts/07_cross_references.py` | Cross-reference risk lists → `data/cross_references.json`. |
| 8 | `python scripts/08_enrich_leads.py` | Enrich cross-referenced leads with NPPES + Perplexity → `data/enriched_leads.json`. |

Steps 5, 6, and 8 call external APIs; 1–4 and 7 are local DuckDB only.

---

## Multi-agent (conversational)

From the project root, run the agent from the `agent` directory so imports resolve:

```bash
cd agent && python multi_agent.py
```

Then type natural-language requests, e.g. “Investigate NPI 1234567890” or “Who are the highest-risk providers for cost-per-claim?” The **Investigator** will delegate to the Analyst, Researcher, Network Mapper, and Report Generator and return a single answer. Type `quit` to exit.

Requires the same `data/` outputs as the scripts (at least 03 and 04 run) so that `all_anomalies`, `provider_summaries`, `procedure_benchmarks`, and `medicaid-provider-spending.parquet` exist.

---

## Project layout

```
medicaid-sherlock/
├── agent/                 # Multi-agent system
│   ├── multi_agent.py      # Investigator + Analyst, Researcher, Network Mapper, Report Generator
│   ├── tools.py            # DuckDB queries for Analyst
│   ├── hcpcs_loader.py     # HCPCS/CPT code lookup
│   └── hcpcs_codes.json    # Procedure code descriptions (e.g. CMS 2026)
├── data/                   # Input/output data (parquet, JSON, briefing)
│   ├── medicaid-provider-spending.parquet   # Input: T-MSIS-style claims
│   ├── procedure_benchmarks.parquet
│   ├── provider_summaries.parquet
│   ├── provider_monthly.parquet
│   ├── all_anomalies.parquet
│   ├── intelligence_report.json
│   ├── cross_references.json
│   ├── enriched_leads.json
│   └── executive_briefing.md
├── scripts/                # Batch pipeline
│   ├── 01_explore.py .. 08_enrich_leads.py
│   └── npi_lookup.py
├── docs/
│   ├── ARCHITECTURE.md     # Diagrams: scripts, agents, shared data
│   └── PROJECT_ANALYSIS.md # Suggestions and quality notes
├── dashboard/              # Optional Next.js UI (see dashboard/README if present)
├── .env.example
├── requirements.txt
└── README.md
```

---

## Docs

- **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** — How the scripts pipeline and multi-agent framework work and how they connect (Mermaid diagrams and file reference).
- **[docs/PROJECT_ANALYSIS.md](docs/PROJECT_ANALYSIS.md)** — Analysis, improvement ideas, and known limitations.

---

## License and disclaimer

This is an analytical tool to help investigators prioritize review. It does not determine fraud. Use outputs in accordance with your organization’s policies and applicable law.


## Detected evidence (automated analysis)

Indexed codebase: 36 recognized source files, 220 KB.
- Anthropic (technology) — detected in the code
- CSS (language) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (49 of 49)

```
.env.example
.gitignore
agent/hcpcs_codes.json
agent/hcpcs_loader.py
agent/multi_agent.py
agent/tools.py
dashboard/.eslintrc.json
dashboard/.gitignore
dashboard/jsconfig.json
dashboard/next.config.mjs
dashboard/package.json
dashboard/postcss.config.mjs
dashboard/public/data/cross_references.json
dashboard/public/data/enriched_leads.json
dashboard/public/data/executive_briefing.md
dashboard/public/data/intelligence_report.json
dashboard/README.md
dashboard/src/app/briefing/page.js
dashboard/src/app/globals.css
dashboard/src/app/layout.js
dashboard/src/app/page.js
dashboard/src/app/providers/page.js
dashboard/src/components/briefing/briefing-page.js
dashboard/src/components/common/animated-counter.js
dashboard/src/components/common/missing-data.js
dashboard/src/components/dashboard/anomaly-breakdown.js
dashboard/src/components/dashboard/dashboard-page.js
dashboard/src/components/dashboard/pipeline-hero.js
dashboard/src/components/dashboard/stat-cards.js
dashboard/src/components/dashboard/trends-charts.js
dashboard/src/components/layout/app-shell.js
dashboard/src/components/layout/sidebar.js
dashboard/src/components/layout/top-header.js
dashboard/src/components/providers/provider-investigation-demo.js
dashboard/src/components/providers/providers-page.js
dashboard/src/lib/data.js
dashboard/src/lib/format.js
dashboard/tailwind.config.js
README.md
requirements.txt
scripts/01_explore.py
scripts/02_enrich_npi.py
scripts/03_benchmarks.py
scripts/04_anomaly_detection.py
scripts/05_deep_analysis.py
scripts/06_generate_report.py
scripts/07_cross_references.py
scripts/08_enrich_leads.py
scripts/npi_lookup.py
```

### Dependencies

- dashboard/package.json: eslint@^8, eslint-config-next@14.2.35, framer-motion@^12.34.0, next@14.2.35, postcss@^8, react@^18, react-dom@^18, react-markdown@^10.1.0, recharts@^3.7.0, tailwindcss@^3.4.1
- requirements.txt: anthropic@>=0.39.0, duckdb@>=0.10.0, numpy@>=1.24.0, pyarrow@>=14.0.0, python-dotenv@>=1.0.0, requests@>=2.28.0

### Recent commits (newest first)

- added search feature
- Update .gitignore
- Initial commit

## Key source files (fetched from GitHub, selected and truncated for size)

### dashboard/public/data/executive_briefing.md

```markdown
# Medicaid Sherlock Intelligence Briefing

## Dataset & Methodology

This analysis examines **227,083,361 Medicaid claim rows** representing **$1,093,562,833,513** in total spending across **617,503 unique providers** from January 2018 through December 2024. The detection system employs five complementary anomaly detection algorithms:

1. **High Total Spending**: Identifies providers whose aggregate spending significantly exceeds peers in their taxonomy category (z-score >3)
2. **High Cost-Per-Claim**: Flags providers billing substantially above typical reimbursement rates for the same procedures
3. **Billing Spikes**: Detects sudden month-over-month increases in billing volume or spending (>200% increase)
4. **High Mismatch Rate**: Identifies organizational NPIs where billing and servicing provider NPIs diverge at unusual rates
5. **Procedure Concentration**: Flags providers with abnormally narrow procedure portfolios (potential upcoding or limited service schemes)

Each algorithm generates severity scores; providers triggering multiple anomaly types receive elevated scrutiny. The system identified **41,393 providers (6.7%)** with one or more anomalies, generating **210,580 individual flags**.

---

## Executive Summary

This comprehensive analysis of seven years of Medicaid claims data identified $925.6 billion in flagged spending across 41,393 providers—representing approximately 6.7% of all Medicaid providers but substantial portions of program expenditures. However, **statistical anomalies should not be conflated with fraudulent activity**. The majority of high-value flags occur in large organizational providers (hospitals, health systems, FQHCs) where structural billing patterns legitimately differ from solo practitioners.

**Key findings warrant investigative prioritization:**

- **High-severity outliers**: 2,492 providers flagged for extraordinary total spending (avg severity 8.1) account for $366.1 billion in flagged expenditures
- **Billing spike patterns**: 2,746 providers exhibited sudden volume increases (avg severity 11.3), with notable clustering in COVID-era months (Nov 2020: 134 spikes)
- **Procedure concentration risks**: 12,099 providers demonstrate abnormally narrow service portfolios, potentially indicating billing schemes focused on specific high-reimbursement codes
- **Organizational complexity**: The largest billing network encompasses 5,745 servicing NPIs, illustrating the challenge of distinguishing legitimate integrated delivery systems from coordination schemes

**Critical context for investigators**: The top 20 flagged providers include multiple children's hospitals, tribal health facilities, and Federally Qualified Health Centers (FQHCs)—entity types with inherently different billing structures. Of these, **five are FQHCs** billing under Prospective Payment System (PPS) rates, which naturally trigger cost-per-claim and mismatch flags. Web research identified prior enforcement actions against only three providers: Kai
[truncated — 26145 more characters]
```

### requirements.txt

```
# Medicaid Sherlock — Python dependencies
# Install: pip install -r requirements.txt

anthropic>=0.39.0
duckdb>=0.10.0
numpy>=1.24.0
pyarrow>=14.0.0
python-dotenv>=1.0.0
requests>=2.28.0

```

### dashboard/package.json

```
{
  "name": "dashboard",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "framer-motion": "^12.34.0",
    "next": "14.2.35",
    "react": "^18",
    "react-dom": "^18",
    "react-markdown": "^10.1.0",
    "recharts": "^3.7.0"
  },
  "devDependencies": {
    "eslint": "^8",
    "eslint-config-next": "14.2.35",
    "postcss": "^8",
    "tailwindcss": "^3.4.1"
  }
}

```

### dashboard/src/app/page.js

```javascript
import { MissingData } from '@/components/common/missing-data';
import { DashboardPage } from '@/components/dashboard/dashboard-page';
import { loadAllData } from '@/lib/data';

export default function Page() {
  const { report } = loadAllData();

  if (!report) {
    return <MissingData title="Dashboard data missing" />;
  }

  return <DashboardPage report={report} />;
}

```

### dashboard/src/app/layout.js

```javascript
import './globals.css';
import { AppShell } from '@/components/layout/app-shell';

export const metadata = {
  title: 'Medicaid Sherlock Dashboard',
  description: 'Medicaid fraud detection intelligence dashboard',
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className="bg-sand-50 text-sand-900 antialiased">
        <AppShell>{children}</AppShell>
      </body>
    </html>
  );
}

```

### dashboard/src/app/briefing/page.js

```javascript
import { MissingData } from '@/components/common/missing-data';
import { BriefingPage } from '@/components/briefing/briefing-page';
import { loadAllData } from '@/lib/data';

export default function BriefingRoute() {
  const { briefingMd } = loadAllData();

  if (!briefingMd) {
    return <MissingData title="Briefing file missing" />;
  }

  return <BriefingPage briefingMd={briefingMd} />;
}

```

### dashboard/src/app/providers/page.js

```javascript
import { MissingData } from '@/components/common/missing-data';
import { ProvidersPage } from '@/components/providers/providers-page';
import { loadAllData, loadHCPCSMap } from '@/lib/data';

function buildProcedureDescriptions(providers, hcpcsMap) {
  const descriptions = {};

  providers.forEach((provider) => {
    (provider.top_procedures || []).forEach((procedure) => {
      const code = procedure.HCPCS_CODE;
      if (!code || descriptions[code]) return;
      descriptions[code] = hcpcsMap[code] || `${code}: Description unavailable in lookup table`;
    });
  });

  return descriptions;
}

export default function ProvidersRoute() {
  const { report, crossRefs, enrichedLeads } = loadAllData();

  if (!report || !Array.isArray(report.top_20_providers)) {
    return <MissingData title="Provider data missing" />;
  }

  const hcpcsMap = loadHCPCSMap();
  const procedureDescriptions = buildProcedureDescriptions(report.top_20_providers, hcpcsMap);

  return (
    <ProvidersPage
      providers={report.top_20_providers}
      report={report}
      crossRefs={crossRefs || {}}
      enrichedLeads={enrichedLeads || {}}
      procedureDescriptions={procedureDescriptions}
    />
  );
}

```

### scripts/02_enrich_npi.py

```python
import duckdb

con = duckdb.connect()
FILE = 'data/medicaid-provider-spending.parquet'

# First, get all unique NPIs we need to look up
print("=== EXTRACTING UNIQUE NPIs ===")
npis = con.execute(f"""
    SELECT DISTINCT npi FROM (
        SELECT BILLING_PROVIDER_NPI_NUM as npi FROM '{FILE}'
        UNION
        SELECT SERVICING_PROVIDER_NPI_NUM as npi FROM '{FILE}' 
        WHERE SERVICING_PROVIDER_NPI_NUM IS NOT NULL
    )
""").fetchdf()
print(f"Total unique NPIs: {len(npis):,}")

# Save for later use
npis.to_parquet('data/unique_npis.parquet', index=False)
print("Saved to data/unique_npis.parquet")
```

### dashboard/tailwind.config.js

```javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {
      colors: {
        sand: {
          50: '#fefdfb',
          100: '#faf7f2',
          200: '#f2ece3',
          300: '#e8dfd2',
          400: '#d4c8b5',
          500: '#b5a48e',
          600: '#8c7a63',
          700: '#6b5d4f',
          800: '#4a3f34',
          900: '#2d261e',
        },
        accent: {
          DEFAULT: '#e85d2a',
          light: '#f4845f',
          dark: '#c44a1e',
          50: '#fef3ee',
          100: '#fde4d6',
          200: '#fbc5ab',
          500: '#e85d2a',
          600: '#c44a1e',
        },
      },
      fontFamily: {
        sans: ['DM Sans', 'system-ui', 'sans-serif'],
        mono: ['JetBrains Mono', 'monospace'],
      },
      borderRadius: {
        '2xl': '1rem',
        '3xl': '1.5rem',
      },
    },
  },
  plugins: [],
};

```

### agent/hcpcs_loader.py

```python
import json
import os

HCPCS_FILE = os.path.join(os.path.dirname(__file__), "hcpcs_codes.json")

# Common CPT codes not in the HCPCS Level II file (AMA-licensed)
CPT_COMMON = {
    "99213": "Office/outpatient visit, established patient, low complexity (15-29 min)",
    "99214": "Office/outpatient visit, established patient, moderate complexity (30-39 min)",
    "99215": "Office/outpatient visit, established patient, high complexity (40-54 min)",
    "99211": "Office/outpatient visit, established patient, minimal problem",
    "99212": "Office/outpatient visit, established patient, straightforward",
    "99283": "Emergency department visit, moderate complexity",
    "99284": "Emergency department visit, high complexity",
    "99285": "Emergency department visit, high complexity with significant threat",
    "99202": "Office/outpatient visit, new patient, straightforward (15-29 min)",
    "99203": "Office/outpatient visit, new patient, low complexity (30-44 min)",
    "99204": "Office/outpatient visit, new patient, moderate complexity (45-59 min)",
    "99205": "Office/outpatient visit, new patient, high complexity (60-74 min)",
    "90686": "Influenza vaccine, quadrivalent, preservative free",
    "90471": "Immunization administration, first vaccine",
    "96372": "Therapeutic/prophylactic/diagnostic injection, subcutaneous or intramuscular",
    "85018": "Blood count, hemoglobin",
    "85025": "Complete blood count (CBC), automated",
    "80053": "Comprehensive metabolic panel",
    "98940": "Chiropractic manipulative treatment, spinal, 1-2 regions",
    "98941": "Chiropractic manipulative treatment, spinal, 3-4 regions",
    "98942": "Chiropractic manipulative treatment, spinal, 5 regions",
    "97110": "Therapeutic exercises, each 15 minutes",
    "97140": "Manual therapy techniques, each 15 minutes",
    "36415": "Venipuncture (routine blood draw)",
    "81001": "Urinalysis, automated, with microscopy",
    "71046": "Chest X-ray, 2 views",
    "93000": "Electrocardiogram (ECG/EKG), routine",
}

_codes = None

def load_codes():
    global _codes
    if _codes is not None:
        return _codes
    
    _codes = {}
    
    # Load the HCPCS Level II file
    if os.path.exists(HCPCS_FILE):
        with open(HCPCS_FILE, 'r') as f:
            _codes = json.load(f)
    
    # Add CPT common codes (won't overwrite HCPCS if overlap)
    for code, desc in CPT_COMMON.items():
        if code not in _codes:
            _codes[code] = desc
    
    return _codes


def lookup_hcpcs(code: str) -> str:
    """Look up an HCPCS/CPT code and return its description."""
    codes = load_codes()
    if code in codes:
        return f"{code}: {codes[code]}"
    return f"{code}: Unknown procedure code (not in HCPCS Level II or common CPT lookup)"
```

[26 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]