SecondLine
A phone line that gets better after every call.
Answer the calls a small business misses, and make every call an input to the next version of the agent.
- YC Voice Agents Hackathon
- Hackathon build, deployed
- One day, May 2026
- Pipecat · Cekura · NVIDIA · AWS · Twilio
- Phone line · WebRTC · owner dashboard
- Built in one day at the YC Voice Agents Hackathon. Deployed and demonstrable; not a running business.
A small business that misses a call usually loses the customer outright. Most callers do not leave a voicemail and do not try again — they call the next shop on the list. For a florist or a clinic, the phone is a large share of revenue, and the missed-call problem is a revenue problem wearing a support-tooling costume.
SecondLine is the number a business forwards its missed calls to. It answers over a real phone line, recognises returning callers, takes the order through typed tools, and files a structured task for the owner. The part I cared about is the last one: it tests itself, scores the failures, and rewrites its own policy.
Call flow
Forwarded missed call over telephony
Real WebRTC session from the eval platform
Streaming, with turn detection
Open-weight by default, provider-switchable
Eleven tools, one shared dispatch
Back out over the same transport
Customers, allergies, orders, transcripts
Structured task filed for every order
Same dispatch layer as the live bot
A real call and an automated test call take the same path through the agent. The evaluation harness and the live bot share one dispatch layer, so a test exercises production code.
The core decision: typed tools, not a trusted model
The model never holds business state. Customers, allergies, past orders, inventory, and owner tasks live in a backend module behind eleven typed tools and a single dispatch function. If the model wants to know what someone ordered last time, it calls a tool; it cannot recall, approximate, or invent it.
That one decision is what made the safety guarantees possible. Rules like the allergen guard live at the tool layer, below the model, so they hold regardless of what the model was persuaded to say.
Where safety is enforced
“Add a lily bouquet to this order”
Allergen guard, low-confidence escalation
Written only if validation passes
Caller has a recorded lily allergy. The write is refused and safe alternatives are offered instead.
The same rule in a prompt is a suggestion. In the tool layer it survives every future prompt change.
Validation sits between the model's intent and the business state. A blocked call returns a refusal and safe alternatives rather than failing silently.
The scenario that mattered
From the demo script — a returning caller, recognised by caller ID, with an allergy already on file.
- Hi — same as last time, but no lilies, my mom's allergic.
- Welcome back! I've got your usual — a dozen red roses, and I'll keep it lily-free for your mom. Want that for pickup?
- Perfect, pickup at five.
This is the scripted demo scenario, not a captured production transcript. The same scenario runs in the evaluation harness as the allergy trap.
The self-improvement loop
Sixteen scenarios — new orders, repeat callers, the allergy trap, refunds, escalation, manager requests — run against a simulated caller. Each call is graded on six dimensions: task completion, correct tool use, memory accuracy, escalation behaviour, hallucination, and latency.
Failures are not just reported. The improvement engine classifies each one into a validation rule, an escalation rule, a prompt patch, or a memory update, writes it into the agent's policy file, and re-runs the suite to prove the change landed.
Before and after
Local evaluation harness, sixteen scenarios, open-weight model under test.
- 88%94%
- 10
The unsafe action was the agent about to add a lily bouquet for a caller with a recorded lily allergy. The loop wrote a validation rule that blocks it at the tool layer and proved it gone on re-run.
The first automated voice-testing run scored zero percent. Every transcript said the same thing: the main agent did not speak.
The production bug that only automated calls could find
That zero was not a scoring artefact. The deployed bot handled the Twilio websocket transport and local WebRTC, but not the Daily transport the hosting platform uses for WebRTC sessions — so on those sessions it silently constructed no pipeline at all and sat there. Local tests could not see it, because locally the transport was different.
Adding the missing transport case and redeploying took the agent from silent to fully conversational, verified by the same automated calls that caught it. Find, fix, re-run, on the real deployment.
Starter template versus what was built
The project began from the Pipecat Field & Flower starter. The split is worth stating plainly.
| Already existed | Built during the hackathon |
|---|---|
| Pipeline skeleton, speech-to-text and text-to-speech wiring, Twilio serializer | Business brain with persistent caller-ID memory: customers, allergies, past orders, transcripts, owner tasks |
| Local WebRTC and Twilio transports | Daily transport support — the fix the automated testing surfaced |
| Hosted model and speech endpoints | Eleven typed tools and a shared dispatch used by both the live bot and the harness |
| Evaluation platform and its API | Sixteen-scenario harness, six-dimension grader, and the failure-to-fix improvement engine |
| — | Allergen safety guard at the tool layer, owner dashboard, provider switching, deployment, and project site |
What I built
Built during a single-day hackathon on top of a starter pipeline. Concretely:
Built the business backend and the eleven typed tools, with one shared dispatch function used by both the live bot and the evaluation harness so tests exercise production code paths.
Implemented the allergen safety guard at the tool layer, below the model, along with safe-alternative suggestions when an order is blocked.
Wrote the sixteen-scenario evaluation harness with a simulated caller and a six-dimension grader.
Wrote the improvement engine that classifies each failure into one of four fix types, patches the agent policy file, and re-runs to prove the change.
Integrated the automated voice-testing platform through its REST API — agent creation, scenario generation, live WebRTC test calls, and result retrieval.
Diagnosed and fixed the production transport bug that made the deployed agent silent on hosted WebRTC sessions.
Built the owner dashboard — task queue, transcripts, and the before-and-after pass rate — and deployed the agent behind a real phone number.
What remains unproven
- No business has used it. This was a one-day hackathon build, and the evaluation results come from a simulated caller, not from real customers on a real line.
- The pass-rate improvement is measured on the local harness against sixteen scenarios I designed. It is a real before-and-after on a fixed suite, not a claim about general voice-agent quality.
- Owner SMS was built and wired but ran on a trial phone number that cannot send messages, so notifications surfaced as dashboard tasks rather than texts.
What I took from it
Automated calls against the real deployment find what local tests cannot
The silent-agent bug existed only under a transport that local development never used. No amount of unit testing would have surfaced it; one automated voice call did, immediately.
Put the guarantee below the model
An allergen rule in a prompt is a suggestion. The same rule in the tool layer is a guarantee, and it survives every future prompt change.
A score of zero is information
The instinct is to assume the harness is broken. Reading the transcripts instead turned a scoring failure into a production fix within the hour.
Stack
- Business logic, typed tool layer, and persistent caller memory
- Allergen safety guard enforced below the model
- Sixteen-scenario evaluation harness with a simulated caller
- Automatic failure-to-fix improvement loop
- Multi-transport deployment and production debugging
- Owner dashboard and task queue