MediCall — Hackathon Presentation
Real World Impact
The Problem
Every outbound pre-arrival call a clinic makes is invisible work. A nurse calls the patient to confirm, asks if anything has changed, and either everything is fine (call is forgotten) or the patient mentions a new symptom (and the nurse writes it on a sticky note, tells another nurse, or pages the physician — all informal, all lossy).
The core problem is not that the call happens — it's that nothing structured comes out of it.
- New symptoms reported verbally are not reliably captured before the patient arrives.
- Staff time is consumed by calls that could be automated: routine confirmations, reschedule requests with a confirmed new slot.
- When something does need clinical attention, the triage chain depends on memory rather than an auditable record.
Who It Solves It For
Clinic staff at any outpatient facility that makes pre-arrival calls: GP practices, specialist clinics, procedure units. The problem is practice-universal, not niche.
Why It's Worth Building Further
- The handoff card produced by MediCall is what goes into the pre-visit prep chart — the artefact the care team consults before the patient walks through the door.
- ROUTINE dispositions require zero staff time — the call runs, the record is updated, the queue stays clean.
- HUMAN_REVIEW dispositions surface only what needs human attention, with verbatim patient statements, evidence, and a transcript excerpt already attached.
- The policy engine is deterministic and auditable:
D = f(R, C, P)— every disposition can be traced back to a specific rule and a specific patient statement.
Quality of the Idea
Why This Is Non-Obvious
The obvious CALL-E use case is "automate the call". MediCall does that — but the real contribution is the post-call workflow:
- The conversation policy embedded in the goal text is the first safety layer: CALL-E is told explicitly what to collect and what it must never say.
- The structured result is validated twice before any human ever sees it: Pydantic schema layer (forbidden clinical field names) and semantic layer (regex detects clinical language that should not appear in any field).
- The policy engine is entirely deterministic — no LLM chooses the disposition. The same call result always produces the same disposition.
- The handoff card contains the evidence chain: which rule fired, which patient statement triggered it, and at what offset in the call.
This is not "AI that makes phone calls". This is a care coordination workflow with a phone call as its input channel and an auditable handoff as its output.
Contribution to the Community
SKILL.md defines the pre-arrival-coordination pattern in a
domain-agnostic way. The same pattern — outbound call → structured intake →
deterministic policy → human handoff — works for:
- Field service dispatch preparation
- Delivery exception coordination
- Insurance claim information collection
- Interview scheduling confirmation
The MediCall codebase is the reference implementation. Any developer can
read SKILL.md, pick up the pattern, and adapt it to their domain without
having to reinvent the safety boundary or the policy engine.
Technical Implementation
How CALL-E Is Used
CALL-E is the execution substrate. It is imported and called at runtime
via the calle CLI subprocess in medicall/calle/real_adapter.py.
Every production call goes through:
calle call start --to-phone <E.164> --goal <text> --json
→ {run_id, status_result: {structuredContent}}
while not terminal:
calle call status --run-id <id> --json
→ {result: {structuredContent}}
- Attribution env vars set on every subprocess call:
CALLE_SOURCE=skills_sh CALLE_INTEGRATION=skills_sh_skill - Status strings normalised at parse time (
"NO ANSWER"→"NO_ANSWER") — discovered from live CLI output during acceptance testing. - Language flag passed for non-English calls:
--language Hinditested end-to-end with a full engine run.
Verified Live Calls
Two real outbound calls were placed during development and testing:
| run_id | Status | Notes |
|---|---|---|
run_xxxxxxxxxxxxxxx_no_answer |
NO_ANSWER |
First acceptance run — discovered "NO ANSWER" status format; bug fixed |
run_xxxxxxxxxxxxxxx_1 |
COMPLETED |
Second acceptance run — call connected, bot spoke, callee responded, transcript captured; 81s end-to-end |
Test Suite
| Layer | Tests | Notes |
|---|---|---|
| Unit | 15 | Policy engine (7 rules), state machine, result validator |
| Integration | 33 | CoordinationEngine × 12 scenarios (incl. voicemail + Hindi), handoffs router × 8 |
| Acceptance | 3 | Real CALL-E calls — CALLE_ACCEPTANCE=1 ACCEPTANCE_PHONE=<your-number> |
| Smoke eval | 11 | All recorded scenarios via python -m eval.run_eval |
Total: 48 unit+integration, 11 eval, 3 acceptance — all pass.
Verified live acceptance runs (2026-09-08):
| Test | run_id | Status | Duration |
|---|---|---|---|
test_real_adapter_single_call |
run_xxxxxxxxxxxxxxx_1 |
COMPLETED |
80s |
test_real_full_workflow |
run_xxxxxxxxxxxxxxx_2 |
COMPLETED |
~90s |
Architecture Highlights
Appointment
↓
CALL-E outbound call (calle call start → poll calle call status)
↓
Patient conversation (consent → intake → structured result)
↓
Deterministic policy (D = f(R, C, P) — no LLM in the decision path)
↓
ROUTINE / HUMAN_REVIEW / ESCALATION
↓
Staff handoff card (evidence-linked, auditable)
Four safety layers — none relying on LLM judgment:
- Conversation policy in goal text (what CALL-E collects / never says)
- Pydantic schema (forbidden clinical field names raise
ValidationError) - Semantic boundary (regex rejects forbidden clinical language in transcripts)
- Deterministic policy (
Dis always operational, never a diagnosis)
Components:
real_adapter.py— CLI subprocess, polling loop, activity printer, parsercoordinator.py— 15-state workflow enginepolicy.py— 7-rule deterministic policy enginevalidator.py— transcript + intake semantic boundarygoal_builder.py— conversation policy embedded in CALL-E goal texthandoff.py— evidence-linked staff handoff generatorapi/— FastAPI server with/appointmentsand/handoffsrouters
Complete, Coherent Experience
- CLI batch runner:
python -m eval.run_eval --csv examples/appointments.example.json— live call progress printed to terminal - REST API:
uvicorn medicall.api.main:app—POST /appointments/places a real call;GET /handoffs/feeds the staff review queue;PATCH /handoffs/{id}/acknowledgecloses the loop when a staff member reviews the handoff - Docker:
docker-compose up— mounts the host CLI token cache into the container
Log in or sign up for Devpost to join the conversation.