AfterVisit: every patient followed up, without the recall list

Watch the demo: https://www.youtube.com/watch?v=GWiwZul4Kss

Inspiration

Clinics are overwhelmed. There are too many patients and not enough hours, so follow-up calls are the first thing to go.

Manual follow-up is broken. After a consultation, the doctor writes a note like "check for dizziness and ankle swelling." Then the patient goes home, and nobody calls. Recall lists are kept by hand, and the busiest clinics drop them first. The patient who is in trouble is often the one who stops picking up, and nobody notices for a week.

Patients deserve better care after they leave the room. We wanted the note to be enough: the doctor writes it, and the follow-up happens.

What it does

AfterVisit is a clinical follow-up agent built on CALL-E. It runs the whole follow-up, not just one call.

  • The front desk registers the patient and records their consent to automated calls. Without consent, nothing is dialed.
  • The doctor writes the note they already write, plus an optional "Escalate to me if…". Then they press Save and start follow-up.
  • AI reads the note into a goal, up to five things to find out, and a schedule. Every topic quotes the note's own words. Every value is marked from your note or default.

What the calls find out, each quoted from the note, with the patient's answer

  • Every call appears as a dated row before anything rings. The doctor can move, skip, or place any call now.
  • A cron job calls each patient automatically, every day, in their language. The agent says it is an AI, asks about each topic in its own words, and retries when nobody answers. It ends the call if the patient describes something urgent or asks for a person.
  • The Follow-ups board shows how each patient is doing, in their own words. Anyone who needs the doctor goes to the top, with the doctor's own conditions they matched.

Follow-ups: how each patient is doing

Try a call lets judges ring their own phone. Paste a note, and the call follows up on it. You see the recap, the findings, and the transcript. Nothing is saved.

How we built it

  • Next.js 16, React 19, and TypeScript, deployed on Vercel.
  • Neon Postgres with Drizzle.
  • CALL-E for the calls: task carries the goal and every safety rule, resultSchema returns typed answers per topic, idempotencyKey stops duplicate calls, and webhookUrl plus calls.get fetch the results.
  • OpenAI reads the note with a strict schema. After each call, it reads the transcript for severity.
  • A single port file is the only code that talks to CALL-E. Consent, the phone number check, the dial allowlist, and the script guard all run inside it.
  • A cron job on cron-job.org drives the scheduler every five minutes.
  • 382 tests cover the safety logic, run against an offline fake of CALL-E.

Challenges we ran into

  • CALL-E has no scheduling API. So AfterVisit owns the calendar, the retries, and the escalation. On Vercel Hobby, built-in crons run once a day, so an external cron drives the scheduler every five minutes. A call more than 90 minutes late is dropped, not dialed. A queue that was down all day must not wake up and call forty people at once.
  • An early call ended instantly and reached nobody. CALL-E needed a routing region, so we now derive it from the phone number itself.
  • A real call came back "480" and the console said "No answer." That blamed the patient for a network that never rang the phone. We now explain each failure code in plain words, and redial only when it could help.
  • On a test call, the person said "I feel like fainting" and the agent replied "I can't answer that one." The deflection was written too broadly. Now it only covers questions the patient asks, and anything urgent ends the call.
  • Our first retry ladder never scheduled a single retry. An unanswered call also triggered the "couldn't understand the answer" rule. Silence is not an unclear answer, so each now has its own rule.
  • The model phrases its own questions. So we check what it actually said after the call, not just the script before it. That check is English-only for now, and we say so.

Accomplishments that we're proud of

  • The doctor's whole job is one button. The follow-up runs by itself until the patient recovers or a clinician steps in.
  • The safety model. The agent never gives advice or diagnoses. The guard runs three times: on the note, on the script, and on the transcript. It also fails any script that is missing the AI disclosure or the emergency stop.
  • A model reads every call, and four simple rules stand under it. If the model is down, a patient who asked for a person still reaches one.
  • A fresh deploy calls nobody. It needs an API key, an allowlist, and recorded consent.
  • We packaged the pattern as a reusable agent skill in skills/aftervisit/.

The patient record: how they're doing, in their own words

What we learned

  • Real calls find bugs tests don't. Most of our safety rules exist because a real call went wrong first.
  • Silence is data. A missed call is the signal this product exists to catch, so it must never be explained away.
  • A number is only kept when it is one. "About 38, I think" stays in the patient's words and never shows up as a reading.
  • When the model is unsure, a human decides. Nothing is guessed to close a loop.

What's next for AfterVisit

  • Check the agent's words after the call in every call language, not just English.
  • Let patients pick a better time when they can't talk.
  • Log in for clinicians and front desk, so consent and the allowlist are tied to a real person.

Built With

Share this project:

Updates

Submission history