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.
pip install pusharyimport 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.
hermes plugins install pushary
export PUSHARY_API_KEY="pk_xxx.xxx"
# ~/.hermes/config.yaml
security:
approval:
transport: pusharyHow 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.
- 01
Install the Python SDK
Hermes runs in its own virtualenv, so run pip install pushary with that interpreter. Set PUSHARY_API_KEY.
- 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.
- 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.
- 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.
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?
How does the agent wait for the answer?
Can each end-user get approvals on their own phone?
What does the agent see on a decline or a timeout?
Can one Hermes deployment serve approvals for many customers?
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 freePartner plan, $99 a month. Your users never make a Pushary account or pay us.