Opus flagged a real upgrade gap on the #4449 state-dir contract folded into
#4454: a deployment that relocated HERMES_HOME to a non-default base WITHOUT
setting HERMES_WEBUI_STATE_DIR sees WebUI state move to $HERMES_HOME/webui on
upgrade (empty app at the new address). Add (1) README note documenting the
move + how to keep the old location, and (2) two backward-compat regression
tests pinning the invariants: HERMES_HOME-unset stays at the platform default
(normal installs don't relocate), and HERMES_WEBUI_STATE_DIR takes precedence.
* docs: weekly contributor tally refresh (20260619)
Regenerated by scripts/regen_contributors.py --apply. Includes the source (e)/(f)
ship-signal accuracy fix that recovers systematically-undercounted cherry-picked
contributions (~77 contributors). 280 contributors / 1559 credits (was 263/1232).
Markers spliced, prose untouched, --verify clean, 0 double-counts.
* docs: align CONTRIBUTORS header prose with the 5-source credit algorithm
Addresses greptile P2: the header still described the old three-source union
(merged-PR list + CHANGELOG + Co-authored-by) but regen_contributors.py now adds
two more — ship-comment scans and absorb-commit scans — for five total. Updates
the prose to match what the script actually runs.
---------
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
start.sh exec's bootstrap.py without --foreground, which double-forks into a
detached daemon, so it belongs in the 'find PID + kill' row, not the Ctrl-C
foreground row. Docs-only, no version stamp.
Co-authored-by: tomas-forgac
Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
* docs: refresh contributor tally for v0.51.390 (248 contributors)
Regenerated via scripts/regen_contributors.py after fixing three real
over-counting bugs in the generator (release-vehicle PR# leak, reporter
false-positives, prose-token leakage — see workspace commit). Net:
- 248 contributors / 1092 credits (corrected; the prior generator inflated
this with ~106 spurious release-vehicle co-author credits + reporter mentions)
- CONTRIBUTORS.md now recognizes 3+ PR contributors in ranked tables and lists
everyone with 1-2 PRs in a combined roll, so nobody already credited is dropped
- README top-10 snapshot + notable-contribution counts updated to match
(franksong 180, Michaelyklam 118, rodboev 83 [new], ai-ag2026 75, bergeouss 70)
Every name in the tally is authorship-verified (merged PR, CHANGELOG attribution,
or a Co-authored-by trailer); bug reporters / relayers / confirmers are no longer
miscredited as authors.
* docs: add generated-region markers so the contributor tally regenerates cleanly
Wraps the machine-generated tables in CONTRIBUTORS.md + README.md with
<!-- BEGIN/END GENERATED CONTRIBUTORS --> markers. scripts/regen_contributors.py
--apply now splices fresh tables between them on each run while leaving the
hand-written prose (How credit is tracked, Special thanks, README Notable
contributions) untouched. Verified idempotent: a second --apply is a no-op.
This is what the weekly refresh cron runs.
Tally re-synced to current master: 248 contributors / 1093 credits.
---------
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
* docs(#3794): clarify how to stop each launch method in Quick start
* docs(#3794): use lsof/ss for PID discovery instead of implying bootstrap prints it
---------
Co-authored-by: nesquena-hermes <nesquena+hermes@gmail.com>
## Release v0.51.256 — Release HX (stage-r4)
Performance — bound WebUI memory growth & idle CPU on large installs.
### Fixed
| Issue | Author | Fix |
|-------|--------|-----|
| #3506 | @nesquena-hermes (reported w/ profiling by @djenttleman) | On a large install (~615 sessions / 40k messages / 454 MB state.db) the WebUI process climbed ~100 MB → ~1.5 GB RSS over days and held high idle CPU. Three root causes fixed: (1) `session_lifecycle._sessions` grew unbounded → new `discard_session()` drops the entry at agent-eviction boundaries, only when no in-flight commit / no uncommitted memory work (retry invariant preserved); (2) cache caps now operator-tunable (`HERMES_WEBUI_AGENT_CACHE_MAX` default 50→25, `HERMES_WEBUI_SESSIONS_MAX`); (3) GatewayWatcher computes a cheap fingerprint before the expensive per-session `MAX(messages.timestamp)` projection and only re-projects on change. |
### Rebase + review notes
- Rebased onto current master; the code diff was verified **byte-identical to the nesquena-APPROVED head** at rebase time (only CHANGELOG re-resolved).
- The Codex regression gate then surfaced **two correctness gaps** the approval didn't catch, both fixed here with regression tests:
1. **Watcher fingerprint missed same-count transcript rewrites.** `/retry`,`/undo`,`/compress` (`SessionDB.replace_messages`) rewrite messages with new timestamps but can leave `message_count` unchanged → stale sidebar `last_activity`. Fixed with a **per-session** grouped message aggregate (`id, count, user_count, MAX(timestamp)`) over the same non-excluded sessions (a global MAX would miss a rewrite of an older, non-newest session); cron/webui stay excluded so idle churn still doesn't re-project.
2. **LRU agent-cache eviction could close a live worker's agent** (`popitem(last=False)`, liveness-blind — pre-existing, but the lower 50→25 cap made it more likely). Eviction now snapshots `ACTIVE_RUNS` session_ids (before the cache lock — no nested lock) and skips live sessions, deferring (temporarily exceeding cap) rather than closing a live agent.
### Gate
- Full pytest suite: **7612 passed, 0 failed** (one boot-cascade flake re-run; clean on re-run)
- ruff: CLEAN · Codex (regression): 4 rounds → both gaps + a stale test fixed → **SAFE TO SHIP**
Co-authored-by: nesquena <nesquena@users.noreply.github.com>
## Release v0.51.252 — Release HT (stage-q24)
Two trivially-safe @rodboev changes (independent).
### Fixed
| Issue | Author | Fix |
|-------|--------|-----|
| #2481 | @rodboev | The floating "selected-text reply" button now has `user-select:none`, so its own label can't get caught in a text selection (no bleed-through). CSS one-liner. |
### Docs
- README **Compatibility** section: upgrade WebUI + hermes-agent together until the stable agent API (#2491) lands. (@rodboev)
### Dropped from this batch
- **#2977 `/use` skill command** was staged here but **dropped** — the Codex regression gate found an async stale-directive race (`cmdUse()` awaits `/api/skills` but `send()` doesn't await the handler → a fast next send can miss it, or a stale directive leaks to a later message) plus an over-eager `finally` clear that silently discards the directive on a local slash-command early-return. Held with `changes-requested` + a detailed rework note (tracked pending promise + clear-on-consume). Concept approved; needs lifecycle hardening.
### Gate
- Full pytest suite: **7570 passed, 0 failed**
- ESLint: CLEAN · ruff: CLEAN · browser-smoke: CLEAN
- Codex (regression): **SAFE TO SHIP** — `user-select:none` scoped to the button only, README docs-only, no `/use` code remains
Co-authored-by: rodboev <rodboev@users.noreply.github.com>
Information-architecture pass on the 840-line README so the most important
things come first and secondary/niche content is linked rather than inline:
- Reorder: Why -> Quick start -> FEATURES (was at line 502, now right after
Quick start) -> Configuration & access -> Docker -> Running tests ->
Architecture -> Docs -> Contributors. Readers see what it does before the
deployment minutiae.
- Consolidate the scattered access sections (start.sh discovery, overrides,
remote/SSH, Tailscale, manual launch) under one '## Configuration & access'
H2 with H3 subsections.
- Extract two genuinely-niche blocks to new linked docs (nothing deleted):
- docs/advanced-chat-setup.md — dynamic recall-prefill + Gateway-backed chat
- docs/remote-access.md — SSH tunnel + Tailscale + ARM64-Android field report
Quick start keeps a one-line pointer to each.
- Update Contents TOC + Docs index for the new order and new files.
README 840 -> 705 lines; content preserved (verified moved-not-dropped); all
internal links + new docs verified to resolve; docs/*.md gitignore-allowlisted.
- ROADMAP.md: 8-themes -> 11-skins in status snapshot; replace stale per-file
LOC architecture table with role descriptions + CI gate list (ruff/shard/
browser/docker); note LOC drifts.
- ARCHITECTURE.md: refresh File Inventory — drop chronically-stale per-file LOC,
add missing modules (state_sync.py, updates.py, i18n/login/icons/sw.js,
pyproject.toml, ctl.sh, CONTRIBUTORS.md), refresh test count to ~7,150.
- README.md: update the 8 'Notable contributions' blurb headers (PR counts +
release ranges) to match the regenerated tally.
Regenerate CONTRIBUTORS.md + README contributors section from a verified
3-source union: GitHub merged-PR list, CHANGELOG.md attribution lines, and
Co-authored-by trailers on master commits (the canonical signal for a CLOSED
contributor PR whose commits were cherry-picked/absorbed and attributed).
- New tally: 194 contributors / 843 PR credits (was a stale 137 / 646).
- The increase: ~135 releases since the v0.51.58 pin PLUS newly-detected
absorbed-CLOSED PRs the prior hand-count missed (e.g. franksong2702 148 =
129 merged + 19 cherry-picked-and-attributed).
- UNION with the existing hand-curated file as a floor: 27 old contributors
had no machine-readable signal (very old closed PRs) — preserved, ZERO dropped.
- Refreshed special-thanks PR counts to match.
- Generator committed to the maintainer workspace as scripts/regen_contributors.py
(--merge-existing keeps it safe for all future refreshes).
Verified: every one of the original 137 logins still present (+57 new).
README:
- Add a Contents table of contents for navigability (800-line doc).
- Freshen stale snapshots: test count 5303/488 files -> ~7,150/~700 files;
reframe contributor counts to point at CONTRIBUTORS.md as the live source.
- Rebuild the Architecture section: drop per-file exact LOC (drifts every
release -> chronic staleness) in favor of a stable backend/frontend role map;
add pyproject.toml + the ruff/browser/docker CI gates.
- Reorganize the Docs index by purpose (Start here / Using / Deploying /
Contributing & design / Release history); add missing CONTRIBUTING.md,
DESIGN.md, docs/workspace-git.md; convert bare paths to working links.
ARCHITECTURE.md: header v0.51.54/5303 -> v0.51.192/~7,150 + note that the
numbers are a periodic snapshot (authoritative source = git tag + collect-only).
TESTING.md: header + footer test counts refreshed; drop the stale
'through v0.50.21' framing; note the ruff/browser/docker gates.
ROADMAP.md: refresh the 'Last updated' stamp (v0.51.31/5028 -> v0.51.192/~7,150)
with recent themes.
Markdown-only; all internal links verified to resolve.
Squashed from 3 author commits onto current master (3 base commits from
already-shipped #2783 were filtered out by the squash). #2805's expanded
candidate-path discovery + PathType Container check preserved from prior
stage commit.
Authorship preserved. CHANGELOG entry merged into batch stamp commit.
Add a narrow README note for the community ARM64 Android AVF field
report: Hermes Agent + WebUI running inside a Debian 12 VM on a
mid-range Android phone with cloud-hosted inference.
The note frames the report as a compatibility signal rather than an
official support baseline or provider/model benchmark, and records
practical mobile caveats around first-install compile time, Android
tab reloads, and battery optimization.
Refs #2364Closesnesquena/hermes-webui#2483
Co-authored-by: Frank Song <franksong2702@gmail.com>