# Project export: RescueRX

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: How many drugs have been shelved that could save lives for diseases they were never tested on? We use AI to find drugs abandoned for business reasons & pinpoint diseases they're best suited to fight.
- Devpost: https://devpost.com/software/rescuerx
- GitHub: https://github.com/Donglomur/TreeHacks
- Video: https://www.youtube.com/embed/bNT22FCYhoA?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner ([OpenEvidence] Best Use of Clinical Information (4x Apple Watches))
- Team: 1 GitHub contributor(s) — Nicholas L (2 commits)

## Devpost submission (written by the team)

### Inspiration

Baricitinib. It's an arthritis pill. Costs about $70 a month. In 2020, an AI system figured out (in 48 hours) that this drug could treat COVID-19. It went through an emergency trial. It reduced deaths by 38%. The FDA fully approved it. But here's the thing: Baricitinib had been sitting in pharmacies for YEARS before anyone made that connection. How many other drugs are sitting on shelves right now that could save lives for diseases they were never tested on? We built the system that finds them.

### What it does

RescueRX is a multi-agent AI system that uncovers pre-existing drugs that could treat new diseases. Given a disease, we mine “unsuccessful” late-stage clinical trials to surface promising drugs that were shelved for non-scientific reasons, then produce a ranked set of repurposing opportunities with evidence.

### How we built it

RescueRX runs a parallel team of 9 specialized agents across 3 layers, where each agent works together to solve the drug repurposing question. Agent 1: Knowledge Graph Discovery Performs graph-based biological plausibility modeling using a large-scale heterogeneous biomedical knowledge graph: 97,000+ entities 5.87M typed relationships 107 interaction categories 97,000+ entities 5.87M typed relationships 107 interaction categories Uses custom neural relational embeddings (trained on GPU infrastructure) to estimate drug–disease association likelihoods via rotations in 200 dimensional embedding space. Enables latent pathway inference across complex multi-hop biological interactions and produces the initial candidate pool. Once a high-confidence candidate pool is established, the remaining agents execute concurrently as independent validation modules. Agent 2: Trial Scanner Ingests and classifies 500,000+ ClinicalTrials.gov trials, focusing on Phase 2 / Phase 3 terminations caused by non-scientific reasons (e.g., sponsor bankruptcy, enrollment failure, epidemic-related disruption). Implements a hybrid classification pipeline: Deterministic rule-based filtering Contextual intent inference Deterministic rule-based filtering Contextual intent inference Produces three labels: Rescuable Non-Rescuable Ambiguous Rescuable Non-Rescuable Ambiguous Agent 3: FAERS Inverse Signal Performs pharmacoepidemiological signal analysis over the FDA’s FAERS database. Computes inverse reporting odds ratios (ROR < 1) to identify statistically significant protective signals (reverse-signal mining), leveraging real-world patient safety data to uncover population-scale therapeutic correlations. Agent 4: Literature Review While the Knowledge Graph Agent can explain that there is a correlation, the Literature Review Agent is used to determine WHY the correlation exists. Executes retrieval-augmented literature synthesis via the Perplexity Sonar Research Agent, querying 2.3M PubMed-indexed publications Extracts evidence across four dimensions: Mechanistic rationale Prior clinical validation Regulatory trajectory Recent translational developments Mechanistic rationale Prior clinical validation Regulatory trajectory Recent translational developments All outputs are citation-linked to prevent hallucination and ensure traceability. Agent 5: Molecular Similarity Performs cheminformatics validation using: 2048-bit Morgan fingerprints Tanimoto similarity scoring 2048-bit Morgan fingerprints Tanimoto similarity scoring Quantifies structural similarity between candidate compounds and FDA-approved therapeutics, leveraging the similarity-property principle to estimate shared target engagement potential. Runs via high-throughput, vectorized computation for molecular-level plausibility assessment. Agent 6: Orchestrator + Safety Arbitration Aggregates outputs across agents and enforces a strict safety override protocol. Cross-validates: Contraindications Adverse event frequencies Black-box warnings Contraindications Adverse event frequencies Black-box warnings Automatically excludes any candidate with historical safety concerns or positive risk signals in FAERS, ensuring safety constraints supersede predictive optimism. Agents 7–9: Adversarial Court Agent 7 (Advocate): constructs the strongest possible case for repurposing viability. Agent 8 (Skeptic): performs systematic critique: identifying statistical weaknesses, cross-agent inconsistencies, and evidence gaps. Agent 9 (Judge): synthesizes both arguments into a calibrated final verdict with a transparent reasoning chain. This adversarial architecture reduces confirmation bias, improves calibration, and transforms predictive scoring into defensible scientific argumentation.

