Human-in-the-loop for AI agents — approve, confirm and ask are language primitives
A gate that waits for a real person — in the terminal, or queued behind one-time links when the program runs as a server — and denies when nobody is there. An agent cannot fake an approval.
Every agent framework has a human-in-the-loop story, usually a callback you wire yourself and hope every path goes through. In Synsema the gate is a statement of the language, so the runtime — not your discipline — decides where the answer can come from.
Four words§
approve "Deploy to production?" -- yes/no gate
confirm "Send this email to 500 customers?" -- confirmation
let env be ask "Which environment?" with ["staging", "prod"]
show plan as "What the agent is about to do" -- preview for the human
let ok be approve "Refund " + text(amount) + " to " + customer + "?" within 1h
when not ok
give nothing
within bounds the wait (s, m, h, d). On expiry the gate returns false and says so once. It never hangs forever.
Where the answer comes from§
- A terminal. The prompt appears and the program waits for
y/n. - No terminal — a pipe, CI, an agent driving the program: the gate denies instantly, with a
notice that tells an AI agent a human must approve. There is no environment variable that auto-approves.
- Under
serve. The gate is queued; the request blocks until a person answers or the deadline
denies. The console prints a one-time token and the ready-to-use command; GET /approvals lists what is pending, POST /approvals/{id} answers. With SYNSEMA_HUMAN_WEBHOOK every gate also posts to your channel with signed yes/no links you can tap from a phone.
Why a primitive and not a callback§
Because the property you want is negative: no path exists where the model's own output counts as consent. With a callback, that is true until someone forgets it. With a statement the interpreter implements, it is true by construction — the same way a fetch to an undeclared host is refused before any byte leaves.
This is how Lampson approves a scheduled task's dangerous step from your phone, and how the support-ticket agent on the home page refunds nothing without a person.
See it run: the human interaction page in the docs has every option, and try.synsema.org lets you write the gate and watch it deny you in the browser.