# Hermes Agent setup

Source: https://pushary.com/docs/agents/guides/hermes
Last updated: 2026-11-01

> Set up Hermes Agent notifications and phone approvals in one command. The Pushary plugin sends Hermes's dangerous-command approvals and questions to your phone.

Pushary sends Hermes Agent notifications and approvals to your phone. A Python plugin adds Pushary tools to Hermes, makes Pushary the transport for Hermes's dangerous-command approvals, and routes Hermes's questions to your phone. You get a push when Hermes marks a run as failed, and you can approve or deny a flagged command from your lock screen while Hermes runs.

## Set it up [#set-it-up]

```bash
npx pushary@latest setup
```

On Windows PowerShell, run `npx.cmd pushary@latest setup`. The CLI needs Node.js 20.17+, 22.13+ or 23.5+.

<Steps>
  <Step>
    ### Scan the QR code with your phone [#scan-the-qr-code-with-your-phone]

    Setup shows a QR code first. Scan it with your phone's camera or the Pushary app. Sign in or create an account, check that the code on your phone matches the one in your terminal, then tap **Approve** on &#x2A;*Connect this computer?** and allow notifications.

    New accounts start a 3-day free trial, then pay $9.99 a month. A card is needed to start the trial. If this computer already has a Pushary key, setup reuses it and skips this step.
  </Step>

  <Step>
    ### Pick Hermes [#pick-hermes]

    Setup asks &#x2A;*Which agents do you use?** with the agents it found already selected. Keep Hermes selected. To skip the question, run `npx pushary@latest setup --agents hermes`.

    Setup writes the Pushary plugin to `~/.hermes/plugins/pushary`, the folder where Hermes keeps your own plugins. That folder survives `hermes update`. Setup then turns the plugin on with Hermes's own commands:

    ```bash
    hermes plugins enable pushary
    hermes config set security.approval.transport pushary
    hermes config set security.approval.transport_fallback builtin
    ```
  </Step>

  <Step>
    ### Answer the test question [#answer-the-test-question]

    Setup sends a test push, then a test question. Answer it on your phone. The terminal says **You're set** once your answer arrives.
  </Step>

  <Step>
    ### Restart Hermes [#restart-hermes]

    Hermes loads plugins when it starts. Restart it so it loads Pushary:

    ```bash
    hermes gateway restart
    ```

    If you use Hermes in the terminal, start a new session too.
  </Step>
</Steps>

On a Mac you can use [Pushary Isle](/docs/agents/mac-app) instead. Connecting your agents there writes the same plugin to `~/.hermes/plugins/pushary`, turns it on with the same Hermes commands, and saves your key in `~/.pushary/config.json`, where the plugin reads it. It needs Hermes installed, with the `hermes` command working.

## Install from the Hermes plugin catalog [#install-from-the-hermes-plugin-catalog]