### Challenges we ran into

Orchestrator complexity! Stitching outputs from multiple agents into a cohesive, readable final verdict required robust output contracts and formatting logic. Scale + heterogeneity of bioclinical data! Normalizing, cleaning, selecting meaningful biological features, and deciding what signals to trust vs. ignore.

### Accomplishments we're proud of

Built an end-to-end multi-agent system that turns messy biomedical data into actionable ranked hypotheses.

### What we learned

We learned a lot about making multiple agents work together, and even more about how the whole process of drug repurposing worked!

### What's next

Adding more data to the knowledge graph to incorporate more drugs and diseases Expand RescueRX to model drug combinations instead of only mapping single-drug impact. Add human-in-the-loop feedback so clinicians/researchers can correct mappings and teach the system over time.

## README (from the GitHub repository)

# RescueRX 

## 🏆 Winner: Best Use of Clinical Information in TreeHacks 2026

### How many drugs have been shelved that could save lives for diseases they were never tested on? We use AI to find drugs abandoned for business reasons & pinpoint diseases they're best suited to fight. 



---

## Overview

**RescueRX** is a multi-agent drug repurposing system that finds **high-potential, previously-shelved drugs** for a target disease and explains *why* they’re worth pursuing.

It combines:
- **Knowledge graph discovery** (biological plausibility)
- **Clinical trials scanning** (why drugs were dropped)
- **Real-world safety signals** (FAERS inverse signals)
- **Literature grounding** (citations-backed mechanisms)
- **Molecular confirmation** (fingerprints + optional docking)
- **Adversarial “evidence court”** (Advocate vs Skeptic → Judge verdict)

The result is a **ranked list of candidates** with **tiered confidence**, safety considerations, and transparent reasoning clinicians can inspect.

---

## How It Works (3 Layers • 9 Agents)

### Layer 1: Discovery
1) **Knowledge Graph Agent**: scores drugs vs. the disease using learned graph embeddings (RotatE-style scoring)

### Layer 2: Evidence Wall (runs in parallel)
2) **Trial Scanner**: queries ClinicalTrials.gov for terminated/withdrawn trials and classifies whether failure was *scientific* vs *non-scientific*  
3) **FAERS Inverse Signal Agent**: asks “what does this drug *prevent*?” via reporting odds ratios  
4) **Literature Agent**: produces citation-backed mechanism + prior evidence summaries  
5) **Molecular Similarity Agent**: Morgan fingerprints + Tanimoto similarity vs known treatments  
6) **Safety Arbitration**: excludes candidates with strong risk signals / contraindication concerns

### Layer 3: Adversarial Court
7) **Advocate**: best case *for* rescuing the drug  
8) **Skeptic**: best case *against* rescuing the drug  
9) **Judge**: weighs both sides then assigns a final **Rescue Score** and recommended next steps

---
Built with ❤️ during TreeHacks 2026


## Detected evidence (automated analysis)

Indexed codebase: 64 recognized source files, 799 KB.
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code

## Codebase structure (from repository index)

### Files (105 of 105)

```
.gitignore
deploy.sh
diagnose.py
drugrescue-frontend/index.html
drugrescue-frontend/package.json
drugrescue-frontend/src/App.jsx
drugrescue-frontend/src/main.jsx
drugrescue-frontend/src/useData.js
drugrescue-frontend/sync-data.js
drugrescue-frontend/vite.config.js
env.example
files/candidates_summary.md
files/candidates.json
files/court/advocate_brief.md
files/court/skeptic_brief.md
files/court/verdict_scores.json
files/court/verdict.md
files/evidence/clinical_trials.json
files/evidence/faers_signals.json
files/evidence/literature.json
files/evidence/molecular.json
files/evidence/summary.json
files/evidence/summary.md
files/glioblastoma_candidates_summary.md
files/glioblastoma_candidates.json
logs/session_20260214_120907/transcript.txt
logs/session_20260214_121052/transcript.txt
logs/session_20260214_121531/transcript.txt
logs/session_20260214_121850/transcript.txt
Outputs/als_evidence/als_candidates_summary.md
Outputs/als_evidence/als_candidates.json
Outputs/als_evidence/clinical_trials.json
Outputs/als_evidence/faers_signals.json
Outputs/breast_cancer/candidates_summary.md
Outputs/breast_cancer/candidates.json
Outputs/breast_cancer/court/advocate_brief.md
Outputs/breast_cancer/court/skeptic_brief.md
Outputs/breast_cancer/court/summary.json
Outputs/breast_cancer/court/summary.md
Outputs/breast_cancer/court/verdict_scores.json
Outputs/breast_cancer/evidence/clinical_trials.json
Outputs/breast_cancer/evidence/faers_signals.json
Outputs/breast_cancer/evidence/literature.json
Outputs/breast_cancer/evidence/molecular.json
Outputs/depression/court/advocate_brief.md
Outputs/depression/court/skeptic_brief.md
Outputs/depression/court/verdict_scores.json
Outputs/depression/court/verdict.md
Outputs/depression/depression_candidates_summary.md
Outputs/depression/depression_candidates.json
Outputs/depression/evidence/clinical_trials.json
Outputs/depression/evidence/faers_signals.json
Outputs/depression/evidence/literature.json
Outputs/depression/evidence/molecular.json
Outputs/depression/evidence/summary.json
Outputs/depression/evidence/summary.md
Outputs/glioblastoma/candidates_summary.md
Outputs/glioblastoma/candidates.json
Outputs/glioblastoma/court/advocate_brief.md
Outputs/glioblastoma/court/skeptic_brief.md
Outputs/glioblastoma/court/verdict_scores.json
Outputs/glioblastoma/court/verdict.md
Outputs/glioblastoma/evidence/clinical_trials.json
Outputs/glioblastoma/evidence/faers_signals.json
Outputs/glioblastoma/evidence/literature.json
Outputs/glioblastoma/evidence/molecular.json
Outputs/glioblastoma/evidence/summary.json
Outputs/glioblastoma/evidence/summary.md
Outputs/glioblastoma/glioblastoma_candidates_summary.md
Outputs/glioblastoma/glioblastoma_candidates.json
pyproject.toml
README.md
scripts/check_coverage.py
scripts/check_lookup.py
scripts/diagnose_matching.py
scripts/discover.py
scripts/populate_drugbank_ids_modal.py
scripts/populate_drugbank_ids.py
scripts/resolve_all_compounds.py
scripts/resolve_mesh_compounds.py
src/drug_rescue/__init__.py
src/drug_rescue/__main__.py
src/drug_rescue/agent.py
src/drug_rescue/engines/__init__.py
src/drug_rescue/engines/discover.py
src/drug_rescue/engines/faers.py
src/drug_rescue/engines/literature.py
src/drug_rescue/engines/scorer.py
src/drug_rescue/prompts/__init__.py
src/drug_rescue/prompts/advocate.py
src/drug_rescue/prompts/discovery.py
src/drug_rescue/prompts/investigator.py
src/drug_rescue/prompts/judge.py
src/drug_rescue/prompts/orchestrator.py
src/drug_rescue/prompts/skeptic.py
src/drug_rescue/prompts/system.py
src/drug_rescue/tools/__init__.py
src/drug_rescue/tools/_http.py
src/drug_rescue/tools/clinical_trials.py
src/drug_rescue/tools/docking.py
src/drug_rescue/tools/faers_safety.py
src/drug_rescue/tools/kg_discovery.py
src/drug_rescue/tools/literature.py
src/drug_rescue/tools/similarity.py
test_tools.py
```

### Dependencies

- drugrescue-frontend/package.json: @vitejs/plugin-react@^4.2.0, react@^18.2.0, react-dom@^18.2.0, vite@^5.0.0
- pyproject.toml: claude-agent-sdk@>=0.1.30, numpy@>=1.24, pytest@>=7.0, pytest-asyncio@>=0.21

### Recent commits (newest first)

- Update README.md
- Update README.md
- Update README.md
- final commit
- orchestrator agent complete
- Add scripts and drug_rescue engines/tools
- Merge pull request #3 from Donglomur/core-agent-2
- Add core agent project structure
- Initial commit

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

### files/candidates_summary.md

