Browse by topic

Hermes yesterday, October 16, 2026: Hermes stops deleting your old sessions

What landed on Hermes Agent main on October 16, 2026: session auto-prune is opt-in again, API keys stay with their own endpoint, disabled plugins really stop, fewer execute_code prompts, mid-turn model picks and 30 new catalog plugins.

Neon grid title card reading Hermes stops deleting old chats, auto-prune is opt-in again, from the Hermes yesterday motion recap.

Heads-up, Hermes stops deleting your old sessions by default. Auto-prune is opt-in again on main, and Hermes asks once when the disk runs low. The rest of the day went to the one-gateway runtime that landed on Wednesday: API keys that went to the wrong host, plugins that outlived their disable, and approvals that asked too often. 696 commits landed on main; here are the 10 that matter.

1. Hermes stops deleting old sessions unless you say so

Before: with sessions.auto_prune on by default, Hermes quietly deleted ended sessions older than retention_days (90 by default) from state.db. After: auto-prune is off by default again. While your config.yaml has no sessions.auto_prune key, Hermes asks once when the disk holding state.db runs low (under 2 GiB free, or under 10% free with less than 20 GiB left): a y/n question at classic CLI startup, one notice in the TUI and Desktop, and a message on each served profile’s home channel for the messaging gateway. /autoprune on|off|later|status answers it everywhere (on Slack, /hermes autoprune); on or off saves the key for good, later asks again in a week. The question estimates what pruning would free and says plainly when it would not fix the disk. Who gets it: auto_prune: true keeps pruning, false keeps everything and is never asked, and a value your administrator manages is never asked about. After a prune, the state.db file shrinks only at the next VACUUM. Heads-up: v0.22.2 still prunes by default until the next release.

Pull request: Auto-prune opt-in.

2. API keys stay with their own endpoint

Before, on main: a --provider pick without a base_url kept the profile’s endpoint, so the new provider’s key went to the old provider’s host; Desktop onboarding’s provider: auto with an OpenRouter base_url sent the Google key to OpenRouter; a model pick in a Bot Chat whose profile had moved checked the new key against the old endpoint; a pre-0.22.1 session resumed after the upgrade lost its saved route and got HTTP 404 on every turn, aimed at the profile’s server with the profile’s key; and changing any secret in config.yaml, even an unrelated MCP token, broke every older session after a restart with a generic error. After: a provider pick drops the replaced provider’s endpoint and key settings (an explicit base_url in the same request still wins); endpoint and key move together on every pick, or the pick is refused by name; adopted older sessions keep their saved route and never borrow the profile’s key; and a changed secret stops only the sessions whose route uses it, naming it (providers.left.api_key: changed in config.yaml since this session started). Not covered: a stale model.key_env sending an old key to NVIDIA NIM predates these changes and is left for a follow-up.

Pull requests: Provider pick drops the old endpoint, Endpoint and key together, Older sessions keep their route, Changed secrets.

3. Disabled plugins really stop, websockets included

Before: on the shared gateway, a plugin disabled while it ran kept accepting new websocket connections until a restart, and a secondary profile could still reach a plugin the launch profile had disabled. hermes plugins disable said Takes effect on next session while the gateway kept the plugin’s hooks, commands and tools. Classic CLI plugin commands ran in a second copy of the plugin, so ctx.call_mcp failed with MCP server not connected, and pre_gateway_dispatch fired twice for every message from a messaging platform. After: one gate covers HTTP, websockets, assets and the plugin list, and a secondary profile’s own dashboard plugins run in its own plugin host; disable unloads the plugin from the running gateway and says what happened; CLI plugin commands run in the gateway; pre_gateway_dispatch fires once per message, and pre_command fires in the gateway for the commands local clients send. Not covered: callbacks a plugin already wired into a platform adapter keep running until hermes gateway restart, Desktop’s own pickers and several TUI commands do not fire pre_command yet, and project plugins in ./.hermes/plugins still do not load (you now get a warning).

Pull requests: Websocket and profile gate, CLI commands and live disable, Hooks once per message, pre_command in the gateway, Secondary profile plugin host.

4. execute_code stops asking for the whole script in your own turns

Before: since the one-gateway change, approvals.mode: manual raised a whole-script approval on every execute_code call in classic CLI, TUI, Desktop and ACP sessions, which the classic CLI and ACP never did before. After: a turn you typed, with a window that can approve attached, skips the whole-script prompt, and each dangerous terminal() command inside the script still asks on your prompt; smart mode likewise drops its whole-script check there. Everything else keeps the gate: plugin-injected turns, /loop ticks, delegation and background completions, heartbeats, delegated children, side tasks, turns that run after you detached, messaging, API and cron. Heads-up: as in the classic CLI before the one-gateway change, Python code in the script that deletes or runs things without terminal() (shutil.rmtree, subprocess) is not prompted in your own turns.

Pull request: execute_code approval.

5. A model pick made mid-turn applies to the next turn

