Inspiration / The problem
A restaurant table is perishable inventory: empty at 8pm means that revenue is gone forever. Guests cancel at the last minute, and during service nobody has time to work the waitlist by phone - so freed capacity is simply lost. Cornell's restaurant revenue management research treats no-show handling as a core revenue lever, and the reminder literature (Cochrane; McLean 2016; Parikh 2010) shows interactive reminder calls outperform one-way messages. Table Rescue turns that evidence into software: an agent that confirms reservations by phone and, the moment a cancellation happens, offers the freed table to waitlist guests in priority order until someone accepts.
What it does
- Confirm: calls each upcoming reservation. The CALL-E agent identifies itself as
an automated assistant, asks keep/cancel/move, and closes every call by stating a
machine-readable
OUTCOME:token (CONFIRMED / CANCELLED / RESCHEDULED / NO_ANSWER). - Cascade: for each cancelled slot, waitlist guests are matched (consent, party size within tolerance, slot inside their availability window) and called in priority order until one ACCEPTS. The slot is marked RECOVERED.
- Writeback: reservation/waitlist files update atomically, every decision lands in
an append-only audit log, and the staff report masks phone numbers and estimates
protected revenue (
--avg-check-per-guest 25-> "Estimated revenue protected: $100").
The same pattern ships twice: a runnable Python app (apps/python/table-rescue) and a
portable Agent Skill (skills/capacity-backfill-cascade) reusable for tours, classes,
clinics-with-waitlists - any booking system where cancellations free capacity.
How we built it
CALL-E is called at runtime exactly the way the platform's own batch-runner does it:
the calle CLI owns login and the token cache, and calls go over MCP Streamable HTTP -
plan_call -> run_call -> get_call_run polled to a terminal status. Structured
results use an OUTCOME token protocol with keyword fallback and ERROR escalation
(trust-but-verify), because structured-output research shows well-formed does not mean
correct. Safety rails are fail-closed: dry-run is the default; live requires --live
plus a stop-before-dial call budget; per-record consent; idempotent run ids prevent
duplicate calls; a call-window guard; a cancel command; masked numbers everywhere; and
every call goal instructs the agent to disclose it is an automated assistant (FCC 24-17
aligns AI voices with TCPA consent rules; Google Duplex set the disclosure precedent).
Accomplishments and verification
35 automated tests (unit + Hypothesis property tests for budget/consent/duplicate invariants + end-to-end) and a 34-check edge-case battery all pass, with zero network or credentials required. Every design decision maps to a verifiable reference - listed in the README (Cornell CHR, Cochrane CD007458, McLean 2016, Parikh 2010, FCC 24-17, arXiv:2606.09395, Google Duplex 2018).
Testing instructions (judges, ~5 minutes)
git checkout feat/table-rescue-cascade
cd apps/python/table-rescue
python -m venv .venv && source .venv/Scripts/activate # .venv/bin/activate on POSIX
pip install -e ".[dev]"
cp data/reservations.sample.jsonl data/reservations.jsonl
cp data/waitlist.sample.jsonl data/waitlist.jsonl
table-rescue run --run-id smoke-1 --avg-check-per-guest 25 \
--call-window-start 00:00 --call-window-end 23:59
python -m pytest
Expected: report with Slots recovered: 1 and Estimated revenue protected: 100, then
35 tests passing. Live mode is opt-in: install the CALL-E CLI, log in, and run with
--live --max-calls 1 against a phone you control.
What's next for Table Rescue
Same-day reschedule flows, HubSpot/OpenTable-style writebacks, and a plugin variant for n8n/Dify so non-developers can run capacity recovery from their existing tools.
Where the data comes from
The JSONL files are the integration boundary, not a product UI: restaurants keep their
waitlist and reservations wherever they live today - a booking platform (OpenTable,
Resy), the POS, or a shared sheet - and any export or API poll that maps those records
into the documented schema (see the skill's io-schemas.md) feeds the cascade. The
consent flag is captured by staff when a guest joins the waitlist; guests without
consent are skipped and audited. Native connectors (booking-platform writebacks,
n8n/Dify plugins) are the natural next step.
Built with
Python 3.10+, CALL-E (MCP Streamable HTTP + calle CLI auth), fastmcp, pytest, Hypothesis.
Built With
- agent-skills
- ai-agents
- automation
- call-e
- cascading-workflows
- cli
- hospitality
- hypothesis
- mcp
- open-source
- phone-calls
- pytest
- python
- restaurants
- voice-ai
Log in or sign up for Devpost to join the conversation.