```markdown
# Glioblastoma Drug Candidates - Knowledge Graph Analysis

## Summary
- **Disease**: glioblastoma
- **Total compounds scored**: 24,313
- **Candidates returned**: 30
- **Method**: RotatE embeddings
- **Analysis time**: 558.2ms

## Candidate Breakdown
- **Dropped** (failed trials, prime repurposing targets): 6
- **Withdrawn**: 0
- **Novel** (not in clinical database): 24

---

## DROPPED DRUGS (Prime Repurposing Candidates)

| Rank | Drug Name | Max Phase | KG Percentile | KG Score | SMILES | ChEMBL | DrugBank |
|------|-----------|-----------|---------------|----------|--------|--------|----------|
| 11 | TALAMPANEL | Phase 2 | 99.96 | -11.75 | CC(=O)N1N=C(c2ccc(N)cc2)c2cc3c(cc2C[C@H]1C)OCO3 | CHEMBL61872 | DB04982 |
| 17 | RIVOCERANIB | Phase 3 | 99.93 | -11.86 | N#CC1(c2ccc(NC(=O)c3cccnc3NCc3ccncc3)cc2)CCCC1 | CHEMBL3186534 | DB14765 |
| 23 | GENISTEIN | Phase 2 | 99.91 | -11.88 | O=c1c(-c2ccc(O)cc2)coc2cc(O)cc(O)c12 | CHEMBL44 | DB01645 |
| 24 | EDOTECARIN | Phase 3 | 99.91 | -11.89 | O=C1c2c(c3c4ccc(O)cc4n([C@@H]4O[C@H](CO)[C@@H](O)[C@H](O)[C@H]4O)c3c3[nH]c4cc(O)ccc4c23)C(=O)N1NC(CO)CO | CHEMBL435191 | DB04882 |
| 25 | CEDIRANIB | Phase 3 | 99.90 | -11.89 | COc1cc2c(Oc3ccc4[nH]c(C)cc4c3F)ncnc2cc1OCCCN1CCCC1 | CHEMBL491473 | DB04849 |
| 30 | PERIFOSINE | Phase 3 | 99.88 | -11.94 | CCCCCCCCCCCCCCCCCCOP(=O)([O-])OC1CC[N+](C)(C)CC1 | CHEMBL372764 | DB06641 |

---

## NOVEL/APPROVED DRUGS

| Rank | Drug Name | KG Percentile | KG Score | ChEMBL | DrugBank |
|------|-----------|---------------|----------|--------|----------|
| 1 | AF38469 | 100.00 | -11.58 | - | - |
| 2 | 4-BORONOPHENYLALANINE | 100.00 | -11.59 | - | - |
| 3 | SORAFENIB | 99.99 | -11.60 | - | - |
| 4 | NIMUSTINE HYDROCHLORIDE | 99.99 | -11.61 | CHEMBL1256616 | - |
| 5 | GEFITINIB | 99.98 | -11.61 | - | - |
| 6 | ETOPOSIDE | 99.98 | -11.62 | CHEMBL44657 | DB00773 |
| 7 | TEMOZOLOMIDE | 99.98 | -11.65 | - | - |
| 8 | ERLOTINIB | 99.97 | -11.69 | - | - |
| 9 | CISPLATIN | 99.97 | -11.72 | - | DB00515 |
| 10 | SUNITINIB | 99.96 | -11.72 | - | - |
| 12 | DOCETAXEL | 99.95 | -11.75 | - | - |
| 13 | DACOMITINIB | 99.95 | -11.77 | - | - |
| 14 | TAMOXIFEN | 99.95 | -11.78 | CHEMBL83 | DB00675 |
| 15 | NAC-SAR-GLY-VAL-(D-ALLO-ILE)-THR-NVA-ILE-ARG-PRONET | 99.94 | -11.79 | - | - |
| 16 | CAPECITABINE | 99.94 | -11.86 | - | - |
| 18 | BACILLITHIOL(1-) | 99.93 | -11.86 | - | - |
| 19 | 5-FLUOROURACIL | 99.93 | -11.86 | CHEMBL185 | DB00544 |
| 20 | TALAPORFIN | 99.92 | -11.86 | CHEMBL2111186 | DB11812 |
| 21 | PACLITAXEL | 99.92 | -11.87 | CHEMBL428647 | DB01229 |
| 22 | DOXORUBICIN | 99.91 | -11.88 | CHEMBL53463 | DB00997 |
| 26 | RAPAMYCIN | 99.90 | -11.90 | CHEMBL413 | DB00877 |
| 27 | 4-AMINO-5-FLUORO-3-(5-(4-METHYLPIPERAZIN-1-YL)-1H-BENZIMIDAZOL-2-YL)QUINOLIN-2(1H)-ONE | 99.89 | -11.91 | - | - |
| 28 | CABOZANTINIB | 99.89 | -11.93 | CHEMBL2105717 | DB08875 |
| 29 | IFOSFAMIDE | 99.88 | -11.93 | CHEMBL1024 | DB01181 |

---

## Notes
- **KG Percentile**: Higher = stronger evidence in knowledg
[truncated — 392 more characters]
```

### files/glioblastoma_candidates_summary.md

