Inspiration

On 1 January 2027, most adults aged 19 to 64 on Medicaid must prove, every month, that they work, study, volunteer or train for 80 hours, or earn about $580, to keep their health coverage (P.L. 119-21 §71119; CMS interim final rule CMS-2454-IFC). Nine categories of people are exempt. Medicaid covers roughly 70 million people in the United States.

Arkansas already ran this experiment. In 2018, more than 18,000 people lost coverage in seven months, and there was no significant change in employment. Almost everyone who lost coverage was already working or already exempt. They just never completed the paperwork (Sommers et al., New England Journal of Medicine, 2019).

It happened again during the 2023-24 Medicaid unwinding: 69% of all disenrollments were procedural. The state could not reach the person, not that the person did not qualify (KFF).

So the failure mode is not fraud and it is not unemployment. It is silence. And every tool currently funded against that silence, whether portals, mailings, texts or IVR trees, fails hardest for exactly the people most likely to be dropped: no online account, returned mail, limited English, already disenrolled once for paperwork.

A phone call is the one channel that reaches them. There has never been enough staff to make those calls. Now there can be.

What it does

Still Covered takes the enrollee list a state already has and does four things.

1. It clears people without calling them at all. If the state's own data already proves someone is exempt, because they receive SNAP, they are on disability, they are a caregiver, or their wage records already show the hours, they are cleared ex parte and never dialled. In our sample run, the data clears several people before a single call is placed. Every call not made is money not spent and a person not bothered.

2. It calls the rest, in their language, once. One short CALL-E call that does three things and stops:

  • confirms it is really them, before saying anything about coverage;
  • explains the new rule in plain words, because most people have never heard of it;
  • asks only the exemption questions their record has not already answered.

The language is pinned to the person's own record for the whole call. Limited English is one of the strongest predictors of a procedural disenrollment, so it is the worst possible place to guess.

3. The agent never decides anything. This is the core design decision. The agent gathers; a documented, fail-closed classifier in code decides. If the transcript is ambiguous, if the person gave a partial answer, if confidence is low, the outcome degrades to needs_review, never to a determination. Nothing the agent says on the phone changes anyone's coverage.

4. Every call becomes human work. An exemption packet for a caseworker, an hours-reporting reminder, a navigator callback, or a mailed letter for anyone the phone could not reach. If the transcript shows the agent overstated something anyway, the code detects it and schedules a correction call from a human. The agent proposes, the code decides, a person signs off.

There is a live dashboard showing the campaign as it runs, and a report at the end.

How we built it

TypeScript on Node, the CALL-E TypeScript SDK, and no other runtime dependency.

  • Policy is data, not code. The nine exemptions, their questions, and the state's script live in a rules file. We loaded a second state with different rules to prove the engine is not hard-coded to one policy.
  • An append-only ledger. Every decision is an event on disk, so a campaign can be interrupted and resumed without double-calling anyone, and the final report is reproducible from the ledger alone.
  • Webhooks are trusted for nothing but the call id. CALL-E deliveries are unsigned, so we de-duplicate on the event id and then re-fetch the call through the authenticated API before anything is decided.
  • Dry-run is the default, everywhere. A bundled fake CALL-E server runs the entire campaign, including webhooks, retries and idempotency replay, with no credentials and no network. Placing a real call requires three independent signals plus a human at a terminal.

Challenges we ran into

We made real calls, and they broke things. Four live CALL-E calls produced six distinct defects, and every one traced back to something our instructions either failed to forbid or forbade too loosely: the agent combining two eligibility questions into one, previewing which answers would qualify, inventing a criterion that does not exist, dropping a question after an interruption and never re-asking it.

That taught us the thing we did not expect: testing the code is not testing the agent. So we built conformance probes, scripted adversarial calls where a human plays a difficult recipient (refusing to confirm identity, demanding a yes or no answer, answering in the wrong language) and the transcript is then checked mechanically against the boundaries the task promised. Six live probes, seventeen assertions. Sixteen passed.

We published the one that failed. On one call the agent said "you likely qualify", which is stronger than it was authorised to say. It is in the repository, in the report, with the transcript. A safety claim you have not tried to break is not a safety claim.

We also hit a real limit worth naming: on one call the audio ran 151 seconds, the transcript covered 127, and the event stream stopped around 100, leaving about 24 seconds no assertion could examine. A probe that passes means nothing in the transcript violated the boundary, which is weaker than the agent did not violate it. We report it that way.

Accomplishments that we're proud of

The linter. Those six defects were not about Medicaid. We packaged every lesson as 14 rules that read any CALL-E call task and report which boundaries it leaves undefended, each rule naming the real call that produced it and the exact line that fixes it. A naive task scores 3 of 14.

It is reachable four ways, because the person who needs it is not always sitting where we are: a CLI, a self-contained browser page (no server, no install, no network), an MCP server so any agent can call it, and a token-gated HTTP API for systems that are neither. No tool in the MCP server can place a phone call. The two that shell out are pinned to dry-run by the server, not by their arguments.

Self-hosted on purpose: a call task is usually the most sensitive text in a benefits system, and it should never have to leave your machine to be checked.

What we learned

Most of the hard problems in agent phone calls are not engineering problems. They are authority problems: what the agent is allowed to say, what it must not say first, and who is permitted to decide. Almost every defect we found was the agent quietly assuming authority it did not have.

The fix is never a better prompt. It is a boundary stated explicitly in the task, and then a transcript check that proves the boundary held on the day.

What's next for Still Covered

  • A pilot with one state or managed-care plan against a real enrollee list, measured on the only number that matters: procedural disenrollments avoided.
  • Contributing transcript-coverage reporting upstream, because a conformance check against a partial transcript is a check with a hole in it, and the platform is the only place that can close it.
  • Growing the linter's rule set from other people's live calls, not just ours.

Sources: P.L. 119-21 §71119 · CMS-2454-IFC (June 2026) · Sommers et al., NEJM 2019 · KFF Medicaid Unwinding Tracker · FCC 24-17 and DA 23-62 (AI voices and consented outreach).

Built With

Share this project:

Updates

Submission history