{
  "markdown": "<div align=\"center\">\n\n<img src=\".github/assets/hotato-banner.svg\" alt=\"hotato\" width=\"442\" style=\"max-width:100%;height:auto;\">\n\n<p>\n<a href=\"https://pypi.org/project/hotato/\"><img src=\"https://img.shields.io/pypi/v/hotato?style=flat-square&color=c23c07&label=pypi\" alt=\"PyPI version\"></a>\n<a href=\"https://pypistats.org/packages/hotato\"><img src=\"https://img.shields.io/pypi/dm/hotato?style=flat-square&color=c23c07&label=downloads\" alt=\"Downloads per month\"></a>\n<a href=\"https://pypi.org/project/hotato/\"><img src=\"https://img.shields.io/pypi/pyversions/hotato?style=flat-square&color=6f5d44\" alt=\"Python versions\"></a>\n<a href=\"https://github.com/attenlabs/hotato/actions/workflows/tests.yml\"><img src=\"https://github.com/attenlabs/hotato/actions/workflows/tests.yml/badge.svg?branch=main\" alt=\"CI status\"></a>\n<a href=\"https://github.com/attenlabs/hotato/blob/main/LICENSE\"><img src=\"https://img.shields.io/pypi/l/hotato?style=flat-square&color=6f5d44\" alt=\"MIT license\"></a></p>\n<!-- Add a stars badge (shields.io github/stars/attenlabs/hotato) here once the repo reaches ~25 stars; below that it advertises the low number. -->\n\n# hotato\n\n**Find what broke in your agent calls. Pin it and CI stays red until you fix it.**\n\n```bash\npip install hotato\nhotato check --demo             # a bundled failing call: what broke, and when\nhotato check ./call.wav         # then your own recording\nhotato vapi health              # or your last 100 Vapi calls\n```\n\nZero config. Vapi, Retell, Bland, Synthflow, Millis, or local audio.\nWorks with any recording: mono, dual-channel, or a transcript. Timing math, not a judge. Offline. Free. MIT.\n\n**[hotato.dev](https://hotato.dev)**\n\n</div>\n\n## What it finds\n\n- **Say-do gaps**: the caller interrupts to cancel (a barge-in), the agent says \"canceled\", the booking tool fires anyway. hotato takes the turn timing from the audio and the tool call from your OTel trace.\n- **Latency spikes**: the pause before a reply going from 800 ms to over 2 s.\n- **Dead air**: that pause reaching 5 s, or the line going quiet.\n- **Talk-over**: the agent starts a fresh utterance over the caller.\n\n## Quickstart\n\n### Vapi\n\n```bash\npip install hotato\nexport VAPI_API_KEY=...\nhotato vapi health --last 7d --output report.html\n```\n\nOpen `report.html`: every critical incident, timestamped, and your Voice Stability Score.\n\n### Retell\n\n```bash\nexport RETELL_API_KEY=...\nhotato retell health --call-id CALL_ID\n```\n\n`--call-id` is required and repeatable: you name the Retell calls to pull.\n`hotato bland health`, `hotato synthflow health`, and `hotato millis health`\nfollow the Vapi shape. Those stacks mix both voices onto one channel, so\nthey measure silence timing, dead air and latency gaps, each finding with\nits measured confidence; barge-in and talk-over need two channels.\n\n### Local audio\n\n```bash\nhotato autopsy ./call.wav\n```\n\nWrites a self-contained HTML report to `hotato-output/`, plus the JSON\n`pin` reads. Open the HTML in your browser.\n\n## From finding a bug to gating on it\n\n`autopsy` turns one recording into timestamped incidents. `scan` reads a\nfolder and tracks the trend. When you are ready, move a finding into CI:\n`hotato pin` turns one incident into a portable failure check, and `hotato\nprove` re-runs every stored check and fails the build rather than pass on\nevidence it cannot re-read. Every verdict carries its own evidence across\nfive dimensions: outcome, policy, conversation, speech, reliability.\n\nA pinned check re-measures its own stored recording, so it holds the build\nred on that bug and catches an edited bundle, a loosened policy, or an\nengine upgrade that scores the same bytes differently. Clearing it takes a\nfresh recording of the same moment against the current agent: `hotato drive\n<bundle>` places that call on Vapi or Twilio, and\n[`docs/RECAPTURE.md`](docs/RECAPTURE.md) is the walkthrough for every other\nstack.\n\n[Pin a bug →](docs/CI.md)\n\nFor continuous use: run `hotato vapi health` on a schedule, and open\n`hotato console --production-db evidence.db` to watch calls land live.\n\n## Wire it into CI\n\nThe exit code **is** the verdict: `0` pass, `1` fail, `2` refuse (could not tell).\n\n```yaml\n# .github/workflows/voice-qa.yml\non: [pull_request]\njobs:\n  hotato:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: attenlabs/hotato@v1.20.0\n        with:\n          contracts: contracts/\n          hotato-version: 1.20.0\n```\n\n`contracts/` holds what `pin` wrote. Full workflow: [`docs/CI.md`](docs/CI.md).\n\n## Point your agent at it\n\nPoint Claude Code, Cursor, or any coding agent at this repo: it reads\n[`AGENTS.md`](AGENTS.md) and runs the loop end to end offline, no key. Over local\nstdio the MCP server adds the scorer plus read/verify/propose tools:\n`uvx --from \"hotato[mcp]\" hotato-mcp` ([`docs/MCP.md`](docs/MCP.md)). Deploying is yours.\n\n## Nothing leaves your machine\n\nhotato runs offline, on the machine that invokes it. The core is stdlib-only\nPython: no account, no key, no network call of its own. Your traces, prompts,\nand audio stay on your disk. Scoring with a language model you host yourself\nis a separate opt-in add-on, outside that core.\n\n## Go deeper\n\nThe whole loop, command by command: [`docs/LIFECYCLE.md`](docs/LIFECYCLE.md).\nFirst touch to a CI gate: [`docs/GETTING-STARTED.md`](docs/GETTING-STARTED.md).\nFeed it what you already have: [`docs/CONNECT.md`](docs/CONNECT.md) &#183;\n[`docs/TRACE.md`](docs/TRACE.md) &#183; [`docs/SIMULATE.md`](docs/SIMULATE.md).\nWhat every verdict stands on: [`docs/EVIDENCE-CONTRACT.md`](docs/EVIDENCE-CONTRACT.md).\nNext to the hosted alternatives: [`docs/COMPARE.md`](docs/COMPARE.md).\n\nThe deep toolkit -- capture, simulation, load, benchmarking, the fix ladder,\nthe fleet control plane -- lives under `hotato lab` (`hotato lab --help`).\nThe public commands are durable. hotato lab moves faster, and every\ncommand name that worked before 1.17 still runs unchanged.\n\n## Specifications\n\n| Property | Value |\n| :-- | :-- |\n| Footprint | ~10 MiB installed, 0 runtime dependencies (stdlib-only) |\n| Reproducibility | byte-for-byte: the same recording, the same report |\n| Exit codes | `0` pass &#183; `1` fail &#183; `2` refuse |\n| Release integrity | OIDC Trusted Publishing + build-provenance attested |\n| Runtime | offline, off the production data path |\n\n<details>\n<summary><b>Verify the measurement yourself</b></summary>\n\n```bash\nPYTHONPATH=src python3 -m hotato.benchmark \\\n  --scenarios corpus/real/scenarios --audio corpus/real/audio\n```\n\nOn 13 recorded AMI Meeting Corpus clips, the median error between measured caller-onset and the human word-alignment label is **20 ms**. Provenance: [`corpus/real/README.md`](corpus/real/README.md) &#183; method: [`METHODOLOGY.md`](METHODOLOGY.md).\n\nTiming is measurable only when the two voices arrive on separate channels; a mono or mixed export is marked **NOT SCORABLE** and refused (`hotato trust --stereo call.wav`). The full four-tier evidence policy (what each verdict stands on, per input) is [`docs/EVIDENCE-CONTRACT.md`](docs/EVIDENCE-CONTRACT.md).\n\n</details>\n\n## Contribute\n\nIssues and PRs welcome: [`CONTRIBUTING.md`](CONTRIBUTING.md) &#183; [`SECURITY.md`](SECURITY.md) &#183; [`CHANGELOG`](CHANGELOG.md) &#183; [`docs/`](docs/)\n\n## License\n\nMIT ([`LICENSE`](LICENSE))\n\n<div align=\"center\"><sub>Know when to pass it on.</sub></div>\n\nmcp-name: io.github.attenlabs/hotato\n",
  "bytes": 7389,
  "sha": "f2ff91980710bdddc22cc430eb0e3aee42c9d64dff1ab645318968a9b91e6e3d",
  "repo_slug": "attenlabs/hotato",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_attenlabs_hotato_a4836b68/readme"
}