Approving unattended agent actions: your options compared

An agent that's running without anyone watching still sometimes needs a human to say yes. There are several real ways to wire that up — not just pendnt's. This page compares five of them honestly, including the two cases where you're better off not using pendnt at all.

On this page

Comparison at a glance

DIY: ntfy/Pushover + hooks Remote Control + push Pushary OpenClaw ask_user pendnt
Cost Free (ntfy) or a one-time ~$5/platform app license (Pushover); the send API is free either way Free, built into Claude Code $9.99/mo (Agent), up to $19.99–59.99/mo for more agents/seats; 3-day trial, no free tier Free, built into OpenClaw Free (Trial or 100/mo Free) or $9/mo Pro, unlimited
Server you have to run None to send; something has to receive the tap-back if you want real approve/deny, not just a one-way ping None None None beyond the OpenClaw Gateway you already run None
Works unattended (cron/SDK/headless) Yes — it's an HTTP call from a hook script, fires from anywhere No — interactive sessions only Not documented — built around a live, blocking hook in a session you started No — ask_user needs a live chat session; cron jobs get none Yes — this is the case it's built for
Durable, answer-it-later state No — nothing persists past the hook call/process that made it Session-scoped, tied to the live session Bounded — a configurable hook timeout (docs example: 120s) with an auto-fallback, not a durable store you come back to days later No Yes — 7 days (Free) / 90 days (Pro), poll or long-poll a request_id whenever
Answer channels Whatever you wire up: ntfy app (with action buttons), Pushover app (emergency-priority ack callback for a rough approximation of "waiting for an answer") Claude's mobile/web app push iOS/Android app (QR setup, no app store), Mac notch app, Slack Whatever chat surface the session is attached to Email, Telegram, outbound webhook (Slack/Discord-shaped payload), web inbox
Setup Write the hook script and the receiver yourself Built in npx @pushary/agent-hooks setup Built in MCP tool call or REST call; plugin for Claude Code, snippet for the Agent SDK, skill for OpenClaw
Self-hostable Yes — ntfy can run on your own box; Pushover can't No — Anthropic-hosted No — hosted service Yes — it's your Gateway No — hosted service (Cloudflare Workers/D1)

DIY: ntfy/Pushover + Claude Code hooks

What it is: a PreToolUse or Notification hook (see the hooks guide) that shells out to curl against ntfy or Pushover's send API. Both are genuinely free to send from: ntfy's public server takes anonymous POSTs to a topic with no account, or you self-host it; Pushover needs a one-time, roughly $5-per-platform app purchase after a 30-day trial, but the API used to send messages from your script is free within a generous per-app monthly quota.

# ntfy — a one-way ping, no answer expected
curl -d "Deploy release/1.4.0 to prod?" ntfy.sh/your-topic-here

# ntfy — an actual approve/deny button, via its action-button feature
curl -H "Actions: http, Approve, https://your-host/approve?id=42, method=POST" \
     -d "Deploy release/1.4.0 to prod?" ntfy.sh/your-topic-here

That second example is the honest nuance most comparisons skip: ntfy's action buttons can fire an HTTP request when tapped, and Pushover's emergency-priority messages support a callback URL that fires when someone acknowledges — so "DIY" isn't limited to one-way pings, it can genuinely do approve/deny. The catch is that both of those need https://your-host/approve to exist: something that receives the tap, marks the request answered, and hands that back to the still-running (or re-invoked) hook. Writing and hosting that receiver, and the correlation logic between "which request is this tap for," is the DIY glue — no one ships it for you, and nothing about it survives past whatever you built to hold it (a file, a variable, an in-memory map) once that process exits. Pushover's emergency-priority retries and callback stretch that window to hours; nothing here gets you to days.

Good fit when: a single machine, a hobby project or personal automation, and you're fine owning a small bash script and a webhook receiver in exchange for paying nobody and depending on nothing but two well-established free/cheap notification services.
Not a fit when: you want this working across more than one machine or agent without re-deriving the glue each time, need an answer to survive a process restart, or don't want to be the one who finds and fixes the bug in your own correlation logic at 3am.

Claude Code Remote Control + push

What it is: Anthropic's own answer for a Claude Code session you started yourself, from your terminal — Remote Control lets you step away and keep approving permission prompts and steering the session from your phone via push notification, free, built into Claude Code and the Claude apps with no separate account or setup.

The entire mechanism assumes a live session on the other end. A claude -p run kicked off by cron, a headless Agent SDK daemon, or any script with no interactive session open in the first place has nothing for Remote Control to attach to — there's no session for your phone to remote into. That's not a shortcoming so much as a difference in what problem it's solving: Remote Control is "let me leave my desk without losing my running session," not "let this unattended job ask someone something."

