Skip to content

Tavus-Engineering/tavus-intake

Repository files navigation

Medical Intake Experience

A forkable starter kit for AI-powered medical intake, built on Tavus. Clone it, configure the persona, and ship a real-time video intake experience where patients complete a structured pre-appointment intake with an AI coordinator that sees, hears, and responds to them in real time.

Deploy with Vercel

One-click deploy to Vercel. You'll be prompted for TAVUS_API_KEY (required). The persona_id/replica_id ship in config/presets.config.json, so they aren't deployment env vars.

Key Terms

If you're new to Tavus, here's a quick glossary of terms used throughout the repo:

Term What it means
Persona The AI's complete identity — system prompt, behavior rules, and conversation structure. Created via the Tavus API.
Replica The AI's face and voice — a video avatar trained from real footage. You pick one during setup.
Objective A single step in the intake (e.g., "Collect chief complaint and symptom duration"). Objectives chain together to form the intake flow.
Guardrail A behavioral constraint (e.g., "Never diagnose or prescribe"). Keeps the AI within its role as a data collector.
Raven Tavus's perception model. Observes the patient's environment, privacy, distress signals, and audio quality via camera and microphone.
Sparrow Tavus's turn-taking model. Controls when the AI speaks vs. listens — configured here for patient-paced, unhurried interaction.

What You'll Build

  • Real-time video medical intake — a Tavus-powered AI coordinator that sees, hears, and responds to the patient in real time
  • Structured intake flow — four objectives guide the session step by step (patient info, chief complaint, medical history, consent & insurance)
  • Hair-check lobby — live camera preview via a single getUserMedia({video, audio}) call (one combined browser permission prompt); audio + video tracks are stopped and removed before handing off so Daily takes over capture cleanly
  • Live transcript + text input — closed-captions side panel with the full running transcript (selectable, with a "Copy all" button next to the close ×) and an inline text-message input (sends conversation.respond). Both user and replica text stream in progressively via conversation.utterance.streaming (the canonical transcript event for both roles); the single-shot conversation.utterance is used only to carry Raven awareness fields, not transcript text. The video shrinks to make room when CC is open (no overlay).
  • Closed captions on by default — the conversation is created with enable_closed_captions: true
  • 10-minute hard cap — every conversation is created with properties.max_call_duration: 600 and the title bar shows a live MM:SS / 10:00 timer; the call auto-leaves at 10:00
  • Perception analysis — Tavus Raven observes room privacy, patient distress, engagement, and audio clarity throughout the session
  • Magic Canvas cards — persona-driven cards render mid-call (the name text-input, the date-of-birth calendar, and the urgency question card). Submitted values flow back into the conversation context.
  • Developer Inspector — always rendered. A right-docked, collapsible developer panel that boots collapsed (a small terminal-style toggle) and expands to a full-height panel against the right edge. A pinned Live State vitals strip sits below the header, above two tabs (Inspector + Events). The Inspector tab shows objectives progress, live persona guardrails, persona tools captured (LLM + visual + audio), and Raven perception state; the Events tab is a severity-colored CVI event console. The running utterance transcript lives in a separate TranscriptPanel (toggled by the CC button), not in the inspector. Open/closed state + active tab persist in localStorage under medical-intake.dev-panel.v3. Every column reads exclusively from the Tavus API and live CVI events — no hardcoded fallbacks. In post-call summary mode the columns reflect truth — tri-state objectives (done / active / not-reached), "Guardrails configured", and "no observations" if Raven didn't capture any.
  • Patient-facing results + clinician report — a "thanks, you're done" ResultsScreen for the patient, with a View summary button that opens a clinician-facing ReportScreen: an intake summary, chief complaint, urgency level + rationale, the collected intake fields, and Raven perception notes. The report is produced by the persona's submit_intake_report post-call tool (no Anthropic key) and read back from the conversation once Tavus finishes it.

Prerequisites

You'll need basic familiarity with the terminal (running commands, navigating directories). Install these before you start:

