-
-
05:12, someone calls in sick. Ten people on the standby list, one slot to fill.
-
The four capabilities the agent was never given - each with its own reason, on the front page.
-
Every outcome opens the real call behind it - the goal the agent was given, and what was said.
-
One call in flight, ever. Ringing all twenty at once is how four people turn up for one shift.
-
The fifth call says yes. The cascade stops, and four people below the line are never rung.
-
When nobody can take it, it says so and stops. No looping, no widening the list, nobody twice.
Inspiration
05:40. A care home is one nurse short. A supervisor picks up the phone and works down a list of twenty casual staff, one at a time, until somebody says yes.
It has to be one at a time. Ring all twenty and four of them say yes, and now somebody has to un-invite three people who already got out of bed - worse for them than never being called, and the fastest way to empty a standby list. It is time-critical, it happens before dawn, and there is no email substitute: whoever is asleep at 05:40 is not reading email, but they will answer a ringing phone.
That is a cascade, not a campaign. It is why a human still does this by hand.
What it does
One trigger - a gap in the roster - and the agent works the standby list in the order the employer gave it, one call in flight, stopping the moment somebody accepts.
The parts that are not a loop, each asserted in the test suite: one call in flight ever (a second concurrent call raises an error); stop on the first accept, with everyone still queued explicitly stood down and recorded; a no-answer gets one retry at the end of the list, never an immediate redial, and nobody is rung a third time; a callback is honoured once, at the time the callee named; quiet hours are respected and overridden only when the shift starts within ninety minutes; and a yes that arrives after the shift started is reported as a shortfall in minutes rather than shown as a clean fill.
How we built it
The cascade is a pure state machine in server/cascade.js - no I/O, no clock, no network. It is a reducer: hand it a state and an event, get the next state, and a separate query says what to do next. Every decision is a pure function of state and clock, so the interesting behaviour is provable in milliseconds without spending one of twenty free calls. The runner holds no rules at all; it asks the cascade and does what it is told, which is why the behaviour in the tests is the behaviour in production. The event log IS the state - replay the events into a fresh cascade and you get the same summary, including how it ended.
The phone sits behind one interface with two backings. CALLE_LIVE=1 drives the real CALL-E CLI, which owns the OAuth token and the MCP session so the app never touches a credential. Without it, the same code path replays recorded responses.
Zero npm dependencies, on purpose. npm install on a stranger's machine is the step where a judge gives up, so there is nothing to install.
Fixture mode, and why it is the point
A judge cannot reproduce a phone call.
Most entries built on a calling API ship a repo that only works if the reviewer signs up, gets a number, and spends their own free calls - so most reviewers read the README and watch the video. Standby replays four REAL CALL-E calls, placed to a consenting number and frozen verbatim into the repo: a yes with an arrival time, a refusal, a request to be rung back in twenty minutes, and one that reached voicemail. Real German transcripts, real timings. npm start and the whole cascade runs offline in thirty seconds.
The fixtures are captures rather than hand-written fiction, so if CALL-E ever changes shape, fixture mode breaks loudly instead of quietly flattering us. Six of the assertions run directly against those recordings.
Challenges we ran into
The documentation describes a response CALL-E does not send. There is no structured decision field and no result-schema parameter on plan_call - the tool list was checked. What actually comes back is result.summary and result.outcome.evidence in ENGLISH whatever language the call was in, plus the transcript in the call's own language. The classifier was rewritten against four real recordings rather than against the docs.
Voicemail reports itself as success. A call that reached an answering machine returns status COMPLETED with call status finished, because a message was delivered. Read only the status and you fill the shift with an answering machine. It is a no-answer.
Reading the answer is deliberately lopsided. Anything that is not a clear yes is not a yes. A false acceptance ends the cascade and leaves the shift unfilled with everyone else already stood down; a false refusal costs one more call. The trap worth naming: "Sorry, I can't take it today" contains the word "can", so refusal markers are tested before agreement markers, and an unreadable call is recorded as a decline AND flagged unparsed - so "they said no" and "we could not tell" stay distinguishable in the log.
Spawning the CLI on Windows. shell: true concatenates argv instead of escaping it, so a call goal - which always has spaces - arrives as thirty separate arguments. shell: false then fails outright, because Node 24 refuses to spawn a .cmd. Running the package's own entry point under node avoids both.
What we learned
Build the rules where they can be proved. Every claim this submission makes about the cascade is asserted against a state machine with no phone, no network and no account, which meant the twenty free calls went to capturing real conversations instead of debugging a loop.
And record the real thing early. The four recordings did not just make the demo honest - they immediately falsified the response shape the code had been written against.
What's next
Unify the roster source with a real scheduling system, persist the audit trail beyond the process, and add a second stopping condition for shifts that need two people rather than one.
Try it
No CALL-E account, nothing to install: npm start. Same code path against real calls: CALLE_LIVE=1 npm start. The rules, as tests: npm test - 46 assertions in two seconds.
Built With
- agent-skill
- call-e
- javascript
- mcp
- node.js
- playwright
- server-sent-events
- state-machine
- voice-agent
- zero-dependencies
Log in or sign up for Devpost to join the conversation.