Before, on main: a model, provider or reasoning pick in Desktop while a turn ran was refused as session_busy and Desktop showed nothing; reasoning changes failed over and over with stale_generation; a typed /model in the TUI was announced but never reached a request, and its picker failed whenever a reasoning row was picked; and on a gateway serving several profiles, a secondary profile’s Desktop pick was ignored until a restart. After: the running turn keeps its model, the pick is saved (it survives a restart) and applied when the next turn starts, and Desktop says the model applies from your next message, or names why the pick was refused. Not covered: /model --once on a local session is refused by name, and session info shows the old model until the next turn starts.

Pull requests: Mid-turn pick, TUI /model and reasoning, Secondary profile pick.

6. Your tools run with your shell’s toolchain again

Before: with one gateway running every session, terminal commands, background processes and execute_code started from the classic CLI or TUI used the gateway’s environment, so python and node resolved to whatever the gateway started with instead of your activated venv or nvm; and HERMES_EPHEMERAL_SYSTEM_PROMPT, HERMES_PREFILL_MESSAGES_FILE and HERMES_INFERENCE_PROVIDER from whichever client started the gateway applied to every session, messaging and cron included. After: the CLI and TUI send an allowlisted toolchain (PATH, VIRTUAL_ENV, CONDA_*, NODE_*, NVM_*, PYENV_*, GOPATH, CARGO_HOME, JAVA_HOME and more, plus names in the new terminal.client_env_passthrough), applied to that session’s tools only and only when the client is proven to run on the same machine; the HERMES_* values apply to their own session; credential-looking names are never sent or stored. Not covered: Desktop, messaging and cron keep the gateway’s environment, a login shell’s .bash_profile still runs over it, and when the gateway cannot find hermes on its own PATH, Hermes’s bin folder can land ahead of yours.

Pull request: Client toolchain.

7. Exit and /new end a session’s delegations

Before: once the CLI and TUI became viewers of a session on the gateway, async delegations kept running after you left, and their completions and background-process notices started model turns nobody watched. After: when the last viewer exits, runs /new or switches with resume, the gateway interrupts that session’s own delegations at once and refuses new ones until a viewer comes back; a completion that reaches the queue with nobody attached is written into the session as a note the next turn reads, with no model call; with a viewer attached it runs as a turn, as before. A plain detach (closing Desktop, a dropped connection) cancels nothing. Not covered: background processes keep running after exit, as they always did.

Pull request: Delegations on exit.

8. Follow-up questions about a photo see the photo again

Before: the session database stores each image as a [screenshot] line, so every turn rebuilt from it (API-server sessions continued with X-Hermes-Session-Id, hermes chat --resume, a gateway restart) sent the model that placeholder, and a question about the photo you sent one message earlier got a guess. After: when the model takes images natively, Hermes re-attaches the newest images (vision.replay_recent_images, default 3, 0 turns it off) from the copy it already keeps, byte-identical to the original, so the prompt cache still hits. Not covered: on the gateway, the kept copy of a chat image is removed after 24 hours, so a follow-up a day later sees [screenshot] again; images attached through the legacy TUI sidecar and remote image URLs stay text.

Pull request: Image replay.

9. Fresh Macs install Hermes again

Before: on a Mac without Apple’s Command Line Tools, /usr/bin/git is a stub, so the installer printed prerequisites ok and then died at the clone with git clone failed ... see man xcode-select (reported from a live workshop). After: the installer checks that git actually runs; it installs git with Homebrew when present, otherwise opens Apple’s Command Line Tools dialog, waits up to 15 minutes and continues the install in the same run. Hermes-Setup waits too, a plain --non-interactive run fails at once with the remedy, and a Mac whose developer tools exist but are broken gets git’s own error. Already live: the curl one-liner serves the installer from main.

Pull request: macOS installer.

10. 30 new plugins in the catalog, and a new Verified tier

30 new entries, all community tier, and model providers were the day’s theme. Heads-up: the catalog gained a third tier, verified, for plugins made by the company behind the product they integrate, granted only by Nous; none of these 30 carries it. Several entries disclose that they run a local server, install a CLI or send data to a hosted service: read the disclosure before installing. Catalog entries do not wait for a release: they go live once the published catalog refreshes.

Pull request: Verified tier.

Meanwhile, in the engine room

Dozens of fixes landed yesterday that most users will never see, and most of them went to the one-gateway runtime: sessions that resume, restart and queue the way separate processes used to.

  • Messages queued behind a turn that ran out of context now run, in order, on the fresh session the auto-reset creates, instead of staying stuck on the old one (pull request, queued /queue turns and compression deadline).
  • Resuming a chat re-reads its config, so hermes tools disable web followed by hermes -c no longer offers web tools, and a newly added MCP server reaches it (pull request).
  • Oversized tool results saved to disk are kept for the session retention window instead of 24 hours, so a session resumed the next day can still read them (pull request).
  • 19 Dependabot alerts cleared, including critical PyJWT, shell-quote and proxy-addr bumps (pull request).

If you noticed none of this, it worked.

All on main, ships in the next release; the macOS installer fix is already live on the one-liner. Latest stable: v0.22.2.

Watch the recap

The 52-second motion recap, made with Remotion, is on X.

Was this configuration guide helpful?

If you have questions, encountered issues during setup, or want to discuss networking and security, connect or reach out on LinkedIn.

Connect on LinkedIn