Requirement How to get it Verify
Node.js v18+ nodejs.org (LTS recommended — this also installs npm) node -v and npm -v
Git git-scm.com git --version
Tavus account + API key Sign up at platform.tavus.io, then go to API Keys You'll paste the key during setup
Camera + microphone Built-in or external — the intake is a live video call with the AI Test with your browser's permission settings before starting
Modern browser Chrome, Firefox, or Edge recommended. Safari has partial WebRTC support. Mobile browsers are not supported. The app uses WebRTC (via Daily.js) for real-time video — requires a desktop browser.
AI coding assistant (recommended) Claude Code (npm install -g @anthropic-ai/claude-code) or Cursor Not required, but highly recommended for customization

Quick Start

1. Clone the repo

git clone https://github.com/Tavus-Engineering/tavus-intake.git
cd tavus-intake

2. Install dependencies

npm install

3. Configure environment variables

Copy .env.example to .env and fill in the values. Each variable is documented inline — at minimum you need TAVUS_API_KEY. The persona and replica IDs live in config/presets.config.json, not in .env.

cp .env.example .env

Then open .env and paste in:

The persona_id and replica_id are set in config/presets.config.json (under presets[0]), which is the single source of truth:

  • persona_id — pick an existing persona from platform.tavus.io/personas, or run npm run init (see below) to copy a reference persona into your account and have the new ID written to the preset
  • replica_id (optional) — overrides the persona's default replica

One-time persona setup: After setting TAVUS_API_KEY in .env, run npm run init to copy a reference persona to your account. The copy command writes the new persona_id into config/presets.config.json automatically. (Skip this if the preset already has a custom persona ID.)

The Developer Inspector is always rendered — a right-docked, collapsible developer panel that boots collapsed (a small terminal-style toggle) and expands to a full-height panel against the right edge. A pinned Live State vitals strip sits below the header, above two tabs (Inspector + Events). The Inspector tab shows objectives, guardrails (with verbal/visual modality tags), LLM tools, and Raven visual/audio awareness in real time. The Events tab shows a severity-colored CVI event console. The running utterance log lives in a separate TranscriptPanel (opened by the CC button), not in the inspector. Open/closed state + active tab persist in localStorage under medical-intake.dev-panel.v3. Every column reads exclusively from the Tavus API or live CVI events — no hardcoded fallbacks.

4. Start the dev server

npm run dev

Your browser will open automatically to http://localhost:5173.

Your First Intake

Once the app is running, here's what to expect:

  1. Lobby — the app boots directly into the lobby (there is no separate welcome screen). It shows the intake intro ("Welcome", "You're starting your medical intake", a short description of the 10-minute intake naming the AI coordinator Jolene) alongside a hair-check: live camera preview plus three device selectors (Camera, Microphone, Audio output). The conversation is created in the background while you pick devices. The browser will ask for camera + microphone permission once (single combined prompt) — click Allow, then click I'm ready when you want to join.
  2. Join — clicking "I'm ready" connects you to the Tavus conversation that was created on lobby entry.
  3. Intake — the AI replica appears and begins the session. The title bar shows a live MM:SS / 10:00 timer; the call auto-leaves when it hits 10:00 (Tavus also force-ends the call server-side via max_call_duration: 600). The 4-button control bar (mic, camera, CC, end intake) is at the bottom of the video frame. Noise cancellation is applied automatically by default — there is no user toggle. The CC button opens the TranscriptPanel beside the video (the video shrinks to make room — no overlay); the transcript is selectable and has a "Copy all" button. The Developer Inspector overlay shows objective progress, live guardrails, captured persona tools, and Raven perception state.
  4. Results — when the intake ends, you'll see a "Thanks for completing the intake" thank-you card. Click View summary to open the clinician-facing summary: chief complaint, urgency, the collected intake fields, and Raven perception notes. The report is generated by the persona's submit_intake_report post-call tool a few seconds after the call ends, so the screen briefly shows a loading state while Tavus finishes it.

Tip: The intake is capped at 10 minutes end-to-end. Try it once before customizing anything — it helps you understand what each config file controls.

Open in Your AI Coding Assistant

