Inspiration

My parents live in Thoothukudi. I don't. Every NRI I know has the same 3 a.m. fear: something happens, and by the time you hear about it, the decisions that mattered have already been made by whoever was standing there.

And even once you hear, you cannot get there. Thirty-five to forty-eight hours door to door if everything goes right, and it rarely all goes right: leave that has to be approved, a visa appointment, a passport with somebody else, a seat that has tripled in price since this morning, a bag packed at 2 a.m. Five days is ordinary. Everything this system does happens inside those five days, because that is the window where the person who loves her most can do nothing at all. It does not shorten the flight. It makes the wait survivable for the people who are already in the room.

The existing answer is a person: a family friend, a paid proxy, a sibling WhatsApp thread. Sahaayak, Samarth Care, Care247, Policybazaar's NRI Care Program are all human-coordinator models. I wanted to know whether an agent could take that role, and what would have to be true before I let it near my own mother.

One rule fell out of that and shaped everything else: any step that needs the son to act is a design failure. He is asleep, nine and a half time zones away. That is the problem, not a detail of it. So every feature got tested with him unreachable.

What it does

She sends a voice note in Tamil. Nobody presses anything after that. Within about fifteen seconds her son gets an alert in English, the neighbour gets a notice in Tamil carrying a scoped revocable bedside link, a cashless pre-authorisation is filed against her policy, and a one-hour regulatory clock starts.

That clock is not decoration. The IRDAI Master Circular on Health Insurance Business (IRDAI/HLT/CIR/PRO/84/5/2024, 29 May 2024) gives an insurer one hour to decide a complete cashless request. When it lapses the family is told what they are owed, and told in the same breath that Anbu Care has filed nothing, can compel nobody, and is not claiming this will be won.

From there it keeps going without being asked:

  • It books a real clinic. A doctor dictates a test at the bedside, in Tamil, into a handset bound to the case for sixty minutes. Nobody picks a lab. It searches real Thoothukudi diagnostic centres, ranks them against a mandate, then drives each centre's own booking site in a real headless browser: read the form, map the fields, fill it, read it back, submit, screenshot. Seven of the eight real centres cannot take a submission. One can.
  • It pays the family's share of a hospital bill, not the hospital's whole balance. Under a cashless authorisation the insurer settles its part with the hospital directly, so paying the printed balance would pay the insurer's share out of the family's money. On our day-four bill that is INR 27,300 on the paper where INR 9,733 is owed.
  • The claim files itself on discharge. A photographed discharge summary assembles the packet, submits it, starts the real 30-day clock, and renders a filled Part A claim form: a PDF a person could sign and send, filled from the record, with any field the system does not hold printed as not on record rather than guessed.
  • An arriving lab report closes the test it belongs to, and closes neither when two are outstanding, because attributing it means reading it to decide which, and that is a model choosing which clinical order was carried out.
  • It checks on her for a fortnight after discharge, once a day, in Tamil. It also learns which language she answers in, and the next admission's first check-in goes out in that rather than the one a son in another country picked on a form.

Every action leaves an Ed25519-signed receipt whose hash covers the previous one, and anyone can verify the chain with no credential.

How we built it

The first decision was the channel: take the intelligence to where the family already is, instead of asking a seventy-one year old to come to it. There is no Anbu Care app, no account to make and nothing to be shown how to use. She is not going to install one, learn one, or remember a password for one, and the neighbour who actually goes round is doing a favour: you cannot ask somebody for a favour and ask them to install software in the same sentence. The adoption cost is zero because there is nothing to adopt. WhatsApp is where this family already talks, so she sends a voice note in the language she speaks and never types anything, the neighbour scans a QR and is done, and the son reads it where he reads everything else. Every lane in this system had to arrive on a thread they were already looking at, or it did not ship.

That choice is also where the hardest constraint comes from, which is why it belongs at the top rather than in a footnote. India's DPDP Act and Meta's healthcare policy mean clinical detail cannot travel on this channel, so the comms gate that classifies content rather than the sender's claim about it exists because of the channel, not despite it. And with no approved message templates, the system can only write to her inside a twenty-four hour window she opened, which is a real limit on a product whose whole idea is acting while nobody is awake.

Five agents on Google ADK, a coordinator delegating to onboarding, triage, evidence, insurer liaison and WhatsApp comms, each with an isolated tool scope, running Gemini 3.5 Flash on Vertex AI for document vision, Tamil transcription, translation and policy-clause matching. A second, smaller model, Gemini 2.5 Flash Lite, decides which language she actually writes in: asking a frontier model a question with a two-letter answer, on a path that already owes her a reply inside fifteen seconds, is the wrong trade.

Underneath them is a deterministic layer no agent can reach past. The model proposes; that layer decides, and it is the only thing that can write.

Google-managed services doing real work:

  • Cloud Run for the agent API, the Twilio webhook and the dashboard, plus a second service for the headless browser, because Chromium will not fit beside the API
  • Firestore for case state and the hash-chained receipt ledger, single-table PK/SK
  • Cloud Scheduler for the recovery tick and the claims SLA tick. Cloud Run holds no timer, which is what makes the regulatory clock real rather than a setTimeout in a demo
  • Pub/Sub for intake, case and claim events across a multi-day admission
  • Cloud Storage for photographs, booking screenshots and claim forms
  • Vertex AI Agent Engine Memory Bank for the one class of fact that outlives a case
  • Google Places so every hospital and diagnostic centre carries a place_id and a verification date

