AI & Agents

Human-in-the-Loop Notifications: Let Your AI Agent Ping You When It Needs a Decision

Human-in-the-loop notification for AI agents: when your agent hits a risky decision, it pings your phone, you tap approve, and it keeps going.

Red and black halftone illustration: a hand hovering just above two unmarked buttons on a console, not yet pressing either (TheNotificationApp)

You kicked off an agent to clean up a database, went to lunch, and came back to find it had been sitting idle for 40 minutes. Not crashed. Not done. Just… waiting, stuck on a Delete 1,240 rows? (y/n) prompt that nobody was there to answer.

That's the quiet failure mode of autonomous agents. At every real decision point they have exactly two bad options: freeze and wait for a human who isn't watching the terminal, or barrel ahead and do the irreversible thing you would never have approved. Neither is great when the action is "drop the production table" or "spend $80 on API calls."

A human-in-the-loop notification fixes the gap without chaining you to the screen. When the agent hits a decision it shouldn't make alone, it pings your phone, you tap to approve or reject, and it picks up right where it paused. You get the autonomy of an agent and the veto power of being in the room.

The one call that asks for approval

The ping itself is a single HTTP POST. No SDK, no websocket, no polling service to run. Here it is in Python, the link field is the important part, because it's what opens when you tap the notification on your phone:

import requests

def request_approval(question, approve_url):
    requests.post(
        "https://thenotification.app/api/sendNotification",
        headers={
            "app_key": "YOUR_API_KEY",
            "Content-Type": "application/json",
        },
        json={
            "title": "Your agent needs a decision",
            "body": question,
            "link": approve_url,
        },
    )

Call it the moment your agent reaches a step it flagged as risky, and put the actual stakes in the body so you can decide from the lock screen without opening anything:

request_approval(
    "Delete 1,240 rows from the production orders table?",
    "https://your-app.dev/approve/run-42",
)

Now your phone buzzes with "Your agent needs a decision: Delete 1,240 rows from the production orders table?" and tapping it opens your approve page. That's the whole notification side of it.

Closing the loop: from ping to answer

Here's the honest bit up front: the notification is one-way. It's how the agent reaches you: it can't collect your answer on its own. So you need somewhere for your tap to land. In practice that's a tiny endpoint the approve link hits, and an agent that waits for it to flip:

import time

def wait_for_approval(question, approve_url, is_approved):
    request_approval(question, approve_url)
    while is_approved() is None:   # None = still waiting
        time.sleep(5)
    return is_approved()           # True = approved, False = rejected

is_approved() is whatever you already have handy: a row in your database, a value in Redis, even a file on disk that your approve/reject page writes to. Wiring it into an agent step looks like this:

if action.is_destructive:
    if not wait_for_approval(
        f"Run: {action.describe()}?",
        f"https://your-app.dev/approve/{action.id}",
        lambda: check_decision(action.id),
    ):
        print("Rejected by human. Skipping.")
        return

run(action)

The agent now blocks on exactly the steps you told it to, and only those. Everything else runs at full speed. You're the tiebreaker, not the bottleneck.

Not writing Python? One line of curl

Plenty of agents are really a Bash deploy script wearing a trench coat. Same gate, one curl call: slot it right before the line that pushes to prod, and the deploy waits for your thumb:

curl -X POST https://thenotification.app/api/sendNotification \
  -H "app_key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Your agent needs a decision",
    "body": "Deploy build 217 to production?",
    "link": "https://your-app.dev/approve/deploy-217"
  }'

Every field is documented in the API reference: there are only four, and two of them are optional.

What to actually gate

The trick isn't sending approval requests. It's sending few enough that you still read them. A notification on every step trains you to swipe them away without looking, which defeats the point. Good candidates to gate:

  • Anything destructive: deletes, drops, force-pushes, prod migrations
  • Anything that spends money: a large batch of paid API calls, a cloud resource spin-up
  • A genuine fork in the road: two valid plans and the agent honestly can't pick

Everything reversible and cheap should just run. Save the buzz for the choices you'd actually want a say in.

The real talk: watch your notification count

Fair warning on the numbers. The free tier is 100 notifications total, not per month, total, which is plenty to try this out on one agent but not something to wire into a chatty loop. Pro is $2.99/month for 1,000 notifications a month. If you gate carefully (destructive and expensive actions only), a single agent will send a handful of approval pings a day and you'll stay well inside either tier. If you ping on every step, you'll blow through the free 100 in an afternoon. Gate first, then scale up.

Wire it up once

You already ping your phone when an agent run finishes. Approval-on-pause is the same one-line POST, moved earlier, from "it's done" to "should I?" Add it to the two or three steps you'd lose sleep over, and let the agent handle the rest.

It's genuinely handy the first time an agent pauses instead of nuking something at 2 a.m. Worth a look if you're tired of choosing between an agent that freezes and one that goes rogue.

New to this? Start with what an MCP server is.