Relay: the right colleague for the hard case
Relay connects isolated physicians to the specialist who actually treats what they treat. It matches on real prescribing history, not job titles, learns from every connection with reinforcement learning, and uses zero patient data.
🔗 Live: https://docdocknockknock.tech
Inspiration
We came into HackGT wanting to build something for the Impiricus challenge that wasn't just another idea we guessed our way into — so early on we sat down with people on the Impiricus team and just asked questions. That conversation ended up shaping almost everything about this project.
A few things they told us stuck with us more than anything we'd have come up with on our own:
- Their platform (Spark) already triggers messages to doctors about conferences, follow-ups, and rep visits — but there is no way for a doctor to connect with another doctor on their platform at all. Zero. That floored us, because it's such an obvious gap once you hear it stated plainly.
- They have a program called DocUpdate Network that gives enrolled doctors extra info, samples, and event access — but almost no doctors are in it, and when we asked why, the honest answer was "we just haven't marketed it." No eligibility bar, no reason it's small — just an unadvertised room nobody knew existed.
- Every time they want to add a new type of data to what a pharma client can see, it requires manual, ad-hoc back-and-forth, every single time. A real, named, ongoing operational headache.
That's the moment the project stopped being "an idea for a hackathon" and became "a response to three specific, confirmed problems a real company told us they have." We didn't want to build something that competed with what Spark already does — we wanted to build the things Spark was never designed to do.
What it does
Relay is not a social network. It has no feeds, no followers, and no profiles to scroll. A physician says what they need, and Relay finds the one peer who fits.
| Feature | What the physician gets |
|---|---|
| Doctor Connect | Describe the problem in four short, structured fields (topic, therapy, age group, condition context). Relay ranks eligible, opted-in specialists with a reinforcement-learning matcher and explains every match ("relevant SGLT2 publication history", "5 helpful prior connections"). Contact details are shared only when both doctors agree. |
| Practice Mirror | See who practices like you. Physicians are grouped by k-means clustering on their real prescribing vectors, not by job title. You also get a private, judgment-free comparison of your prescribing mix against similar peers. |
| Ledger / Updates | When a drug you prescribe changes (a reformulation or a new excipient), see exactly what changed in plain language. Then ask specialists who prescribe it, "How do we fit this into our workflow?" |
Instead of returning "300 cardiologists," Relay returns the cardiologist who prescribes what you prescribe, treats what you treat, and has already helped physicians like you.
How it fits into Impiricus
Impiricus already reaches physicians at scale through AI-driven engagement: Spark messaging and the DocUpdate network. When we talked with the Impiricus team, they confirmed that the platform has no doctor-to-doctor connection today. Relay fills that gap using what Impiricus already has, without building a separate network from scratch.
- Impiricus's reach becomes the peer pool. Every physician Impiricus already engages is a potential expert for someone else.
- Engagement signals become evidence of expertise. An
IMPIRICUS_SIGNALevidence source feeds the matcher, used only with consent and respecting the anonymization opt-out Impiricus already offers. - DocUpdate content leads to a conversation. A drug-change update in Ledger links directly into Doctor Connect, so a notification becomes a question answered by a peer.
- It looks native. The UI uses Impiricus's charcoal, cyan, and magenta palette so it sits beside the existing products.
- It changes Impiricus's value to doctors. Impiricus becomes something physicians get value from directly, not only a channel for pharma messages, and every connection makes the network better.
How we built it: reinforcement learning at the core
Why a contextual bandit
Doctor Connect models peer matching as a contextual multi-armed bandit, the single-step form of reinforcement learning. Each connection is an independent decision with immediate feedback ("Was this useful?"). A full sequential MDP would add hidden state and complexity without any benefit.
| RL concept | In Relay |
|---|---|
| Context | The physician's request reduced to topic tags (drug class, condition, help mode), plus each candidate's expertise evidence |
| Arms | The eligible peers who could be recommended |
| Reward | Consented post-connection feedback: useful yes = 1.0, somewhat = 0.5, no = 0.0 |
| Belief | A Beta posterior over usefulness for every (expert, topic) pair |
The matching funnel: safety first, then learning
Every stage is a hard filter, and the bandit runs only on the peers that pass all four filters. Exploration can never surface an ineligible peer.
Scoring
score = 0.50 × expertise evidence
+ 0.30 × bandit trust estimate
+ 0.10 × specialty fit
+ 0.10 × availability fit
- Expertise evidence combines independent sources:
strength = 1 − Π(1 − wₛ). The sources are publications (0.50), self-declared expertise (0.40), Impiricus signals (0.35), and specialty (0.30). Expertise confirmed by several sources outranks a single self-declaration. - Bandit trust (UCB, the default):
trust = mean + c · √(ln(N + 1) / (nᵢ + 1))withc = 0.15. Proven experts are exploited. Under-connected peers get a small exploration bonus that shrinks as evidence builds up. - Thompson sampling is also implemented:
θ ~ Beta(1 + successes, 1 + failures), sampled with a seeded RNG and a Marsaglia–Tsang gamma sampler, so exploration is random but reproducible. - Trust is clamped to
[0, 1]and weighted at only 0.30. Exploration breaks ties between comparable peers but never overrides real expertise. Peers surfaced by exploration are labeled honestly in the UI ("Newer peer — surfaced to grow the network").
Exploration is a social-good feature, not just a math detail. Without the exploration bonus, the same few well-known experts would get every request. Newer and isolated physicians would never become visible or build a track record. The bandit gives them a fair path into the network.
The learning loop
recordConnectionOutcome is a pure function. It stores only counts, scores, topic IDs, and a timestamp, never message content or patient data. Status: UCB ranking is live in Doctor Connect. The learning update and feedback loop are implemented and covered by tests. Wiring the "Was this useful?" prompt into the live UI is our next step.
The other models
- Practice Mirror runs k-means with k-means++ seeding (k = 3, seed 42) on prescribing vectors, which are each physician's share of prescriptions per drug class (SGLT2, GLP-1 RA, DPP-4, basal insulin, and others). Peers are ranked by cosine similarity. A "similar prescribers" view finds peers within ±6 percentage points on a single drug class.
- Generative AI (Gemini) is limited to an explanation layer. It turns already-approved facts into readable summaries. It never decides eligibility, ranks peers, or reviews privacy, and every AI surface has a deterministic fallback.
- Everything is deterministic and reproducible. The same data and seed always give the same result, which matters for auditability in a regulated industry.
Security layer: zero patient data, by design
The riskiest moment in a doctor-to-doctor product is when a physician types about a real patient. Impiricus told us this was their #1 concern, so we designed Doctor Connect around one rule: only general, non-identifying clinical-practice context may leave the form. The design follows HIPAA's minimum necessary principle and uses the HHS Safe Harbor identifier list as its checklist.
- No open chat. The question is built from four short fields (120/100/40/120 characters). The answer is capped at 700 characters. There are no threads, attachments, images, or exact-dose fields.
- Deterministic identifier scan. It covers names, initials, possessives ("Bob's renal impairment"), addresses, ZIP codes, dates, phone and fax numbers, emails (including "name at domain dot com"), SSNs, MRNs and plan IDs, license numbers, URLs, and IPs.
- Age is generalized, not deleted.
72becomes Adults 65–89, and only the range is stored. - Blocked, never silently redacted. Auto-rewriting could change the clinical meaning without the physician noticing, so flagged text must be edited and re-checked.
- Safety-event stop path. "Adverse event" or "patient died" stops the flow, because those belong in pharmacovigilance reporting, not peer matching.
- Defense in depth. The scan runs again at the storage boundary, so text that fails the check can't be stored even if the UI is bypassed.
- Consent, policy, and audit everywhere. A peer appears only if the deterministic policy engine confirms they're verified, have an active
PEER_MATCHINGconsent, and are available. Emails are revealed only after both doctors approve. Every read goes through a purpose-aware data broker, and every decision is written to an append-only, hash-chained audit log.
Relay stores zero patient data. It stores only professional data: specialty, expertise, prescribing patterns, region, and connection outcomes. The RL model sees only counts, posteriors, and topic IDs.
We're honest about the limits. This layer greatly reduces the risk of physicians sharing PHI, but it isn't a HIPAA certification on its own. Production would need server-side enforcement, BAAs, and formal privacy and clinical review.
Built with Cursor and Grok: our development environment and agents
We built Relay as a small team in one weekend. The codebase is a TypeScript monorepo with 5 feature packages, 7 shared packages, a policy engine, and a test suite. Building it at that pace depended on how we worked with AI agents.
- Cursor was our main development environment and coding agent. All the code was written in Cursor. We used its agent for multi-file work across the monorepo: scaffolding feature and shared packages, implementing the bandit, the k-means clustering, and the Safe Harbor scanner, writing the tests for each, and refactoring as the design changed. When Impiricus told us patient data was their biggest risk, we rebuilt Doctor Connect from an open form into structured fields. Cursor's agent carried that change through the UI, the domain types, the storage validation, and the tests.
- Grok was our reasoning and research agent. We used Grok to test the product against Impiricus's real constraints, work through the RL formulation (bandit vs. full MDP, UCB vs. Thompson sampling, how to keep exploration from overriding expertise), and research the HIPAA Safe Harbor identifiers and prescriber-data regulations that shaped the security layer.
- Shared context for every agent. We kept a single canonical
AGENTS.mdplus livingorg/CONTEXT.md,org/DECISIONS.md, andorg/STATUS.mdfiles. Every agent session started with the same architecture rules, dependency direction, and decision history, so the agents built consistently instead of drifting. - Humans stayed in charge of the risky parts. Agents wrote code quickly. We reviewed every eligibility rule, privacy rule, and scoring weight ourselves, and the deterministic tests are the final check.
Tech stack
TypeScript · React · Vite · Node 20 · Supabase Realtime · Gemini · Cursor · Grok
- Monorepo:
apps/web→features/*(network-graph, peer-clustering, practice-mirror, doctor-connect, ledger) → sharedpolicy-engine,data-broker,audit, anddomainpackages - Cross-device consult delivery via Supabase Realtime, with a polling fallback
- All physician data is deterministic and synthetic
- Production design: MongoDB for profiles, consent, and audit; Neo4j for the expertise and trust graph
Challenges we ran into
- Making RL safe in a regulated setting. Exploration is essential for fairness, but it can't recommend an unqualified or non-consenting doctor. We solved this by running hard eligibility filters first and letting the bandit only reorder the peers that pass.
- Useful vs. safe. Open chat is the most useful and the most dangerous. Structured fields, Safe Harbor scanning, and "block, don't redact" kept questions clinically meaningful without letting patient data in.
- Cold start. A new network has no feedback yet. Combining expertise evidence from several sources gives good matches on day one, and the bandit improves them as feedback comes in.
Accomplishments that we're proud of
- A working RL matcher that explains its choices and labels exploration honestly
- A privacy layer mapped identifier by identifier to HIPAA Safe Harbor, with zero patient data stored anywhere
- A real two-physician flow that works across two laptops in about a second
- A clear fit with a confirmed gap in Impiricus's product
What we learned
- The simplest RL formulation that fits the problem (a contextual bandit) beat anything more elaborate.
- In healthcare, "don't let the data in" is stronger than "detect and clean it up later."
- AI agents are most useful when they share one source of truth for context and when humans own the high-stakes rules.
What's next
- Capture "Was this useful?" feedback in the live UI to close the RL loop in production
- Server-side authentication and the same validation enforced on an authenticated API
- Expose Thompson sampling and compare it with UCB on real outcomes
- Integration with Impiricus's physician base, engagement signals, and DocUpdate content
- Formal privacy, security, and clinical review, plus BAAs, before any real patient conversations
Try it
| Physician | Password | |
|---|---|---|
| Dr. Elena Ruiz | [email protected] | Relay2026! |
| Dr. Maya Chen | [email protected] | Relay2026! |
- Sign in as Elena and send a Doctor Connect request to Maya.
- Sign in as Maya (in another browser or on another laptop), open Inbox, and answer it.
- Back as Elena, see the answer arrive.
Built With
- node.js
- npm
- react
- react-router
- typescript
- vite
- vitest


Log in or sign up for Devpost to join the conversation.