```markdown
# Glioblastoma Drug Candidates - DRKG Discovery Results

**Disease:** Glioblastoma
**Method:** RotatE embeddings
**Compounds Scored:** 24,313
**Candidates Returned:** 30
**Query Time:** 575.6 ms

## Summary Statistics

- **Dropped Drugs:** 6 (candidates that reached Phase I-III but never approved - prime repurposing targets)
- **Novel/Other Compounds:** 24 (compounds in knowledge graph but not in dropped drugs database)
- **Withdrawn Drugs:** 0

---

## Top Candidates (sorted by status, then KG percentile)

### DROPPED DRUGS - Prime Repurposing Candidates

| Rank | Drug Name | Max Phase | KG Percentile | KG Score | SMILES | ChEMBL | DrugBank |
|------|-----------|-----------|---------------|----------|--------|---------|----------|
| 11 | TALAMPANEL | Phase 2 | 99.96 | -11.7475 | CC(=O)N1N=C(c2ccc(N)cc2)c2cc3c(cc2C[C@H]1C)OCO3 | CHEMBL61872 | DB04982 |
| 17 | RIVOCERANIB | Phase 3 | 99.93 | -11.8613 | N#CC1(c2ccc(NC(=O)c3cccnc3NCc3ccncc3)cc2)CCCC1 | CHEMBL3186534 | DB14765 |
| 23 | GENISTEIN | Phase 2 | 99.91 | -11.8821 | O=c1c(-c2ccc(O)cc2)coc2cc(O)cc(O)c12 | CHEMBL44 | DB01645 |
| 24 | EDOTECARIN | Phase 3 | 99.91 | -11.8856 | O=C1c2c(c3c4ccc(O)cc4n([C@@H]4O[C@H](CO)[C@@H](O)[C@H](O)[C@H]4O)c3c3[nH]c4cc(O)ccc4c23)C(=O)N1NC(CO)CO | CHEMBL435191 | DB04882 |
| 25 | CEDIRANIB | Phase 3 | 99.90 | -11.8879 | COc1cc2c(Oc3ccc4[nH]c(C)cc4c3F)ncnc2cc1OCCCN1CCCC1 | CHEMBL491473 | DB04849 |
| 30 | PERIFOSINE | Phase 3 | 99.88 | -11.9366 | CCCCCCCCCCCCCCCCCCOP(=O)([O-])OC1CC[N+](C)(C)CC1 | CHEMBL372764 | DB06641 |

### NOVEL/OTHER COMPOUNDS

| Rank | Drug Name | KG Percentile | KG Score | ChEMBL | DrugBank |
|------|-----------|---------------|----------|---------|----------|
| 1 | AF38469 | 100.00 | -11.5766 | - | - |
| 2 | 4-BORONOPHENYLALANINE | 100.00 | -11.5920 | - | - |
| 3 | SORAFENIB | 99.99 | -11.6020 | - | - |
| 4 | NIMUSTINE HYDROCHLORIDE | 99.99 | -11.6055 | CHEMBL1256616 | - |
| 5 | GEFITINIB | 99.98 | -11.6124 | - | - |
| 6 | ETOPOSIDE | 99.98 | -11.6237 | CHEMBL44657 | DB00773 |
| 7 | TEMOZOLOMIDE | 99.98 | -11.6545 | - | - |
| 8 | ERLOTINIB | 99.97 | -11.6933 | - | - |
| 9 | CISPLATIN | 99.97 | -11.7184 | - | DB00515 |
| 10 | SUNITINIB | 99.96 | -11.7230 | - | - |
| 12 | DOCETAXEL | 99.95 | -11.7542 | - | - |
| 13 | DACOMITINIB | 99.95 | -11.7685 | - | - |
| 14 | TAMOXIFEN | 99.95 | -11.7798 | CHEMBL83 | DB00675 |
| 15 | NAC-SAR-GLY-VAL-(D-ALLO-ILE)-THR-NVA-ILE-ARG-PRONET | 99.94 | -11.7881 | - | - |
| 16 | CAPECITABINE | 99.94 | -11.8562 | - | - |
| 18 | BACILLITHIOL(1-) | 99.93 | -11.8614 | - | - |
| 19 | 5-FLUOROURACIL | 99.93 | -11.8617 | CHEMBL185 | DB00544 |
| 20 | TALAPORFIN | 99.92 | -11.8647 | CHEMBL2111186 | DB11812 |
| 21 | PACLITAXEL | 99.92 | -11.8730 | CHEMBL428647 | DB01229 |
| 22 | DOXORUBICIN | 99.91 | -11.8754 | CHEMBL53463 | DB00997 |
| 26 | RAPAMYCIN | 99.90 | -11.9004 | CHEMBL413 | DB00877 |
| 27 | 4-AMINO-5-FLUORO-3-(5-(4-METHYLPIPERAZIN-1-YL)-1H-BENZIMIDAZOL-2-YL)QUINOLIN-2(1H)-ONE | 99.89 | -11.9117 | - | - |
| 28 | C
[truncated — 861 more characters]
```

### pyproject.toml

