Hermes Agent

Hermes drafts atomic checkpoint recovery without directory swaps

Hermes proposes activating verified checkpoint generations with an atomic selector instead of replacing a live multi-gigabyte store. Companion work keeps gateway sockets out of backups and adopts bot sessions stranded in the default profile store.

← Back to homeOriginal source ↗

NousResearch/hermes-agent PR #93376 is the inspected primary source: “fix(checkpoints): atomic store activation via generation selector.” The related records below were inspected as supporting context rather than independent confirmation.

The facts

- NousResearch/hermes-agent PR #93376 was created 2026-08-24T00:34:43Z and was open at inspection; its title is “fix(checkpoints): atomic store activation via generation selector.” - NousResearch/hermes-agent PR #93374 was created 2026-08-24T00:31:43Z and was open at inspection; its title is “fix(backup): skip non-regular files so the gateway control socket doesn't mark archives incomplete.” - NousResearch/hermes-agent PR #93369 was created 2026-08-24T00:25:48Z and was open at inspection; its title is “fix(gateway): adopt stranded bot sessions from the default store on profile resume.” - The repository reported 234985 stars, 35190 open issues, default branch main, and last push 2026-08-24T00:37:12Z. - The latest tagged-release baseline checked was v2026.8.19 published 2026-08-21T12:16:39Z.

What changed

NousResearch/hermes-agent PR #93376 reports: fix(checkpoints): atomic store activation via generation selector Fixes #93314 Problem The shared checkpoint store always lives at checkpoints/store/ (_store_path() returns a fixed path). When that store becomes structurally damaged, an offline repair can produce a fully verified candidate (git fsck --strict clean) — but there is no way to make that candidate canonical except renaming/replacing the live multi-gigabyte directory at the fixed path. On filesystems like Unraid's fuse.shfs that directory swap failed for the reporter, retrying would depend again on an unproven FUSE rename primitive, and any attempt creates a window where the canonical store path does not exist at all. Solution An optional one-line generation selector, exactly as sketched in the issue: **Resolver:** _store_path() becomes a dynamic resolver. Absent pointer = byte-for-byte today's behaviour (no migration, no new files). Valid pointer = every reader/writer/pruner/status path transparently operates on the selected generation (all consumers already re-resolve per operation). Every checkpoint consumer resolves dynamically. **Fail closed:** a present-but-untrustworthy pointer (symlinked pointer or target, multi-line/non-generation content, missing target directory) raises CheckpointStoreSelectorError instead of silently falling back to the possibly-damaged legacy store. Manager methods degrade to "checkpoint store unavailable" results; startup auto-prune logs and skips; status surfaces selector_error so operators can repair. **Activation** (hermes checkpoints activate DIR): copies the candidate into a new sibling generation (never moves/deletes either store), verifies the copy (HEAD

NousResearch/hermes-agent PR #93374 reports: What does this PR do? Since #92447, a running gateway creates a Unix domain socket at $HERMES_HOME/gateway.sock. hermes backup walks HERMES_HOME and tries to archive it; zipfile.write() raises OSError: [Errno 102] Operation not supported on socket, the failure lands in errors, and every backup taken while the gateway runs is reported Backup incomplete — even though the archive is fine. "Backup incomplete" is also the signal for real problems (e.g. a dropped database snapshot), so wrappers that treat it as fatal now fail on every run. _should_skip_backup_file() already skips symlinks for the same reason. This PR extends it to skip all non-regular files (sockets, FIFOs, device nodes) via stat.S_ISREG(abs_path.stat().st_mode), so runtime state that cannot be archived no longer flips the summary. Both call sites (the CLI scan and the automatic _write_full_zip_backup_locked walk) go through this function, so both are covered. One deliberate nuance: abs_path.is_file() returns False when the stat itself fails, which would turn unreadable files into silent skips. The stat() call is wrapped so an OSError there does NOT skip the file — it falls through to the archive phase, where the existing except (PermissionError, OSError, ValueError) handler records it as a warning. Nothing is ever dropped silently. Related Issue Fixes #93347 Type of Change [x] Bug fix (non-breaking change that fixes an issue) [ ] New

NousResearch/hermes-agent PR #93369 reports: Summary Completes the Bot Mode reliability train for EXISTING installs: profile-scoped session.resume now adopts a session stranded in the default profile's store instead of hard-failing 4001/4007 forever. The gap this closes 93296/#93311 fixed RPC routing (dispatch by the session the RPC targets). But that fix is only forward-looking: every profile bot that ran BEFORE it accumulated its canonical session in the DEFAULT profile's state.db (the misroute wrote it there). After updating, the profile backend correctly receives the resume — and correctly reports it has no such session. The user experience is unchanged: the bot chat still doesn't work, now because the fix made the stranded conversation unreachable rather than misrouted. Real-world shape (Teknium's Windows install, session c93770): weeks of Developer-bot history in root state.db; post-update resumes 4007 on the developer backend. Without this PR his options are "discard the chat and start over." Changes hermes_state_portability.py — SessionDB.adopt_session_lineage_from(donor_db, session_id): composes the EXISTING export_session_lineage() → import_sessions() primitives (no new import/export machinery). Donor rows are archived — never deleted — with end_reason='adopted_by_profile', deliberately NOT in RECOVERABLE_END_REASONS so #93217's canonical-lookup resurrection cannot undo an adoption. Idempotent: re-running skips already-present ids. tui_gateway/methods_session.py — profile-scoped session.resume (the owns_db branch only) falls back to adoption from the default store immediately before the 4007. Ids unknown to BOTH stores still 4007 exactly as before; launch-profile resumes never consult

Why it matters

Recovery is only useful when activation, backup and profile resumption preserve a canonical owner through failure. The operator test is whether the system remains bounded and its receipts still describe the action after failure, retry or restart.

Current

The primary record was open when captured on 2026-08-24. The tagged-release baseline was v2026.8.19 published 2026-08-21T12:16:39Z. Repository metadata, full source bodies, current pull requests and issues, releases, Google News, Hacker News, Lobsters, Metamesh and the rendered ClawCharts row were inspected. ClawCharts selected the subject; it did not prove the claim.

Evidence

The primary URL is https://github.com/NousResearch/hermes-agent/pull/93376. Supporting records are https://github.com/NousResearch/hermes-agent/pull/93374 and https://github.com/NousResearch/hermes-agent/pull/93369. Source bodies, timestamps and states are preserved in the daily evidence bundle. Test counts and reproductions remain attributed to their authors unless identified as independently rerun.

Source boundary

Open work is described as open, closed work as closed, and operator reports as reports. A pull request is evidence of proposed or reviewed direction, not proof of a shipped release. Search residue, package mirrors and historically published source spines were excluded.

Operator take

Keep repaired stores immutable until verification passes, make pointer corruption fail closed, and archive donor session rows instead of silently deleting history. Preserve a before-state receipt, make the smallest reversible change, and verify the original failure independently.

Caveat

Public project records are mutable. Status, scope and evidence can change after publication. This brief records the inspected state and does not authorize changes to a reader’s deployment.

Source inspected; source state, environment and release boundary remain explicit.