Inspiration

I've sat in that chair enough times to know the feeling. The therapist asks "so, how was your week?" and my mind goes blank. A week of real weight, a fight that stuck with me, a pattern I almost noticed, and I end up talking about work deadlines because it's the first thing I can reach. The session circles. We never get to the real thing. I leave feeling like I wasted both our time. That first 20 minutes is where therapy goes to die. Not because the therapist isn't good. Because there's no bridge between the week you lived and the session you're sitting in. 40% of appointments are cancelled or no-shows, and for a lot of people that number isn't avoidance. It's just not knowing what to say. We built PreVisit because we've been that patient. And we're tired of the 20 minutes that go nowhere.

What it does

PreVisit activates 24-48 hours before a therapy session. The patient has a natural conversation with the INTAKE agent, no forms, no mood ratings, just talking. Behind the scenes, the ANALYST agent reads between the lines and separates what the patient said from what they actually mean, then generates a Patient Prep Card with three questions to bring into session and a Therapist Brief with a suggested focus. The GROWTH agent tracks patterns across weeks, surfacing things like "you've brought up work anxiety three sessions in a row" so neither the patient nor the therapist has to hold all of that manually.

How we built it

Three specialized agents orchestrated with LangGraph, communicating over Redis pub/sub. All LLM calls go through Claude Sonnet via the Anthropic API. The frontend is a React chat UI with two views, one for the patient and one for the therapist. The GROWTH agent formalizes emotional change mathematically. If SnS_n Sn​ represents patient state at session nn n, encoding tone, avoidance signals, and core topics, the growth delta is: ΔG=Sn−∑i=1n−1wiSi\Delta G = S_n - \sum_{i=1}^{n-1} w_i S_iΔG=Sn​−i=1∑n−1​wi​Si​ where wiw_i wi​ weights recent sessions more heavily when there has been a gap in time.

Challenges we ran into

Getting INTAKE to know when to stop was harder than expected. People can talk forever, and cutting them off feels wrong. We had to build exit logic that detects when enough structured signal has been gathered and closes the conversation gracefully, without the patient feeling rushed or dismissed. The second big one was JSON validation. ANALYST publishes to two separate channels with different schemas. Any malformed output silently breaks the pipeline downstream, so we added strict schema validation as a hard gate before anything gets published.

Accomplishments that we're proud of

The mirroring behavior in INTAKE actually works. When the agent reflects a patient's own language back without reframing it, people naturally surface what they actually want to talk about. We didn't expect it to feel that human. The therapist brief also came out cleaner than we hoped, concise, clinically framed, and genuinely useful as a session-opening tool.

What we learned

AI in mental health shouldn't try to be the therapist. It should be the space before the therapist, where you figure out what you actually want to say. The prompt architecture matters more than the model. Two separate system prompts for the patient-facing and therapist-facing outputs made a bigger difference than any other single decision we made.

What's next for Mind Mesh

Persistent longitudinal tracking across real sessions, not just a demo store. A mobile-first INTAKE experience so the conversation happens naturally on the commute or the couch, not at a desktop. And tighter integration with therapist scheduling tools so the brief lands in the right place before the session starts, automatically.

Built With

  • anthropic-claude-api-(claude-sonnet-4-20250514)
  • claude-analyst-agent
  • claude-intake-agent
  • claudeapi
  • fastapi
  • javascript
  • langgraph
  • python
  • react
  • redis
Share this project:

Updates