```
[project]
name = "drug-rescue"
version = "0.1.0"
description = "AI-powered drug repurposing agent — TreeHacks 2026"
requires-python = ">=3.10"
dependencies = [
    "numpy>=1.24",
]

[project.optional-dependencies]
agent = [
    "claude-agent-sdk>=0.1.30",
]
dev = [
    "pytest>=7.0",
    "pytest-asyncio>=0.21",
]

[project.scripts]
drug-rescue = "drug_rescue.agent:main"

[tool.setuptools.packages.find]
where = ["src"]

[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"

```

### drugrescue-frontend/package.json

```
{
  "name": "rescuerx-frontend",
  "private": true,
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "sync": "node sync-data.js"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@vitejs/plugin-react": "^4.2.0",
    "vite": "^5.0.0"
  }
}

```

### drugrescue-frontend/src/main.jsx

```javascript
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
ReactDOM.createRoot(document.getElementById('root')).render(<App />)

```

### deploy.sh

```shell
#!/bin/bash
#
# DrugRescue Deployment Script
# ============================
# Copies all fixed files to the correct locations and clears caches.
#
# Usage: cd TreeHacks && bash deploy.sh
#

set -e

echo "🚀 DrugRescue Deployment"
echo "========================"
echo ""

# ── Detect project structure ──
# Nicholas has code at BOTH:
#   TreeHacks/drug_rescue/engines/faers.py   (root level)
#   TreeHacks/src/drug_rescue/engines/faers.py (src level — what Python imports!)
# We need to update BOTH.

ROOT_PKG=""
SRC_PKG=""

if [ -d "drug_rescue/engines" ]; then
    ROOT_PKG="drug_rescue"
    echo "✓ Found root-level package: drug_rescue/"
fi

if [ -d "src/drug_rescue/engines" ]; then
    SRC_PKG="src/drug_rescue"
    echo "✓ Found src-level package: src/drug_rescue/"
fi

if [ -z "$ROOT_PKG" ] && [ -z "$SRC_PKG" ]; then
    echo "✗ Cannot find drug_rescue package! Run from TreeHacks/ directory."
    exit 1
fi

# ── Determine source of truth ──
# The files in this script's directory are the latest versions
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
echo ""
echo "Source: $SCRIPT_DIR"
echo ""

# ── Copy function ──
copy_file() {
    local src="$1"
    local relpath="$2"
    
    if [ ! -f "$src" ]; then
        echo "  ✗ Source not found: $src"
        return 1
    fi
    
    local copied=0
    
    if [ -n "$ROOT_PKG" ]; then
        local dst="$ROOT_PKG/$relpath"
        mkdir -p "$(dirname "$dst")"
        cp "$src" "$dst"
        echo "  → $dst"
        copied=1
    fi
    
    if [ -n "$SRC_PKG" ]; then
        local dst="$SRC_PKG/$relpath"
        mkdir -p "$(dirname "$dst")"
        cp "$src" "$dst"
        echo "  → $dst"
        copied=1
    fi
    
    return 0
}

# ── Deploy files ──
echo "📦 Copying fixed files:"
echo ""

echo "  engines/faers.py (requests + count-endpoint apostrophe fix):"
copy_file "$SCRIPT_DIR/engines/faers.py" "engines/faers.py"

echo ""
echo "  tools/similarity.py (precomputed FPs + ConnectivitySMILES):"
copy_file "$SCRIPT_DIR/tools/similarity.py" "tools/similarity.py"

echo ""
echo "  tools/clinical_trials.py (requests migration):"
copy_file "$SCRIPT_DIR/tools/clinical_trials.py" "tools/clinical_trials.py"

echo ""
echo "  tools/_http.py (SSL helpers):"
copy_file "$SCRIPT_DIR/tools/_http.py" "tools/_http.py"

echo ""
echo "  tools/docking.py (ConnectivitySMILES fallback):"
copy_file "$SCRIPT_DIR/tools/docking.py" "tools/docking.py"

echo ""
echo "  tools/faers_safety.py (tool wrapper):"
copy_file "$SCRIPT_DIR/tools/faers_safety.py" "tools/faers_safety.py"

echo ""

# ── Copy test file to project root ──
echo "  test_tools.py → project root:"
if [ -f "$SCRIPT_DIR/test_tools.py" ]; then
    cp "$SCRIPT_DIR/test_tools.py" "./test_tools.py"
    echo "  → ./test_tools.py"
fi

# ── Clear __pycache__ ──
echo ""
echo "🧹 Clearing __pycache__:"
find . -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true
find . -name "*.pyc" -delete 2>/dev/null || true
echo "  Done"

# ── Verify Python resolves to the right file ──
echo ""
echo "🔍 Import verification:"
python3 -c "
import sys
# Add src/ to path if it exists (matches what their project does)
import os
if os.path.isdir('src'):
    sys.path.insert(0, 'src')

import drug_rescue.engines.faers as fm
print(f'  faers.py loaded from: {fm.__file__}')
src = open(fm.__file__).read()

checks = [
    ('requests library', 'import requests' in src and '_req.get' in src),
    ('_count_exact_term', '_count_exact_term' in src),
    ('_event_broad_filter', '_event_broad_filter' in src),
    ('FAERSClient alias', 'FAERSClient = OpenFDAClient' in src),
    ('contingency apostrophe branch', \"has_apostrophe\" in src),
    ('caret normalization', '_normalize_term' in src and \"replace(\\\"^\\\"\" in src),
    ('correct alzheimer mapping', 'DEMENTIA ALZHEIMER' in src and \"ALZHEIMER\\'S DISEASE\" not in src.split('DISEASE_TO_MEDDRA')[1].split('}')[0] if 'DISEASE_TO_MEDDRA' in src else False),
]
all_ok = True
for label, ok in checks:
    print(f'  {\"✓\" if ok else \"✗\"} {label}')
    if not ok: all_ok = False

if all_ok:
    print('  ✅ All fixes verified!')
else:
    print('  ❌ Some fixes missing — check file paths')
"

echo ""
echo "═══════════════════════════════"
echo "  Ready! Run: python test_tools.py free"
echo "═══════════════════════════════"

```

### diagnose.py

```python
#!/usr/bin/env python3
"""
DrugRescue Deep Diagnostic
===========================
Run this on your Mac to find EXACTLY what's broken.

    python diagnose.py

Tests SSL, PubChem, ClinicalTrials.gov, and FAERS event queries
with full error output — no silent swallowing.
"""
import json
import ssl
import urllib.error
import urllib.parse
import urllib.request
import sys

# ── Colors ──
G = "\033[92m"  # green
R = "\033[91m"  # red
Y = "\033[93m"  # yellow
B = "\033[1m"   # bold
E = "\033[0m"   # reset


def section(title):
    print(f"\n{B}{'='*60}{E}")
    print(f"  {B}{title}{E}")
    print(f"{B}{'='*60}{E}\n")


# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#  SSL CONTEXT TESTS
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

section("1. SSL CONTEXT")

# Try default
try:
    ctx = ssl.create_default_context()
    print(f"  ssl.create_default_context() → {G}created{E}")
except Exception as e:
    print(f"  ssl.create_default_context() → {R}FAILED: {e}{E}")

# Try certifi
try:
    import certifi
    ctx_cert = ssl.create_default_context(cafile=certifi.where())
    print(f"  certifi → {G}found: {certifi.where()}{E}")
except ImportError:
    print(f"  certifi → {Y}NOT INSTALLED (pip install certifi){E}")

# Try macOS cert
import os
for path in ["/etc/ssl/cert.pem", "/etc/ssl/certs/ca-certificates.crt"]:
    exists = os.path.exists(path)
    print(f"  {path} → {'exists' if exists else 'not found'}")


# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#  HELPER: fetch with full error reporting
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

# Unverified context for all tests (since we know macOS has SSL issues)
_ctx = ssl.create_default_context()
_ctx.check_hostname = False
_ctx.verify_mode = ssl.CERT_NONE


def fetch(label, url, headers=None):
    """Fetch URL with FULL error reporting."""
    print(f"  {B}{label}{E}")
    print(f"    URL: {url[:120]}{'...' if len(url) > 120 else ''}")
    req = urllib.request.Request(url, headers=headers or {})
    try:
        with urllib.request.urlopen(req, timeout=15, context=_ctx) as resp:
            body = resp.read().decode()
            data = json.loads(body) if body.startswith("{") or body.startswith("[") else body
            status = resp.status
            print(f"    {G}HTTP {status}{E}")
            return data, status
    except urllib.error.HTTPError as e:
        body = e.read().decode("utf-8", errors="replace")[:300]
        print(f"    {R}HTTP {e.code}{E}: {body[:200]}")
        return None, e.code
    except urllib.error.URLError as e:
        print(f"    {R}URLError{E}: {e.reason}")
        return None, 0
    except Exception as e:
        print(f"    {R}Exception{E}: {type(e).__name__}: {e}")
        return None, 0


# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#  2. PUBCHEM
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

section("2. PUBCHEM SMILES")

PUBCHEM = "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/name/{}/property/CanonicalSMILES/JSON"
for drug in ["aspirin", "metformin", "temozolomide"]:
    encoded = urllib.parse.quote(drug, safe="")
    url = PUBCHEM.format(encoded)
    data, code = fetch(drug, url)
    if data and isinstance(data, dict):
        props = data.get("PropertyTable", {}).get("Properties", [])
        if props:
            smiles = props[0].get("CanonicalSMILES", "?")
            print(f"    → {G}SMILES: {smiles[:60]}{E}")
        else:
            print(f"    → {R}No properties in response{E}")
            print(f"    → Response: {json.dumps(data)[:200]}")

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#  3. CLINICALTRIALS.GOV
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

section("3. CLINICALTRIALS.GOV")

CT_BASE = "https://clinicaltrials.gov/api/v2/studies"

# Test without User-Agent
params = {"query.intr": "metformin", "filter.overallStatus": "TERMINATED", "pageSize": 1}
qs = urllib.parse.urlencode(params)
data, code = fetch("Without User-Agent", f"{CT_BASE}?{qs}")

# Test WITH User-Agent
data2, code2 = fetch(
    "With User-Agent",
    f"{CT_BASE}?{qs}",
    headers={"User-Agent": "DrugRescue/1.0 (academic research; TreeHacks 2026)"},
)
if data2 and isinstance(data2, dict):
    total = data2.get("totalCount", "?")
    studies = data2.get("studies", [])
    print(f"    → {G}totalCount={total}, returned {len(studies)} studies{E}")

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#  4. FAERS — Drug vs Event queries
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

section("4. FAERS — Comparing Drug vs Event Queries")

FAERS = "https://api.fda.gov/drug/event.json"

def faers_count(label, search):
    """Count FAERS reports for a search term."""
    params = {"search": search, "count": "receivedate"}
    qs = urllib.parse.urlencode(params)
    url = f"{FAERS}?{qs}"
    data, code = fetch(label, url)
    if data and isinstance(data, dict) and "results" in data:
        total = sum(r.get("count", 0) for r in data["results"])
        print(f"    → {G}{total:,} reports{E}")
        return total
    print(f"    → {R}0 reports (code={code}){E}")
    return 0


# Drug queries (these work)
print(f"  {Y}--- Drug queries (should work) ---{E}")
faers_count("metformin (generic_name.exact)",
    'patient.drug.openfda.generic_name.exact:"METFORMIN"')
faers_count("aspirin (generic_name.exact)",
    'patient.drug.openfda.generic_name.exact:"ASPIRIN"')

# Event queries — test ALL variants
print(f"\n  {Y}--- Event queries: SINGLE WORD ---{E}")
faers_count("DEMENTIA (no .exact, uppercase)",
    'patient.reaction.reactionmeddrapt:"DEMENTIA"')
faers_count("DEMENTIA (.exact, uppercase)",
    'patient.reaction.reactionmeddrapt.exact:"DEMENTIA"')
faers_count("dementia (no .exact, lowercase)",
    'patient.reaction.reactionmeddrapt:"dementia"')
faers_count("Dementia (no .exact, titlecase)",
    'patient.reaction.reactionmeddrapt:"Dementia"')

print(f"\n  
[truncated — 2125 more characters]
```

