Merge origin/main into bb/gui (2026-05-24)

Bring 313 commits of upstream main into the bb/gui dashboard
refactor branch.  Eight conflicts resolved by hand, the rest
auto-merged.  One missing class (_StreamErrorEvent) restored from
main after the auto-merger dropped it.

Conflict resolutions:

  apps/dashboard/README.md          take HEAD: main's text described
                                    the pre-rename web/ layout that
                                    bb/gui refactored away.

  apps/dashboard/package.json       combine: keep HEAD's @hermes/shared
                                    workspace dep, take main's
                                    @nous-research/ui 0.16.0 bump.

  apps/dashboard/package-lock.json  regenerate via
                                    npm install --package-lock-only.
                                    Root lock also regenerated; only
                                    dashboard and apps/desktop entries
                                    moved (apps/desktop version 0.0.1 →
                                    0.0.2 to match bb/gui's
                                    package.json bump).

  apps/dashboard/src/pages/         take main (4 hunks): text-xs
    EnvPage.tsx                     replaces text-[0.65rem] per the
                                    typography rule HEAD's own README
                                    documents.

  hermes_cli/gateway.py             take main (2 hunks): Discord
                                    setup metadata moved to plugin
                                    (architectural migration); s6
                                    service-manager dispatch helpers
                                    additive.

  hermes_cli/main.py                combine (2 hunks): take main's
                                    Termux-aware
                                    _sync_bundled_skills_for_startup;
                                    combine gui + portal subcommands
                                    in the known-subcommand list.

  hermes_cli/web_server.py          mixed (10 hunks):
                                    - take main on _PUBLIC_API_PATHS
                                      (bb/gui's own test asserts the
                                      rescan endpoint must require auth)
                                    - combine WS helpers: keep HEAD's
                                      _ws_client_label + main's
                                      Host/Origin guard + composing
                                      _ws_request_is_allowed
                                    - take HEAD's debug-level broadcast
                                      drop log (matches the comment
                                      "subscriber went away mid-send")
                                    - take main's _safe_plugin_api_relpath
                                      GHSA-5qr3-c538-wm9j fix and the
                                      paired discovery-time validation
                                    - take main's {name:path} route
                                      converter for plugin visibility

  tui_gateway/server.py             take main: PR #31379's verbose-
                                    args gating supersedes HEAD's
                                    unconditional args dump on
                                    tool.start.

Post-merge restoration:

  run_agent.py                      restored class _StreamErrorEvent
                                    (40 lines, from origin/main:288).
                                    Auto-merge silently dropped it,
                                    breaking imports in
                                    agent/codex_runtime.py and three
                                    test files
                                    (test_codex_xai_oauth_recovery.py,
                                    test_streaming.py).  Restored
                                    verbatim from main.

Sanity checks:

  * git diff --check / --cached --check: clean (no stray markers)
  * ast.parse + import on all touched .py files: clean
  * targeted pytest on resolved files: 756 passed, 1 pre-existing
    Windows-curses failure unrelated to the merge
  * full pytest_parallel run: 105 files / 391 failures vs baseline
    98 files / 346.  Differential vs origin/bb/gui shows all 11
    "new" failure files come from main's added tests/code and
    reproduce identically against origin/main on the same Windows
    host (pure Windows path-separator / perms / git-bash issues
    in upstream tests, not merge regressions).  4 baseline
    failures fixed: 3 in test_codex_xai_oauth_recovery (the
    _StreamErrorEvent restoration), 1 each in test_pairing,
    test_runner_startup_failures, test_stream_consumer.
  * sentinel-token sweep on main's eight largest commits:
    every audited symbol present in the merged tree at expected
    counts (TTSProvider 61, NtfyAdapter 29, S6ServiceManager 70,
    install_bws 12, security_audit 16, register_image_gen_provider
    23, list_profile_gateways 22, DISCORD_FREE_RESPONSE_CHANNELS
    48, …).
  * byte-diff sweep: 30/30 sampled main-only-modified files
    byte-identical to origin/main; the four bb/gui-only files
    that drifted (i18n/types.ts, i18n/ru.ts, ThemeSwitcher.tsx,
    ToolCall.tsx) correctly absorbed main's web/ → apps/dashboard/
    edits through git's rename detection (main's added lines all
    present, removed lines all absent).
