Human-in-the-loop for Hermes

Human-in-the-loop for Hermes agents, on a phone.

Put one call inside your risky Hermes tool, and it waits until your user approves on their phone.

What Hermes gives you

Dangerous-command approval and pre_tool_call

Hermes already spots dangerous commands and asks before running them: allow once, allow for the session, always allow, or deny. By default that question waits at the terminal. Plugins can also register a pre_tool_call hook that runs before any tool.

Where it stops

  • The built-in approval asks the person running Hermes, not the user the action affects.
  • Hermes gives up on a pre_tool_call hook after 30 seconds by default, and blocks the call.
  • Gateway mode runs many users through one agent, and a session id names a conversation, not a person.

The fix

Pushary gets your user's answer.

A Hermes tool handler is a plain Python function. One decisions.ask() call inside it puts the question on your user's phone, waits for Approve or Deny, and saves the answer.

The plugin registers an ask_human tool whose handler calls decisions.ask(). The question goes to your user's phone and the handler waits for the answer, 55 seconds by default. Anything short of an explicit yes comes back as not approved.

bash
pip install pushary
two calls
import os
from pushary import PusharyServer

px = PusharyServer(api_key=os.environ["PUSHARY_API_KEY"])

def ask_human(params, **kwargs):
    d = px.decisions.ask(
        question=params["question"],
        external_id=current_user_id(),  # your own user id, never the model's
        type="confirm",
    )
    return "approved" if d["approved"] else f"not approved ({d['status']})"

def register(ctx):
    ctx.register_tool(
        name="ask_human",
        toolset="approvals",
        schema={"type": "object", "properties": {
            "question": {"type": "string"},
        }, "required": ["question"]},
        handler=ask_human,
        description="Ask a real person to approve before acting.",
    )

Or install the Pushary plugin from the Hermes catalog

The Pushary plugin is in the Hermes Agent plugin catalog, so Hermes installs the release Nous reviewed. It routes Hermes' own dangerous-command approvals to your phone, adds pushary_ask and pushary_notify, and on the Partner plan pushary_ask_end_user asks one of your own users. Set your API key once, and do not run a second installer over the catalog copy.

catalog install
hermes plugins install pushary
export PUSHARY_API_KEY="pk_xxx.xxx"

# ~/.hermes/config.yaml
security:
  approval:
    transport: pushary

How it works

From install to the first answer

Connect your user once. Put the approval on the risky step. Pushary sends the question, waits for the answer and saves it.

  1. 01

    Install the Python SDK

    Hermes runs in its own virtualenv, so run pip install pushary with that interpreter. Set PUSHARY_API_KEY.

  2. 02

    Connect your user once

    One SDK call per user returns a connect link. Your user opens it on their phone with the free Pushary app. No account, no payment.

  3. 03

    Register an ask_human tool

    In your plugin's register(ctx), call ctx.register_tool with a handler that calls px.decisions.ask(). Take the user id from your own user model, never from the model's arguments.

  4. 04

    Act on the answer

    Return not approved for anything short of an explicit yes. A no, an expired request or no answer means the agent does not act.

A question can be a yes or no, a choice from a list, or a typed answer. Every answer is saved.

Before you ship

Things that bite on Hermes

A session is not a person
Gateway mode runs many users through one agent. A session id names a conversation, and it drifts from the person as soon as someone opens a second tab or comes back tomorrow. Key every approval on your own user id, so it stays tied to the person accountable for the action.
Hook gates get 30 seconds
If you ask from a pre_tool_call hook instead of a tool, Hermes abandons the hook after plugins.hook_callback_timeout, 30 seconds by default, and blocks the call. Keep the wait inside that budget, or raise the setting.
A tool the model can skip is not a gate
ask_human is a tool the model chooses to call, so it is optional. A prompt that says “ask first” does not stop a refund. Call decisions.ask() inside the refund tool's own handler, and run the refund only when approved is true.

The Partner plan

Your agent asks your users, not just you

Ship your agent to your users. Each of them approves its risky actions from their phone, under your brand.

$99/ month, every framework included
Start free

Your users never make a Pushary account or pay us.

Your users answer on their own phones

Connect each user once with a link. They install the free Pushary app and answer from the lock screen, with no account of their own.

No answer means no

Run the action only after an explicit Approve. A request that is still waiting, expired or cancelled never counts as a yes. Pushary keeps every request, so your code can pick it up again after a restart.

Reaches them on their phone

The app comes first, because only the app puts Approve and Deny on the lock screen. Browser notifications come next. You build no delivery system.

Every answer saved

Every answer is saved with who answered and when. You can search and export it, and with a callback URL, each answer is also sent to your server as a signed webhook.

FAQ

Questions, answered

Is there a Hermes-specific Pushary package?
Yes. hermes-plugin-pushary on PyPI sends Hermes' own dangerous-command approvals to your phone, and on the Partner plan adds tools that connect and ask your own users. For full control over which person answers which action, register your own tool with pip install pushary, as shown above.
How does the agent wait for the answer?
decisions.ask() holds the tool handler open until your user answers or the wait ends, 55 seconds by default. Hermes keeps the tool call open meanwhile, so the agent carries on with your user's answer. Pushary keeps the request after that, so a late answer is still saved.
Can each end-user get approvals on their own phone?
Yes. Pass each user's own id from your user model. In gateway mode, do not reuse the Hermes session id for this, because a session names a conversation, not the person accountable for the action.
What does the agent see on a decline or a timeout?
The handler returns not approved with the status, so the model knows the action was refused rather than skipped, and the answer is saved. Telling the two apart matters: a refusal is information the model should act on, and a timeout usually means asking someone else.
Can one Hermes deployment serve approvals for many customers?
Yes. Gateway mode plus your own user id on each call does it. One agent process serves everyone, and each decisions.ask() reaches the person whose data or money the action touches. They connect with a link and the free Pushary app, with no account, and the decision page shows your name and logo.

Let your Hermes agent ask before it acts.

Connect a user once, ask with one call, and run the action only on a yes. Every answer is saved.

Start free

Partner plan, $99 a month. Your users never make a Pushary account or pay us.