Pushary is listed in the [Hermes Agent plugin catalog](https://github.com/NousResearch/hermes-agent/blob/main/plugin-catalog/pushary.yaml), so Hermes can install it for you:

```bash
hermes plugins install pushary
```

The catalog installs the release Nous reviewed, pinned to a commit. On Hermes v2026.9.11, run `hermes update` before installing: that release can read the catalog but lacks the redaction function the pinned plugin needs, so its approval cards would arrive without the command. Then select Pushary as the approval transport, as shown in [Set it up by hand](#set-it-up-by-hand). If the install did not ask for your API key, save it in Hermes:

```bash
hermes config set PUSHARY_API_KEY pk_xxx.xxx
```

The catalog's release can be older than the one setup installs. Check `version` in `~/.hermes/plugins/pushary/plugin.yaml`, or in the catalog entry linked above before you install. A copy older than 0.8.1 cannot tell Pushary when Hermes marks a run as failed, so the push for that run says Hermes finished. A catalog copy leaves Hermes's `clarify` questions in Hermes's own prompt; a copy that setup or the Mac app installed sends them to your phone. If setup or the Mac app finds a catalog copy in `~/.hermes/plugins/pushary`, it keeps it and only changes the settings. From 0.8.0, a catalog copy reads your key only through Hermes, as the catalog requires, so save it with `hermes config set PUSHARY_API_KEY`. Never install a second copy over an existing one.

## What setup changes on your computer [#what-setup-changes-on-your-computer]

| File                                            | What changes                                                                                                                                                                              |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `~/.hermes/plugins/pushary`                     | The Pushary plugin. A `.pushary-install.json` file in the folder records that Pushary installed it.                                                                                       |
| `~/.hermes/config.yaml`                         | Changed only through `hermes plugins enable pushary` and `hermes config set`. Enables the plugin and selects Pushary as the approval transport, with Hermes's own prompt as the fallback. |
| `~/.pushary/setup/hermes-plugin.json`           | A record of what `config.yaml` had before, so `npx pushary@latest clean` can put it back. Setups from before October 2026 kept it in `hermes-config.json`, which is left as it was.       |
| `~/.pushary/config.json` and your shell profile | Your API key. The plugin reads `PUSHARY_API_KEY` through Hermes first, then `~/.pushary/config.json`.                                                                                     |

The settings in `~/.hermes/config.yaml` after setup:

```yaml
plugins:
  enabled:
    - pushary
security:
  approval:
    transport: pushary
    transport_fallback: builtin
```

Setup does not turn off Hermes's `clarify` tool. While the plugin setup or the Mac app installed is loaded, it sends `clarify` questions to `pushary_ask`. If the plugin is missing, or it is a catalog copy, Hermes asks them in its own prompt. If an older Pushary setup added `clarify` to `agent.disabled_toolsets`, setup takes it out again, unless it kept a catalog copy.

If an older Pushary setup installed `hermes-plugin-pushary` into Hermes's Python with pip, setup removes that copy, so Hermes loads the one in `~/.hermes/plugins/pushary`.

## Check that it works [#check-that-it-works]

```bash
npx pushary@latest doctor
```

Doctor checks your key and plan, that the plugin is in `~/.hermes/plugins/pushary` and enabled, that approvals go through Pushary, and that questions go through Pushary. It also says whether the running Hermes has loaded the plugin: the plugin writes a file to `~/.hermes/plugin-data/pushary/loaded/` when Hermes loads it. If doctor says to restart Hermes, run `hermes gateway restart`. Doctor sends a real test push. Add `--roundtrip` to send a test question too.

Then ask Hermes to do something its dangerous-command check flags, such as deleting a scratch folder. Your phone buzzes with Hermes's four choices.

## Approve Hermes's dangerous commands from your phone [#approve-hermess-dangerous-commands-from-your-phone]

Hermes already detects dangerous commands and asks a person before it runs them. With `security.approval.transport: pushary`, that question goes to your phone instead of a terminal nobody is watching. You get the same four choices Hermes offers in the terminal:

| Choice                 | Effect                                                 |
| ---------------------- | ------------------------------------------------------ |
| Allow once             | Runs this command.                                     |
| Allow for this session | Runs it, and stops asking for the rest of the session. |
| Always allow           | Runs it, and writes a standing allow rule.             |
| Deny                   | Blocks it. The agent is told you did not consent.      |

How long your phone has depends on your approval mode. In Always, it is Hermes's own `approvals.timeout` (300 seconds by default). In When away, your phone has the push window, then Hermes's own prompt takes over.

`transport_fallback: builtin` makes the transport safe to leave on. If your key is missing, your mode is In agent, or no device can be reached, Pushary steps aside (withdrawing any question it already sent) and Hermes asks in its own prompt. If cancellation says stop, or Pushary cannot confirm the withdrawal, the command is denied. A network failure while Pushary waits never reopens approval silently. Remove the `transport_fallback` line and an unreachable Pushary becomes a denial instead.

### Gate named tools with PUSHARY\_GATE\_TOOLS [#gate-named-tools-with-pushary_gate_tools]

To gate specific tools rather than Hermes's dangerous-command set, list them in `PUSHARY_GATE_TOOLS`. The check runs in the plugin's blocking `pre_tool_call` hook.

```bash
export PUSHARY_GATE_TOOLS="terminal,write_file"
export PUSHARY_GATE_TIMEOUT_MS=25000
```

| Outcome                                      | Result                                          |
| -------------------------------------------- | ----------------------------------------------- |
| You approve                                  | The tool runs.                                  |
| You deny                                     | The tool is blocked, and the agent is told why. |
| No answer in the window                      | The tool is blocked.                            |
| Pushary unreachable, or no API key           | The tool is blocked.                            |
| No phone, browser or Slack channel connected | The tool is blocked, with that as the reason.   |

Hermes abandons any `pre_tool_call` callback that outlives `plugins.hook_callback_timeout` (30 seconds by default). The plugin keeps its wait inside that limit. `PUSHARY_GATE_TIMEOUT_MS` defaults to 55000 and is capped by it. Raise `plugins.hook_callback_timeout` to give your phone longer, up to the plugin's own limit of 55 seconds.

When Pushary is also the selected transport, the transport wins. The hook hands the call to Hermes's own approval gate, which gets the full 300-second window and the four choices. **Always allow** on such a call creates a standing rule for the whole tool name, including future calls with different arguments. Choose **Allow once** when you mean only the call on screen.

### Hermes approvals off (dangerously skip permissions) [#hermes-approvals-off-dangerously-skip-permissions]

Hermes's `approvals.mode: off` turns off its native approval enforcement. Hermes then raises no dangerous-command approvals, so the Pushary transport has nothing to send. Plain MCP, the plugin's question tools and the skill only make questions cooperative: the agent decides whether to ask, so they are not an enforced gate. `PUSHARY_GATE_TOOLS` with no transport selected asks Pushary directly from the plugin's own hook. With the transport selected, it hands the call to Hermes's approval gate instead.

## Hermes notifications and tools [#hermes-notifications-and-tools]

The plugin registers 8 native Hermes tools:

| Tool                    | What it does                                                                            |
| ----------------------- | --------------------------------------------------------------------------------------- |
| `pushary_notify`        | Send a push with optional rich context.                                                 |
| `pushary_ask`           | Ask a question: yes or no, multiple choice, or free text.                               |
| `pushary_wait`          | Poll once for the answer to a question created with `wait=false`.                       |
| `pushary_cancel`        | Cancel a pending question.                                                              |
| `pushary_remind`        | Schedule, list or cancel a personal reminder. Pushary sends it even after Hermes exits. |
| `pushary_propose_scope` | Ask you to agree a file boundary or record a promise before a run.                      |
| `pushary_enroll`        | Connect one of your application's end users (Partner plan).                             |
| `pushary_ask_end_user`  | Ask an enrolled end user (Partner plan).                                                |

Automatic notifications:

* **Failed runs:** when Hermes marks a turn as failed, your phone gets a push that reads "Hermes run failed" with the reason Hermes gives. It follows your updates setting. A turn that ends cleanly is recorded without a push. A tool call that fails along the way, such as a `grep` that finds nothing, does not reach your phone, because Hermes recovers from it. A provider error that stops Hermes before it finishes the turn, such as a rejected API key, sends no push.
* **Session end:** set `PUSHARY_AUTO_NOTIFY_SESSION_END=1` to get a summary with tool and error counts when a session ends. Completed sessions use task-completion routing.

Hermes redacts gated argument summaries, targets and the reason a turn failed before they are shortened or sent. If the host redactor is missing or fails, that detail is left out.

For questions, `pushary_ask` does its first wait and one server-directed poll per call; use pushary\_wait with the same id while pending. Follow `answered`, `status` and `handoffAction` (or `nextAction`). Do not create a duplicate question or cancel a pending one because a poll ended. Cancel a live question before moving it to the current chat, stop if cancellation says `stop`, and if cancellation loses a race, poll once for one second and honor the winning answer. Silence is never approval.

### Environment variables [#environment-variables]

| Variable                          | What it does                                                                                                                    |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `PUSHARY_API_KEY`                 | Your API key, read through Hermes, so `~/.hermes/.env` works too. Overrides the key in `~/.pushary/config.json`.                |
| `PUSHARY_CONFIG_FILE`             | Read the key from a different file than `~/.pushary/config.json`. A copy from the catalog or copied by hand reads neither file. |
| `PUSHARY_AGENT_NAME`              | Label shown in notifications. Defaults to `Hermes`. Example: `"Hermes - daily-briefing"`.                                       |
| `PUSHARY_AUTO_NOTIFY_SESSION_END` | Set to `1` to get notified when sessions end.                                                                                   |
| `PUSHARY_GATE_TOOLS`              | Comma-separated tool names to gate in `pre_tool_call`.                                                                          |
| `PUSHARY_GATE_TIMEOUT_MS`         | How long the per-tool gate waits, in milliseconds. Defaults to 55000.                                                           |

### When to use Pushary and when to use Hermes's chat platforms [#when-to-use-pushary-and-when-to-use-hermess-chat-platforms]

Hermes can also talk to you through chat platforms such as Telegram, Discord and Slack. Use Pushary when you have no active chat open, when a quick decision should reach your lock screen, when a background task or cron job finishes, or when Hermes flags a dangerous command. Use the active chat platform when you are already in the conversation and the question is part of it.

## Set it up by hand [#set-it-up-by-hand]

Hermes now manages its own Python, and it does not support installing plugins into it with pip. Install Pushary as a folder plugin instead.

Copy the `pushary_plugin` folder from [Pushary/hermes-plugin-pushary](https://github.com/Pushary/hermes-plugin-pushary) to `~/.hermes/plugins/pushary`:

```bash
git clone --depth 1 https://github.com/Pushary/hermes-plugin-pushary /tmp/hermes-plugin-pushary
mkdir -p ~/.hermes/plugins
cp -R /tmp/hermes-plugin-pushary/pushary_plugin ~/.hermes/plugins/pushary
```

Turn it on with Hermes's own commands:

```bash
hermes config set security.approval.transport pushary
hermes config set security.approval.transport_fallback builtin
hermes plugins enable pushary
```

Save your key in Hermes. A copy you placed by hand reads the key only through Hermes, not from `~/.pushary/config.json`:

```bash
hermes config set PUSHARY_API_KEY pk_xxx.xxx
```

Restart Hermes with `hermes gateway restart`, then run `npx pushary@latest doctor`.

A copy made by hand does not send Hermes's `clarify` questions to your phone, and setup will not overwrite it. To switch to setup later, delete `~/.hermes/plugins/pushary` first.

### Use MCP instead of the plugin [#use-mcp-instead-of-the-plugin]

You can connect Hermes to the Pushary MCP server instead. Add this to `~/.hermes/config.yaml`:

```yaml
mcp_servers:
  pushary:
    url: https://pushary.com/api/mcp/mcp
    headers:
      Authorization: "Bearer ${PUSHARY_API_KEY}"
```

Then install the Pushary skill, so Hermes knows when to notify you and how to choose between Pushary and the active chat platform:

```bash
hermes skills tap add Pushary/pushary-skill
hermes skills install pushary
```

The MCP route gives Hermes the agent tools under their MCP names (`send_notification`, `ask_user`, `wait_for_answer`, `cancel_question` and `propose_scope`). It has none of the plugin's automatic notifications and no approval transport.

## Turn it off [#turn-it-off]

There is no `pushary disconnect` for Hermes. Use Hermes's own commands instead, then restart Hermes:

* To send approvals back to the terminal, run `hermes config unset security.approval.transport`.
* To turn the plugin off, run `hermes plugins disable pushary`. Hermes then asks its `clarify` questions in its own prompt again.

`npx pushary@latest clean` removes Pushary from this computer, for every agent. For Hermes it removes the plugin folder with `hermes plugins remove pushary` if Pushary installed it, puts the approval settings back from `~/.pushary/setup/hermes-plugin.json`, and deletes that record and the older `hermes-config.json`. A copy from the Hermes plugin catalog stays in place, switched off unless it was on before setup. While Pushary Isle is installed, `clean` leaves a Hermes setup the app connected, and the key the app saved for it, to the app. Add `--dry-run` to see what it would change first.

## Troubleshooting [#troubleshooting]

### Pushary stopped working after `hermes update` [#pushary-stopped-working-after-hermes-update]

Hermes now runs from Python it manages itself, so the pip copy that older Pushary setups installed no longer loads. Run `npx pushary@latest setup --agents hermes` to move to the plugin folder. `npx pushary@latest upgrade` does the same when it installs a newer version. On a Mac, update Pushary Isle and reopen it: it moves Hermes over when it starts. Then run `hermes gateway restart`.

### Setup says the Hermes CLI was not found [#setup-says-the-hermes-cli-was-not-found]

Setup looks for `hermes` on your PATH, then in `~/.local/bin`, `/opt/homebrew/bin` and `/usr/local/bin`. Install Hermes, check that `hermes` runs in a new terminal, then run setup again.

### Setup says a pushary plugin it did not install is in the way [#setup-says-a-pushary-plugin-it-did-not-install-is-in-the-way]

`~/.hermes/plugins/pushary` holds a plugin that neither Pushary nor `hermes plugins install` put there. Remove that folder, then run setup again.

### Setup says Hermes would not report its settings [#setup-says-hermes-would-not-report-its-settings]

Setup reads Hermes's settings with `hermes config get`. Run `hermes update`, then run setup again.

### Setup wrote the plugin but Hermes refused a settings change [#setup-wrote-the-plugin-but-hermes-refused-a-settings-change]

Run `hermes plugins enable pushary`, then run setup again. Or run the commands in [Set it up by hand](#set-it-up-by-hand) yourself.

### Doctor says to restart Hermes [#doctor-says-to-restart-hermes]

The plugin is installed, but the running Hermes started before it, or still runs an older Pushary plugin. Run `hermes gateway restart`, and start a new terminal session if you use one.

### Doctor says approvals stay in the terminal [#doctor-says-approvals-stay-in-the-terminal]

`security.approval.transport` is not `pushary` in `~/.hermes/config.yaml`. Run `npx pushary@latest setup --agents hermes` again, or set it by hand.

## Next steps [#next-steps]

<Cards>
  <Card title="Hermes notifications" description="What Hermes sends to your phone, and when." href="/hermes-notifications" />

  <Card title="Set your approval rules" description="Choose which actions run on their own and which wait for you." href="/docs/agents/policies" />

  <Card title="Human in the loop" description="How questions, answers and timeouts work across agents." href="/docs/agents/human-in-the-loop" />
</Cards>