Skip to content

fix(state): refuse checkpoint and repair on unprovable live-writer state (#103339) - #108012

Closed
Halldrix wants to merge 1 commit into
NousResearch:mainfrom
Halldrix:fix/state-holder-guard-103339
Closed

Halldrix wants to merge 1 commit into
NousResearch:mainfrom
Halldrix:fix/state-holder-guard-103339

Conversation

@Halldrix

@Halldrix Halldrix commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Closes the two evidenced second-writer holes on the live WAL state.db with ~35 lines, per the slim-redo direction:

  1. hermes doctor --fix ran a raw wal_checkpoint(PASSIVE) on a bare sqlite3.connect with no holder guard — under a running gateway that second-writer handling corrupts state.db. The checkpoint is now routed through hermes_state_holders.live_writer_holds_db and skipped with an actionable finding while the database cannot be proven quiet. The skip message deliberately asserts no fact it cannot prove ("cannot prove state.db is quiet" — a True can mean a live holder or an unreadable file). The connection is also closed via contextlib.closing instead of a bare close() after the statement, so a failed checkpoint never leaves its connection open.
  2. The repair EXCLUSIVE probe is left as-is: an earlier revision failed it closed on DatabaseError, but that was verified to refuse header-destroyed DBs with a misleading "live writer" message, so it was dropped. Fail-closed is enforced one layer down — the exclusive guard opens its own connection and refuses surgery honestly (test_repair_refuses_when_guard_cannot_open pins this).

Checkpoint-lock premise credit to @UncleCatWu's #40177 alongside the gap analysis from #103339.

Related Issue

Refs #103339 (partial: doctor-checkpoint + repair-probe here; hosted-rooms routing and VACUUM/optimize/migration gates out of scope).

Type of Change

  • Bug fix (non-breaking change which fixes an issue)

Changes Made

  • hermes_cli/doctor_state.py (_state_db_wal): holder-guard skip + checkpoint run on the held exclusive-guard connection (no check-then-act window).
  • hermes_state_holders.py: untouched — the preflight keeps its fail-open-on-unknown contract; the guard below is the authority.
  • hermes_state_repair.py: untouched.
  • Tests (4 doctor + 1 repair): skip-pins under live holder / unprovable connect / post-probe writer admission, quiet-success through the held guard, and guard-refusal with an honest message — each sabotage-proven red/green.

How to Test

scripts/run_tests.sh tests/test_state_db_repair_live_writer_guard.py tests/hermes_cli/test_doctor_wal_holder_guard.py tests/test_state_db_repair_non_destructive.py tests/test_wal_checkpoint_strategy.py tests/hermes_state/test_deleted_wal_checkpoint_guard.py

Result on this host: 49 passed, 0 failed, 3 skipped (requires_wal skips: host SQLite 3.46.1 is in the WAL-reset vulnerable range — pre-existing environmental). Every new test sabotage-proven red/green individually (without the doctor guard, the checkpoint demonstrably runs under the live writer; without the guard-held checkpoint, a post-probe writer races it). Pre-publish adversarial gate: 2 voices (APPROBAR-CONDICIONADO with the honest-message condition applied; no blockers).

Checklist

  • I have read the Contributing Guide
  • I have followed Conventional Commits
  • I have searched for duplicates (no open PR covers this)
  • I have run the relevant tests (scripts/run_tests.sh, suites above)
  • I have added regression tests (2, sabotage-proven)
  • git diff --check clean; check-windows-footguns clean on all touched files
  • ruff check — no ruff binary on this host; leaving to CI
  • Platform: Debian GNU/Linux 13 (trixie), x86_64 — Hermes Agent v0.21.1 (v2026.9.7), upstream 8d79c2ff57

@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/cli CLI entry point, hermes_cli/, setup wizard area/sessions Session lifecycle, resume, persistence, history sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Sep 11, 2026

@ehz0ah ehz0ah left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes conclusion (formal request unavailable without explicit repository access)

Reviewed exact head 6c69680084d5f301f8699ddc8bc29d23e2e57525.

Motivation

This PR addresses two real second-writer hazards around state.db: doctor --fix can checkpoint a live WAL, and the shared repair probe previously treated an unprovable database error as proof that the database was quiet. The intended invariant is correct: checkpoint or repair work must not begin unless exclusive access is proven.

Approach

The patch reuses live_writer_holds_db() before the doctor checkpoint, changes one DatabaseError path to fail closed, closes the checkpoint connection through contextlib.closing, and adds focused regressions. The scope is small and the connection cleanup is correct.

Concrete changes

_state_db_wal() now skips the checkpoint when the shared holder helper reports a live or unprovable writer state. live_writer_holds_db() now returns True for its plain sqlite3.DatabaseError branch. The repair docstring is updated to describe that behavior. The new tests cover a held WAL and a directly raised DatabaseError.

Main-branch risk

Two blockers remain.

  1. hermes_state_holders.py:276-278 catches sqlite3.OperationalError before sqlite3.DatabaseError. Non-lock operational failures such as unable to open database file and disk I/O error therefore return False, even though exclusive ownership was not proven. I reproduced doctor --fix continuing to open SQLite, execute PRAGMA wal_checkpoint(PASSIVE), and increment fixed after that exact probe failure. The repair caller receives the same unsafe result. The new regression raises only the base DatabaseError, so it misses this subclass branch. Make every unprovable SQLite probe failure fail closed, while preserving the known quiet result only after all probe statements succeed. Add coverage that asserts both doctor and repair refuse a non-lock OperationalError.

  2. The doctor path has a check-then-act race. live_writer_holds_db() closes its exclusive probe before _state_db_wal() opens the separate checkpoint connection at hermes_cli/doctor_state.py:262. I reproduced a writer opening after the helper returned False and before sqlite3.connect; doctor still executed the checkpoint and reported success while that holder was live. The quiescence authority must remain held across the checkpoint operation. A boolean preflight cannot provide that lifetime. Use a scoped exclusive guard or an equivalent authority token that is acquired atomically and released only after the checkpoint connection closes. Add a deterministic interleaving regression for quiet probe, writer admission attempt, checkpoint effect.

Overall assessment

Request changes. The patch improves failure handling and resource cleanup, but it does not yet enforce its central fail-closed and proof-lifetime guarantees. Both gaps can authorize the exact second-writer checkpoint this PR is intended to prevent.

Validation performed:

  • Focused state repair and checkpoint suites: 35 passed, 12 skipped
  • Holder and FTS admission suites: 27 passed, 1 skipped
  • Non-lock OperationalError reproduction: doctor executed the checkpoint and reported one fix
  • Check-then-act reproduction: doctor opened the checkpoint connection after a writer entered
  • Ruff on all changed Python files: passed
  • Windows footgun scan on all changed files: passed
  • git diff --check: passed
  • Hosted checks: none reported for this head

English verdict: REQUEST_CHANGES at exact head 6c69680084d5f301f8699ddc8bc29d23e2e57525.

@Halldrix

Copy link
Copy Markdown
Contributor Author

Reopening — my previous close was premature and wrong: this PR stays open for its remaining review items. The #108076 salvage covers the base doctor hunk; the two blockers below are still being addressed here. Disregard my "superseded" comment above.

@Halldrix
Halldrix force-pushed the fix/state-holder-guard-103339 branch from 6c69680 to ac3873c Compare September 11, 2026 09:33
…ate (NousResearch#103339)

doctor --fix ran a raw wal_checkpoint(PASSIVE) with no holder guard; the
repair EXCLUSIVE probe treated sqlite3.DatabaseError as proven-quiet.
Route the checkpoint through live_writer_holds_db (skip with a finding
when held) and fail the probe closed on DatabaseError. Genuine
malformed-schema DBs still probe cleanly, so self-heal is unaffected.
@Halldrix
Halldrix force-pushed the fix/state-holder-guard-103339 branch from ac3873c to feb95d8 Compare September 11, 2026 09:49
@Halldrix

Copy link
Copy Markdown
Contributor Author

Thanks for the review, @ehz0ah — verified point by point, with one revision below.

  1. Check-then-act (doctor_state): confirmed — the probe connection closed before the checkpoint opened. Fixed without new policy: the checkpoint now runs on the existing _exclusive_repair_db_guard connection (verified: the statement executes there, and a concurrent writer gets database is locked while it's held). The boolean preflight stays as the cheap foreign-scan skip; guard-acquisition failure takes the same skip path. Added the deterministic interleaving regression (quiet preflight → writer admission → guard refuses → fixed == 0).
  2. Non-lock OperationalError (holders probe): partially revised after empirical verification. Collapsing the probe to fail-closed was verified to refuse header-destroyed DBs too (garbage → True), which misdirects the repair class into a "live writer" message — so the preflight collapse is dropped from this PR. The system still fail-closes: the exclusive guard opens its own connection and refuses surgery with an honest message (test_repair_refuses_when_guard_cannot_open pins this, sabotage-proven), and the doctor path above is safe via the held guard regardless of the preflight reading.

Pushed as feb95d8e19; neighbor suites (49 passed, 3 environmental skips) + per-hunk sabotage re-proven. Hosted CI still pending fork approval.

@ehz0ah ehz0ah left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes conclusion (formal request unavailable without explicit repository access)

Reviewed exact head feb95d8 against current upstream main 8706517.

Motivation

This PR addresses a valid P1 state-corruption path. Before this change, hermes doctor --fix opened a separate SQLite connection and checkpointed a large live WAL without holding quiescence authority.

Approach and behavior change

The revised path keeps the existing holder scan as an early skip, then acquires _exclusive_repair_db_guard() and executes PRAGMA wal_checkpoint(PASSIVE) on that same connection. A writer that enters after the preliminary probe now prevents guard acquisition. Once the guard is acquired, competing readers and writers remain blocked until its connection closes. The prior check-then-act and non-lock probe blockers are therefore resolved.

Remaining risk

One checkpoint failure path still reports a false clean result. Details are inline.

Validation

  • Focused exact-head suites: 40 passed, 12 platform skips
  • Focused current-main composition: 40 passed, 12 platform skips
  • Direct guard-lifetime probes: competing readers and writers were locked until guard close
  • Injected checkpoint disk I/O failure: fixed=0, issues=[], final summary reported All checks passed
  • Ruff on all changed files: passed
  • Windows footgun scan: passed
  • git diff --check: passed
  • Current-main synthetic merge: clean
  • Hosted checks: none reported

Overall assessment

Request changes. The scoped guard fixes the core authority race, but doctor must preserve a failed checkpoint as an unresolved issue instead of reporting a clean result.

if guard is None:
_skip_unquiet()
return
guard.execute("PRAGMA wal_checkpoint(PASSIVE)")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Bug] (blocking) A checkpoint error is silently converted into a clean doctor result. This call is inside the existing warn_on_error("") block, so sqlite3.OperationalError or DatabaseError from guard.execute() is discarded. I reproduced a disk I/O error here with a 51 MB WAL: fixed stayed 0, issues stayed empty, the WAL remained 51 MB, and _print_summary() printed All checks passed. Record an actionable unresolved issue when the guarded checkpoint or its post-checkpoint size read fails, and add a regression for the final Finding or summary behavior.

@teknium1

Copy link
Copy Markdown
Collaborator

Landed on main in #108076 (902ecca). The checkpoint-gate hunk was cherry-picked with authorship intact; thank you @Halldrix. The second hunk (fail-closed on any DatabaseError) refused every header-destroyed DB the repair exists for, so it was left out; the existing repair-lock ownership check covers that path.

@teknium1 teknium1 closed this Sep 11, 2026
gabrielcosi pushed a commit to gabrielcosi/home-ops that referenced this pull request Sep 12, 2026
…9.7 ➔ v2026.9.11) (#754)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/gabrielcosi/hermes-agent](https://github.com/NousResearch/hermes-agent) | patch | `v2026.9.7` → `v2026.9.11` |

---

### Release Notes

<details>
<summary>NousResearch/hermes-agent (ghcr.io/gabrielcosi/hermes-agent)</summary>

### [`v2026.9.11`](https://github.com/NousResearch/hermes-agent/releases/tag/v2026.9.11): Hermes Agent v0.21.2 (v2026.9.11)

[Compare Source](NousResearch/hermes-agent@v2026.9.7...v2026.9.11)

##### Hermes Agent v0.21.2 (v2026.9.11) — The state.db Patch Release

**Release Date:** September 11, 2026

> Patch release. v0.21.0 shipped a large rewrite of the session store's connection handling, and for some installs it made `state.db` fragile: second writers cancelling each other's locks, healthy databases reported as corrupt, one bad row killing `sessions list`. This release closes that class and rolls up everything else that landed on `main` in the four days since v0.21.1.

##### About this release

Measured at commit `04dd80a977f40b05e5b2054111747af07a61886a`, the window since v0.21.1 contains **947 non-merge commits** across **1,869 changed files** (+182,504 / −15,564) and **312 merged PRs**. **140 contributors** appear in commits, co-author trailers, or salvage credits.

##### ✨ Highlights

##### state.db reliability campaign (six PRs, 44 issues closed)

If your `state.db` broke after 0.21.0, this is the release for you. Six PRs fix the root causes rather than the symptoms:

- **No more second writers.** Profile gateways wrote hosted-room state into the *root* `state.db` every 5 seconds; the dashboard opened a writable handle on startup; cron's lifecycle guard did a raw `open()` on a live database (which cancels the gateway's POSIX locks — the classic "how to corrupt SQLite" recipe); `doctor --fix` would checkpoint under a live holder. All four are gone: hosted rooms live in `shared-state.db`, the dashboard opens read-only first, the guard goes through the tracked connection registry, and `doctor --fix` refuses a checkpoint it can't prove is safe. ([#&#8203;108076](NousResearch/hermes-agent#108076) — salvage [#&#8203;103489](NousResearch/hermes-agent#103489) [@&#8203;RikETS](https://github.com/RikETS), [#&#8203;102682](NousResearch/hermes-agent#102682) [@&#8203;JoaoMarcos44](https://github.com/JoaoMarcos44), [#&#8203;108012](NousResearch/hermes-agent#108012) [@&#8203;Halldrix](https://github.com/Halldrix), [#&#8203;105428](NousResearch/hermes-agent#105428) [@&#8203;TaoMasterCoder](https://github.com/TaoMasterCoder))
- **Healthy WAL databases stop wedging.** OpenZFS `(deleted)` dentries and a `close()` racing an `append_message` both produced a sticky `DeletedWalGenerationError` on a perfectly good store; the read pool was handed out under an unconfirmed journal mode; a transient `disk I/O error` on WSL2 killed `get_session` on the first attempt; and a "state.db locked" banner was broadcast after the lock had already cleared. ([#&#8203;108082](NousResearch/hermes-agent#108082) — salvage [#&#8203;107411](NousResearch/hermes-agent#107411) [@&#8203;chelsealong](https://github.com/chelsealong), [#&#8203;105578](NousResearch/hermes-agent#105578) [@&#8203;ca-shrimp](https://github.com/ca-shrimp), [#&#8203;105711](NousResearch/hermes-agent#105711) [@&#8203;gaoanze888](https://github.com/gaoanze888), [#&#8203;106958](NousResearch/hermes-agent#106958) [@&#8203;nikkoxgonzales](https://github.com/nikkoxgonzales); co-authored [@&#8203;QDung210](https://github.com/QDung210), [@&#8203;fangliquanflq](https://github.com/fangliquanflq), [@&#8203;Sahilvishnaliya](https://github.com/Sahilvishnaliya))
- **FTS damage no longer kills your turn.** An error scoped to the full-text-search index was classified as whole-file corruption and fail-closed the conversation. It's now `fts_index`: search degrades, the index rebuilds later, the transcript store is untouched. Same PR: doctor names structural damage honestly instead of "FTS write corruption", the FTS write probe catches the stale-index shape that passed every check while every write failed, `.recover` output no longer fails startup on orphan FTS5 shadow tables, header-zeroed databases recover instead of being refused, and the dashboard analytics poller returns a 503 instead of 520K tracebacks a day. ([#&#8203;108130](NousResearch/hermes-agent#108130) — salvage [#&#8203;97843](NousResearch/hermes-agent#97843) [@&#8203;SulthanZahran1](https://github.com/SulthanZahran1) + [#&#8203;97841](NousResearch/hermes-agent#97841) [@&#8203;Finn763](https://github.com/Finn763), [#&#8203;88604](NousResearch/hermes-agent#88604) [#&#8203;56824](NousResearch/hermes-agent#56824) [#&#8203;103657](NousResearch/hermes-agent#103657) [@&#8203;liuhao1024](https://github.com/liuhao1024), [#&#8203;106890](NousResearch/hermes-agent#106890) [@&#8203;nftpoetrist](https://github.com/nftpoetrist), [#&#8203;103321](NousResearch/hermes-agent#103321) [@&#8203;jangomango76](https://github.com/jangomango76), [#&#8203;91413](NousResearch/hermes-agent#91413) [@&#8203;leegunwoo98](https://github.com/leegunwoo98), [#&#8203;102808](NousResearch/hermes-agent#102808) [@&#8203;TaoMasterCoder](https://github.com/TaoMasterCoder))
- **One corrupt row no longer kills `sessions list`, export, or insights.** A TEXT timestamp or a `1e30` epoch used to crash the whole listing; malformed marker JSON crashed `json_extract`; more than 999 ids crashed bulk delete/prune. One `coerce_epoch()` helper on every reader (bad rows render `?` with a WARNING naming the session), a `json_valid` guard, IN-list chunking, and batched export hydration. ([#&#8203;108086](NousResearch/hermes-agent#108086) — salvage [#&#8203;106071](NousResearch/hermes-agent#106071) [@&#8203;Xipong](https://github.com/Xipong), [#&#8203;101726](NousResearch/hermes-agent#101726) [@&#8203;efe-arv](https://github.com/efe-arv), [#&#8203;94701](NousResearch/hermes-agent#94701) [@&#8203;liuhao1024](https://github.com/liuhao1024), [#&#8203;102679](NousResearch/hermes-agent#102679) [@&#8203;mssteuer](https://github.com/mssteuer), [#&#8203;100658](NousResearch/hermes-agent#100658) [@&#8203;Mi55ed](https://github.com/Mi55ed))
- **Sessions never bind to or read another profile's database.** The Desktop launch backend could pin itself to the wrong profile's `state.db` under a HERMES\_HOME override race; `session_search` by bare ID silently scanned every profile and returned someone else's transcript; recovery guidance pointed at the wrong file; profile delete kept a handle open (WinError 32). ([#&#8203;108074](NousResearch/hermes-agent#108074) — salvage [#&#8203;102534](NousResearch/hermes-agent#102534) [@&#8203;HexLab98](https://github.com/HexLab98), [#&#8203;106975](NousResearch/hermes-agent#106975) [@&#8203;Sora-bluesky](https://github.com/Sora-bluesky))
- **Opening state.db no longer takes the write lock when nothing needs writing.** A one-shot `hermes` process opening the store behind a busy gateway stalled 4–20 s and then failed with "database is locked". Now 0.01 s. ([#&#8203;108067](NousResearch/hermes-agent#108067) — salvage [#&#8203;106751](NousResearch/hermes-agent#106751) [@&#8203;kshitijk4poor](https://github.com/kshitijk4poor), [#&#8203;101881](NousResearch/hermes-agent#101881) [@&#8203;jonpol01](https://github.com/jonpol01))

Also in the window from the same subsystem: a fresh `state.db` no longer publishes FTS tables before owning the rebuild lock ([#&#8203;106311](NousResearch/hermes-agent#106311)), a handle that lost its WAL generation no longer checkpoints stale frames at shutdown ([#&#8203;106315](NousResearch/hermes-agent#106315), [#&#8203;106840](NousResearch/hermes-agent#106840)), a clobbered first page is quarantined with its WAL instead of opened destructively ([#&#8203;106587](NousResearch/hermes-agent#106587)), WAL setup leaves an unverifiable database untouched ([#&#8203;106568](NousResearch/hermes-agent#106568)), and quarantined handles refuse VACUUM/FTS optimize ([#&#8203;106343](NousResearch/hermes-agent#106343), [#&#8203;106349](NousResearch/hermes-agent#106349)). Most of these salvaged community diagnoses by [@&#8203;kshitijk4poor](https://github.com/kshitijk4poor).

##### Multi-profile isolation hardening

A cluster of fixes for installs running several profiles under one gateway (multiplex): secondary-profile bots no longer inherit the default profile's allow-lists ([#&#8203;107616](NousResearch/hermes-agent#107616)), adapters no longer send credentials to the default profile's host ([#&#8203;107617](NousResearch/hermes-agent#107617)), stdio MCP servers no longer receive the default profile's vault secrets ([#&#8203;107630](NousResearch/hermes-agent#107630)), `MEDIA:` delivery can no longer attach another profile's `.env` / `auth.json` / `state.db` ([#&#8203;107609](NousResearch/hermes-agent#107609)), Feishu drive callbacks and `/p/<profile>/` webhook replies stay on the routed profile ([#&#8203;107620](NousResearch/hermes-agent#107620), [#&#8203;107626](NousResearch/hermes-agent#107626)), and secondary profiles no longer get a sibling's Nous bearer from per-process memos ([#&#8203;107611](NousResearch/hermes-agent#107611)).

##### Desktop backend spawn storms are over

Bot Mode used to spawn or dial one backend per profile on launch and on every roster tick, hovering the Bots roster spawned a backend per row, and profile switches could spawn a duplicate primary. ([#&#8203;108069](NousResearch/hermes-agent#108069), [#&#8203;108107](NousResearch/hermes-agent#108107), [#&#8203;108118](NousResearch/hermes-agent#108118), [#&#8203;108134](NousResearch/hermes-agent#108134), [#&#8203;107969](NousResearch/hermes-agent#107969), [#&#8203;108112](NousResearch/hermes-agent#108112) — salvage [#&#8203;102512](NousResearch/hermes-agent#102512), [#&#8203;103634](NousResearch/hermes-agent#103634), [#&#8203;103399](NousResearch/hermes-agent#103399), [#&#8203;107997](NousResearch/hermes-agent#107997) and others by [@&#8203;kshitijk4poor](https://github.com/kshitijk4poor))

##### Password-blind credential vault

The agent can now sign in, pay, and fill addresses from 1Password, Bitwarden, or the local Hermes vault without ever seeing a secret; two-factor codes come from a saved authenticator key or are asked for in the user's UI ([#&#8203;106480](NousResearch/hermes-agent#106480), [#&#8203;107585](NousResearch/hermes-agent#107585)). Private git plugins install with the user's stored credentials ([#&#8203;106981](NousResearch/hermes-agent#106981)).

##### Plugin catalog and one Plugins page

A curated, SHA-pinned plugin index with CLI, admission CI, docs and dashboard ([#&#8203;69446](NousResearch/hermes-agent#69446)); Desktop gets one Plugins page owning agent + desktop plugins, install, catalog and per-commit pinning ([#&#8203;107212](NousResearch/hermes-agent#107212), [#&#8203;107314](NousResearch/hermes-agent#107314), [#&#8203;107321](NousResearch/hermes-agent#107321)); Radio ships as an opt-in SDK plugin ([#&#8203;107072](NousResearch/hermes-agent#107072)).

##### Nous free tier and guided first launch

Free inference and connectors out of the box with one command to sign in ([#&#8203;105258](NousResearch/hermes-agent#105258), [#&#8203;105260](NousResearch/hermes-agent#105260)), `/login` from a chat ([#&#8203;105261](NousResearch/hermes-agent#105261)), connector tools (Gmail, Linear, Notion, ...) searchable through `tool_search` ([#&#8203;106842](NousResearch/hermes-agent#106842)), and a guided first launch behind `HERMES_GUEST_ONBOARDING=1` ([#&#8203;107697](NousResearch/hermes-agent#107697), [#&#8203;107958](NousResearch/hermes-agent#107958), [#&#8203;107985](NousResearch/hermes-agent#107985), [#&#8203;108211](NousResearch/hermes-agent#108211)).

##### 🐛 Notable Bug Fixes

**Gateway & platforms**

- A bare `display:` key in config.yaml no longer crashes every gateway turn ([#&#8203;106305](NousResearch/hermes-agent#106305)); a queued-lane final refused by the platform is recorded and redelivered ([#&#8203;106316](NousResearch/hermes-agent#106316)); a stalled WebSocket send no longer blocks every later event ([#&#8203;106581](NousResearch/hermes-agent#106581)); the first turn no longer waits on the Python toolchain probe ([#&#8203;106556](NousResearch/hermes-agent#106556)).
- Telegram bots must @&#8203;mention when `bots_require_mention` is on, breaking bot-to-bot loops ([#&#8203;106534](NousResearch/hermes-agent#106534)); Matrix renders LaTeX ([#&#8203;106515](NousResearch/hermes-agent#106515)); Signal renders markdown tables ([#&#8203;106538](NousResearch/hermes-agent#106538)); WhatsApp replies to view-once messages keep their quote ([#&#8203;106541](NousResearch/hermes-agent#106541)); media-only replies report SUCCESS everywhere ([#&#8203;106557](NousResearch/hermes-agent#106557)).

**Providers & routing**

- `/model` and auxiliary auto never bill a provider you didn't select ([#&#8203;107366](NousResearch/hermes-agent#107366)); never auto-switch to a provider you have no credentials for ([#&#8203;107281](NousResearch/hermes-agent#107281)); Bedrock Claude/Converse/Mantle models survive `/model`, fallback and restore ([#&#8203;107621](NousResearch/hermes-agent#107621), [#&#8203;107658](NousResearch/hermes-agent#107658)); Bedrock Guardrails enforced ([#&#8203;107815](NousResearch/hermes-agent#107815)).
- Codex: patch-budget image 400 shrinks and retries ([#&#8203;106525](NousResearch/hermes-agent#106525)); unentitled primary + fallback no longer oscillate ([#&#8203;106549](NousResearch/hermes-agent#106549)); Azure Foundry replayed-reasoning rejection classified and pruned ([#&#8203;106718](NousResearch/hermes-agent#106718) [@&#8203;erosika](https://github.com/erosika)). MCP OAuth refresh no longer erases the refresh token ([#&#8203;106185](NousResearch/hermes-agent#106185)). Anthropic clients send exactly one credential ([#&#8203;107978](NousResearch/hermes-agent#107978)).
- DeepSeek V4.1 Flash on Nous Portal and OpenRouter pickers ([#&#8203;107489](NousResearch/hermes-agent#107489)); GPT Image 2.5 via OpenAI and FAL ([#&#8203;105988](NousResearch/hermes-agent#105988)); Opus 5 / Fable 5.1 on the native Anthropic picker ([#&#8203;106636](NousResearch/hermes-agent#106636) [@&#8203;xxxigm](https://github.com/xxxigm)).

**Agent loop & compression**

- One blocked periodic callback no longer stalls lease refresh ([#&#8203;106308](NousResearch/hermes-agent#106308)); a mid-turn `/steer` is persisted as its own user row ([#&#8203;106317](NousResearch/hermes-agent#106317), [#&#8203;106344](NousResearch/hermes-agent#106344)); local-inference memory-ceiling rejections back off instead of compressing history ([#&#8203;106307](NousResearch/hermes-agent#106307)); context-overflow after partial streaming ends the turn ([#&#8203;106567](NousResearch/hermes-agent#106567)); length continuation stops when the prompt filled the window ([#&#8203;106571](NousResearch/hermes-agent#106571)); compression no longer times out silently on aux retries ([#&#8203;106866](NousResearch/hermes-agent#106866)); `model_thresholds` keys can be provider-scoped ([#&#8203;108061](NousResearch/hermes-agent#108061)).
- Surface switch (Desktop↔TUI) no longer rebuilds the system prompt and busts the prompt cache ([#&#8203;105844](NousResearch/hermes-agent#105844)); CLI keeps the `api_content` sidecar so the cache survives an early persist ([#&#8203;105842](NousResearch/hermes-agent#105842)).

**CLI, TUI & Desktop**

- `hermes -z --resume` continues the session ([#&#8203;106313](NousResearch/hermes-agent#106313)); Shift+letter and Cmd+Shift+Z work on extended-key terminals ([#&#8203;90674](NousResearch/hermes-agent#90674) [@&#8203;francip](https://github.com/francip), [#&#8203;105493](NousResearch/hermes-agent#105493)); `browser_exec` timeout kills the whole process tree ([#&#8203;106589](NousResearch/hermes-agent#106589)); update checks poll the GitHub API once a day instead of git-fetching every 30 min ([#&#8203;107648](NousResearch/hermes-agent#107648)); `hermes update` names the real cause and can't hang on a stalled fetch ([#&#8203;108053](NousResearch/hermes-agent#108053)).
- Desktop: UI language survives the update relaunch ([#&#8203;106476](NousResearch/hermes-agent#106476)), expired OAuth grants get a one-click re-sign-in ([#&#8203;106965](NousResearch/hermes-agent#106965)), HUD mode shows the transcript again and always gives the window back ([#&#8203;107491](NousResearch/hermes-agent#107491), [#&#8203;107423](NousResearch/hermes-agent#107423)), the backend exits when its Desktop parent dies ([#&#8203;107977](NousResearch/hermes-agent#107977)), Windows updates stop reporting false failures ([#&#8203;106175](NousResearch/hermes-agent#106175), [#&#8203;107183](NousResearch/hermes-agent#107183)), WSLg renders on the Windows GPU ([#&#8203;106528](NousResearch/hermes-agent#106528)), Telegram quick setup with QR ported from the dashboard ([#&#8203;107242](NousResearch/hermes-agent#107242)), and \~60 more Desktop fixes largely from [@&#8203;OutThisLife](https://github.com/OutThisLife) and [@&#8203;kshitijk4poor](https://github.com/kshitijk4poor).

**Cron & Kanban**

- An off-tick "run now" no longer cancels the next scheduled run ([#&#8203;106306](NousResearch/hermes-agent#106306)); a killed manual run no longer blocks the next one for 5 minutes ([#&#8203;106733](NousResearch/hermes-agent#106733)); a one-shot changed to recurring keeps firing ([#&#8203;106532](NousResearch/hermes-agent#106532)); unpinned jobs run on their creation-snapshot model ([#&#8203;106499](NousResearch/hermes-agent#106499)); `--clone-all` no longer copies cron jobs ([#&#8203;106478](NousResearch/hermes-agent#106478)); `kanban promote` refuses undone parents ([#&#8203;106550](NousResearch/hermes-agent#106550)); `kanban_request_review` rejects unknown reviewer profiles ([#&#8203;106547](NousResearch/hermes-agent#106547)).

**Tools & memory**

- A stdio MCP server dying mid-call no longer replays the tool call ([#&#8203;106546](NousResearch/hermes-agent#106546)); a skills-only background review can no longer delete memory entries ([#&#8203;106310](NousResearch/hermes-agent#106310)); mem0 memory no longer drops long turns ([#&#8203;106542](NousResearch/hermes-agent#106542)); `tool_search` returns nothing rather than five tools sharing one word ([#&#8203;106676](NousResearch/hermes-agent#106676)); remote NOPASSWD sudo no longer prompts ([#&#8203;107939](NousResearch/hermes-agent#107939)); RSS and Reddit reading no longer activate by default ([#&#8203;105873](NousResearch/hermes-agent#105873)).

**Housekeeping**

- `config.yaml` backups live in one bounded `backups/config/` dir ([#&#8203;106388](NousResearch/hermes-agent#106388)); `hermes backup` keeps the newest 3 zips ([#&#8203;106455](NousResearch/hermes-agent#106455)); `hermes setup --reset` backs up the real config ([#&#8203;106453](NousResearch/hermes-agent#106453)); `debug share` retention shrunk to 1 day on the dpaste fallback ([#&#8203;106531](NousResearch/hermes-agent#106531)).

##### 👥 Contributors

Thank you to the **140 contributors** whose commits, co-author trailers, and salvaged PRs landed in this window.

**state.db campaign — salvaged PR authors:** [@&#8203;RikETS](https://github.com/RikETS), [@&#8203;JoaoMarcos44](https://github.com/JoaoMarcos44), [@&#8203;Halldrix](https://github.com/Halldrix), [@&#8203;TaoMasterCoder](https://github.com/TaoMasterCoder), [@&#8203;chelsealong](https://github.com/chelsealong), [@&#8203;ca-shrimp](https://github.com/ca-shrimp), [@&#8203;gaoanze888](https://github.com/gaoanze888), [@&#8203;nikkoxgonzales](https://github.com/nikkoxgonzales), [@&#8203;QDung210](https://github.com/QDung210), [@&#8203;fangliquanflq](https://github.com/fangliquanflq), [@&#8203;Sahilvishnaliya](https://github.com/Sahilvishnaliya), [@&#8203;kshitijk4poor](https://github.com/kshitijk4poor), [@&#8203;jonpol01](https://github.com/jonpol01), [@&#8203;HexLab98](https://github.com/HexLab98), [@&#8203;Sora-bluesky](https://github.com/Sora-bluesky), [@&#8203;Xipong](https://github.com/Xipong), [@&#8203;efe-arv](https://github.com/efe-arv), [@&#8203;liuhao1024](https://github.com/liuhao1024), [@&#8203;mssteuer](https://github.com/mssteuer), [@&#8203;Mi55ed](https://github.com/Mi55ed), [@&#8203;SulthanZahran1](https://github.com/SulthanZahran1), [@&#8203;Finn763](https://github.com/Finn763), [@&#8203;nftpoetrist](https://github.com/nftpoetrist), [@&#8203;jangomango76](https://github.com/jangomango76), [@&#8203;leegunwoo98](https://github.com/leegunwoo98), [@&#8203;ggoldani](https://github.com/ggoldani).

**state.db campaign — issue reporters** (the forensics in these threads were often better than the fixes): [@&#8203;thedigitalcarpenterdad](https://github.com/thedigitalcarpenterdad), [@&#8203;Rroven](https://github.com/Rroven), [@&#8203;aoeman84](https://github.com/aoeman84), [@&#8203;StephanRosin](https://github.com/StephanRosin), [@&#8203;rubensandrade-sketch](https://github.com/rubensandrade-sketch), [@&#8203;wanliqin](https://github.com/wanliqin), [@&#8203;chenzheshushi-commits](https://github.com/chenzheshushi-commits), [@&#8203;CarlosReyesPena](https://github.com/CarlosReyesPena), [@&#8203;revazone](https://github.com/revazone), [@&#8203;reservassai-art](https://github.com/reservassai-art), [@&#8203;Cuttingwater](https://github.com/Cuttingwater), [@&#8203;soroush5](https://github.com/soroush5), [@&#8203;e-shizz](https://github.com/e-shizz), [@&#8203;shobhit-87labs](https://github.com/shobhit-87labs), [@&#8203;shivanathd](https://github.com/shivanathd), [@&#8203;hoelzl](https://github.com/hoelzl), [@&#8203;i8ei](https://github.com/i8ei), [@&#8203;Ace-Kelly](https://github.com/Ace-Kelly), [@&#8203;YinsenWANG](https://github.com/YinsenWANG), [@&#8203;zbabiarz](https://github.com/zbabiarz), [@&#8203;Sravanjangam](https://github.com/Sravanjangam), [@&#8203;0gl20shk0sbt36](https://github.com/0gl20shk0sbt36), [@&#8203;RChina](https://github.com/RChina), [@&#8203;bronder](https://github.com/bronder), [@&#8203;ccwssy](https://github.com/ccwssy), [@&#8203;bottenbenny](https://github.com/bottenbenny), and [@&#8203;Hitman117890](https://github.com/Hitman117890) whose Discord report kicked the campaign off.

**Everyone in the window (alphabetical):** [@&#8203;0genlab](https://github.com/0genlab), [@&#8203;0xalydev](https://github.com/0xalydev), [@&#8203;100yenadmin](https://github.com/100yenadmin), [@&#8203;1052326311](https://github.com/1052326311), [@&#8203;686f6c61](https://github.com/686f6c61), [@&#8203;69k4xmdfm2-blip](https://github.com/69k4xmdfm2-blip), [@&#8203;abundantbeing](https://github.com/abundantbeing), [@&#8203;Adolanium](https://github.com/Adolanium), [@&#8203;Ahmett101](https://github.com/Ahmett101), [@&#8203;albert748](https://github.com/albert748), [@&#8203;AlexxRussell](https://github.com/AlexxRussell), [@&#8203;alt-glitch](https://github.com/alt-glitch), [@&#8203;auroracapital](https://github.com/auroracapital), [@&#8203;austinpickett](https://github.com/austinpickett), [@&#8203;babatorik](https://github.com/babatorik), [@&#8203;Bartok9](https://github.com/Bartok9), [@&#8203;benbarclay](https://github.com/benbarclay), [@&#8203;bennybuoy](https://github.com/bennybuoy), [@&#8203;brian717](https://github.com/brian717), [@&#8203;briandevans](https://github.com/briandevans), [@&#8203;buihongduc132](https://github.com/buihongduc132), [@&#8203;ca-shrimp](https://github.com/ca-shrimp), [@&#8203;cervantesh](https://github.com/cervantesh), [@&#8203;Cesar-Azeredo](https://github.com/Cesar-Azeredo), [@&#8203;ChanPark03](https://github.com/ChanPark03), [@&#8203;chelsealong](https://github.com/chelsealong), [@&#8203;ckomma](https://github.com/ckomma), [@&#8203;ClintonEmok](https://github.com/ClintonEmok), [@&#8203;crazyief](https://github.com/crazyief), [@&#8203;ctaylor86](https://github.com/ctaylor86), [@&#8203;dalzio](https://github.com/dalzio), [@&#8203;DavidMetcalfe](https://github.com/DavidMetcalfe), [@&#8203;Drexuxux](https://github.com/Drexuxux), [@&#8203;edosulai](https://github.com/edosulai), [@&#8203;efe-arv](https://github.com/efe-arv), [@&#8203;emozilla](https://github.com/emozilla), [@&#8203;ericmaddox](https://github.com/ericmaddox), [@&#8203;erosika](https://github.com/erosika), [@&#8203;ethernet8023](https://github.com/ethernet8023), [@&#8203;everm1nd](https://github.com/everm1nd), [@&#8203;FalconOrtiz](https://github.com/FalconOrtiz), [@&#8203;fangliquanflq](https://github.com/fangliquanflq), [@&#8203;Finn763](https://github.com/Finn763), [@&#8203;FirmamentalSpring](https://github.com/FirmamentalSpring), [@&#8203;francip](https://github.com/francip), [@&#8203;g3org3yo](https://github.com/g3org3yo), [@&#8203;gaoanze888](https://github.com/gaoanze888), [@&#8203;ggoldani](https://github.com/ggoldani), [@&#8203;Halldrix](https://github.com/Halldrix), [@&#8203;haydster7](https://github.com/haydster7), [@&#8203;hbizi](https://github.com/hbizi), [@&#8203;helix4u](https://github.com/helix4u), [@&#8203;HexLab98](https://github.com/HexLab98), [@&#8203;huklaa](https://github.com/huklaa), [@&#8203;IAvecilla](https://github.com/IAvecilla), [@&#8203;infinitycrew39](https://github.com/infinitycrew39), [@&#8203;jahfaliabdulrahman-dev](https://github.com/jahfaliabdulrahman-dev), [@&#8203;jangomango76](https://github.com/jangomango76), [@&#8203;JoaoMarcos44](https://github.com/JoaoMarcos44), [@&#8203;jonpol01](https://github.com/jonpol01), [@&#8203;jwilson411](https://github.com/jwilson411), [@&#8203;KeyArgo](https://github.com/KeyArgo), [@&#8203;kokhlo](https://github.com/kokhlo), [@&#8203;KoNit-K](https://github.com/KoNit-K), [@&#8203;kshitijk4poor](https://github.com/kshitijk4poor), [@&#8203;kyssta-exe](https://github.com/kyssta-exe), [@&#8203;leegunwoo98](https://github.com/leegunwoo98), [@&#8203;lesterlxt](https://github.com/lesterlxt), [@&#8203;liuhao1024](https://github.com/liuhao1024), [@&#8203;Mabolla](https://github.com/Mabolla), [@&#8203;manuelschipper](https://github.com/manuelschipper), [@&#8203;MaxFreedomPollard](https://github.com/MaxFreedomPollard), [@&#8203;mearls0501](https://github.com/mearls0501), [@&#8203;mengyuyuan](https://github.com/mengyuyuan), [@&#8203;Mi55ed](https://github.com/Mi55ed), [@&#8203;MiseHinoha](https://github.com/MiseHinoha), [@&#8203;mjshorty](https://github.com/mjshorty), [@&#8203;mkrb84](https://github.com/mkrb84), [@&#8203;moisesvalero](https://github.com/moisesvalero), [@&#8203;moken627-hub](https://github.com/moken627-hub), [@&#8203;mssteuer](https://github.com/mssteuer), [@&#8203;nateEc](https://github.com/nateEc), [@&#8203;nftpoetrist](https://github.com/nftpoetrist), [@&#8203;nickseelert](https://github.com/nickseelert), [@&#8203;nikkoxgonzales](https://github.com/nikkoxgonzales), [@&#8203;notwitcheer](https://github.com/notwitcheer), [@&#8203;onuraycicek](https://github.com/onuraycicek), [@&#8203;outdog-hwh](https://github.com/outdog-hwh), [@&#8203;OutThisLife](https://github.com/OutThisLife), [@&#8203;philmossman](https://github.com/philmossman), [@&#8203;phuongvm](https://github.com/phuongvm), [@&#8203;pierrenode](https://github.com/pierrenode), [@&#8203;portavales](https://github.com/portavales), [@&#8203;PRATHAMESH75](https://github.com/PRATHAMESH75), [@&#8203;QDung210](https://github.com/QDung210), [@&#8203;rewbs](https://github.com/rewbs), [@&#8203;RikETS](https://github.com/RikETS), [@&#8203;romanovzky](https://github.com/romanovzky), [@&#8203;ryantuc](https://github.com/ryantuc), [@&#8203;Sahilvishnaliya](https://github.com/Sahilvishnaliya), [@&#8203;salch-cred](https://github.com/salch-cred), [@&#8203;sgarrand](https://github.com/sgarrand), [@&#8203;shannonsands](https://github.com/shannonsands), [@&#8203;simpolism](https://github.com/simpolism), [@&#8203;Solitud1nem](https://github.com/Solitud1nem), [@&#8203;somewheresy](https://github.com/somewheresy), [@&#8203;Sora-bluesky](https://github.com/Sora-bluesky), [@&#8203;sprmn24](https://github.com/sprmn24), [@&#8203;squevo](https://github.com/squevo), [@&#8203;StellarisW](https://github.com/StellarisW), [@&#8203;Stoltemberg](https://github.com/Stoltemberg), [@&#8203;SulthanZahran1](https://github.com/SulthanZahran1), [@&#8203;Svector-anu](https://github.com/Svector-anu), [@&#8203;szicely](https://github.com/szicely), [@&#8203;TaoMasterCoder](https://github.com/TaoMasterCoder), [@&#8203;teknium1](https://github.com/teknium1), [@&#8203;ten82e](https://github.com/ten82e), [@&#8203;thedavidweng](https://github.com/thedavidweng), [@&#8203;tkaufmann](https://github.com/tkaufmann), [@&#8203;Totoro-qaq](https://github.com/Totoro-qaq), [@&#8203;Tranquil-Flow](https://github.com/Tranquil-Flow), [@&#8203;tuancookiez-hub](https://github.com/tuancookiez-hub), [@&#8203;TurgutKural](https://github.com/TurgutKural), [@&#8203;ugoenyioha](https://github.com/ugoenyioha), [@&#8203;unsupportedpastels](https://github.com/unsupportedpastels), [@&#8203;victor-kyriazakos](https://github.com/victor-kyriazakos), [@&#8203;webtecnica](https://github.com/webtecnica), [@&#8203;wliu-dev](https://github.com/wliu-dev), [@&#8203;wukangcheng1994](https://github.com/wukangcheng1994), [@&#8203;Xipong](https://github.com/Xipong), [@&#8203;Xixiartemis](https://github.com/Xixiartemis), [@&#8203;xkam7ar](https://github.com/xkam7ar), [@&#8203;xxxigm](https://github.com/xxxigm), [@&#8203;yavarb](https://github.com/yavarb), [@&#8203;yoniebans](https://github.com/yoniebans), [@&#8203;Youssef](https://github.com/Youssef), [@&#8203;yoyodine-industries](https://github.com/yoyodine-industries), [@&#8203;yuanchenglu](https://github.com/yuanchenglu), [@&#8203;YuhGuan](https://github.com/YuhGuan), [@&#8203;Zeus-Deus](https://github.com/Zeus-Deus).

Also: Youssef.

##### Updating

- Existing install: `hermes update`
- Fresh install: `curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash`
- Managed deployments should update through their deployment tooling using the new tag.
- If your `state.db` was already damaged by 0.21.0/0.21.1: run `hermes doctor` first; it now names structural vs index damage correctly and points at `hermes sessions recover --inspect-only` (profile-pinned) when a rebuild isn't enough.

**Full Changelog:** [v2026.9.7...v2026.9.11](NousResearch/hermes-agent@v2026.9.7...v2026.9.11)

</details>

---

### Configuration

📅 **Schedule**: (in timezone Europe/Berlin)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC42NS4wIiwidXBkYXRlZEluVmVyIjoiNDQuNjUuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsicmVub3ZhdGUvY29udGFpbmVyIiwidHlwZS9wYXRjaCJdfQ==-->

Reviewed-on: https://git.xcd.dev/gabrielcosi/home-ops/pulls/754
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/sessions Session lifecycle, resume, persistence, history comp/cli CLI entry point, hermes_cli/, setup wizard P1 High — major feature broken, no workaround sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants