mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-15 09:21:36 +00:00
Full-corpus correctness audit of the hand-written docs against the codebase, plus a 2-week merged-PR coverage sweep and one live dashboard screenshot. Correctness (verified against COMMAND_REGISTRY / PROVIDER_REGISTRY / TOOLSETS / tools.registry / DEFAULT_CONFIG / source): - reference: add /version slash command, context_engine toolset, openai-api + novita-ai to --provider; fix tool count 64->71; model_catalog ttl 24->1; add profile describe to summary table; add real provider env vars (LM_API_KEY/LM_BASE_URL, KIMI_CODING_API_KEY, ALIBABA_CODING_PLAN_*, ANTHROPIC_BASE_URL, COPILOT_API_BASE_URL); fix faq "Windows: not natively". - user-guide: fix broken `hermes -w -q` (->-z) and `hermes logs --tail` (->-f); language list 8->16; aux slots 8->11; docker separate-dashboard claim; _SECURITY_ARGS -> _BASE_SECURITY_ARGS. - features: curator prune_builtins truth + missing CLI verbs; codex-runtime aux keys (context_compression->compression, vision_detect->vision); kanban terminate endpoint + promote/reassign/schedule/diagnostics/edit + per-profile cap; mcp mTLS (client_cert/client_key); built-in-plugins nemo_relay + teams_pipeline; api-server run approval endpoint; computer-use frontmatter. - features N-Z + integrations: StepFun step-3-mini->step-3.5-flash; web-search backends 4->8; tool-gateway image-model IDs; voice-mode STT/TTS enums; remove phantom `rl` toolset; nous-portal status subcommand. - messaging: WeCom typing/streaming cols; telegram transport default edit->auto; sms host default; simplex/ntfy `gateway setup` + pairing approve; line smart-chunking; matrix MATRIX_DM_AUTO_THREAD. - developer-guide: build-a-plugin code examples (register_command signature, ContextEngine/ImageGenProvider/MemoryProvider ABCs); model-provider-plugin entry-point group hermes.plugins->hermes_agent.plugins; PLUGIN.yaml->plugin.yaml; agent-loop stale LOC; web-search-provider phantom crawl(). PR coverage (2-week window, 149 feat PRs): - desktop.md refreshed for ~15 shipped features (zh-Hans switcher, rebindable shortcuts + zoom + Cmd+K, status-bar model picker + YOLO toggle, session-by-id + archive, multi-profile concurrent + cross-profile @session, composer history, Providers pane, per-profile remote hosts, Grok OAuth, aux-pin warning). - configuration.md gateway-streaming default corrected to per-platform. - tool-gateway.md free tool pool entitlement note. Media: - New /img/dashboard/admin-config.png — live dashboard Config admin page (captured from a clean profile, no secrets/personalization).
157 lines
7.2 KiB
Markdown
157 lines
7.2 KiB
Markdown
# ntfy
|
|
|
|
[ntfy](https://ntfy.sh/) is a simple HTTP-based pub-sub notification service. It works with the free public server at `ntfy.sh` or any self-hosted instance, and supports any client that can make HTTP requests — phones, browsers, scripts, watches.
|
|
|
|
ntfy makes a great lightweight push channel for Hermes: subscribe to a topic from the [ntfy mobile app](https://ntfy.sh/docs/subscribe/phone/), send messages to the topic to talk to the agent, get the response back on your phone.
|
|
|
|
> Run `hermes gateway setup` and pick **ntfy** for a guided walk-through.
|
|
|
|
## Prerequisites
|
|
|
|
- A topic name (any unique string — `hermes-myname-2026` works fine)
|
|
- The [ntfy mobile app](https://ntfy.sh/docs/subscribe/phone/) installed and subscribed to that topic
|
|
- Optional: a self-hosted ntfy server, or an `ntfy.sh` account token for private/reserved topics
|
|
|
|
That's it. No SDK, no daemon, no Node.js. The adapter uses `httpx` which is already a Hermes dependency.
|
|
|
|
## Configure Hermes
|
|
|
|
### Via setup wizard
|
|
|
|
```bash
|
|
hermes gateway setup
|
|
```
|
|
|
|
Select **ntfy** and follow the prompts.
|
|
|
|
### Via environment variables
|
|
|
|
Add these to `~/.hermes/.env`:
|
|
|
|
```
|
|
NTFY_TOPIC=hermes-myname-2026
|
|
NTFY_ALLOWED_USERS=hermes-myname-2026
|
|
NTFY_HOME_CHANNEL=hermes-myname-2026
|
|
```
|
|
|
|
| Variable | Required | Description |
|
|
|---|---|---|
|
|
| `NTFY_TOPIC` | Yes | Topic to subscribe to (incoming messages) |
|
|
| `NTFY_SERVER_URL` | Optional | Server URL (default: `https://ntfy.sh`) — point to a self-hosted ntfy for privacy |
|
|
| `NTFY_TOKEN` | Optional | Bearer token (e.g. `tk_xyz`) or `user:pass` for Basic auth |
|
|
| `NTFY_PUBLISH_TOPIC` | Optional | Different topic for outgoing replies (defaults to `NTFY_TOPIC`) |
|
|
| `NTFY_MARKDOWN` | Optional | Set `true` to send replies with `X-Markdown: true` header |
|
|
| `NTFY_ALLOWED_USERS` | Recommended | Comma-separated topic names allowed (treated as user IDs; see below) |
|
|
| `NTFY_ALLOW_ALL_USERS` | Optional | Set `true` to allow every publisher — only safe for private topics with read tokens |
|
|
| `NTFY_HOME_CHANNEL` | Optional | Default topic for cron / notification delivery |
|
|
| `NTFY_HOME_CHANNEL_NAME` | Optional | Human label for the home channel |
|
|
|
|
## Identity model — read this before deploying
|
|
|
|
ntfy has no native authenticated user identity. The `title` field on a published message is **publisher-controlled** and can be anything the sender wants. The Hermes adapter does NOT use `title` for authorization — it would let any publisher who knows the topic spoof an allowed user.
|
|
|
|
Instead, **the topic name itself is the identity**. Every message published to the topic is treated as coming from the same logical user (the topic). `NTFY_ALLOWED_USERS` is therefore typically just the topic name itself — a single-entry allowlist that gates the whole channel.
|
|
|
|
This means **anyone who knows the topic can talk to the agent**. To make that a real trust boundary:
|
|
|
|
- **Self-host ntfy** and lock the topic down with [Access Control](https://docs.ntfy.sh/config/#access-control). Only authorized clients with the read/write token can publish.
|
|
- Or **use a private topic on ntfy.sh** ([reserved topics](https://docs.ntfy.sh/publish/#reserved-topics) require an account) and protect it with a `NTFY_TOKEN`.
|
|
- Or **pick a long, unguessable topic name** (`hermes-7d4f9c8b-2026`) and treat it as the shared secret. This is the lightest setup but the topic name leaks via any logs or screenshots.
|
|
|
|
In all cases, do not put sensitive data through ntfy unless the underlying topic is access-controlled.
|
|
|
|
## Quick start — talk to your agent from your phone
|
|
|
|
1. Pick a topic name: `hermes-myname-2026`
|
|
2. On your phone: install the [ntfy app](https://ntfy.sh/docs/subscribe/phone/), tap **+**, enter `hermes-myname-2026`
|
|
3. On the host:
|
|
```bash
|
|
echo 'NTFY_TOPIC=hermes-myname-2026' >> ~/.hermes/.env
|
|
echo 'NTFY_ALLOWED_USERS=hermes-myname-2026' >> ~/.hermes/.env
|
|
hermes gateway restart
|
|
```
|
|
4. From the ntfy app, send a message to the topic. The agent's reply lands as a push notification.
|
|
|
|
## Using ntfy with cron jobs
|
|
|
|
Once `NTFY_HOME_CHANNEL` is set, cron jobs can deliver to ntfy:
|
|
|
|
```python
|
|
cronjob(
|
|
action="create",
|
|
schedule="every 1h",
|
|
deliver="ntfy", # uses NTFY_HOME_CHANNEL
|
|
prompt="Check for alerts and summarise."
|
|
)
|
|
```
|
|
|
|
Or target a specific topic explicitly:
|
|
|
|
```python
|
|
send_message(target="ntfy:alerts-channel", message="Done!")
|
|
```
|
|
|
|
This works even when the cron runs out-of-process from the gateway — the plugin registers a `standalone_sender_fn` that opens its own HTTP connection.
|
|
|
|
## Self-hosting ntfy
|
|
|
|
If you want full control:
|
|
|
|
```bash
|
|
# Docker
|
|
docker run -p 80:80 -it binwiederhier/ntfy serve
|
|
|
|
# Native
|
|
go install heckel.io/ntfy/v2@latest
|
|
ntfy serve
|
|
```
|
|
|
|
Then point Hermes at it:
|
|
|
|
```
|
|
NTFY_SERVER_URL=https://ntfy.mydomain.com
|
|
NTFY_TOPIC=hermes
|
|
NTFY_TOKEN=tk_abc123 # if you've set up access control
|
|
```
|
|
|
|
Self-hosting gives you topic access control, message persistence policies, attachments, and emoji tags. See the [ntfy server docs](https://docs.ntfy.sh/install/).
|
|
|
|
## Markdown formatting
|
|
|
|
ntfy clients render markdown when the publisher sets the `X-Markdown: true` header. To enable for outgoing Hermes replies:
|
|
|
|
```
|
|
NTFY_MARKDOWN=true
|
|
```
|
|
|
|
Or in `config.yaml`:
|
|
|
|
```yaml
|
|
platforms:
|
|
ntfy:
|
|
extra:
|
|
markdown: true
|
|
```
|
|
|
|
The mobile app supports a subset of CommonMark — bold, italic, lists, links, fenced code blocks. See [ntfy's markdown docs](https://docs.ntfy.sh/publish/#markdown-formatting) for the exact set.
|
|
|
|
## Outgoing-only setup (notifications without inbound)
|
|
|
|
If you only want Hermes to *push* notifications to ntfy (cron summaries, alerts) and never accept messages back, set both `NTFY_TOPIC` and `NTFY_PUBLISH_TOPIC` to the same value and skip `NTFY_ALLOWED_USERS` entirely. With no allowlist, the agent never responds to inbound messages — your phone gets the pushes, but the conversation is one-way.
|
|
|
|
## Limits
|
|
|
|
- **Message size**: ntfy caps message bodies at 4096 chars. Hermes truncates with a warning when this is exceeded.
|
|
- **No typing indicators**: the protocol doesn't expose one; `send_typing` is a no-op.
|
|
- **No threads or attachments**: ntfy is plain push notifications. Long replies stay in the message body, no thread fanout.
|
|
- **No native user identity**: see the identity-model section above.
|
|
|
|
## Troubleshooting
|
|
|
|
**Auth failure / 401** — `NTFY_TOKEN` is wrong, or the token doesn't have publish/subscribe rights on this topic. The adapter halts its reconnect loop on 401 and the gateway runtime status will show `fatal: ntfy_unauthorized`. Fix the token and restart the gateway.
|
|
|
|
**Topic not found / 404** — `NTFY_TOPIC` doesn't exist on the configured server. For ntfy.sh, topics are auto-created on first publish, so a 404 means you're pointed at a self-hosted server that doesn't have the topic provisioned. The adapter halts its reconnect loop with `fatal: ntfy_topic_not_found`.
|
|
|
|
**Connected but no messages** — Check that `NTFY_ALLOWED_USERS` includes the topic name itself. With ntfy's identity model, the topic IS the user; leaving the allowlist empty rejects everything.
|
|
|
|
**Reconnects every 60s** — The stream keepalive default is 55s; ntfy may have intermittent network issues. The adapter applies exponential backoff (2 → 5 → 10 → 30 → 60s) and resets to 0 once a stream stays alive ≥60s.
|