Inspiration

This started with a conversation, not a product idea. I was at a tech event in Chicago and got talking with a doctor about how his day actually works. He's constantly switching between surgeries and seeing patients, and he never has enough time. The thing that stuck with me was when he said how much of every appointment is just gathering information. Where does it hurt, when did it start, what are you taking. By the time he's asked all of it, a chunk of the visit is already gone before any real diagnosing happens. He asked, half joking, whether something could do that pre-intake part for him so he could walk in already knowing the picture.

I kept thinking about it on the flight back. That is the whole project. Move the questions to before the visit, and hand the doctor a summary instead of a blank chart.

What it does

This started with a conversation, not a product idea. I was at a tech event in Chicago and got talking with a doctor about how his day actually works. He's constantly switching between surgeries and seeing patients, and he never has enough time. The thing that stuck with me was when he said how much of every appointment is just gathering information. Where does it hurt, when did it start, what are you taking. By the time he's asked all of it, a chunk of the visit is already gone before any real diagnosing happens. He asked, half joking, whether something could do that pre-intake part for him so he could walk in already knowing the picture.

I kept thinking about it on the flight back. That is the whole project. Move the questions to before the visit, and hand the doctor a summary instead of a blank chart.

How we built it

FastAPI backend, React frontend, Supabase for auth, database, and storage, and GPT-5.6 mini running the conversation. I built it in phases and didn't move to the next one until the last one actually worked. The chat loop first, then persistence, then authentication, then the doctor side.

The design decision I'm most proud of is that the server decides when the interview is done, not the model. Every turn, the model reports which of the nine intake topics have been covered, and the request only closes once all of them are answered, declined, or marked unknown. If even one topic is still open, the interview keeps going, so the model can't wrap up early or write a summary on its own. I did the same with the emergency red flags. Those are simple rules that run before the model ever sees the message, so the safety part never depends on what the model decides to say.

I picked GPT-5.6 mini because this is a back and forth chat and the patient feels every extra second of latency. A faster model mattered more than a bigger one here. I used Codex a lot for the parts around the model. It wrote my test cases, helped me fix frontend bugs, and helped me debug problems I couldn't figure out on my own. What made it useful was that it worked from my actual codebase, so I could describe a symptom and it would trace it back to the cause.

Challenges we ran into

Most of the tricky bugs were about state. A completed intake was still quietly accepting new messages. It looked finished, but every "ok" the patient typed reopened a full turn. Fixing that properly meant building a real request lifecycle. One active request per patient, enforced by a database constraint, and closed requests that reject new input.

Getting data isolation right was the other big one. I had to make sure one patient could never load another patient's session, and I enforced that both in the application code and again with row level security, so a bug in one layer couldn't leak through the other. There was also a smaller annoying one where the model would repeat its follow-up question twice in the same reply, which turned out to be it filling two response fields with the same text.

Accomplishments that we're proud of

I shipped the whole thing end to end and put it online. Patient chat, authentication with roles, a doctor dashboard, emergency escalation, PDF report reading, and a summary a doctor can actually use. The part I'm proudest of is that the safety-critical logic doesn't depend on the language model. The completion rule and the red-flag checks are enforced by my code, so the model can help with the conversation without being trusted with the decisions that matter. For a solo build in a short window, getting all of that working and deployed felt like a real result.

What we learned

The hard part of an LLM app usually isn't the LLM. The prompt got the conversation working pretty quickly. Everything after that was normal engineering. Where state lives, who is allowed to see what, when something is actually done, and what happens when the model misbehaves. That is where most of my time went. I also learned to keep the safety logic out of the model's hands completely. The parts of this project I trust the most are the parts the model can't touch.

What's next for Patient Intake Assistant

The next step is using the patient's own history. Right now every intake starts fresh, but the completed summaries are already in the database, so a returning patient's interview could open with what happened last time and ask smarter questions because of it. After that, I'd want a real doctor to try it in a live setting and tell me what's missing, since the whole idea came from one, and the only way to know if it actually saves time is to put it back in front of them.

Built With

Share this project:

Updates