Browse by topic

Hermes yesterday, October 17, 2026: file edits stop waiting on the language server

What landed on Hermes Agent main on October 17, 2026: patch and write_file return in milliseconds, /rollback keeps hand-edits, the gateway boots after a deleted Bot Chat, built-in keys stay off custom endpoints and 33 new catalog plugins.

Rain-soaked neon city title card reading 10 seconds per edit, now 0.06, LSP no longer blocks writes, from the Hermes yesterday motion recap.

A clean TypeScript edit used to wait 10 seconds on the language server. On main it now takes about 0.06, and the model still sees its type errors. The rest of the day went to fixes: rollbacks that wiped your hand-edits, a gateway that stopped booting a week after you deleted a Bot Chat, and a built-in API key sent to a custom endpoint with the same name. 568 commits landed on main; here are the 10 that matter.

1. patch and write_file return in milliseconds

Before: with LSP on (the default), every patch or write_file waited on the language server twice, up to lsp.wait_timeout (5 s) each; typescript-language-server sends nothing for a clean file, so a clean .ts edit took 10.1 s and a patch to a 16k-line Python file 2.9 s. After: the write no longer waits on the server, and the same edits take about 0.06 s and 0.09 s. A warm TypeScript or pyright verdict still comes back inside the edit’s own result; a slower one rides the next tool result, and if the model tries to finish while checks are still running, Hermes waits up to 5 s and hands it the errors so it can fix them in the same turn, one-shot hermes chat -q included. Not covered: a verdict slower than 5 s at the end of a turn (a cold project still loading) waits for your next message, so a one-shot run misses it; only typescript-language-server gets the fast synchronous check (vue, eslint and other push-only servers keep waiting for a push); remote backends (Docker, SSH, Modal) keep the slower shell write path.

Pull request: LSP edits.

2. /rollback keeps your hand-edits, and hermes -z prints its answer again

Before: since the one-gateway change, a whole-tree /rollback from the TUI, Desktop or the classic CLI attached to the gateway reverted files you had edited by hand after Hermes’ last write, although the help says restores keep hand-edits, and Ink sent --all as a file path. hermes -z with gateway streaming on printed a blank line and exited 1 while the answer sat in state.db. /memory approve, reject and the other review commands were refused on local and Desktop sessions, and Desktop’s one-shot helpers (commit messages, summaries, plugins) ran on the profile’s default model instead of the chat’s. After: a whole-tree restore keeps hand-edits unless you pass --all (or --force) and lists what it left alone; -z prints the reply, and a textless exit says so on stderr; the /memory review commands work locally again; Desktop one-shots borrow the chat’s model. Not covered: when too many one-shots pile up, Desktop shows the new busy refusal as a generic failure.

Pull request: Commands on the gateway.

3. The gateway starts again a week after you delete a Bot Chat

Before: about 7 days after you deleted a Bot Chat that had received a bot delivery, its cleanup records expired and every gateway start aborted with storage_unavailable; the service manager restarted it into the same failure, and on a gateway serving several profiles all of them went down. After: Hermes keeps the deletion marker for good, a delivery receipt whose session is gone settles without being resent, a receipt the store cannot answer is logged and skipped, and a secondary profile whose startup recovery still fails is parked while the others start. A parked profile is temporarily unavailable, not gone: relay and webhook traffic to it is retried, and a message a shared bot routes to it gets an in-chat notice asking to resend in a moment. Who gets it: a failure in the launch profile’s own recovery still stops the start; a parked profile comes back with a rescan or hermes -p <name> gateway run. The same expiry made a Responses Idempotency-Key for a deleted session answer 503 forever; it now gets a 409.

Pull request: Gateway boot after a Bot Chat delete.

4. A built-in’s API key stays off a custom endpoint with the same name

Before: a providers: entry keyed like a built-in (providers.deepseek with its own key_env) sent the built-in’s DEEPSEEK_API_KEY to the entry’s endpoint whenever both variables were set, also on a bare custom route to that URL, after a fallback restored the primary, in a delegated child and in auxiliary calls such as session titles; seen on v0.22.1 and main. After: an entry that declares a credential (api_key, key_env or key_cmd) uses only its own key or keys you added with hermes auth add, and a placeholder api_key no longer hides a working key_env. In a profile that holds such a custom:deepseek entry, a bare deepseek pick now goes to the entry; pick the built-in from another profile. Behavior change: an entry whose declared credential is unset now sends the no-key-required placeholder instead of the host’s env key (providers.work on api.openai.com with an empty key_env no longer sends OPENAI_API_KEY). Not covered: an entry that declares no credential still gets the built-in’s env key on any host; that follow-up is tracked in issue #140297.

Pull requests: Key ownership, Bare pick goes to the entry, Follow-ups.

5. Idle profiles and older sessions open again

