mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-26 11:12:03 +00:00
Merge remote-tracking branch 'origin/main' into hermes/hermes-6b48295e
This commit is contained in:
commit
2ecb4e62bb
239 changed files with 18356 additions and 2494 deletions
|
|
@ -1350,6 +1350,7 @@ Launch the web dashboard — a browser-based UI for managing configuration, API
|
|||
| `--host` | `127.0.0.1` | Bind address |
|
||||
| `--no-open` | — | Don't auto-open the browser |
|
||||
| `--insecure` | off | Allow binding to non-localhost hosts. Exposes dashboard credentials on the network; use only behind trusted network controls. |
|
||||
| `--isolated` | off | When launched from a named profile (`worker dashboard`), run a dedicated per-profile server instead of routing to the machine dashboard. |
|
||||
| `--stop` | — | Stop running `hermes dashboard` processes and exit. |
|
||||
| `--status` | — | List running `hermes dashboard` processes and exit. |
|
||||
|
||||
|
|
@ -1359,6 +1360,10 @@ hermes dashboard
|
|||
|
||||
# Custom port, no browser
|
||||
hermes dashboard --port 8080 --no-open
|
||||
|
||||
# From a profile alias — routes to the machine dashboard with the
|
||||
# profile preselected in the sidebar switcher (attach if running)
|
||||
worker dashboard
|
||||
```
|
||||
|
||||
## `hermes profile`
|
||||
|
|
|
|||
|
|
@ -410,15 +410,31 @@ For cloud sandbox backends, persistence is filesystem-oriented. `TERMINAL_LIFETI
|
|||
| `MATRIX_USER_ID` | Matrix user ID (e.g. `@hermes:matrix.org`) — required for password login, optional with access token |
|
||||
| `MATRIX_PASSWORD` | Matrix password (alternative to access token) |
|
||||
| `MATRIX_ALLOWED_USERS` | Comma-separated Matrix user IDs allowed to message the bot (e.g. `@alice:matrix.org`) |
|
||||
| `MATRIX_ALLOWED_ROOMS` | Comma-separated Matrix room IDs allowed to trigger bot responses |
|
||||
| `MATRIX_HOME_ROOM` | Room ID for proactive message delivery (e.g. `!abc123:matrix.org`) |
|
||||
| `MATRIX_ENCRYPTION` | Enable end-to-end encryption (`true`/`false`, default: `false`) |
|
||||
| `MATRIX_E2EE_MODE` | Matrix E2EE behavior: `off`, `optional`, or `required`. Overrides `MATRIX_ENCRYPTION` when set. |
|
||||
| `MATRIX_DEVICE_ID` | Stable Matrix device ID for E2EE persistence across restarts (e.g. `HERMES_BOT`). Without this, E2EE keys rotate every startup and historic-room decrypt breaks. |
|
||||
| `MATRIX_REACTIONS` | Enable processing-lifecycle emoji reactions on inbound messages (default: `true`). Set to `false` to disable. |
|
||||
| `MATRIX_REQUIRE_MENTION` | Require `@mention` in rooms (default: `true`). Set to `false` to respond to all messages. |
|
||||
| `MATRIX_FREE_RESPONSE_ROOMS` | Comma-separated room IDs where bot responds without `@mention` |
|
||||
| `MATRIX_IGNORE_USER_PATTERNS` | Comma-separated regular expressions for Matrix bridge/appservice ghost user IDs to ignore |
|
||||
| `MATRIX_PROCESS_NOTICES` | Process inbound Matrix `m.notice` events (default: `false`) |
|
||||
| `MATRIX_SESSION_SCOPE` | Matrix session scope for project rooms: `auto`, `room`, or `thread` (default: `auto`) |
|
||||
| `MATRIX_TOOLS_ALLOW_CROSS_ROOM` | Allow Matrix tools to target explicit rooms other than the current room (default: `false`) |
|
||||
| `MATRIX_TOOLS_ALLOW_CROSS_ROOM_DESTRUCTIVE` | Allow cross-room Matrix redaction/invite-like tools; requires `MATRIX_TOOLS_ALLOW_CROSS_ROOM=true` (default: `false`) |
|
||||
| `MATRIX_TOOLS_ALLOW_REDACTION` | Allow Matrix message redaction tool execution (default: `false`) |
|
||||
| `MATRIX_TOOLS_ALLOW_INVITES` | Allow Matrix invite tool execution (default: `false`) |
|
||||
| `MATRIX_TOOLS_ALLOW_ROOM_CREATE` | Allow Matrix room creation tool execution (default: `false`) |
|
||||
| `MATRIX_ALLOW_ROOM_MENTIONS` | Allow outbound `@room` mentions to notify all room members (default: `false`) |
|
||||
| `MATRIX_AUTO_THREAD` | Auto-create threads for room messages (default: `true`) |
|
||||
| `MATRIX_DM_MENTION_THREADS` | Create a thread when bot is `@mentioned` in a DM (default: `false`) |
|
||||
| `MATRIX_APPROVAL_REQUIRE_SENDER` | Require approval/model-picker reactions to come from the original requester when known (default: `true`) |
|
||||
| `MATRIX_APPROVAL_TIMEOUT_SECONDS` | Timeout for Matrix reaction approval/model-picker prompts (default: `300`) |
|
||||
| `MATRIX_ALLOW_PUBLIC_ROOMS` | Allow Matrix room-creation tools to create public rooms (default: `false`) |
|
||||
| `MATRIX_MAX_MEDIA_BYTES` | Maximum Matrix media upload/download size in bytes (default: `104857600`) |
|
||||
| `MATRIX_RECOVERY_KEY` | Recovery key for cross-signing verification after device key rotation. Recommended for E2EE setups with cross-signing enabled. |
|
||||
| `MATRIX_RECOVERY_KEY_OUTPUT_FILE` | Optional one-time path for a generated Matrix recovery key. Created with mode `0600` and never overwritten. |
|
||||
| `HASS_TOKEN` | Home Assistant Long-Lived Access Token (enables HA platform + tools) |
|
||||
| `HASS_URL` | Home Assistant URL (default: `http://homeassistant.local:8123`) |
|
||||
| `WEBHOOK_ENABLED` | Enable the webhook platform adapter (`true`/`false`) |
|
||||
|
|
|
|||
|
|
@ -86,7 +86,8 @@ Type `/` in the CLI to open the autocomplete menu. Built-in commands are case-in
|
|||
| `/tools [list\|disable\|enable] [name...]` | Manage tools: list available tools, or disable/enable specific tools for the current session. Disabling a tool removes it from the agent's toolset and triggers a session reset. |
|
||||
| `/toolsets` | List available toolsets |
|
||||
| `/browser [connect\|disconnect\|status]` | Manage a local Chromium-family CDP connection. `connect` attaches browser tools to a running Chrome, Brave, Chromium, or Edge instance (default: `http://127.0.0.1:9222`). `disconnect` detaches. `status` shows current connection. Auto-launches a supported Chromium-family browser if no debugger is detected. |
|
||||
| `/skills` | Search, install, inspect, or manage skills from online registries |
|
||||
| `/skills` | Search, install, inspect, or manage skills from online registries. Also the review surface for the skill write-approval gate: `/skills pending`, `/skills diff <id>`, `/skills approve <id>`, `/skills reject <id>`, `/skills approval on\|off`. See [Gating agent skill writes](/user-guide/features/skills#gating-agent-skill-writes-skillswrite_approval). |
|
||||
| `/memory [pending\|approve\|reject\|approval]` | Review pending memory writes staged by the write-approval gate (`memory.write_approval`) and toggle the gate. See [Controlling memory writes](/user-guide/features/memory#controlling-memory-writes-write_approval). |
|
||||
| `/bundles` | List configured skill bundles — `/<name>` slash aliases that preload several skills at once. Configure under `bundles:` in `~/.hermes/config.yaml`. See [Skill Bundles](/user-guide/features/skills#skill-bundles). |
|
||||
| `/cron` | Manage scheduled tasks (list, add/create, edit, pause, resume, run, remove) |
|
||||
| `/curator` | Background skill maintenance — `status`, `run`, `pin`, `archive`. See [Curator](/user-guide/features/curator). |
|
||||
|
|
@ -222,6 +223,8 @@ The messaging gateway supports the following built-in commands inside Telegram,
|
|||
| `/goal <text>` | Set a standing goal Hermes works toward across turns — our take on the Ralph loop. A judge model checks after each turn; if not done, Hermes auto-continues until it is, you pause/clear it, or the turn budget (default 20) is hit. Subcommands: `/goal status`, `/goal pause`, `/goal resume`, `/goal clear`. Safe to run mid-agent for status/pause/clear; setting a new goal requires `/stop` first. See [Persistent Goals](/user-guide/features/goals). |
|
||||
| `/footer [on\|off\|status]` | Toggle the runtime-metadata footer on final replies (shows model, context %, and cwd). |
|
||||
| `/curator [status\|run\|pin\|archive]` | Background skill maintenance controls. |
|
||||
| `/memory [pending\|approve\|reject\|approval]` | Review pending memory writes staged by the write-approval gate (`memory.write_approval`) — approve or reject them right in chat — and toggle the gate with `/memory approval on\|off`. See [Controlling memory writes](/user-guide/features/memory#controlling-memory-writes-write_approval). |
|
||||
| `/skills [pending\|approve\|reject\|diff\|approval]` | Review pending **skill** writes staged by the write-approval gate (`skills.write_approval`). Shows a one-line gist per staged write; `/skills diff <id>` is truncated for chat — read the full diff on the CLI or in `~/.hermes/pending/skills/<id>.json`. Only appears when the gate is on (or staged writes remain); search/install stay CLI-only. |
|
||||
| `/kanban <action>` | Drive the multi-profile, multi-project collaboration board from chat — identical argument surface to the CLI. Bypasses the running-agent guard, so `/kanban unblock t_abc`, `/kanban comment t_abc "…"`, `/kanban list --mine`, `/kanban boards switch <slug>`, etc. work mid-turn. `/kanban create …` auto-subscribes the originating chat to the new task's terminal events. See [Kanban slash command](/user-guide/features/kanban#kanban-slash-command). |
|
||||
| `/reload-mcp` (alias: `/reload_mcp`) | Reload MCP servers from config. |
|
||||
| `/yolo` | Toggle YOLO mode — skip all dangerous command approval prompts. |
|
||||
|
|
@ -236,7 +239,8 @@ The messaging gateway supports the following built-in commands inside Telegram,
|
|||
|
||||
## Notes
|
||||
|
||||
- `/skin`, `/snapshot`, `/gquota`, `/reload`, `/tools`, `/toolsets`, `/browser`, `/config`, `/cron`, `/skills`, `/platforms`, `/paste`, `/image`, `/statusbar`, `/plugins`, `/busy`, `/indicator`, `/redraw`, `/clear`, `/history`, `/save`, `/copy`, `/handoff`, and `/quit` are **CLI-only** commands.
|
||||
- `/skin`, `/snapshot`, `/gquota`, `/reload`, `/tools`, `/toolsets`, `/browser`, `/config`, `/cron`, `/platforms`, `/paste`, `/image`, `/statusbar`, `/plugins`, `/busy`, `/indicator`, `/redraw`, `/clear`, `/history`, `/save`, `/copy`, `/handoff`, and `/quit` are **CLI-only** commands.
|
||||
- `/skills` is **CLI-only for search/browse/install**; its write-approval review subcommands (`pending`, `approve`, `reject`, `diff`, `approval`) also work on messaging platforms when `skills.write_approval` is on. `/memory` works on **both** surfaces.
|
||||
- `/verbose` is **CLI-only by default**, but can be enabled for messaging platforms by setting `display.tool_progress_command: true` in `config.yaml`. When enabled, it cycles the `display.tool_progress` mode and saves to config.
|
||||
- `/sethome`, `/update`, `/restart`, `/approve`, `/deny`, `/topic`, and `/commands` are **messaging-only** commands.
|
||||
- `/status`, `/version`, `/background`, `/queue`, `/steer`, `/voice`, `/reload-mcp`, `/reload-skills`, `/rollback`, `/debug`, `/fast`, `/footer`, `/curator`, `/kanban`, `/sessions`, and `/yolo` work in **both** the CLI and the messaging gateway.
|
||||
|
|
|
|||
|
|
@ -533,6 +533,17 @@ skills:
|
|||
|
||||
When on, any flagged `skill_manage` write surfaces as an approval prompt with the scanner's rationale. Accepted writes land; denied writes return an explanatory error to the agent.
|
||||
|
||||
### Write approval for skill writes
|
||||
|
||||
Independent of the content scanner above, `skills.write_approval` gates **every** agent skill write (create / edit / patch / delete / supporting files) behind your explicit approval — the same approve/deny mechanism as dangerous commands:
|
||||
|
||||
```yaml
|
||||
skills:
|
||||
write_approval: false # false = write freely (default) | true = stage every write for review
|
||||
```
|
||||
|
||||
When on, skill writes are staged under `~/.hermes/pending/skills/` and reviewed with `/skills pending`, `/skills diff <id>`, `/skills approve <id>`, `/skills reject <id>` — from the CLI or any messaging platform. Toggle at runtime with `/skills approval on|off`. Memory has the same gate (`memory.write_approval`, below). Full walkthrough: [Gating agent skill writes](/user-guide/features/skills#gating-agent-skill-writes-skillswrite_approval).
|
||||
|
||||
## Memory Configuration
|
||||
|
||||
```yaml
|
||||
|
|
@ -541,8 +552,11 @@ memory:
|
|||
user_profile_enabled: true
|
||||
memory_char_limit: 2200 # ~800 tokens
|
||||
user_char_limit: 1375 # ~500 tokens
|
||||
write_approval: false # true = require approval before any memory write
|
||||
```
|
||||
|
||||
With `memory.write_approval: true`, memory writes need your approval before they land: interactive CLI turns prompt inline; messaging sessions and the background self-improvement review stage the write for `/memory pending` → `/memory approve <id>` / `/memory reject <id>` review. Toggle at runtime with `/memory approval on|off`. See [Controlling memory writes](/user-guide/features/memory#controlling-memory-writes-write_approval).
|
||||
|
||||
## File Read Safety
|
||||
|
||||
Controls how much content a single `read_file` call can return. Reads that exceed the limit are rejected with an error telling the agent to use `offset` and `limit` for a smaller range. This prevents a single read of a minified JS bundle or large data file from flooding the context window.
|
||||
|
|
|
|||
|
|
@ -125,35 +125,6 @@ When `workdir` is set:
|
|||
Jobs with a `workdir` run sequentially on the scheduler tick, not in the parallel pool. This is deliberate: the cron worker applies the job workdir through process-global terminal state, so two workdir jobs running at the same time would corrupt each other's cwd. Workdir-less jobs still run in parallel as before.
|
||||
:::
|
||||
|
||||
## Running cron jobs in a specific profile
|
||||
|
||||
By default a cron job inherits whichever Hermes profile owned the gateway / CLI that created it. Pass `--profile <name>` (CLI) or `profile=` (cronjob tool) to re-target the job at a different profile — the scheduler resolves that profile's `HERMES_HOME`, temporarily switches into it for the duration of the run, loads its `.env` + `config.yaml`, and executes the job there:
|
||||
|
||||
```bash
|
||||
# Pin a job to the `night-ops` profile regardless of where it was scheduled
|
||||
hermes cron create "every 1d at 03:00" \
|
||||
"Tail the security log and flag anomalies" \
|
||||
--profile night-ops
|
||||
```
|
||||
|
||||
```python
|
||||
# From a chat, via the cronjob tool
|
||||
cronjob(
|
||||
action="create",
|
||||
schedule="every 1d at 03:00",
|
||||
prompt="Tail the security log and flag anomalies",
|
||||
profile="night-ops",
|
||||
)
|
||||
```
|
||||
|
||||
Use `--profile default` to explicitly pin to the root Hermes profile. The named profile must already exist; the scheduler refuses to create profiles on the fly. To clear a profile pin during `cron edit`, pass an empty string (`--profile ""` or `profile=""`) — the job reverts to running in whatever profile the scheduler itself is in.
|
||||
|
||||
If the pinned profile is later deleted, the scheduler logs a warning and falls back to running the job in its current profile rather than crashing — so a stale `profile` reference never wedges a job.
|
||||
|
||||
:::note Serialization
|
||||
Jobs with a `profile` set also run sequentially, for the same reason as `workdir`-pinned jobs: switching `HERMES_HOME` is a process-global mutation, so two profile-pinned jobs running in parallel would race each other. Unpinned jobs still run in the normal parallel pool.
|
||||
:::
|
||||
|
||||
## Editing jobs
|
||||
|
||||
You do not need to delete and recreate jobs just to change them.
|
||||
|
|
@ -223,7 +194,7 @@ What they do:
|
|||
- `resume` — re-enable the job and compute the next future run
|
||||
- `run` — trigger the job on the next scheduler tick
|
||||
- `remove` — delete it entirely
|
||||
- `edit` — modify schedule, prompt, profile, delivery, etc.
|
||||
- `edit` — modify schedule, prompt, delivery, etc.
|
||||
|
||||
**Name-based lookup.** All four mutating verbs (`pause`, `resume`, `run`, `remove`, `edit`) plus the agent's `cronjob` tool now accept a job **name** (case-insensitive) in place of the hex ID. The agent and CLI both prefer an exact ID match if one exists; ambiguous name matches (multiple jobs sharing the same name) are refused with the full list of candidate IDs so you can pick one explicitly. Names are not unique, so this guard is load-bearing — it prevents silently mutating the wrong job when two share a name.
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,13 @@ Two files make up the agent's memory:
|
|||
Both are stored in `~/.hermes/memories/` and are injected into the system prompt as a frozen snapshot at session start. The agent manages its own memory via the `memory` tool — it can add, replace, or remove entries.
|
||||
|
||||
:::info
|
||||
Character limits keep memory focused. When memory is full, the agent consolidates or replaces entries to make room for new information.
|
||||
Character limits keep memory focused. Memory does **not** auto-compact: when a
|
||||
write would exceed the limit, the `memory` tool returns an error instead of
|
||||
silently dropping entries. The agent then makes room itself — consolidating or
|
||||
removing entries in the same turn before retrying (see [What Happens When Memory
|
||||
is Full](#what-happens-when-memory-is-full)). Note that `replace` is also bound
|
||||
by the limit: swapping an entry for a longer one can still overflow, so the new
|
||||
content must be shortened (or another entry removed) to fit.
|
||||
:::
|
||||
|
||||
## How Memory Appears in the System Prompt
|
||||
|
|
@ -264,6 +270,7 @@ inline, but the full diff stays out-of-band:
|
|||
On a messaging platform, approve a skill from its gist + metadata, or open
|
||||
`/skills diff` on the CLI / dashboard / the staged file under
|
||||
`~/.hermes/pending/skills/<id>.json` when you want to read the whole change.
|
||||
Full details in [Gating agent skill writes](/user-guide/features/skills#gating-agent-skill-writes-skillswrite_approval).
|
||||
|
||||
|
||||
## External Memory Providers
|
||||
|
|
|
|||
|
|
@ -401,6 +401,43 @@ The agent can create, update, and delete its own skills via the `skill_manage` t
|
|||
The `patch` action is preferred for updates — it's more token-efficient than `edit` because only the changed text appears in the tool call.
|
||||
:::
|
||||
|
||||
### Gating agent skill writes (`skills.write_approval`)
|
||||
|
||||
By default the agent writes skills freely — including from the [background
|
||||
self-improvement review](/user-guide/features/memory#controlling-memory-writes-write_approval)
|
||||
that runs after a turn. If you'd rather approve every skill write first
|
||||
(small models that misjudge what they learned, secure environments, or just
|
||||
wanting eyes on the self-improvement loop), turn on the write-approval gate:
|
||||
|
||||
```yaml
|
||||
skills:
|
||||
write_approval: false # false = write freely (default) | true = require approval
|
||||
```
|
||||
|
||||
When `write_approval: true`, every `skill_manage` write (create / edit /
|
||||
patch / delete / write_file / remove_file) is **staged** instead of committed —
|
||||
a SKILL.md is too large to review inline, so staging applies regardless of
|
||||
whether the write came from a foreground turn or the background review.
|
||||
Staged writes survive restarts under `~/.hermes/pending/skills/` and are
|
||||
reviewed with the same familiar approve/deny flow as dangerous commands:
|
||||
|
||||
```
|
||||
/skills pending # list staged skill writes + a one-line gist each
|
||||
/skills diff <id> # full unified diff (best viewed in CLI or dashboard)
|
||||
/skills approve <id> # apply it (or 'all')
|
||||
/skills reject <id> # drop it (or 'all')
|
||||
/skills approval on # turn the gate on (or 'off') and persist it
|
||||
```
|
||||
|
||||
The review surface works in the interactive CLI and on messaging platforms
|
||||
(diff output is truncated for chat bubbles — read the full diff on the CLI or
|
||||
in the pending JSON file). Memory writes have the same gate under
|
||||
`memory.write_approval` — see [Controlling memory writes](/user-guide/features/memory#controlling-memory-writes-write_approval).
|
||||
|
||||
> The separate `skills.guard_agent_created` setting is a content scanner
|
||||
> (dangerous-pattern heuristics), not an approval gate — the two are
|
||||
> independent. See [Guard on agent-created skill writes](/user-guide/configuration#guard-on-agent-created-skill-writes).
|
||||
|
||||
## Skills Hub
|
||||
|
||||
Browse, search, install, and manage skills from online registries, `skills.sh`, direct well-known skill endpoints, and official optional skills.
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ This starts a local web server and opens `http://127.0.0.1:9119` in your browser
|
|||
| `--host` | `127.0.0.1` | Bind address |
|
||||
| `--no-open` | — | Don't auto-open the browser |
|
||||
| `--insecure` | off | Allow binding to non-localhost hosts (**DANGEROUS** — exposes API keys on the network; pair with a firewall and strong auth) |
|
||||
| `--isolated` | off | When launched from a named profile (`worker dashboard`), run a dedicated per-profile server instead of routing to the machine dashboard |
|
||||
|
||||
```bash
|
||||
# Custom port
|
||||
|
|
@ -40,6 +41,43 @@ hermes dashboard --host 0.0.0.0
|
|||
hermes dashboard --no-open
|
||||
```
|
||||
|
||||
## Managing multiple profiles
|
||||
|
||||
The dashboard is a **machine-level** management surface: one server manages
|
||||
every [profile](../profiles.md) on the machine. A profile switcher in the
|
||||
sidebar (visible whenever more than one profile exists) decides which
|
||||
profile the management pages read and write — Config, API Keys, Skills,
|
||||
MCP, Models, and the Chat tab all follow it. While a profile other than
|
||||
the dashboard's own is selected, an amber banner names the managed profile
|
||||
so the write target is never ambiguous.
|
||||
|
||||
The selection lives in the URL (`?profile=<name>`), so deep links like
|
||||
`http://127.0.0.1:9119/skills?profile=worker` land with the switcher
|
||||
preselected and survive refresh.
|
||||
|
||||
Launching the dashboard from a profile alias routes to the machine
|
||||
dashboard instead of starting a second server:
|
||||
|
||||
```bash
|
||||
worker dashboard
|
||||
# → already running: opens the browser at ?profile=worker
|
||||
# → not running: starts the machine dashboard with "worker" preselected
|
||||
```
|
||||
|
||||
Pass `--isolated` to opt out and run a dedicated server scoped to that
|
||||
profile (the pre-unification behavior — useful if you deliberately expose
|
||||
different profiles' dashboards with different auth).
|
||||
|
||||
The **Chat** tab follows the switcher too: a scoped chat spawns its PTY
|
||||
child with the selected profile's `HERMES_HOME`, so the conversation runs
|
||||
with that profile's model, skills, memory, and session history. Switching
|
||||
profiles starts a fresh terminal session.
|
||||
|
||||
What stays per-profile and is *not* absorbed by the switcher: gateway
|
||||
processes (manage them via `hermes -p <name> gateway …`), each profile's
|
||||
session database, and cron schedulers (the Cron page already aggregates
|
||||
across profiles with its own filter).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The default `hermes-agent` install does not ship the HTTP stack or PTY helper — those are optional extras. The **web dashboard** needs FastAPI and Uvicorn (`web` extra). The **Chat** tab also needs `ptyprocess` to spawn the embedded TUI behind a pseudo-terminal (`pty` extra on POSIX). Install both with:
|
||||
|
|
@ -234,6 +272,17 @@ Create and manage scheduled cron jobs that run agent prompts on a recurring sche
|
|||
- **Trigger now** — immediately execute a job outside its normal schedule
|
||||
- **Delete** — permanently remove a cron job
|
||||
|
||||
### Profiles
|
||||
|
||||
Create and manage [profiles](../profiles.md) — isolated Hermes instances with their own config, skills, and sessions.
|
||||
|
||||
- **Profile cards** — each shows its model/provider, skill count, gateway state, description, and badges (active, default, alias)
|
||||
- **Create** — name + optional clone-from-default / clone-everything / no-bundled-skills, description, and model; the dedicated Profile Builder page (`/profiles/new`) offers the full flow (model, MCPs, skills)
|
||||
- **Manage skills & tools** — jumps to the Skills page scoped to that profile (sets the sidebar profile switcher)
|
||||
- **Set as active** — flips the sticky default that **future CLI/gateway runs** pick up (same as `hermes profile use`). This does *not* change what the dashboard manages — that's the profile switcher's job
|
||||
- **Edit model / description / SOUL** — inline editors writing into that profile
|
||||
- **Rename / Delete** — named profiles only
|
||||
|
||||
### Skills
|
||||
|
||||
Browse, search, and toggle installed skills and toolsets, and install new ones from the hub. Skills are loaded from `~/.hermes/skills/` and grouped by category.
|
||||
|
|
@ -349,6 +398,16 @@ This re-reads `~/.hermes/.env` into the running process's environment. Useful wh
|
|||
|
||||
The web dashboard exposes a REST API that the frontend consumes. You can also call these endpoints directly for automation:
|
||||
|
||||
:::tip Profile-scoped endpoints
|
||||
The management endpoint families — `/api/config`, `/api/env`, `/api/skills`,
|
||||
`/api/tools/toolsets`, `/api/mcp`, and `/api/model/{info,options,auxiliary,set}` —
|
||||
accept an optional `?profile=<name>` query parameter (or `"profile"` in the
|
||||
JSON body for writes) that scopes the read/write to that profile's
|
||||
`HERMES_HOME`. Omitted = the dashboard's own profile. Unknown profile names
|
||||
return `404`. The `/api/pty` WebSocket accepts the same parameter to spawn
|
||||
a chat under the selected profile.
|
||||
:::
|
||||
|
||||
### GET /api/status
|
||||
|
||||
Returns agent version, gateway status, platform states, and active session count.
|
||||
|
|
|
|||
|
|
@ -21,12 +21,36 @@ Before setup, here's the part most people want to know: how Hermes behaves once
|
|||
| **Threads** | Hermes supports Matrix threads (MSC3440). If you reply in a thread, Hermes keeps the thread context isolated from the main room timeline. Threads where the bot has already participated do not require a mention. |
|
||||
| **Auto-threading** | By default, Hermes auto-creates a thread for each message it responds to in a room. This keeps conversations isolated. Set `MATRIX_AUTO_THREAD=false` to disable. Set `MATRIX_DM_AUTO_THREAD=true` (default false) to also auto-create threads for DM messages — this is distinct from `MATRIX_DM_MENTION_THREADS`, which only starts a thread when the bot is `@mentioned` in a DM. |
|
||||
| **Commands** | Hermes accepts normal `/commands` when your Matrix client sends them. If your client reserves `/` for local commands, use `!commands` instead; Hermes normalizes known `!command` aliases to `/command`. |
|
||||
| **Interactive controls** | Dangerous-command approval and `/model` selection can use Matrix reactions. Approval reactions can be limited to the user who requested the action. |
|
||||
| **Thinking and tool activity** | Matrix uses threaded, editable thinking/tool-activity panes when gateway progress is enabled, so updates do not flood the main room timeline. |
|
||||
| **Shared rooms with multiple users** | By default, Hermes isolates session history per user inside the room. Two people talking in the same room do not share one transcript unless you explicitly disable that. |
|
||||
|
||||
:::tip
|
||||
The bot automatically joins rooms when invited. Just invite the bot's Matrix user to any room and it will join and start responding.
|
||||
:::
|
||||
|
||||
## Capability Matrix
|
||||
|
||||
This table is backed by the Matrix adapter capability declaration and Matrix test
|
||||
coverage. E2EE is mode-based because deployments choose whether encrypted rooms
|
||||
are disabled, opportunistic, or required.
|
||||
|
||||
| Capability | Matrix |
|
||||
|------------|--------|
|
||||
| text | yes |
|
||||
| threads | yes |
|
||||
| reactions | yes |
|
||||
| approvals | yes |
|
||||
| model picker | yes |
|
||||
| thinking panes | yes |
|
||||
| images | yes |
|
||||
| multiple images | yes |
|
||||
| files | yes |
|
||||
| voice/audio | yes |
|
||||
| video | yes |
|
||||
| E2EE | off / optional / required |
|
||||
| diagnostics | yes |
|
||||
|
||||
### Session Model in Matrix
|
||||
|
||||
By default:
|
||||
|
|
@ -60,8 +84,17 @@ You can configure mention and auto-threading behavior via environment variables
|
|||
```yaml
|
||||
matrix:
|
||||
require_mention: true # Require @mention in rooms (default: true)
|
||||
allowed_users: # Matrix users allowed to trigger agent turns
|
||||
- "@alice:matrix.org"
|
||||
allowed_rooms: # Matrix rooms allowed to trigger agent turns
|
||||
- "!abc123:matrix.org"
|
||||
free_response_rooms: # Rooms exempt from mention requirement
|
||||
- "!abc123:matrix.org"
|
||||
ignore_user_patterns: # Bridge/appservice ghost users to ignore
|
||||
- "^@telegram_"
|
||||
- "^@whatsapp_"
|
||||
process_notices: false # Ignore m.notice by default
|
||||
session_scope: room # auto|room|thread; room is recommended for project rooms
|
||||
auto_thread: true # Auto-create threads for responses (default: true)
|
||||
dm_mention_threads: false # Create thread when @mentioned in DM (default: false)
|
||||
```
|
||||
|
|
@ -70,20 +103,60 @@ Or via environment variables:
|
|||
|
||||
```bash
|
||||
MATRIX_REQUIRE_MENTION=true
|
||||
MATRIX_ALLOWED_USERS=@alice:matrix.org
|
||||
MATRIX_ALLOWED_ROOMS=!abc123:matrix.org
|
||||
MATRIX_FREE_RESPONSE_ROOMS=!abc123:matrix.org,!def456:matrix.org
|
||||
MATRIX_IGNORE_USER_PATTERNS='^@telegram_,^@whatsapp_'
|
||||
MATRIX_PROCESS_NOTICES=false
|
||||
MATRIX_SESSION_SCOPE=room # recommended for stable project-room context
|
||||
MATRIX_AUTO_THREAD=true
|
||||
MATRIX_DM_MENTION_THREADS=false
|
||||
MATRIX_REACTIONS=true # default: true — emoji reactions during processing
|
||||
MATRIX_ALLOW_ROOM_MENTIONS=false
|
||||
```
|
||||
|
||||
:::tip Disabling reactions
|
||||
`MATRIX_REACTIONS=false` turns off the processing-lifecycle emoji reactions (👀/✅/❌) the bot posts on inbound messages. Useful for rooms where reaction events are noisy or aren't supported by all participating clients.
|
||||
:::
|
||||
|
||||
:::tip Room-wide mentions
|
||||
Hermes sends structured Matrix user mentions for explicit Matrix IDs such as `@alice:example.org`. Room-wide `@room` notifications are disabled by default; set `MATRIX_ALLOW_ROOM_MENTIONS=true` only in rooms where the bot is allowed to notify everyone.
|
||||
:::
|
||||
|
||||
:::note
|
||||
If you are upgrading from a version that did not have `MATRIX_REQUIRE_MENTION`, the bot previously responded to all messages in rooms. To preserve that behavior, set `MATRIX_REQUIRE_MENTION=false`.
|
||||
:::
|
||||
|
||||
### Project Room Isolation
|
||||
|
||||
If you use the same Matrix bot in multiple project rooms, configure stable
|
||||
room-scoped sessions:
|
||||
|
||||
```bash
|
||||
MATRIX_SESSION_SCOPE=room
|
||||
MATRIX_AUTO_THREAD=false
|
||||
```
|
||||
|
||||
`MATRIX_SESSION_SCOPE` accepts:
|
||||
|
||||
| Scope | Behavior |
|
||||
|-------|----------|
|
||||
| `auto` | Backward-compatible default. Existing `MATRIX_AUTO_THREAD` behavior controls synthetic threads. |
|
||||
| `room` | Unthreaded room messages stay in one stable room session. Real Matrix threads still use their thread root. |
|
||||
| `thread` | Unthreaded room messages synthesize a thread/session from the triggering event ID. |
|
||||
|
||||
Hermes now includes the current Matrix room name, room ID, topic, message ID,
|
||||
and a Matrix room-boundary note in the agent prompt. `/status` also shows the
|
||||
current Matrix room/session scope, and `/resume` will not silently resume a
|
||||
named session from another Matrix room unless you explicitly use
|
||||
`/resume --cross-room <session name>`.
|
||||
|
||||
`MATRIX_SESSION_SCOPE=room` controls the room/thread lane. The existing
|
||||
`group_sessions_per_user` setting still controls whether users inside that room
|
||||
share the lane. With `group_sessions_per_user: true` (default), Alice and Bob get
|
||||
separate Project B sessions. With `group_sessions_per_user: false`, the room has
|
||||
one shared Project B transcript.
|
||||
|
||||
This guide walks you through the full setup process — from creating your bot account to sending your first message.
|
||||
|
||||
## Step 1: Create a Bot Account
|
||||
|
|
@ -196,6 +269,9 @@ MATRIX_ACCESS_TOKEN=***
|
|||
# Security: restrict who can interact with the bot
|
||||
MATRIX_ALLOWED_USERS=@alice:matrix.example.org
|
||||
|
||||
# Optional: restrict which rooms can trigger the bot
|
||||
MATRIX_ALLOWED_ROOMS=!abc123:matrix.example.org
|
||||
|
||||
# Multiple allowed users (comma-separated)
|
||||
# MATRIX_ALLOWED_USERS=@alice:matrix.example.org,@bob:matrix.example.org
|
||||
```
|
||||
|
|
@ -212,6 +288,45 @@ MATRIX_PASSWORD=***
|
|||
MATRIX_ALLOWED_USERS=@alice:matrix.example.org
|
||||
```
|
||||
|
||||
## Private Deployment Hardening
|
||||
|
||||
For private Matrix deployments, set both user and room allowlists. If
|
||||
`MATRIX_ALLOWED_USERS` is unset, any sender who can reach the bot in a joined
|
||||
room can trigger an agent turn. If `MATRIX_ALLOWED_ROOMS` is unset, any room the
|
||||
bot joins can trigger an agent turn. A locked-down deployment should set both:
|
||||
|
||||
```bash
|
||||
MATRIX_ALLOWED_USERS=@alice:matrix.example.org,@bob:matrix.example.org
|
||||
MATRIX_ALLOWED_ROOMS=!ops:matrix.example.org,!dmroom:matrix.example.org
|
||||
```
|
||||
|
||||
Bridge and appservice deployments need extra loop protection. Hermes always
|
||||
ignores its own events, Matrix appservice-style users whose localpart starts
|
||||
with `_`, duplicate event IDs, old startup events, edit replacement events, and
|
||||
`m.notice` events by default. Add deployment-specific bridge ghost patterns when
|
||||
your bridge uses a different naming convention:
|
||||
|
||||
```bash
|
||||
MATRIX_IGNORE_USER_PATTERNS='^@telegram_,^@slack_,^@whatsapp_'
|
||||
```
|
||||
|
||||
Only enable notices when a trusted human workflow really sends `m.notice`:
|
||||
|
||||
```bash
|
||||
MATRIX_PROCESS_NOTICES=true
|
||||
```
|
||||
|
||||
Outbound whole-room notifications are disabled by default. Keep
|
||||
`MATRIX_ALLOW_ROOM_MENTIONS=false` unless the bot is explicitly allowed to wake
|
||||
the whole room with `@room`.
|
||||
|
||||
Diagnostics and debug payloads redact Matrix access tokens, recovery keys,
|
||||
device identifiers, and message bodies. Media downloads are limited to Matrix
|
||||
`mxc://` content URIs and rejected when they exceed `MATRIX_MAX_MEDIA_BYTES`.
|
||||
Treat federated rooms and untrusted homeservers as untrusted input: keep room
|
||||
allowlists tight, prefer DMs or private rooms for tool-heavy work, and avoid
|
||||
authorizing bridge ghosts or appservice puppets as allowed users.
|
||||
|
||||
Optional behavior settings in `~/.hermes/config.yaml`:
|
||||
|
||||
```yaml
|
||||
|
|
@ -268,9 +383,21 @@ sudo dnf install libolm-devel
|
|||
Add to your `~/.hermes/.env`:
|
||||
|
||||
```bash
|
||||
MATRIX_ENCRYPTION=true
|
||||
MATRIX_E2EE_MODE=required
|
||||
```
|
||||
|
||||
`MATRIX_E2EE_MODE` accepts:
|
||||
|
||||
| Mode | Behavior |
|
||||
|------|----------|
|
||||
| `off` | Do not initialize Matrix E2EE. |
|
||||
| `optional` | Try E2EE when dependencies are available, but keep unencrypted rooms working if crypto cannot initialize. |
|
||||
| `required` | Fail closed if E2EE dependencies or crypto setup are not available. |
|
||||
|
||||
Optional mode may fall back to non-E2EE operation when crypto setup is unavailable. Required mode fails closed instead of silently downgrading.
|
||||
|
||||
For backwards compatibility, `MATRIX_ENCRYPTION=true` still enables required E2EE behavior.
|
||||
|
||||
When E2EE is enabled, Hermes:
|
||||
|
||||
- Stores encryption keys in `~/.hermes/platforms/matrix/store/` (legacy installs: `~/.hermes/matrix/store/`)
|
||||
|
|
@ -278,6 +405,65 @@ When E2EE is enabled, Hermes:
|
|||
- Decrypts incoming messages and encrypts outgoing messages automatically
|
||||
- Auto-joins encrypted rooms when invited
|
||||
|
||||
### Matrix Tools and Controls
|
||||
|
||||
In Matrix conversations, Hermes exposes Matrix-specific tools to the agent:
|
||||
|
||||
- `matrix_send_reaction`
|
||||
- `matrix_redact_message`
|
||||
- `matrix_create_room`
|
||||
- `matrix_invite_user`
|
||||
- `matrix_fetch_history`
|
||||
- `matrix_set_presence`
|
||||
|
||||
These tools are scoped to Matrix contexts and are not available in non-Matrix toolsets. Admin-style tools are disabled by default: redaction requires `MATRIX_TOOLS_ALLOW_REDACTION=true`, invites require `MATRIX_TOOLS_ALLOW_INVITES=true`, and room creation requires `MATRIX_TOOLS_ALLOW_ROOM_CREATE=true`. Public room creation also requires `MATRIX_ALLOW_PUBLIC_ROOMS=true`.
|
||||
Matrix tools are limited to the current Matrix room by default. Explicit
|
||||
cross-room targets require `MATRIX_TOOLS_ALLOW_CROSS_ROOM=true`; redaction and
|
||||
invite-like cross-room actions additionally require
|
||||
`MATRIX_TOOLS_ALLOW_CROSS_ROOM_DESTRUCTIVE=true`. If `MATRIX_ALLOWED_ROOMS` is
|
||||
set, Matrix tools may only target those rooms.
|
||||
|
||||
Reaction controls use:
|
||||
|
||||
- ✅ approve once
|
||||
- ♾️ approve always
|
||||
- ❌ deny
|
||||
- number reactions for `/model` choices
|
||||
|
||||
Set `MATRIX_APPROVAL_REQUIRE_SENDER=false` if you intentionally want any authorized Matrix user in the room to operate an approval/model picker prompt. The default is requester-bound when Hermes knows who requested the action.
|
||||
|
||||
### Media Limits
|
||||
|
||||
Hermes uploads and downloads Matrix images, files, audio, and video through Matrix media APIs. Multiple generated images are sent as one ordered logical batch, preserving captions and thread context across the batch.
|
||||
|
||||
By default, Matrix media over 100 MB is rejected before upload/download. Override with:
|
||||
|
||||
```bash
|
||||
MATRIX_MAX_MEDIA_BYTES=104857600
|
||||
```
|
||||
|
||||
Inbound media must use Matrix `mxc://` content URIs. Hermes rejects arbitrary
|
||||
HTTP(S) media URLs in Matrix events to avoid turning a federated room into an
|
||||
unrestricted downloader.
|
||||
|
||||
## Synapse Integration Tests
|
||||
|
||||
Hermes includes an opt-in Synapse harness for local validation:
|
||||
|
||||
```bash
|
||||
docker compose -f tests/e2e/matrix_synapse_gateway/docker-compose.yml up -d
|
||||
HERMES_MATRIX_SYNAPSE_INTEGRATION=1 \
|
||||
scripts/run_tests.sh -m "integration and matrix_synapse" \
|
||||
tests/e2e/matrix_synapse_gateway/test_gateway.py
|
||||
docker compose -f tests/e2e/matrix_synapse_gateway/docker-compose.yml down -v
|
||||
```
|
||||
|
||||
The harness creates temporary users through Synapse shared-secret registration
|
||||
and covers private-room send/receive, named-room invite/join, media
|
||||
upload/download, bot response delivery, and startup old-event filtering. E2EE
|
||||
smoke coverage is separately marked with `matrix_e2ee` so it can stay opt-in on
|
||||
developer machines.
|
||||
|
||||
### Cross-Signing Verification (Recommended)
|
||||
|
||||
If your Matrix account has cross-signing enabled (the default in Element), set the recovery key so the bot can self-sign its device on startup. Without this, other Matrix clients may refuse to share encryption sessions with the bot after a device key rotation.
|
||||
|
|
@ -290,6 +476,11 @@ MATRIX_RECOVERY_KEY=EsT... your recovery key here
|
|||
|
||||
On each startup, if `MATRIX_RECOVERY_KEY` is set, Hermes imports cross-signing keys from the homeserver's secure secret storage and signs the current device. This is idempotent and safe to leave enabled permanently.
|
||||
|
||||
If Hermes bootstraps a new Matrix recovery key, it never logs the raw key. Set
|
||||
`MATRIX_RECOVERY_KEY_OUTPUT_FILE=/secure/path/matrix-recovery-key.txt` before
|
||||
startup to write a generated key once with file mode `0600`; the file is not
|
||||
overwritten if it already exists.
|
||||
|
||||
:::warning[Deleting the crypto store]
|
||||
If you delete `~/.hermes/platforms/matrix/store/crypto.db`, the bot loses its encryption identity. Simply restarting with the same device ID will **not** fully recover — the homeserver still holds one-time keys signed with the old identity key, and peers cannot establish new Olm sessions.
|
||||
|
||||
|
|
@ -406,9 +597,9 @@ such as `!important` remain normal chat messages.
|
|||
|
||||
### Bot is not responding to messages
|
||||
|
||||
**Cause**: The bot hasn't joined the room, or `MATRIX_ALLOWED_USERS` doesn't include your User ID.
|
||||
**Cause**: The bot hasn't joined the room, `MATRIX_ALLOWED_USERS` doesn't include your User ID, `MATRIX_ALLOWED_ROOMS` doesn't include the room, or a room message did not mention the bot.
|
||||
|
||||
**Fix**: Invite the bot to the room — it auto-joins on invite. Verify your User ID is in `MATRIX_ALLOWED_USERS` (use the full `@user:server` format). Restart the gateway.
|
||||
**Fix**: Invite the bot to the room — it auto-joins on invite. Verify your User ID is in `MATRIX_ALLOWED_USERS` (use the full `@user:server` format) and the room ID is in `MATRIX_ALLOWED_ROOMS` if that allowlist is configured. In rooms, mention the bot or add the room to `MATRIX_FREE_RESPONSE_ROOMS`. Restart the gateway.
|
||||
|
||||
### Bot joins rooms but silently drops every message (clock skew)
|
||||
|
||||
|
|
@ -685,6 +876,21 @@ Session continuity is maintained via the `X-Hermes-Session-Id` header. The host'
|
|||
**Limitations (v1):** Tool progress messages from the remote agent are not relayed back — the user sees the streamed final response only, not individual tool calls. Dangerous command approval prompts are handled on the host side, not relayed to the Matrix user. These can be addressed in future updates.
|
||||
:::
|
||||
|
||||
### Bot connects and sends, but ignores inbound messages
|
||||
|
||||
**Cause**: Matrix event handlers only fire when sync payloads are dispatched through
|
||||
mautrix's `handle_sync()` machinery. A raw `client.sync()` poll that never calls
|
||||
`handle_sync()` can leave the adapter connected (send works) while inbound
|
||||
messages never reach `_on_room_message`.
|
||||
|
||||
**Fix**: Hermes uses an explicit sync loop that calls `client.handle_sync()` on
|
||||
both the initial sync and every incremental sync response. This matches the
|
||||
diagnosis in upstream issue #7914 and closed PR #37807, but keeps Hermes's own
|
||||
background maintenance tasks (joined-room tracking, invite handling, E2EE key
|
||||
share) instead of delegating the full lifecycle to `client.start()`. If inbound
|
||||
messages still fail after a gateway restart, verify handlers are registered before
|
||||
the first sync and check logs for `sync event dispatch error`.
|
||||
|
||||
### Sync issues / bot falls behind
|
||||
|
||||
**Cause**: Long-running tool executions can delay the sync loop, or the homeserver is slow.
|
||||
|
|
@ -703,10 +909,22 @@ Session continuity is maintained via the `X-Hermes-Session-Id` header. The host'
|
|||
|
||||
**Fix**: Add your User ID to `MATRIX_ALLOWED_USERS` in `~/.hermes/.env` and restart the gateway. Use the full `@user:server` format.
|
||||
|
||||
### Bot ignores an entire room
|
||||
|
||||
**Cause**: `MATRIX_ALLOWED_ROOMS` is set and the current room ID is not listed, or the room requires a mention and the message did not mention the bot.
|
||||
|
||||
**Fix**: Add the room ID to `MATRIX_ALLOWED_ROOMS`, or remove the room allowlist if this is a personal deployment. To find a Room ID in Element, open room settings and check **Advanced**.
|
||||
|
||||
### Bridge messages loop or echo
|
||||
|
||||
**Cause**: A bridge/appservice puppet is relaying bot output back as a new user message, or a bridge uses non-standard ghost user IDs.
|
||||
|
||||
**Fix**: Keep bridge ghosts out of `MATRIX_ALLOWED_USERS`, add a matching `MATRIX_IGNORE_USER_PATTERNS` entry, and leave `MATRIX_PROCESS_NOTICES=false` unless notices are part of a trusted workflow.
|
||||
|
||||
## Security
|
||||
|
||||
:::warning
|
||||
Always set `MATRIX_ALLOWED_USERS` to restrict who can interact with the bot. Without it, the gateway denies all users by default as a safety measure. Only add User IDs of people you trust — authorized users have full access to the agent's capabilities, including tool use and system access.
|
||||
Always set `MATRIX_ALLOWED_USERS` and, for shared/private deployments, `MATRIX_ALLOWED_ROOMS`. Without them, anyone who can message the bot in a joined room may trigger the agent. Only authorize people and rooms you trust — authorized users have full access to the agent's capabilities, including tool use and system access.
|
||||
:::
|
||||
|
||||
For more information on securing your Hermes Agent deployment, see the [Security Guide](../security.md).
|
||||
|
|
|
|||
|
|
@ -199,6 +199,20 @@ If you want this profile to work in a specific project by default, also set its
|
|||
coder config set terminal.cwd /absolute/path/to/project
|
||||
```
|
||||
|
||||
### From the dashboard
|
||||
|
||||
The [web dashboard](features/web-dashboard.md#managing-multiple-profiles)
|
||||
is a machine-level surface that can manage **any** profile's config, API
|
||||
keys, skills, MCPs, and model via the profile switcher in its sidebar — no
|
||||
per-profile dashboard needed. `coder dashboard` routes to the machine
|
||||
dashboard with the `coder` profile preselected. The dashboard's Chat tab
|
||||
also follows the switcher, spawning a conversation under the selected
|
||||
profile's home.
|
||||
|
||||
Note: "Set as active" on the dashboard's Profiles page is the sticky
|
||||
default for **future CLI/gateway runs** (same as `hermes profile use`) —
|
||||
to edit a profile from the dashboard, use the switcher instead.
|
||||
|
||||
## Updating
|
||||
|
||||
`hermes update` pulls code once (shared) and syncs new bundled skills to **all** profiles automatically:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue