Home/Docs/Capture overview

Capture your calls

Separate channels, scored offline, whatever produced them. A frozen recording re-scored in CI proves the evidence and scorer are intact; proving today’s agent needs a new capture, not a replay.

The recording you capture feeds a five-dimension conversation-test: separated caller and agent channels are what the Conversation (turn-taking) and Speech (timing) dimensions read, and the same file drops into hotato test run beside a transcript and trace for the Outcome and Policy checks.

StackAutomatic pullSeparate channelsContract-grade defaultNetwork use
VapiYes: capture fetches by call idYes, out of the boxYesOne call: fetch the recording
TwilioYes: capture fetches by recording SIDNo by default: must request RecordingChannels=dual at creationNo, opt-inOne call: fetch the recording
RetellYes: capture fetches by call idYes, once call recording is turned onOpt-in: enable recording firstOne call: fetch the recording
LiveKitNo: egress runs in your own infraYes, if egress records both tracksOpt-in: configure egress for two tracksNone from Hotato
PipecatNo: the setup recorder runs in your pipelineYes, the scaffold writes caller ch0 / agent ch1Yes, once the recorder is addedNone: local recorder, no network call

Automatic pull: does hotato capture fetch it for you. Separate channels: is caller/agent separation what you get. Contract-grade default: is that separation on without extra setup. Network use: what capture calls out to, not your infrastructure.

The two-channel requirement

Per-channel energy: separation reveals who talked over whom.

  • channel 0 = caller, channel 1 = agent (override: --caller-channel / --agent-channel).
  • Dual-channel / stereo / separate-track recording: Vapi ships it by default; Twilio and LiveKit need it requested at record time; Retell and Pipecat need the recorder turned on. Exact status per stack in the table above.
  • Mono-mixed sums both into one waveform: overlap cannot be attributed. hotato run rejects it by default. Two opt-in flags score it anyway, indicative only, never equivalent to dual-channel: --allow-mono on capture/pull, and --diarize on run (separates the mix via speaker diarization, confidence-gated, refuses below the bar).
caller (ch 0) agent (ch 1) separated: run or capture scores every overlap vs. mono mix (summed) no owner for the overlap: run rejects mono by default --allow-mono or --diarize can score it, indicative only
Diagram of the input format, not scored data. Two channels, or two aligned mono files: every overlap is attributable; run or capture scores it fully. One mixed mono file: the scorer can’t tell who was talking, so run rejects it by default; --allow-mono (on capture/pull) or --diarize (on run) is the only way in, at reduced confidence.

Three ways in

A. Let Hotato pull one recording

Vapi, Twilio, Retell: capture auto-pulls the recording (the only network call) and scores offline: Vapi · Twilio · Retell.

LiveKit and Pipecat: setup prints a recording scaffold; record in your own infra, then score the file. Scoring many calls? hotato analyze ranks every WAV in a local folder, the same dashboard sweep produces for a connected stack.

bash
# auto-pull a Vapi call and score it (needs VAPI_API_KEY)
uvx hotato capture --stack vapi --call-id <id>

# no key? prove the capture → score loop on a bundled call
uvx hotato capture --stack vapi --demo

B. Score a recording you already have

Have the WAV? Caller on channel 0, agent on channel 1:

bash
uvx hotato run --stereo call.wav --stack generic --expect yield

C. Connect once, pull recent calls

connect stores a stack’s credentials once, locally (~/.hotato/connections.json, mode 0600). pull bulk-fetches recent recordings by the vendor’s list endpoint; sweep pulls, then ranks them in one offline dashboard. Vapi and Twilio have a verified list endpoint; Retell needs explicit --call-id.

bash
# connect once, then see candidate turn-taking moments across recent calls
uvx hotato connect vapi --api-key <key>
uvx hotato sweep --since 7d

Five mono stacks pull too, behind --allow-mono: Bland, ElevenLabs, Synthflow, Millis, and Cartesia. One combined track, no per-party channel: capture/pull score it only in degraded mode: indicative only, no contract-grade talk-over attribution. sweep can’t rank it at all; whole-call scanning needs two channels, so pulled mono calls land in the dashboard’s skipped list, not scored.

Every adapter and its limits

What each stack gives Hotato to score. Per-adapter verification status, full detail, and endpoints: ADAPTER-STATUS.md.

StackChannelsSingle call (capture)Bulk (pull / sweep)
Vapidual, separatedauto-pull by --call-idlist endpoint, --since / --limit
Twiliodual, separatedauto-pull by --recording-sidlist endpoint, --since / --limit
Retelldual, separated (multi-channel URL)auto-pull by --call-idno list endpoint: explicit --call-id only
LiveKitdual, separatedcapture-in-your-infra (setup)not connectable: no vendor recording to list
Pipecatdual, separatedcapture-in-your-infra (setup)not connectable: no vendor recording to list
Blandmono only--allow-mono, indicative--allow-mono, list endpoint
ElevenLabsmono only--allow-mono, indicative--allow-mono, list endpoint
Synthflowmono only--allow-mono, indicative--allow-mono + --model-id, list endpoint
Millismono only--allow-mono, indicative--allow-mono, list endpoint
Cartesiatreated as mono--allow-mono, indicative--allow-mono + --agent-id, list endpoint

Per-stack guides

Vapi

Dual-channel recording → stereo WAV.

Vapi →

Twilio

RecordingChannels=dual on both legs.

Twilio →

LiveKit

Separate egress, or live adapter.

LiveKit →

Pipecat

In/out channels, or live adapter.

Pipecat →

Retell

Multichannel recording; auto-pull by call id.

Retell →
The input contract

Hotato’s scorer needs separated caller and agent tracks: one two-channel WAV or two aligned mono WAVs. If your stack only exports one mixed mono file, switch on separated recording first; each guide above shows the setting.