AI phone intake for US law firms
A voice agent that picks up when a personal-injury firm can't, takes the caller's details, checks for conflicts of interest while the call is still going, and never gives legal advice. The rules a firm can't afford to break live in code, not in the prompt.
- Where
- Arthus Systems, remote
- When
- June to August 2026
- Built with
- TypeScript, Fastify, Retell AI, Claude API, PostgreSQL
- Code
- Client work, private
The problem
Law firms lose clients to unanswered calls, but an intake call is regulated work. The agent has to ask the required questions in order, notice when a caller is on the other side of an existing case, and refuse to advise, because it isn't licensed to.
A language model told to follow those rules will follow them most of the time. For a law firm, most of the time is the problem.
Data
There is no training set. The inputs are live speech-to-text turns from Retell, the firm's intake question tree, and its records of existing clients and parties to check callers against. Callers misspell and mispronounce names, so the conflict check has to match approximately, not exactly.
Architecture
- Retell handles the callTelephony, speech-to-text and text-to-speech. Each turn reaches my server over one persistent WebSocket per call.
- State machine decides the stepA Fastify server in TypeScript tracks where the caller is in intake. The model can phrase a question but cannot skip one.
- Claude writes the replyPrompted for the current step only, with the firm's rules.
- Conflict check mid-callPostgreSQL trigram matching (pg_trgm) compares the caller and the other party against existing records in under a second.
- Output filterA second, deterministic layer checks every reply for legal advice before it is spoken.
How it's tested
Unit and integration tests, replays of recorded call fixtures, and an adversarial suite of 52 prompts that try to pull legal advice out of the agent. The deterministic half runs in CI on every change; the live half runs against the real model for about twelve cents.
Results
| Measure | Result |
|---|---|
| Reply time per turn | under 800 ms |
| Conflict-of-interest check | under 1 s, mid-call |
| Adversarial prompts in CI | 52, on every change |
Where it breaks
Written down so nobody finds out during a pilot:
- Testing so far is over web calls, which carry wideband audio. Real phone lines are 8 kHz narrowband, so name and number accuracy on the phone is unmeasured, and the two are never pooled.
- Latency was measured from a development machine in Pakistan, through a tunnel, to US-hosted Retell. Those figures are flagged as contaminated; the production number needs a US deployment.
- Web calls have no caller ID, so the caller lookup has only been exercised with injected test numbers.
- Live transfer to an attorney isn't wired yet. The agent records where it would have transferred, and tests assert on that record.
Next case study: WhatsApp enquiry automation