Once the app is running, open the project in an AI coding assistant to help you understand and customize the codebase. The repo includes a CLAUDE.md file that gives AI assistants full context about the architecture, conventions, and how everything connects.

Claude Code

cd tavus-intake
claude

Cursor

cd tavus-intake
cursor .

Or open Cursor, then File > Open Folder and select the project directory.

Starter prompt

Paste this into your AI assistant to get started:

I just cloned the tavus-intake repo — a Tavus-powered AI medical intake
experience built with React + Vite. I need your help customizing it.

Key context:
- the persona (the AI coordinator's identity, intake objectives, guardrails) is managed on Tavus directly and fetched live from the Tavus API — there are no local persona JSON definition files
- config/ controls frontend branding and the single preset (perception queries live on the persona, fetched live from the Tavus API)
- api/ is the serverless proxy layer that keeps API keys server-side
- Every folder has a .md file explaining its contents
- Setup is manual: copy .env.example to .env, fill in the values, and run npm run dev
- The intake session works with only a Tavus API key; Magic Canvas renders persona-driven cards mid-call (name input, date-of-birth calendar, urgency question)

Read CLAUDE.md first for full architectural context, then help me
[customize this for a different clinic type / add new intake fields / change the
branding / deploy to Vercel].

Replace the bracketed text with what you actually want to do.

Customization

Edit branding (no code, no API calls)

Edit config/branding.config.json to set clinicName (the only branding field) — it shows as the ResultsScreen eyebrow. The LobbyScreen is the patient-facing entry screen (there is no welcome screen); its copy is hardcoded in the component.

Edit the intake fields

To add or change what data is collected, edit the persona's objectives in the Tavus dashboard. Each objective's output_variables define the field names that will be extracted and accumulated in SessionResult.objectiveOutputs. The app fetches objectives live at runtime — no code changes are required.

Change guardrails

Guardrails are managed directly on the persona — create them via the Guardrails API (POST /v2/guardrails) and attach via guardrail_ids / guardrail_tags, or edit them in the Tavus dashboard. The deployed persona is the source of truth. How the app reacts to a triggered guardrail (replica speaks / toast / inspector-only) is configured per guardrail in src/lib/guardrailActions.ts.

Change the replica

Update replica_id in config/presets.config.json (browse replicas at platform.tavus.io/replicas).

Deployment

Designed for Vercel. The api/ directory maps directly to Vercel serverless functions.

  1. Push your repo to GitHub

  2. Import the repo in Vercel

  3. Set environment variables in the Vercel dashboard:

    • TAVUS_API_KEY (required)

    The persona_id and replica_id ship in config/presets.config.json, so they don't need to be set in the dashboard.

  4. Deploy — Vercel automatically maps api/*.ts to serverless functions

# Test the production build locally before deploying
npm run build
npm run preview

For other platforms, adapt api/*.ts to your serverless runtime or add a lightweight Express server. See API.md for details on the proxy layer.

Troubleshooting

Problem Cause Fix
No .env file found Haven't created .env yet Copy .env.example to .env and fill in the values
Missing required: TAVUS_API_KEY .env exists but key is empty Add the key to .env from platform.tavus.io/api-keys
Conversation fails — no persona persona_id not set in config/presets.config.json Pick an existing persona at platform.tavus.io/personas and paste its ID into presets[0].persona_id (or run npm run init to copy a reference persona)
Tavus API error 401 Invalid API key Verify your key at platform.tavus.io/api-keys
Camera/mic not working Browser permissions blocked Click the lock/camera icon in the address bar and allow access. HTTPS is required in production.
Magic Canvas cards not rendering Magic Canvas is a preview feature that must be enabled for your account on production The app talks to production (https://tavusapi.com) only; confirm with Tavus that Magic Canvas is enabled on your account
Lobby shows spinner indefinitely Conversation creation failed Check browser console for API errors. Verify TAVUS_API_KEY is set, and that persona_id/replica_id in config/presets.config.json are correct

Available Scripts

Script Description
npm run dev Start dev server (runs env check + config validation first)
npm run build Production build (type-checks then bundles)
npm run preview Preview the production build locally
npm run validate Validate config files (Zod schemas)
npm run check-env Verify required environment variables are set
npm run init Copy a reference persona into your Tavus account and write its persona_id into the preset

Project Structure

├── api/                  Serverless API proxies         → API.md
├── config/               Frontend config (branding,     → CONFIG.md
│                         presets)
├── persona/              Dev sample answers             → README.md
├── scripts/              Setup and validation scripts   → SCRIPTS.md
├── src/                  React + Vite frontend          → SRC.md
│   ├── screens/          LobbyScreen, IntakeScreen,
│   │                     ResultsScreen, ReportScreen
│   ├── components/
│   │   ├── video/        Tavus video integration (Daily.js)
│   │   ├── layout/       FloatingInspector (right-docked collapsible dev panel: vitals strip + Inspector/Events tabs)
│   │   ├── inspector/    DeveloperInspector four-column panel + VitalsStrip + EventsConsole rendered inside FloatingInspector (always rendered)
│   │   ├── intake/       TranscriptPanel (in-flow flex panel — video shrinks when open; selectable + Copy all)
│   │   └── ui/           Spinner
│   ├── hooks/            State management + event hooks
│   ├── lib/              Utilities, API client, config loader
│   └── types/            TypeScript type definitions
└── docs/                 Architecture + customization   → DOCS.md

Deep Dive Documentation

Every folder contains a .md file that explains the concept behind it. An AI agent (or developer) can drop into any folder, read the doc, and understand what that piece does, why it exists, and how to modify it.

Persona (persona/)

The persona is the AI coordinator's complete identity — who it is, what it collects, and what it won't do. It's managed directly on Tavus (the dashboard or the Tavus API); see persona/README.md. The app references it by persona_id and fetches its objectives, guardrails, and tools live at runtime. Concepts: Objectives, Guardrails. The app's per-guardrail reactions live in src/lib/guardrailActions.ts.

Config (config/)

Frontend configuration that tells the web app how to display and label the experience.

Doc Teaches you
CONFIG.md Branding, presets, and how config connects to the persona

API Proxy (api/)

Serverless functions that keep the Tavus API key on the server.

Doc Teaches you
API.md Why the proxy exists, how each endpoint works, how to add new ones, and security rules

Scripts (scripts/)

CLI tools for setup, deployment, and validation.

Doc Teaches you
SCRIPTS.md Config validation (validate), env check (check-env), persona setup (init), and how they connect

Source Code (src/)

The React + Vite frontend. Screens, components, hooks, types.

Doc Covers
SRC.md Full directory map, FSM routing, event flow, and hooks architecture

Architecture & Guides (docs/)

Doc Covers
DOCS.md Index of documentation files and when to read them
architecture.md Screen flow, FSM states, data flow, key principles
customization.md Step-by-step instructions for common changes
tavus-features.md Which Tavus features are used and how (objectives, guardrails, Raven, Sparrow)
walkthrough.md End-to-end walkthrough from setup to completed intake with results

Recommended reading order

If you want to understand the system deeply enough to reconfigure it for a different clinical use case:

1. config/CONFIG.md       ← Branding + presets
2. api/API.md             ← Server proxy layer
3. scripts/SCRIPTS.md     ← Setup and validation tools
4. src/SRC.md             ← Frontend architecture (only if modifying the app)

The persona itself (identity, intake objectives, guardrails, layers) is managed on Tavus — see persona/README.md and the Tavus persona docs. Items 2-4 are needed only if you're changing the infrastructure or frontend code.

Environment Variables

# Server-side only (no VITE_ prefix — never in browser bundle)
TAVUS_API_KEY=            # Required — from https://platform.tavus.io/api-keys

Note: all Tavus API calls go to production (https://tavusapi.com) — the base URL is hardcoded in api/_lib/handlers/tavus.ts, not configurable.

Persona & replica: These are not environment variables. Set persona_id and replica_id in config/presets.config.json (under presets[0]) — that file is the single source of truth.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors