Inspiration

A 2024 BMJ Public Health paper by UKHSA and LSHTM researchers studied 430,682 deaths in England and wrote: "We are unaware of any guidance for clinicians or patients which addresses this need."

The need: knowing which patients are going to end up in hospital during a heatwave because of the drugs they are on, and doing something before that happens.

I checked the NHS Specialist Pharmacy Service's medication review tool list in February 2026. Everything there covers falls, frailty, polypharmacy. Nothing is triggered by weather. Not for heat. Not for cold. Not for air quality.

129 people died from heat in London in June 2025. Those deaths concentrate in patients on antipsychotics, anticholinergics, diuretics, and ACE inhibitors, in Tower Hamlets, Newham, Hackney. PCNs that had no tool to know they were the highest-priority practices that week.

Pharos is the tool that paper said didn't exist.

What it does

Two things, for two different users.

For PCN pharmacists: a dashboard.

When a UKHSA Heat-Health Alert fires, Pharos ranks every London PCN by medication-driven excess hospitalisation risk. The score fuses six open datasets: NHS prescribing volumes from OpenPrescribing, practice-to-LSOA patient distribution from NHS Digital, LSOA heat exposure from Friends of the Earth, England IMD 2025, Gasparrini/LSHTM DLNM spatial mortality coefficients, and the ONS National Statistics Postcode Lookup.

For each PCN you see the drug breakdown by class with published relative risk ranges and DOI citations, estimated patient counts per cohort, an AI-generated outreach brief, a FHIR R4 export, and nearest cooling centres. The dashboard converts population stats into a prioritised SMR action queue. That is the exact workflow NHS England's Network Contract DES mandates but provides no tool to execute.

For patients: a WhatsApp agent.

Text any medication name to the Pharos number. A LangGraph stateful agent retrieves guidance from a Qdrant hybrid RAG index built over five NHS clinical PDFs using Anthropic's contextual retrieval technique, which cuts retrieval failure rate by 67% versus standard chunking. It calls live tool functions: current UKHSA alert level, drug class heat risk with published RR, nearest GP surgery, nearest cooling space. It responds in under three seconds.

When a patient on furosemide texts "I've been vomiting since this morning," the agent applies NHS Sick Day Rules immediately and tells them to contact their GP before their next dose. That is the feature most likely to prevent an actual AKI hospitalisation. It escalates to 999 instantly on emergency language. It sends proactive alerts to registered users when the alert level changes. It responds in the user's language: Bengali, Somali, Romanian. The highest-risk PCNs in Tower Hamlets and Newham have large non-English-speaking populations and this matters.

How we built it

Pipeline. DuckDB ETL joining OpenPrescribing JSON exports, NHS patients-by-LSOA (1.16M rows), NSPL postcode lookup (2.7M rows), IMD 2025 (33,755 LSOAs), and FoE heat vulnerability (32,844 LSOAs) via the ONS LSOA 2011 to 2021 exact-fit crosswalk. Each practice gets a population-weighted LSOA score rather than a single postcode score. A practice in Whitechapel serving patients across six LSOAs gets a weighted average of those LSOAs' heat exposure, not just the score for its front door's postcode.

Risk engine. PAF-based excess hospitalisation scoring using published RR values from five peer-reviewed studies (Layton 2020, Chen 2025, Hospers 2024, Nordon 2007, Thompson 2024). Modified by the Gasparrini DLNM PC1 spatial vulnerability component, the same framework LSHTM used operationally during the June 2025 heatwave. Output: 6,092 practice scores and 1,297 PCN scores with drug breakdown JSON carrying low/mid/high confidence intervals per drug class.

RAG. Docling parses five NHS PDFs. Chonkie chunks with a markdown recipe. Kimi K2.6 generates 50 to 100 token contextual prefixes per chunk using Anthropic's contextual retrieval technique. Chunks stored in Qdrant Cloud hybrid collection: dense via bge-small-en-v1.5, sparse via BM25. Cross-encoder reranking via bge-reranker-base.

Backend. FastAPI on GCP Cloud Run europe-west2. APScheduler polls UKHSA every 15 minutes. PostgreSQL on Neon.

Agent. LangGraph StateGraph with AsyncPostgresSaver checkpoint persistence keyed by phone number. Four tool functions. Kimi K2.6 primary, Groq Llama 3.3 70B as fallback.

Frontend. React 18, Deck.gl, MapLibre with CARTO dark-matter basemap (no API key needed). TanStack Query. Tailwind.

Challenges we ran into

The Gasparrini DLNM coefficients are in R's binary RDS format. Converting them without losing the uncertainty structure meant understanding the meta-analytical framework before touching the pipeline.

The NHS patients-by-LSOA publication switched from 2011 to 2021 LSOA codes in January 2026. The Gasparrini model uses 2011 codes. Missing the ONS 2011 to 2021 exact-fit crosswalk would have caused a 15 to 20% silent join failure with no errors, just missing risk scores.

Additive PAF overstates joint risk when patients are on multiple drug classes simultaneously. We flag this in the methodology panel and frame the estimate as a conservative upper bound.

The Twilio sandbox requires every recipient to send a join code first. We onboard judges at check-in Saturday morning so the 24-hour session window is open by demo time Sunday.

Accomplishments that we're proud of

The retrospective validation worked. The risk model flagged Tower Hamlets, Hackney, Newham, and Barking as highest-risk before we looked at syndromic surveillance data. The UKHSA NSSP Week 21 2026 report confirmed elevated NHS 111 heat call volumes in those boroughs during the May amber alert.

The drug breakdown chart is the first place a PCN pharmacist can see: "11.15% of my patients are on ACE inhibitors and ARBs, RR 1.3 to 1.9, estimated 3,831 patients," with a DOI on hover and a one-click outreach draft.

The WhatsApp sick day rules response is the first automated clinical prompt for the AKI prevention pathway in the context of heat events. It works in under three seconds, cites NICE NG5, and does not require the patient to call anyone first.

What we learned

The gap between "a paper says no tool exists" and "we built the tool" is surprisingly small when the underlying data is already open and structured. OpenPrescribing, NHS Digital, ONS, UKHSA, and the Gasparrini group published everything needed. The barrier was not data access. It was someone connecting the pieces.

Equity cannot be added at the end. The red-tier PCNs are in Tower Hamlets and Newham because deprivation, heat exposure, and medication burden concentrate in the same postcodes. Keeping the IMD score separate and labelled in the UI rather than folding it into the clinical math was the right call both methodologically and ethically.

What's next for Pharos

Air quality. The LAQN API gives real-time DAQI by London borough. OpenPrescribing already publishes the SABA/ICS ratio as an NHS quality measure. On a high-DAQI day, Pharos surfaces the practices with the highest uncontrolled asthma burden. Same pipeline, same channels, different signal.

Cold weather. The UKHSA Cold Health Alert runs on the same four-tier system from November to March. Beta-blockers, NSAIDs, and thyroid medications carry elevated cold-weather cardiovascular risk. The cold module activates automatically when the Cold Health Alert fires.

Year-round. Heat in summer. Pollen and air quality spring to autumn. Cold in winter. Every month, the same vulnerable patients, the same medications. Pharos is not a heatwave tool.

EHR integration. The FHIR R4 endpoint is live. Next step is SMART on FHIR so the SMR action queue appears inside EMIS and SystmOne directly rather than as a separate dashboard.

CHAPI. System's Climate Health API targets a 2027 public launch with a Clinical Decision Support category. Pharos fits that layer.

GitHub

Link: https://github.com/1337Xcode/pharos Live: http://trypharos.vercel.app

Built With

  • 2025
  • api
  • baai/bge-small-en-v1.5
  • chonkie
  • cloud
  • dashboard
  • data
  • datastore
  • deck.gl
  • dlnm
  • docling
  • duckdb
  • earth
  • england
  • fastapi
  • fhir
  • framework
  • friends
  • gasparrini
  • gcp
  • gla
  • groq
  • heat
  • imd
  • kimi
  • langgraph
  • london
  • lshtm
  • maplibre
  • nhs
  • nspl
  • ods
  • ons
  • openprescribing
  • ord
  • postgresql
  • python
  • qdrant
  • r4
  • react
  • run
  • the
  • twilio
  • uk-hwfcast
  • ukhsa
  • vercel
  • vulnerability
  • whatsapp
Share this project:

Updates