The discipline that mattered: guarantees live in code, and the tests assert claims about the world rather than return values.

Challenges we ran into

An agent claiming a write that never happened. On one run it said "I have successfully read your mother's lab report and ingested it into her health record." Documents actually stored: zero. For a system whose entire pitch is a verifiable record, that is the one bug that discredits everything else. Prompt wording was never going to fix it. The demo now prints the stored count read back from the service next to what the agent claimed, and says CONTRADICTED on screen if they disagree.

A guard that could never fire. The document reader emits the kind lab_report; the record stores it as blood_report. A new guard compared against the stored word. Nothing raises. No error appears anywhere. The guard simply never matches and the loop silently closes nothing, forever. Eighteen unit tests passed anyway, because they all called the function directly and handed it the right word themselves.

A race I caused. Recovery check-ins read the day's slot, then translated, then sent, then wrote the slot. Between the read and the write sit a model call and a provider call, and a second caller reading that same empty slot sends the same message. The demo handset was asked how she was feeling twice in one minute. The slot is now claimed atomically before the send.

Paying the insurer's share out of the family's money. The payment lane handed the enforcer the balance printed on the bill, and nine guards checked the destination, the caps and the anomalies without one of them asking whether the insurer was already paying the hospital directly. The system knew better in the same function, three lines apart: one line paid the balance, the next rendered the coverage split saying most of it was covered.

Gemma, which is not in the build. I wanted a small model normalising messy intake text. It is not available as a managed endpoint on this project's Vertex AI (gemma-3-27b-it, gemma-3-12b-it and gemma-2-9b-it all return 404 on generateContent), and serving it would have meant a GPU-backed deployment billed by the hour for a component that by design could never change a decision. The precheck evidence is in the repo and it is claimed nowhere as built.

Accomplishments that we're proud of

The guardrails are code, not prompts, and I can show that rather than say it.

Tell it "she says it's probably just gas" and severity still returns HIGH. The thing that decides severity is a Python dict; it never reads that sentence as permission.

Clinical detail cannot leave over WhatsApp. India's DPDP Act and Meta's healthcare policy make that a legal line, so the gate classifies the content, not the caller's claim about it. Then the demo bypasses the agent entirely and calls the send function directly. Still blocked. That second half is the whole claim: an agent merely told not to leak a lab value is not a control.

Public where it proves, private where it reveals. Verification is open to everyone and needs no credential, because it proves the record was not altered without revealing what it says. Everything returning content is credentialed. Rewrite a receipt in Firestore leaving hash and signature untouched, and the public endpoint names the sequence number rather than saying something is wrong.

The refusals. Two outstanding tests and one arriving report closes neither. A Memory Bank with no free-text path into it, so a caller cannot put a symptom in it because a caller cannot put a sentence in it. A claim form that prints not on record rather than guessing, because it is signed by a person and a confident wrong field is worse than a blank one.

1,259 tests, none of which need cloud access or a model to run.

What we learned

A test that cannot fail for the reason you care about is not covering that reason. The lab_report bug passed eighteen tests, because every one of them called the function directly and supplied the right word itself. The fix was not the one-word change; it was writing two tests through the real ingestion path and confirming they failed first. Every new guard now gets broken on purpose before the change is allowed to stand.

Managed services break assumptions that mocks cannot. Vertex Memory Bank matches scopes exactly on the whole map rather than a subset, which is why recall here is a keyed lookup rather than a similarity search. One live call established that; no amount of local testing would have.

Silence is a design decision. The lanes that felt most staged were the ones that waited to be asked. Each was fixed by finding the document that already arrives and making it the trigger: an escalation files the pre-authorisation, a discharge summary files the claim, a lab report closes the test, and her own first message establishes what language to write to her in.

What's next for AnbuCare

More of India than two languages. The detector already recognises eight, and the renderer will write any of them. What is missing is the handful of fixed sentences it cannot render on the fly: the immediate replies on the WhatsApp webhook, which Twilio abandons at fifteen seconds, and which are therefore pre-translated rather than generated. Today that means English and Tamil, and a Malayalam speaker gets the English fallback. Widening it is translation work rather than engineering, and it is the difference between a system for Tamil Nadu and a system for India.

The staleness nudge: nothing yet reminds anybody that a booking request has gone unanswered, and callback-only centres never reach confirmed. Real cancellation through a centre's own system, so cancel stops being a record-only act. Per-analyte reference change values instead of a flat 10% band. And Gemma as an intake normaliser, if it ever ships as a managed endpoint.

Built With

  • agent-engine
  • cloud-run
  • cloud-scheduler
  • cloud-storage
  • docker
  • ed25519
  • fastapi
  • firestore
  • fpdf2
  • gemini
  • gemini-3-5-flash
  • google-adk
  • google-places
  • memory-bank
  • playwright
  • pub-sub
  • pydantic
  • pytest
  • python
  • raorpay
  • segno
  • twilio
  • uvicorn
  • vertex
  • whatsapp
Share this project:

Updates

Submission history