AI Receptionist & Booking Platform
Production · live since Oct 2026 · client engagement, sole engineer
Summary
In 30 days (470 commits, 52 documented build rounds) a small service business went from missed calls to a system that answers every call, collects the caller’s details, books within the business’s rules, confirms by text, and falls back to voicemail if anything fails. It runs a local language model for intent classification, uses cloud speech only where local speech proved inadequate, caps spending, monitors itself, and ships through a gated release process with a documented rollback floor.
The problem and who it serves
A sole-operator service business was losing jobs to unanswered calls and had no online booking. It needed a receptionist that answers at any hour, books only inside the business’s rules, never promises what it cannot deliver, and stays inside a fixed budget.
The business owner (who receives bookings and alerts), their customers (callers and web visitors), and the staff dashboard user. The client is unnamed here pending consent for public use.
My role
Sole engineer for the client. I wrote ten dated specification documents before and during the build that set requirements, architecture constraints, the rules of evidence, and acceptance criteria; I reviewed code and call transcripts, ran every real-phone test session, performed every provider-console action, approved every deploy, and made the go-live decision. Implementation was AI-assisted (Claude Code) under that direction: most line-by-line code was generated to my specification and reviewed by me. The client supplied business facts and tested on their own phone.
Architecture
Three application processes plus a resident model server, all running under least-privilege accounts and reachable only through a secure ingress. Node 24 runs TypeScript natively with no build step and seven runtime dependencies. The model never produces customer-facing text or a business fact: it classifies intent against a closed label list, and deterministic code does the rest.
Decisions and trade-offs
- Resident model, not process-per-utterance. Spawning the model per utterance cost ~4,000 ms; a resident server with grammar-constrained output answered in ~330 ms in my first measurement (2026-09-19, smaller model, 8 threads). A later benchmark of the production configuration (2026-10-16, 43 test phrases, not live calls) gave a 470 ms median. A daemon-based alternative was later measured and rejected: 4 of 43 intents differed, 30% slower, 4–5× memory.
- Cloud speech only, everything else local. The first real call exposed a ~3 s per-turn CPU floor and ~50% recognition accuracy for non-native speech on the local stack. Cloud recognition and voice were approved under a budget, with a local admission guard that reserves worst-case cost before admitting a call. Conversation logic, booking and classification stayed local.
- Scheduling enforced in the database. PostgreSQL exclusion constraints prevent overlapping appointments regardless of application bugs; raw SQL because ORMs cannot express them. A deadlock convoy under a 12-way burst was fixed with a per-day advisory lock taken before any row lock.
- Signed binaries only on the call path. A host application-control policy blocked an unsigned inference binary (~2 h pre-launch outage, calls fell back to voicemail). Weakening the policy was rejected; a signed build was adopted and verified for zero output differences across 43 intents, 10 extractions and 6 scripted calls.
- No prompt patches without a controlled evaluation. Tuned phrases scored 17/17 while an untouched held-out set scored 7/18, so fixes were made deterministically and a separate acceptance set is kept.
- Spend as three never-mixed figures. Locally metered, provider aggregate, and settled per-item. After a false alert caused by summing nested provider categories (~2.4× over-count), a standing rule: no computed money figure can alert anyone until it matches the provider’s own total.
Security and reliability
- Security review by three isolated reviewers plus manual host and account checks: 15 findings (3 high, 5 medium, 6 low, 1 informational). All high and medium findings were fixed or mitigated (one high-severity item by mitigation rather than a fix) and verified live; one low item open and documented. Regression tests cover the fixes.
- Rate limiting behind a reverse proxy initially treated every visitor as one client; fixed by using the forwarded client address only from the trusted proxy, with forged headers verified rejected.
- Restart-safe call state: a mid-call process restart recovers in-flight state and callbacks (migration 039, replay test).
- Deploy gate: clean tree → typecheck → full suite with zero failures → migrations twice on an empty database → SHA-256 release manifest → on-host re-validation → health and booking checks. Every promote keeps the previous release as a rollback archive and refuses a downgrade without an explicit flag.
- Voicemail-only hosted fallback; a test scans the source for any dial verb so no call transfer can exist.
Verified results
| Measure | Result | Evidence |
|---|---|---|
| Status | Live since 2026-10-18; release 05c7664 on 2026-10-19 | Launch record, steps 0–6 each with evidence |
| Tests at last release gate | 1,845 passed, 0 failed; 142 test files | Gate log, 2026-10-19 (real PostgreSQL test database, pinned clock) |
| Process-per-utterance vs resident model | ~4,000 ms → ~330 ms per classification (764 ms on the first call); smaller 4-bit model, 8 threads, on the production host | My measurement, recorded in a source-code header comment, 2026-09-19; not re-run |
| Benchmark of the production configuration | Median 470 ms, p90 583 ms server-side classification time (latest of three runs: medians 466–477 ms, p90 582–595 ms) over 43 test phrases (not live calls); larger 8-bit model, 6 threads; first classification after a load 4.6 s (at startup and after a restart, never on a caller's turn) | Round record, 2026-10-16 |
| Caller-perceived end-to-end latency | Not measured; tester-call records show model turns of 0.9–2.9 s per turn | Round record, 2026-10-15 |
| Security review | 15 findings; 3 high + 5 medium fixed or mitigated, 1 low open | docs/SECURITY-REVIEW-2026-10-18 |
| Incidents resolved | 10, each with a fix commit and, where applicable, a regression test | Round documents and commit history |
| Production use | Early production use; business outcomes have not yet been established | Stated so this page never implies volume or results |
| Uptime | Not measured over a defined window | One ~2 h pre-launch outage recorded; monitoring drills passed |
Limitations and remaining work
- This is early production use: business outcomes have not yet been established and there is no uptime figure yet; a 90-day availability and booking record is the next piece of evidence worth collecting.
- One low-severity security finding remains open and is documented in the project’s records.
- Phone name recognition is weak for some names; accent robustness is proven only on tester calls.