Inspiration

Autonomous agents are increasingly handed real credentials and left running unattended. The industry's answer to "what if it is about to do something irreversible" is usually to post a message in a channel and wait — which fails in exactly the case it exists for, the unattended 3am run where nobody is reading.

Two properties made the phone the right escalation channel. A call is the only channel that reliably interrupts a sleeping human. And it produces a recorded, timestamped, identity-asserted account of what was decided.

But two properties make most "human-in-the-loop" plumbing hollow. Asking an agent to stop is not stopping it. And an agent that can still authenticate can still act.

What it does

An unattended agent runs holding a Google OAuth credential on a lease. When the lease expires, a supervisor places one real phone call through CALL-E to the account owner, who has exactly one power: end the lease. Ending it revokes the credential at Google's authorization server, and the agent cannot mint a replacement — that requires a human sitting at a browser.

The call cannot grant anything. Hearing "continue" hands the agent nothing it did not already have. It is not a release; it is the absence of one, and the lease stands only when twelve independent conditions hold at once: the call reached a terminal state, the status is completed, the task completed, confidence is at or above the floor and not labelled low, a structured result exists at all, the decision is continue, the read-back was confirmed, a person was reached, the transcript actually contains human speech, the platform's own evidence corroborates the decision, and the caller's stated reason does not contradict their stated choice.

"Stop" needs one. So does an answering machine picking up, a structured result that disagrees with its own transcript, a result that cannot be read at all, a call that never reaches a terminal status, and the supervisor failing before it finishes evaluating.

In an approval gate, a failed call is a no-op — the pending action simply waits. Here a failed call is the loudest outcome in the system: the credential dies.

How I built it

Python, CALL-E's Developer API, and Google's OAuth 2.0 revocation endpoint. The supervisor creates a call with a frozen task script and a flat result schema, polls to terminal, re-fetches the snapshot before acting on it (webhooks are unsigned, and the docs prescribe exactly this), evaluates the twelve conditions, and either leaves the lease alone or revokes.

The proof is a forced refresh exchange against Google's token endpoint, run before and after the call. It is forced on every run because Google access tokens live about an hour while the two runs sit roughly three minutes apart — a cached token would return 200 both times and prove nothing. It queries the token endpoint and never Drive, because Drive's front end kept honouring a token I had already revoked, for an interval I could not predict.

The whole app runs against a bundled fake CALL-E server with no API key, no credits and no phone call, across sixteen scenarios. A hundred and one tests, almost all asserting a release, because the lease continuing is the rare outcome and every interesting case is one where something is wrong.

Review on the pull request found two things I had missed, and both are fixed: the CALL-E bearer key could be sent to an operator-supplied host, and the phone validator accepted seven-digit destinations. The origin is now an allowlist enforced at construction, live and preflight take no base-URL option at all, and the E.164 floor is strict.

Challenges I ran into

CALL-E screens call scripts before dialling, and it refused two of my drafts. The first described an in-progress hazard and positioned the call as the response to it. The second read a confirmation code aloud and asked the caller to repeat it, and asked whether to keep or release an access credential — which is, structurally, an OTP-phishing call. Both refusals were correct, and I rebuilt rather than rewording to slip past a safety screen. The accepted script never mentions a credential, a token, or a code; it asks one question about a background job, and revocation is the supervisor's own response. Both refusals became shipped guards, and the accepted wording is pinned by SHA-256 because the screen is undocumented and an edit surfaces only as a refusal.

I filed a bug that turned out to be my own mistake. On one call the caller answered "yes" to an awareness question and then declined to take the task on, and my schema's acknowledged field — which I had described as "yes only if the person confirmed they will handle it" — correctly came back "no". I read that as the platform contradicting its own transcript and filed it as a bug. CALL-E closed it with an explanation I could check against my own records, and they were right: evidence[] recorded that the caller acknowledged the reassignment, which is a different question from whether they would take it over, and completion_confidence describes whether the task completed rather than the accuracy of any custom field. The lesson survives the correction. A structured field means exactly what its description says, a confidence score is not a signal about any individual field, and a system acting on one field alone is trusting a sentence it wrote itself. LEASH cross-checks the decision against evidence[] and the transcript for that reason, and that design is unchanged.

A caller contradicted themselves. They said "continue" twice and confirmed it, then gave the reason "the job's done enough, take it back" — a reason that means stop. Extraction was faithful; the human was inconsistent. A system trusting the enum alone would have kept a live credential against the caller's actual intent. That call is why the twelfth condition exists.

Speech recognition misheard the decision word. The caller said "stop" and the transcript recorded "dot". The agent's read-back caught it and the confirmed choice was correct — an unstaged demonstration of why the read-back is there.

What I learned

That the interesting engineering in a voice agent is not the conversation. It is deciding what a machine is allowed to conclude from one, and being honest about the cases where it cannot conclude anything. Every unclear outcome here resolves the same way, and the direction it resolves in is the one that takes capability away.

What's next

Ending a lease is currently all-or-nothing at the project level, because Google's consent is project-wide. Per-scope narrowing rather than full revocation is the obvious next step, as is a second lease tier where a missed call narrows scope before a later one ends it.

Developed solo with AI-assisted tooling for code generation, debugging, and documentation; all design decisions, CALL-E integration, and live testing are my own original work.

Built With

Share this project:

Updates

Submission history