Skip to main content

ntfy-approval

❖ Communityv1.0.1★ 0

Answer Hermes' approval prompts from your phone: once selected with security.approval.transport: ntfy, each dangerous-command prompt arrives as an ntfy push notification with Approve once, Approve for session and Deny buttons, and no answer still means deny.

Open in Hermes Desktop
hermes plugins install ntfy-approval

What it adds

Hooks 1

post_approval_response

README

From the reviewed commit 95d3a4b ↗; it updates when the author re-pins.

ntfy-approval

Answer Hermes' approval prompts from your phone.

When Hermes wants to run a command it flags as dangerous, it normally stops and waits for you at the terminal or in the chat. With this plugin the question goes to your phone as an ntfy push notification instead:

⚠️ Hermes needs your approval
git force push (rewrites remote history)

git push --force origin main

Answer within 5 min. No answer means deny.
[ Approve once ] [ Approve for session ] [ Deny ]

Tap a button and Hermes continues (or stops) right away. Nothing listens on your machine: the button makes your phone post a one-time answer back to ntfy, and Hermes reads it from there.

It uses Hermes' approval transport interface, so Hermes still decides what needs approval, redacts secrets before anything leaves the machine, checks every answer against the request, and treats silence as a no.

Setup

  1. Install the plugin:

    hermes plugins install AhmetArif0/hermes-ntfy-approval#ntfy-approval --enable
    
  2. Get a private topic name and the next steps:

    hermes ntfy-approval setup
    
  3. Install the ntfy app (Android, iOS) and subscribe to the printed topic.

  4. Save the topic for Hermes (it goes to your profile's .env):

    hermes config set NTFY_APPROVAL_TOPIC hermes-…
    
  5. Check that a tap reaches Hermes. This sends a sample request; nothing runs:

    hermes ntfy-approval test
    
  6. Send Hermes' approval prompts to your phone:

    hermes config set security.approval.transport ntfy
    

To go back to terminal and chat prompts: hermes config set security.approval.transport builtin.

What you get

  • Approve once: this command runs, nothing is remembered.
  • Approve for session: Hermes stops asking about this kind of command in this session. Only shown when Hermes offers it for the request.
  • Deny: Hermes blocks the command and tells the agent not to try another way.
  • No answer before approvals.timeout (default 300 s): denied. The notification is then removed from your devices, and a late tap does nothing.
  • You stop the turn (/stop, Ctrl-C) while it waits: denied, and the notification is removed right away.

"Always allow" is never offered from the phone: an ntfy notification has room for three buttons, and permanently allowlisting a command from a lock screen is a step better taken at the keyboard.

Where it applies: interactive sessions, which are the CLI, TUI, Desktop, and messaging-gateway chats. Once selected, the phone replaces the terminal prompt and the chat buttons. Cron jobs, hermes chat -q and webhook/API sessions never ask a human, so the phone is not used there; they follow approvals.cron_mode, approvals.single_query_mode and approvals.unattended_mode.

If ntfy can't be reached, the request is denied. To fall back to the normal prompt instead, set security.approval.transport_fallback: builtin.

Settings

Setting Where Default
Topic NTFY_APPROVAL_TOPIC in .env none Required. Treat it like a password (see below).
Access token NTFY_APPROVAL_TOKEN in .env none For servers with access control.
server plugins.entries.ntfy-approval.settings https://ntfy.sh The server your phone subscribes on.
priority same high min, low, default, high or urgent.
send_command same true false sends only Hermes' reason for asking, not the command.

The Desktop app shows these on the plugin's settings page. Without a token the topic must be at least 16 characters; setup makes a 39-character random one.

Self-hosting with access control

On your own ntfy server you can keep requests private and still let the phone's button post its answer. The button sends no credentials, so the reply topic (your topic plus -reply) must accept anonymous writes. Nobody can read it, and it only accepts one-time answer codes:

ntfy user add hermes
ntfy access hermes hermes-approvals rw
ntfy access hermes hermes-approvals-reply rw
ntfy access everyone hermes-approvals-reply write-only
ntfy token add hermes          # → NTFY_APPROVAL_TOKEN

Log in on the phone app with a user that can read hermes-approvals, then:

hermes config set plugins.entries.ntfy-approval.settings.server https://ntfy.example.com
hermes config set NTFY_APPROVAL_TOKEN tk_…
hermes config set NTFY_APPROVAL_TOPIC hermes-approvals

Security and footprint

  • register() only registers: the ntfy approval transport, the hermes ntfy-approval command, and one observer hook, post_approval_response, which only withdraws a notification Hermes has stopped waiting for. The transport stays inactive until you select it (security.approval.transport: ntfy).
  • Network: only to the configured ntfy server, and only while an approval is pending. The plugin publishes one notification, reads the reply topic until an answer, the timeout, or Hermes stops waiting, and then deletes the notification. Redirects are not followed, and the access token is never put inside a notification.
  • What leaves your machine: the notification title, Hermes' reason for asking, the command as Hermes redacted it (skip it with send_command: false), and three one-time answer codes. On ntfy.sh this passes through a public service. Use your own server if that matters to you.
  • Who can answer: anyone who can read the topic, because the answer codes are in the notification. On ntfy.sh the topic name is the secret, so keep it private. With access control, only users with read access can answer. Each code works once, only for its own request and button; anything else on the reply topic is ignored. Hermes separately rejects an answer that does not match the request or is not a choice it offered.
  • No subprocesses, downloads, file writes, config changes or background threads. It reads the topic and token from your profile's .env, through Hermes' profile secret scope.
  • Profiles: each profile has its own settings and topic. On a gateway that serves several profiles from one process, Hermes currently calls approval transports without the profile's context (hermes-agent #114580). The plugin detects this and denies the request rather than use another profile's topic.

Design notes and verified facts: DESIGN.md.

Changelog

1.0.1

Stopping a turn (/stop, Ctrl-C) while an approval was on your phone left its buttons there until approvals.timeout ran out (5 minutes by default), and for good if Hermes exited in the meantime. Hermes had already denied the request, so a tap did nothing. The notification is now removed as soon as Hermes stops waiting.

1.0.0

First release: approvals from ntfy with Approve once, Approve for session and Deny buttons; hermes ntfy-approval setup and test.

License

MIT

cloudflare-workers-ai-provider❖ Community★ 0

Cloudflare Workers AI as a Hermes model provider (`--provider workers-ai`, or Cloudflare Workers AI in `hermes model`, which asks for the token and the account's base URL): the 16 Workers AI models with function calling and 64K+ context, Cloudflare's context windows (a custom endpoint lists no models and assumes 256K for the 128K gpt-oss), reasoning effort in the form each model accepts, and a clear message when a free-plan account picks a paid-plan model. Not affiliated with Cloudflare. Disclosure — registers one model provider at import and nothing else (no tools, hooks, commands or threads); the model list and details are built in, so nothing is fetched to show them; chat requests go to the URL in CLOUDFLARE_WORKERS_AI_BASE_URL through Hermes' own client with CLOUDFLARE_WORKERS_AI_API_TOKEN, both read by Hermes per profile; the plugin itself opens no connections, reads and writes no files and starts no processes.

Models
groq-provider❖ Community★ 0

Groq as a Hermes model provider (`--provider groq`, or Groq in `hermes model`): reasoning effort is sent in the form each Groq model accepts, so gpt-oss-120b and gpt-oss-20b work (through a custom endpoint, Hermes 0.21.5 sends them a value Groq rejects with HTTP 400), and the model list leaves out Groq's speech-to-text, text-to-speech, prompt-guard and 4K-context models that Hermes cannot run. Not affiliated with Groq. Disclosure — registers one model provider at import and nothing else (no tools, hooks, commands or threads); chat requests and the model list go to https://api.groq.com/openai/v1 (or the configured model.base_url) through Hermes' own client with GROQ_API_KEY, which Hermes reads; the plugin itself opens no connections, reads and writes no files and starts no processes.

Models
memory-rewind❖ Community★ 0

Automatic version history for the built-in memory (MEMORY.md, USER.md), SOUL.md and skills/ (including curator-archived skills): browse, diff and restore any past version with `hermes memory-rewind`, or view it from any chat with the read-only `/memory-history`. Works alongside the built-in memory; not a memory provider. Disclosure — runs the local git binary (isolated from the user's git config, hooks and signing) to keep a bare repository in $HERMES_HOME/plugin-data/memory-rewind/; reads only the tracked files (never .env, auth.json, databases or skills/.hub/); rewrites tracked files only when the user runs `restore`; no network.

General
reaction-feedback❖ Community★ 0

Lets the agent see the emoji reactions you leave on its Telegram messages: react 👍 or 👎 to a reply and the agent's next turn in that private chat starts with a short note naming the reaction and the message it followed. Disclosure — registers pre_gateway_dispatch (always returns None, so dispatch is never changed), pre_llm_call and gateway_platform_event hooks; keeps a bounded in-memory record of private-chat message ids, 60-character excerpts and reactions; writes nothing to disk, makes no network requests, starts no processes and reads no secrets.

General

← Back to the catalog · catalog built Oct 3, 2026