Good fit when: you're driving Claude Code interactively — you ran it, you're watching it (loosely), and you just want to step away without disconnecting.
Not a fit when: nobody started an interactive session — cron, CI, a daemon, or any agent that runs whether or not you're at a keyboard.

Pushary

What it is (as of its public docs): a control-panel product built primarily around Claude Code (it also lists Codex, Cursor, Windsurf, Gemini CLI, and other MCP-compatible agents), installed with npx @pushary/agent-hooks setup. It wires a PreToolUse hook into Claude Code's settings that intercepts matching tool calls (its docs show a matcher of Bash|Write|Edit, i.e. selective, not every tool) and routes them to a phone app (iOS/Android, no app-store install — QR-code setup), a Mac notch app, or Slack, where you can approve, deny, pick from a short list, or type a free-text reply. Pricing is $9.99/mo for the Agent plan (one agent, 5,000 notifications/month, 30-day history) after a 3-day free trial, up through $19.99/mo (Agent Pro, unlimited notifications, multiple agents) and $59.99/mo (Team, up to 10 members) — there's no free tier, only the trial.

The hook example in its own docs sets a "timeout": 120 and a fallback policy (auto-deny for Bash, auto-approve for reads, or handing control back to the terminal) for what happens if you don't answer in time — which describes a live session with a blocking wait, not a durable store you come back to hours or days later. Its documentation doesn't mention claude -p, cron, or headless/unattended usage, so it's fair to read that as undocumented rather than supported — it's built for a session where the hook can actually block and someone is expected to be near their phone.

Good fit when: you live in Claude Code interactively, want a polished native app (and Mac notch, and Slack) rather than something you assembled yourself, and the cost of a monthly subscription is worth it for that UX.
Not a fit when: the thing that needs approving is a cron job or an SDK daemon with no live session for the hook to block inside of, or the request needs to survive longer than a short blocking timeout — its own docs don't describe either case.

OpenClaw's ask_user

What it is: the built-in, free way to pause an OpenClaw turn and put a question in front of whoever's in the live chat session — no separate service, no signup, it's just part of OpenClaw. The catch, covered in full in the OpenClaw cron approvals guide: a job created with openclaw automations create ... --session isolated runs from the Gateway process in a fresh cron:<jobId> session with no chat surface attached and nobody on the other end — ask_user there has nothing to render into. That's not a bug so much as the same category error as Claude Code's -p mode having no TTY: the tool assumes an audience a scheduled run structurally doesn't have.

Good fit when: the OpenClaw session is a live chat someone's actually watching.
Not a fit when: the job runs on cron/every with an isolated session — which is exactly when you need the poll-by-id pattern the guide above walks through.

pendnt

What it is: an MCP server + REST API built specifically for the case none of the above cover — cron, SDK daemons, and any framework, not just Claude Code. See the FAQ for how it sits next to Remote Control specifically. A Trial key (curl https://api.pendnt.dev/try, no signup, 20 requests over 72 hours) or a Free account (100 approvals/notifications a month, no card) both work for real; Pro is $9/mo, unlimited, no sales call. request_approval returns a request_id immediately and lets the agent long-poll or walk away and check back later — answers and pending requests are retained 7 days on Free, 90 on Pro, which is the concrete difference from a session-scoped or short-timeout approach: an agent that crashes, redeploys, or just goes quiet for a day can still pick the same request back up by id. Answers can land by email, Telegram, an outbound webhook shaped for Slack or Discord's incoming-webhook format, or the web inbox with zero setup; see channels for the connection steps each one needs. It's a hosted, multi-tenant service (Cloudflare Workers, Durable Objects, D1) — no self-host build, see the FAQ for why.

Good fit when: the thing asking the question has no terminal and no live session — a cron'd claude -p, a headless Agent SDK daemon, a LangGraph node, a plain script — and you want an answer that's still good if it takes longer than a few minutes to arrive.
Not a fit when: see the next section.

When not to use pendnt

This page exists to be useful even if you end up choosing something else, so here's where that's the right call:

Picking one

The fork that matters most is whether the thing asking the question has a live session behind it. If yes — you're at a terminal, or in an OpenClaw chat — reach for what's built in and free first: Remote Control or ask_user. If no — cron, a daemon, CI, anything unattended — none of the free built-ins reach it, and the choice narrows to how much glue you want to own yourself (ntfy/Pushover) versus how durable and framework-agnostic you need the answer to be (pendnt), or whether the Claude-Code-specific native-app experience (Pushary) is worth a subscription for a session that's still, per its own docs, a live one.