Your phone line is your front door.

Websites got uptime monitoring twenty years ago. Phone lines never did. When an IVR menu or an AI receptionist breaks quietly, nothing throws an error — the line still answers, the menu is still navigable, and every dashboard you own stays green. Callers just hesitate, mis-route, or give up, and you hear about it weeks later, if at all. What exists today is enterprise call-assurance for large contact centers, or simulators that test a voice agent from the inside before it ships. Nobody watches one small business's real line, over the real phone network, every day.

What LineCanary does

It places scheduled CALL-E calls to lines you own, walks the caller journey like a customer, and asserts what it hears.

  • Checks are code. linecanary.config.json lives in your repo: which lines, what the test caller should do, what the structured result must look like, how fast the line must answer.
  • Ownership is a gate, not a footnote. It refuses to dial until you prove you control the line — a short code in your own greeting plus linecanary verify, or a written attestation for client lines. Every call opens with an AI disclosure, and only inside the callWindow you configure.
  • Assert, baseline, diff. Deterministic assertions on a schema-validated result, timing bounds from transcript offsets, confidence floors — then regression detection against that line's own history: new failures, regressed assertions, answer-time blowouts, recoveries.
  • Alerts with substance. Console plus exit codes for CI, Slack for humans. Every alert names the check, the assertion and the delta, and never a full phone number.
  • Start from a call, not a blank config. linecanary discover <line> --live places one mapping call and drafts your checks for you.
  • See it and share it. An operator dashboard with health, answer-time trends and the full timed transcript of every call; plus a client-safe status page per line — uptime only, no transcripts, no numbers.

What it actually caught

On 2026-08-08 the canary called the monitored line and heard "For opponents, press one" where the script says "appointments." The menu was still navigable, so nothing errored, nothing alerted, and no dashboard anywhere would have gone red. LineCanary failed the assertion menu_options contains "appointments" and kept the timed transcript: the substitution at 14s, then "We did not receive a selection" at 24s. That is the class of failure that is only visible from outside, by listening.

Earlier, on 2026-08-03, I broke the billing branch on purpose, the way a bad deploy would. Four consecutive real calls went pass, fail, fail, pass: caught on the next run as a new failure, paged while it stayed broken, closed with a recovery notice once fixed — each one diffed against that line's own baseline rather than a global threshold.

How it's built

TypeScript on Node 22, no framework, two runtime dependencies: @call-e/calle for calls and the Anthropic SDK for the optional explain incident note, loaded lazily and never touched unless you ask for it. 147 tests drive the real SDK against a local fake CALL-E server; npm run demo replays the whole loop with zero network. Dry-run is the default, and a live run where every check is unverified exits 1: fail-closed. The host owns recurrence — cron or GitHub Actions — with no internal scheduler and no self-retry, so one invocation is at most one call per check, idempotency-keyed. Transcripts are treated as data and never as instructions (docs/threat-model.md), and ownership is enforced in the runner, not just documented (docs/compliance.md). The same checks ship as a composite GitHub Action, so "did this deploy break the phone?" becomes a CI gate.

Built on CALL-E, and merged into the CALL-E ecosystem: PR #102 to CALLE-AI/awesome-phone-call-agents, 61 files, merged 2026-08-17.

Built With

Share this project:

Updates

Submission history