Before: the one-gateway change added session tables without bumping the schema version, so a profile whose state.db had not been opened for writing since (any idle profile with no gateway running) lost its whole session list: every surface answered 503 schema is unavailable or corrupt, although the sessions were still on disk. A local session from 0.22.1 that 0.22.2 had compacted was refused on every resume, and a pre-upgrade session whose custom endpoint had since moved in config.yaml looped on Provider temporarily unavailable, retrying the old URL. After: browsing such a profile adds the missing tables and columns once (additive only, after an integrity check), or, when a gateway owns that store, answers a 503 that names the drift and the restart command; the compacted 0.22.1 session reopens on its compressed tip, also from the short local- id the TUI prints at exit; the moved-endpoint session resumes on the profile’s current route. Not covered: a model picked under 0.22.2 in a session created under 0.22.1 goes back to the 0.22.1 pick on main; re-pick it with /model.

Pull requests: Session list schema catch-up, 0.22.1 sessions compacted by 0.22.2, Moved custom endpoint.

6. Background processes stop wasting turns

Before: a foreground terminal command ending in a lone & (python3 -m http.server 8765 &) was refused with Re-send WITHOUT the &, costing a model turn each time (488 such refusals in one user’s month); models re-issued identical process_manage wait or poll calls on a quiet process (about 1,900 of 2,235 waits in one heavy user’s month repeated the previous call); and heartbeat ticks from terminal(background=true, heartbeat=N) were refused, so the agent heard nothing until the job ended. After: a single trailing & runs as a tracked background process through the same approval checks; after the second unchanged wait or poll, Hermes turns on notify_on_complete and tells the model to stop checking, so the exit arrives as its own message; heartbeats reach every chat again, with one waiting tick per process. Who gets it: inline a & b, ; sequences, multi-line scripts and nohup, disown or setsid stay refused; finite turns (chat -q, -z), cron, Kanban workers, API sessions and subagents keep the old wait results; terminal.process_wait_auto_notify: false turns the new wait behavior off.

Pull requests: Trailing &, Quiet waits, Heartbeats.

7. Reasoning shows up again in Ink, Desktop and editors

Before: since the one-gateway change, Ink and Desktop got no live reasoning unless a viewer set a session flag (only the classic CLI did), Ink’s reasoning panel stayed empty after a turn, and with display.show_reasoning on, every reply started with the messaging platforms’ Reasoning block. ACP editors lost live thought chunks, the plan, failed tool states and remote images, which reached the model as a text note. After: Ink and Desktop stream reasoning by default again, following display.show_reasoning (on by default), and /reasoning show or hide applies mid-turn; their replies are the answer alone. ACP editors get live reasoning as thought chunks, the plan, tool calls that close as failed when they fail, and remote image URLs fetched as images. Heads-up: ACP replies still carry the reasoning block for now.

Pull requests: Ink and Desktop, ACP editors.

8. LM Studio, Kimi and MiniMax tool calls stop shattering

Before: some OpenAI-compatible servers send a fresh id on every streamed fragment of one tool call (LM Studio and Kimi without the name, some MiniMax routes with the name repeated); Hermes read each fragment as a new call, so one call broke into a pile of empty ones and nothing ran (issue #5254). After: a fresh id opens a new call only when it names a different tool or the previous call’s arguments are complete, so these streams give one runnable call, while Ollama’s parallel calls, including two of the same tool, still split. Relay shares the fix.

Pull request: Streamed tool calls.

9. Memory providers stay inside their own profile

Before: on a gateway serving several profiles in one process, a memory tool call or hook from another profile’s context, or from one that named no profile, could reach a profile’s memory provider, one provider instance could be shared between profiles, and ByteRover and RetainDB bound their store from the process’s home. After: a provider answers only calls that explicitly name the profile it was set up for, anything else is refused with a pointer to hermes logs errors, a shared instance is dropped for the second profile with a startup warning, and ByteRover and RetainDB bind to their own profile. Not covered: core cannot see inside an external provider; one that keeps process-wide state can still mix profiles’ memories (the rules it must follow are now in the memory-provider plugin guide).

Pull request: Memory profile isolation.

10. 33 new plugins in the catalog, and X Chat is official

33 new entries, and Desktop add-ons were the day’s theme. xchat is official tier: talk to Hermes in X’s end-to-end encrypted DMs, installed with hermes plugins install xchat (Hermes 0.21.5 or later). The other 32 are community tier; several disclose that they run a local server, call a hosted service or, for pay and pay-cli, pay per request in stablecoins: read the disclosure before installing. Catalog entries do not wait for a release: they go live once the published catalog refreshes.

Meanwhile, in the engine room

Dozens of fixes landed yesterday that most users will never see, and most of them went to the shared gateway: sessions, queues and receipts that survive upgrades, deletes and restarts.

  • Background one-shot calls (compression summaries, session titles, the /moa synthesis) no longer pay for a prompt-cache write nobody reads back (pull request).
  • Ctrl+D in the classic CLI attached to the gateway now detaches and lets the running turn finish instead of interrupting its tool; Ctrl+C still interrupts (pull request).
  • A skill installed from another terminal shows up as an Ink /command without /reload-skills, and Desktop and the TUI can answer a hermes chat turn’s multi-question clarify instead of waiting out the timeout (pull request).
  • On Windows, folders an elevated Hermes creates (an admin hermes update, a gateway started from an admin prompt) stay usable by your normal account, and those grants never follow a junction out of the Hermes home; not yet retested on real Windows (pull request).

If you noticed none of this, it worked.

All on main, ships in the next release. Latest stable: v0.22.2.

Watch the recap

The 56-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