### drugrescue-frontend/vite.config.js

```javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({ plugins: [react()], server: { port: 3000, open: true } })

```

### drugrescue-frontend/index.html

```html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><title>RescueRx — AI Drug Repurposing</title></head>
<body><div id="root"></div><script type="module" src="/src/main.jsx"></script></body>
</html>

```

### scripts/check_coverage.py

```python
"""Run from TreeHacks/: python scripts/check_coverage.py"""
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))

from drug_rescue.engines.discover import discover_candidates

print("Checking how many dropped drugs appear at different thresholds...\n")

for max_cand, min_pctl in [(20, 99.0), (50, 95.0), (100, 90.0), (200, 75.0)]:
    r = discover_candidates(
        "glioblastoma", data_dir="./data",
        max_candidates=max_cand, min_percentile=min_pctl, include_novel=True,
    )
    dropped = [c for c in r.candidates if c.status == "dropped"]
    withdrawn = [c for c in r.candidates if c.status == "withdrawn"]
    novel = [c for c in r.candidates if c.status == "novel"]
    print(f"Top {max_cand} (>={min_pctl}th pctl): "
          f"{len(dropped)} dropped, {len(withdrawn)} withdrawn, {len(novel)} novel")
    for c in dropped[:5]:
        smiles = "Y" if c.smiles else "N"
        print(f"  -> {c.drug_name:<30s} Phase {c.max_phase or '?':<3} "
              f"pctl={c.kg_percentile:.1f}  z={c.kg_z_score:.2f}  SMILES={smiles}")
    print()

```

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