This commit is contained in:
Jeffrey Quesnelle
2026-05-25 00:39:46 -04:00
521 changed files with 40613 additions and 3961 deletions
+21 -2
View File
@@ -53,6 +53,7 @@ hermes [global-options] <command> [subcommand/options]
| `hermes webhook` | Manage dynamic webhook subscriptions for event-driven activation. |
| `hermes hooks` | Inspect, approve, or remove shell-script hooks declared in `config.yaml`. |
| `hermes doctor` | Diagnose config and dependency issues. |
| `hermes security audit` | On-demand supply-chain audit (OSV.dev) for the venv, plugin requirements, and pinned MCP servers. |
| `hermes dump` | Copy-pasteable setup summary for support/debugging. |
| `hermes debug` | Debug tools — upload logs and system info for support. |
| `hermes backup` | Back up Hermes home directory to a zip file. |
@@ -68,6 +69,7 @@ hermes [global-options] <command> [subcommand/options]
| `hermes acp` | Run Hermes as an ACP server for editor integration. |
| `hermes mcp` | Manage MCP server configurations and run Hermes as an MCP server. |
| `hermes plugins` | Manage Hermes Agent plugins (install, enable, disable, remove). |
| `hermes portal` | Nous Portal status, subscription link, and Tool Gateway routing. See [Tool Gateway](../user-guide/features/tool-gateway.md). |
| `hermes tools` | Configure enabled tools per platform. |
| `hermes computer-use` | Install or check the cua-driver backend (macOS Computer Use). |
| `hermes sessions` | Browse, export, prune, rename, and delete sessions. |
@@ -137,7 +139,7 @@ Per-run overrides (no mutation to `~/.hermes/config.yaml`):
| Flag | Equivalent env var | Purpose |
|---|---|---|
| `-m` / `--model <model>` | `HERMES_INFERENCE_MODEL` | Override the model for this run |
| `--provider <provider>` | `HERMES_INFERENCE_PROVIDER` | Override the provider for this run |
| `--provider <provider>` | _(none)_ | Override the provider for this run |
```bash
hermes -z "…" --provider openrouter --model openai/gpt-5.5
@@ -257,7 +259,7 @@ the full guide, supported languages, and configuration knobs.
## `hermes setup`
```bash
hermes setup [model|tts|terminal|gateway|tools|agent] [--non-interactive] [--reset] [--quick] [--reconfigure]
hermes setup [model|tts|terminal|gateway|tools|agent] [--non-interactive] [--reset] [--quick] [--reconfigure] [--portal]
```
**First run:** launches the first-time wizard.
@@ -282,6 +284,23 @@ Options:
| `--non-interactive` | Use defaults / environment values without prompts. |
| `--reset` | Reset configuration to defaults before setup. |
| `--reconfigure` | Backwards-compat alias — bare `hermes setup` on an existing install now does this by default. |
| `--portal` | One-shot Nous Portal setup: log in via OAuth, set Nous as the inference provider, and opt into the [Tool Gateway](../user-guide/features/tool-gateway.md). Skips the rest of the wizard. |
## `hermes portal`
```bash
hermes portal [status|open|tools]
```
Inspect Nous Portal auth, Tool Gateway routing, and reach the subscription page. Subcommand-less invocation runs `status`.
| Subcommand | Description |
|------------|-------------|
| `status` (default) | Portal auth state + per-tool Tool Gateway routing summary. Also shown when no subcommand is given. |
| `open` | Open `portal.nousresearch.com/manage-subscription` in your default browser. |
| `tools` | List every Tool Gateway partner (Firecrawl, FAL, OpenAI TTS, Browser Use, Modal) and which are routed via Nous. |
For configuration of the gateway itself, see [Tool Gateway](../user-guide/features/tool-gateway.md). For the one-shot setup path, see `hermes setup --portal` above.
## `hermes whatsapp`
@@ -113,7 +113,6 @@ For native Anthropic auth, Hermes prefers Claude Code's own credential files whe
| Variable | Description |
|----------|-------------|
| `HERMES_INFERENCE_PROVIDER` | Override provider selection: `auto`, `custom`, `openrouter`, `nous`, `openai-codex`, `copilot`, `copilot-acp`, `anthropic`, `huggingface`, `novita`, `gemini`, `zai`, `kimi-coding`, `kimi-coding-cn`, `minimax`, `minimax-cn`, `minimax-oauth` (browser OAuth login — no API key required; see [MiniMax OAuth guide](../guides/minimax-oauth.md)), `kilocode`, `xiaomi`, `arcee`, `gmi`, `stepfun`, `alibaba`, `alibaba-coding-plan` (alias `alibaba_coding`), `deepseek`, `nvidia`, `ollama-cloud`, `xai` (alias `grok`), `xai-oauth` (browser OAuth login for SuperGrok subscribers — no API key required; see [xAI Grok OAuth guide](../guides/xai-grok-oauth.md)), `google-gemini-cli`, `qwen-oauth`, `bedrock`, `opencode-zen`, `opencode-go`, `ai-gateway`, `tencent-tokenhub` (default: `auto`) |
| `HERMES_PORTAL_BASE_URL` | Override Nous Portal URL (for development/testing) |
| `NOUS_INFERENCE_BASE_URL` | Override Nous inference API URL |
| `HERMES_NOUS_MIN_KEY_TTL_SECONDS` | Min agent key TTL before re-mint (default: 1800 = 30min) |
@@ -483,6 +482,24 @@ Used by the bundled LINE platform plugin (`plugins/platforms/line/`). See [Messa
| `LINE_DELIVERED_TEXT` | Reply when an already-delivered postback is tapped again (default: `Already replied ✅`). |
| `LINE_INTERRUPTED_TEXT` | Reply when a `/stop`-orphaned postback button is tapped (default: `Run was interrupted before completion.`). |
### ntfy (push notifications)
[ntfy](https://ntfy.sh/) is a lightweight HTTP-based push notification service. Subscribe to a topic from the [ntfy mobile app](https://ntfy.sh/docs/subscribe/phone/), publish to that topic to talk to the agent.
| Variable | Description |
|----------|-------------|
| `NTFY_TOPIC` | Topic to subscribe to (incoming messages). Required. |
| `NTFY_SERVER_URL` | Server URL (default: `https://ntfy.sh`). Point at a self-hosted ntfy for privacy. |
| `NTFY_TOKEN` | Optional auth token. Bearer token (e.g. `tk_xyz`) or `user:pass` for Basic auth. |
| `NTFY_PUBLISH_TOPIC` | Topic for outgoing replies (defaults to `NTFY_TOPIC`). |
| `NTFY_MARKDOWN` | Set `true` to send replies with `X-Markdown: true` header. Default: `false`. |
| `NTFY_ALLOWED_USERS` | Allowlist (treated as user IDs; on ntfy these are topic names). Typically set to the same value as `NTFY_TOPIC`. |
| `NTFY_ALLOW_ALL_USERS` | Dev-only escape hatch — only safe on access-controlled private topics. Default: `false`. |
| `NTFY_HOME_CHANNEL` | Default delivery target for cron jobs with `deliver: ntfy`. |
| `NTFY_HOME_CHANNEL_NAME` | Human label for the home channel (defaults to the topic name). |
See [the ntfy messaging guide](/docs/user-guide/messaging/ntfy) — particularly the **identity model** section — before deploying with untrusted topics.
### Advanced Messaging Tuning
Advanced per-platform knobs for throttling the outbound message batcher. Most users never need to touch these; defaults are set to respect each platform's rate limits without feeling sluggish.
@@ -542,7 +559,7 @@ Advanced per-platform knobs for throttling the outbound message batcher. Most us
| `HERMES_AGENT_NOTIFY_INTERVAL` | Gateway: interval in seconds between progress notifications on long-running agent turns. |
| `HERMES_CHECKPOINT_TIMEOUT` | Timeout for filesystem checkpoint creation in seconds (default: `30`). |
| `HERMES_EXEC_ASK` | Enable execution approval prompts in gateway mode (`true`/`false`) |
| `HERMES_ENABLE_PROJECT_PLUGINS` | Enable auto-discovery of repo-local plugins from `./.hermes/plugins/` (`true`/`false`, default: `false`) |
| `HERMES_ENABLE_PROJECT_PLUGINS` | Enable auto-discovery of repo-local plugins from `./.hermes/plugins/` for both the agent loader and the dashboard web server. Accepts the standard truthy set: `1` / `true` / `yes` / `on` (case-insensitive). Everything else — including `0`, `false`, `no`, `off`, and the empty string — is treated as **disabled** (default). Note: as of GHSA-5qr3-c538-wm9j (#29156) the dashboard web server refuses to auto-import a project plugin's Python `api` file even when this var is enabled — project plugins may extend the UI via static JS/CSS but their backend routes are only loaded when moved under `~/.hermes/plugins/`. |
| `HERMES_PLUGINS_DEBUG` | `1`/`true` to surface verbose plugin-discovery logs on stderr — directories scanned, manifests parsed, skip reasons, and full tracebacks on parse or `register()` failure. Aimed at plugin authors. |
| `HERMES_BACKGROUND_NOTIFICATIONS` | Background process notification mode in gateway: `all` (default), `result`, `error`, `off` |
| `HERMES_EPHEMERAL_SYSTEM_PROMPT` | Ephemeral system prompt injected at API-call time (never persisted to sessions) |
@@ -571,7 +588,7 @@ Advanced per-platform knobs for throttling the outbound message batcher. Most us
| `HERMES_TUI_DIR` | Path to a prebuilt `ui-tui/` directory (must contain `dist/entry.js` and populated `node_modules`). Used by distros and Nix to skip the first-launch `npm install`. |
| `HERMES_TUI_RESUME` | Resume a specific TUI session by ID on launch. When set, `hermes --tui` skips forging a fresh session and picks up the named session instead — useful for re-attaching after a disconnect or terminal crash. |
| `HERMES_TUI_THEME` | Force the TUI color theme: `light`, `dark`, or a raw 6-character background hex (e.g. `ffffff` or `1a1a2e`). When unset, Hermes auto-detects using `COLORFGBG` and terminal background queries; this variable overrides detection on terminals (Ghostty, Warp, iTerm2, etc.) that don't set `COLORFGBG`. |
| `HERMES_INFERENCE_MODEL` | Force the model for `hermes -z` / `hermes chat` without mutating `config.yaml`. Pairs with `HERMES_INFERENCE_PROVIDER`. Useful for scripted callers (sweeper, CI, batch runners) that need to override the default model per run. |
| `HERMES_INFERENCE_MODEL` | Force the model for `hermes -z` / `hermes chat` without mutating `config.yaml`. Pairs with the `--provider` flag. Useful for scripted callers (sweeper, CI, batch runners) that need to override the default model per run. |
## Session Settings
+3 -1
View File
@@ -36,7 +36,7 @@ Type `/` in the CLI to open the autocomplete menu. Built-in commands are case-in
| Command | Description |
|---------|-------------|
| `/new [name]` (alias: `/reset`) | Start a new session (fresh session ID + history). Optional `[name]` sets the initial session title — e.g. `/new my-experiment` opens a fresh session already titled `my-experiment` so it's easy to find later with `/resume` or `/sessions`. |
| `/new [name]` (alias: `/reset`) | Start a new session (fresh session ID + history). Optional `[name]` sets the initial session title — e.g. `/new my-experiment` opens a fresh session already titled `my-experiment` so it's easy to find later with `/resume` or `/sessions`. Append `now`, `--yes`, or `-y` to skip the confirmation modal — e.g. `/reset now`, `/new --yes my-experiment`. |
| `/clear` | Clear screen and start a new session |
| `/history` | Show conversation history |
| `/save` | Save the current conversation |
@@ -252,4 +252,6 @@ The CLI prompts before running slash commands that throw away unsaved session st
For each of these the CLI opens a three-choice modal: **Approve Once** (proceed this time), **Always Approve** (proceed and persist `approvals.destructive_slash_confirm: false` so future destructive commands run without prompting), or **Cancel**.
**Inline skip:** append `now`, `--yes`, or `-y` to bypass the modal for a single invocation — e.g. `/reset now`, `/new --yes my-session`, `/clear -y`, `/undo -y`. Useful when the modal doesn't render correctly on your terminal (see [issue #30768](https://github.com/NousResearch/hermes-agent/issues/30768) for native Windows PowerShell) or when scripting against the CLI.
Set `approvals.destructive_slash_confirm: false` in `~/.hermes/config.yaml` to disable the prompts globally; set it back to `true` to re-enable. See [Security — Destructive slash command confirmation](../user-guide/security.md#dangerous-command-approval) for context.
+1 -1
View File
@@ -202,7 +202,7 @@ Opt-in toolset (not loaded in the default `hermes-cli` set). Add via `--toolsets
| Tool | Description | Requires environment |
|------|-------------|----------------------|
| `x_search` | Search X (Twitter) posts, profiles, and threads using xAI's built-in `x_search` Responses tool. Use this for current discussion, reactions, or claims on X rather than general web pages. Off by default — opt in via `hermes tools` → 🐦 X (Twitter) Search. Schema is only registered when xAI credentials are configured (check_fn-gated). | XAI_API_KEY **or** xAI Grok OAuth (SuperGrok Subscription) login |
| `x_search` | Search X (Twitter) posts, profiles, and threads using xAI's built-in `x_search` Responses tool. Use this for current discussion, reactions, or claims on X rather than general web pages. Off by default — opt in via `hermes tools` → 🐦 X (Twitter) Search. Schema is only registered when xAI credentials are configured (check_fn-gated). | XAI_API_KEY **or** xAI Grok OAuth (SuperGrok / Premium+) login |
## `tts` toolset