Skip to content

feat(themes): add hermes-agent teal/gold skin (#3357)#3602

Closed
rodboev wants to merge 1 commit into
nesquena:masterfrom
rodboev:pr/hermes-agent-skin
Closed

feat(themes): add hermes-agent teal/gold skin (#3357)#3602
rodboev wants to merge 1 commit into
nesquena:masterfrom
rodboev:pr/hermes-agent-skin

Conversation

@rodboev

@rodboev rodboev commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Thinking Path

  • The hermes-webui appearance picker ships a "Nous" dark skin with a blue-steel palette (--bg:#0A0E14, --accent:#4682B4), which was designed to echo the Nous Research brand colors, not the Hermes agent dashboard.
  • The Hermes agent dashboard and marketing pages use an emerald-green and warm-gold palette; users who run both the dashboard and the WebUI have no built-in way to match them visually.
  • Issue Using the teal and gold theme from Hermes agent's dashboard for the "nous" skin #3357 proposes recoloring the existing "nous" dark variant to use this palette. The maintainer (nesquena-hermes) redirected the approach: instead of overwriting a shipped skin, add a new data-skin="hermes-agent" value so both palettes remain available and the change is purely additive.
  • The maintainer also flagged the typography changes in the original CSS (font-family, font-size, line-height) as out of scope for a color-palette PR, recommending they be split into a separate discussion. Those properties are omitted here.
  • The full registration pattern for a new skin covers five locations: static/style.css (palette + component overrides), static/boot.js (_SKINS array), static/index.html (pre-paint whitelist), static/i18n.js (all cmd_theme help strings), and api/config.py (_SETTINGS_SKIN_VALUES allowlist). The most recently merged skin (Neon) skipped the last two, creating an inconsistency this PR addresses for the new skin while noting the pre-existing gap.
  • The skin is dark-only. In light mode it falls back to the default palette. The maintainer accepted this explicitly.
  • The Zeus PR (feat(skins): add Zeus skin — OLED-near-black dark surfaces with default gold accent #3328) has since merged, touching the same arrays in boot.js, index.html, i18n.js, and api/config.py. This PR is branched from a post-Zeus master, so no rebase conflict.

What Changed

  • static/style.css: new :root.dark[data-skin="hermes-agent"] palette block inserted after the Zeus skin section (before Geist Contrast). Variables use the emerald/gold palette from the issue body with typography properties stripped. Component-level overrides follow the Nous/Neon pattern: new-chat button in gold, gold-tint scrollbar, tool-card borders, tree viewer in gold family, session badge colors, diff/MCP status, and lightbox controls.
  • static/boot.js: {name:'Hermes Agent', value:'hermes-agent', colors:['#C89A5A','#0F1714','#22342C']} added to _SKINS after the Zeus entry.
  • static/index.html: 'hermes-agent':1 added to the pre-paint skins whitelist to prevent flash-of-wrong-skin on first load.
  • static/i18n.js: all 12 locale cmd_theme strings updated to append /hermes-agent to the skin list (after zeus). This closes a pre-existing gap where skins added to boot.js and index.html were never added to the help text.
  • api/config.py: "hermes-agent" added to _SETTINGS_SKIN_VALUES. This allows the skin to be set via the /theme command and persisted through the server-side settings normalization path.
  • tests/test_hermes_agent_skin.py: new test file with 5 tests: 4-file registration, emerald surface values, gold accent values, dark-only constraint (no light root block), and i18n locale count (12, accounting for both ASCII and full-width parens in Chinese locales).
  • tests/test_zeus_skin.py: updated the stale test_zeus_i18n_lists_skin_in_all_locales assertion from count("zeus)") == 10 to count("/zeus/") == 12, since hermes-agent now follows zeus in the slug list and the locale count was already 12.

Why It Matters

Users who run the Hermes agent dashboard alongside the WebUI see two visually unrelated UIs with no way to match them. This skin closes that gap as an opt-in palette change that is purely additive, with zero risk to existing skins. Closes #3357.

Verification

C:\Apps\hermes\hermes-agent\venv\Scripts\python.exe -m pytest tests/test_hermes_agent_skin.py -v --timeout=60
C:\Apps\hermes\hermes-agent\venv\Scripts\python.exe -m pytest tests/ -v --timeout=60

Manual: open Settings -> Appearance -> Skin. Confirm "Hermes Agent" appears in the picker with gold/emerald swatches. Select it; verify the dark emerald palette renders in the chat pane and sidebar. Switch to another skin and back to confirm no style bleed. Confirm light mode falls back to the default palette (no light variant registered).

Risks / Follow-ups

  • Neon/Hepburn inconsistency not fixed: api/config.py._SETTINGS_SKIN_VALUES currently omits "neon" and "hepburn". This PR adds "hermes-agent" using the full pattern but does not retroactively fix the existing gap. A follow-up PR can add "neon" and "hepburn" to config.py.
  • --blue aliased to --accent: components using var(--blue) for informational affordances (links, info badges) render gold instead of blue. This is intentional for visual cohesion with the emerald/gold palette; if the maintainer prefers distinct informational coloring, --blue can be set to a muted teal separately.
  • Typography: font-family, font-size, and line-height from the original issue palette are intentionally absent per maintainer guidance. A follow-up PR can propose typography changes independently.
  • Zeus test fix bundled: the test_zeus_skin.py assertion update fixes a pre-existing stale count (10 vs 12 locales) alongside the pattern change needed for hermes-agent. If this PR is reverted, the zeus test would revert to the stale assertion. Noted for awareness.

Model Used

Claude Opus 4.8 via Claude Code CLI

@greptile-apps

greptile-apps Bot commented Jun 4, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds a new hermes-agent dark skin with an emerald/gold palette, wiring it into all five required registration points (style.css, boot.js, index.html, i18n.js, api/config.py) and covering it with five new tests.

  • New skin registered across all layers: palette variables, swatch entry, pre-paint whitelist, /theme command help strings in all 12 locales, and the server-side allowlist — following the full pattern that Neon and Hepburn had previously skipped.
  • Zeus test corrected as a side-effect: the stale count(\"zeus)\") == 10 assertion (which always missed the 2 full-width-paren Chinese locales) is replaced with count(\"/zeus/\") == 12 now that hermes-agent follows zeus in the slug list.
  • Dark-only design: no light-mode palette block is registered; users on light mode fall back to the default palette, which was explicitly accepted by the maintainer.

Confidence Score: 4/5

Safe to merge — the change is purely additive CSS and minor registration bookkeeping with no risk to existing skins or runtime behavior.

The implementation follows the established skin registration pattern across all five required files, the new test suite covers palette values and the dark-only constraint, and the Zeus test fix corrects a pre-existing locale miscounting bug. The only gaps are a missing CHANGELOG entry (required by AGENTS.md for user-visible changes) and a test function that names itself 'all files' but only asserts three of the five registration locations — meaning a future accidental deletion of the CSS block or the i18n slug would not be caught by that specific test.

tests/test_hermes_agent_skin.py — the registration test function misses CSS and i18n.js assertions

Important Files Changed

Filename Overview
static/style.css Adds :root.dark[data-skin="hermes-agent"] palette block and component-level overrides following the established Nous/Zeus/Neon pattern; scoped entirely to dark mode.
static/boot.js Appends the Hermes Agent entry to _SKINS with an explicit value:'hermes-agent' field (required because the display name contains a space) and correct swatch colors.
static/i18n.js Appends /hermes-agent to the skin list in all 12 locale cmd_theme strings; also implicitly fixes the pre-existing gap where Neon and Hepburn were absent.
api/config.py Adds "hermes-agent" to _SETTINGS_SKIN_VALUES, enabling the skin to be set via /theme and persist through server-side settings normalization.
tests/test_hermes_agent_skin.py New test file with 5 tests covering palette values, dark-only constraint, and i18n locale count; test_hermes_agent_skin_is_registered_in_all_files only asserts 3 of the 5 registration locations (missing CSS and i18n.js), making the function name misleading.
tests/test_zeus_skin.py Updates stale locale count from 10 to 12 and switches from "zeus)" to "/zeus/" now that hermes-agent follows zeus in the slug list.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User selects Hermes Agent skin] --> B{Theme mode?}
    B -->|dark| C[index.html pre-paint script sets data-skin=hermes-agent]
    B -->|light or system-to-light| D[No light palette block - Falls back to default]
    C --> E[style.css applies emerald/gold variables and component overrides]
    A --> G[boot.js _SKINS - Renders gold/emerald swatches in picker]
    A --> H[api/config.py allowlist - i18n.js help strings across 12 locales]
Loading

Reviews (1): Last reviewed commit: "feat(themes): add hermes-agent teal/gold..." | Re-trigger Greptile

Comment thread tests/test_hermes_agent_skin.py
Comment thread static/style.css
nesquena-hermes added a commit that referenced this pull request Jun 5, 2026
…ronze skin #3602)

Adds the Verdigris dark-only appearance skin (emerald/forest-green + bronze-gold),
renamed from the contributor's 'Hermes Agent' to a descriptive material name per
maintainer naming convention. Registered across all 5 skin sites (config allowlist,
boot.js swatch, index.html FOUC map, i18n in 12 locales, scoped CSS palette) + test.
Also fixes the zeus i18n test (zeus is no longer the trailing skin token).

Co-authored-by: rodboev <rodboev@users.noreply.github.com>
nesquena-hermes added a commit that referenced this pull request Jun 5, 2026
Release v0.51.281 — Release IW (stage-verdigris — Verdigris emerald/bronze skin #3602)
@nesquena-hermes

Copy link
Copy Markdown
Collaborator

Shipped in v0.51.281 (Release IW) 🎨

Thank you @rodboev — your skin is now live. We renamed it from "Hermes Agent" to Verdigris (the green-bronze patina on aged copper) to match our existing skin-naming convention (Slate, Graphite, Sienna, Poseidon…) and avoid a self-referential product name; the palette and all your component-level accents are unchanged. Your authorship is preserved via a Co-authored-by trailer on the release commit.

The branch had drifted behind master (it predated ~13 releases), so we re-applied the skin surgically onto current master across all 5 registration sites (config allowlist, boot.js swatch, index.html FOUC map, i18n ×12 locales, scoped CSS palette) plus your test file. We also corrected tests/test_zeus_skin.py since zeus is no longer the trailing skin token.

Selectable now via Settings → Appearance or /theme verdigris. Closing as merged (via the rename); closes #3357.

eleboucher pushed a commit to eleboucher/homelab that referenced this pull request Jun 6, 2026
…➔ 0.51.293) (#856)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/nesquena/hermes-webui](https://github.com/nesquena/hermes-webui) | patch | `0.51.277` → `0.51.293` |

---

### Release Notes

<details>
<summary>nesquena/hermes-webui (ghcr.io/nesquena/hermes-webui)</summary>

### [`v0.51.293`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051293--2026-06-06--Release-JI-stage-s5--thinking-card-no-longer-renders-twice)

[Compare Source](nesquena/hermes-webui@v0.51.292...v0.51.293)

##### Fixed

- **The "Thinking" card no longer renders twice on a settled turn.** For a turn that had both a tool call and reasoning (e.g. think → call a tool → answer), the thinking card could appear once inside the collapsed **Activity** group at the top of the turn and again as a stranded second card below the answer and the `Done in …` footer. The thinking-only inline render path (added in v0.51.258 for [#&#8203;3592](nesquena/hermes-webui#3592)) now only fires when the turn has no Activity group of its own, and when it does render inline it inserts the card **above** the answer body instead of after the footer. Thinking that echoes the visible answer on a trailing reasoning-only message is also de-duplicated against the whole turn's answer text now, not just the same message's body. Genuinely thinking-only turns still show their thinking inline (the [#&#8203;3592](nesquena/hermes-webui#3592) fix is preserved, not reverted). ([#&#8203;3709](nesquena/hermes-webui#3709); supersedes [#&#8203;3708](nesquena/hermes-webui#3708))

### [`v0.51.292`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051292--2026-06-06--Release-JH-stage-s4--compression-exhausted-turns-surface-as-errors-not-fake-completions)

[Compare Source](nesquena/hermes-webui@v0.51.291...v0.51.292)

##### Fixed

- **Context-compression-exhausted turns are no longer finalized as a falsely "completed" response.** When Hermes Agent exhausts context compression in a long tool-heavy turn, the streamed result can end on a tool result or an assistant `tool_calls` turn with no final assistant answer. WebUI previously rendered that as a settled, completed reply. It now classifies a persisted transcript that ends in a tool/tool-call/empty-assistant tail (or an internal `[CONTEXT COMPACTION — REFERENCE ONLY]` marker) — and `compression_exhausted`/`failed`/`partial` agent results — as a terminal failure and surfaces a clear error instead. The compression session-id migration and pre-compression snapshot now run **before** the terminal-failure path returns, so frontend/backend session state stays consistent when exhaustion fires after the agent rotates `session_id`. ([#&#8203;3316](nesquena/hermes-webui#3316), [@&#8203;franksong2702](https://github.com/franksong2702); fixes [#&#8203;3315](nesquena/hermes-webui#3315))

### [`v0.51.291`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051291--2026-06-06--Release-JG-stage-s2--preserve-live-turn-content-when-switching-away-mid-stream)

[Compare Source](nesquena/hermes-webui@v0.51.290...v0.51.291)

##### Fixed

- **Switching away from a streaming session no longer loses the in-progress thinking/tool content.** When you clicked to another chat while a session was streaming during a quiet window (mid tool-execution or silent reasoning, between content events) and then switched back, the live turn's tool cards and thinking could disappear permanently — only the elapsed-time clock survived — until the response finished and the transcript re-rendered from the server. Cause: the live-turn DOM snapshot was only captured on content/`tool_complete` SSE events, so the switch-away teardown could run with a stale-or-absent snapshot, and the switch-back fallback rebuilt an empty thinking card. `closeLiveStream()` now snapshots the live turn **before** tearing the stream down, so switching back restores the exact state shown at switch-away. ([#&#8203;3668](nesquena/hermes-webui#3668))

### [`v0.51.290`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051290--2026-06-06--Release-JF-stage-s1--profile-providermodel-now-respected-in-session-resolution)

[Compare Source](nesquena/hermes-webui@v0.51.289...v0.51.290)

##### Fixed

- **Profile-bound sessions now resolve their provider and model from the profile** instead of silently falling back to the global active provider. Previously, when a chat was started under a profile and the model string was not `@provider:`-qualified (and no explicit provider was sent), the backend used the catalog's global active provider — so a profile wired to one provider/key could silently run on a different one, causing **wrong credentials/billing** and **silent context truncation** (the global default model's advertised context window could differ from what the provider actually served, so the provider dropped the oldest messages and long chats "forgot" earlier content). Resolution is now authoritative from the profile across all four runtime entry points (chat start, streaming worker incl. background/btw runs, and both deferred `/api/session` display resolvers); stale models are still repaired under the profile provider — including the `openai-codex` profile + stale `openai/…` slash-model case — while native slash IDs on OpenRouter/custom providers are preserved and explicit `@provider:` qualifiers still win. ([#&#8203;3448](nesquena/hermes-webui#3448), [@&#8203;rodboev](https://github.com/rodboev); fixes [#&#8203;3405](nesquena/hermes-webui#3405))

### [`v0.51.289`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051289--2026-06-06--Release-JE-hotfix--sidebar-ReferenceError-3696--scope-undef-prevention-gate)

[Compare Source](nesquena/hermes-webui@v0.51.288...v0.51.289)

##### Fixed

- **Sidebar no longer crashes with `ReferenceError: _sessionAttentionState is not defined`.** The session-attention helper was declared *inside* `renderSessionListFromCache()` and relied on function hoisting, but the top-level `_sidebarRowHasVisibleMessages` (reached via `renderSessionListFromCache` → `_partitionSidebarSessionRows`) called it bare — and hoisting is scoped to the enclosing function, so every sidebar cache-render threw and the session list went blank. `_sessionAttentionState` is now a top-level function reachable by both call sites. Regressed in [#&#8203;3672](nesquena/hermes-webui#3672) (v0.51.269). ([#&#8203;3696](nesquena/hermes-webui#3696))
- **Stale-stream terminal events no longer risk a `ReferenceError: source is not defined`.** `_bailOutOfTerminalEventsFromStaleStream` (declared inside `attachLiveStream`) called `_closeSource(source)` against a `source` that was not in its lexical scope — it would have thrown on the late-finalizing-stream path when the user is back in an active session. `source` is now threaded as an explicit parameter. Found by the new scope gate below during review. ([#&#8203;3696](nesquena/hermes-webui#3696))

##### Internal

- **New static-JS scope/undefined-reference gate (`scripts/scope_undef_gate.py`).** Models the WebUI's classic-`<script>` shared global scope and runs ESLint `no-undef` per file, flagging a function that is defined only *nested* but called from a sibling/top-level scope — the brick class behind [#&#8203;3696](nesquena/hermes-webui#3696) that `node --check`, source-presence tests, and the existing `no-const-assign` runtime gate all miss. Wired into the CI `lint` job alongside the `no-const-assign`/`no-import-assign` runtime gate, with an in-suite test (`tests/test_static_js_scope_undef.py`) and a focused structural regression test (`tests/test_issue3696_session_attention_scope.py`). ([#&#8203;3696](nesquena/hermes-webui#3696))

### [`v0.51.288`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051288--2026-06-06--Release-JD-stage-r24--collapsible-approval-card)

[Compare Source](nesquena/hermes-webui@v0.51.287...v0.51.288)

##### Added

- **The tool-call approval card can be collapsed to a thin header strip.** A chevron toggle in the approval-card header shrinks the card to just its "Approval required" heading so the tool-call rationale and transcript scrolled above it stay readable; clicking again re-expands it. Includes full ARIA (`aria-expanded`/`aria-controls`/`aria-label`), an icon swap, and transcript reflow that preserves a near-bottom scroll position. State resets to expanded for each new approval, so a fresh approval is never hidden. ([#&#8203;3515](nesquena/hermes-webui#3515), [@&#8203;rodboev](https://github.com/rodboev); closes [#&#8203;3007](nesquena/hermes-webui#3007))

### [`v0.51.287`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051287--2026-06-06--Release-JC-stage-r22--WeCom-session-classification--worker-profile-picker-hiding)

[Compare Source](nesquena/hermes-webui@v0.51.286...v0.51.287)

##### Fixed

- **WeCom gateway sessions are now classified as messaging conversations.** Rows arriving with raw sources `wecom` / `wecom_callback` are normalized into the messaging category (alongside weixin/telegram/discord/slack/email) and given proper "WeCom" / "WeCom Callback" display names, so they group and surface correctly in the sidebar. ([#&#8203;3653](nesquena/hermes-webui#3653), [@&#8203;franksong2702](https://github.com/franksong2702))

##### Changed

- **Worker profiles are hidden from the chat profile picker.** Worker profiles (used for orchestrator/Kanban dispatch) are no longer offered as normal human chat targets in the picker, while still appearing in the profile management view with a "Hidden from chat" badge. The active profile is never hidden. ([#&#8203;3662](nesquena/hermes-webui#3662), [@&#8203;Chukwuebuka-20](https://github.com/Chukwuebuka-20))

### [`v0.51.286`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051286--2026-06-06--Release-JB-stage-r21--sidebar-tab-reordering)

[Compare Source](nesquena/hermes-webui@v0.51.285...v0.51.286)

##### Added

- **Drag-reorder for sidebar tabs.** In Settings → Appearance, the "Sidebar tabs" chips (Tasks, Kanban, Skills, Memory, Spaces, Profiles, Todos, Insights, Logs) can be dragged to reorder how they appear in the left rail and sidebar nav, persisted via a sanitized `tab_order` setting (collapses duplicates, rejects `chat`/`settings`, strips non-strings). Chat and Settings stay fixed. Reorder is pointer/desktop-based (consistent with the existing Kanban drag-and-drop); the chips remain tappable for show/hide on touch. ([#&#8203;3067](nesquena/hermes-webui#3067), [@&#8203;ai-ag2026](https://github.com/ai-ag2026))

### [`v0.51.285`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051285--2026-06-06--Release-JA-stage-r19--update-reload-server-identity-race-fix)

[Compare Source](nesquena/hermes-webui@v0.51.284...v0.51.285)

##### Fixed

- **Don't reload the page until the *replacement* server is actually up after an update.** The post-update reload previously compared raw `/health` uptime, which couldn't distinguish a still-running old process from the restarted one (it could reload against the old process or hang). The client now reads a stable `server_started_at` identity before the update POST and reloads only once `/health` reports a *different* identity (with a null-baseline fallback). Both the force-update and regular apply paths read and pass the baseline. ([#&#8203;3654](nesquena/hermes-webui#3654), [@&#8203;franksong2702](https://github.com/franksong2702); [#&#8203;874](nesquena/hermes-webui#874))

### [`v0.51.284`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051284--2026-06-05--Release-IZ-stage-w4--sidebar-status-labels--cron-sessions-toggle)

[Compare Source](nesquena/hermes-webui@v0.51.283...v0.51.284)

##### Added

- **Manual session status labels (Todo / In Progress / Done).** Tag any session from its row's ⋯ menu with a colored status badge (blue Todo / amber In Progress / green Done), stored per-session in localStorage. The badge renders inline on the sidebar row and uses theme variables so it adapts to light/dark and skins. ([#&#8203;3570](nesquena/hermes-webui#3570), [@&#8203;rodboev](https://github.com/rodboev))
- **"Show cron sessions" preference** (Settings → Preferences). Surfaces cron-job output as conversations in the sidebar. Off by default and gated under "Show non-WebUI sessions" — only active once non-WebUI sessions are enabled — with a note that high-frequency jobs can flood the sidebar. ([#&#8203;3514](nesquena/hermes-webui#3514), [@&#8203;rodboev](https://github.com/rodboev); closes [#&#8203;2841](nesquena/hermes-webui#2841))

### [`v0.51.283`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051283--2026-06-05--Release-IY-stage-w2--composer-queue-hint-during-auto-compaction)

[Compare Source](nesquena/hermes-webui@v0.51.282...v0.51.283)

##### Fixed

- **The composer now tells you a message will queue during auto-compaction instead of looking dead.** While automatic compression runs, the send button previously went `disabled` with only a "Waiting for compression to finish" tooltip. It now shows a `queue` action with the placeholder + tooltip "Type a message — it will queue and send after compression", so you can type and have it sent automatically when compaction completes. ([#&#8203;3512](nesquena/hermes-webui#3512), [@&#8203;rodboev](https://github.com/rodboev); closes [#&#8203;3079](nesquena/hermes-webui#3079))

### [`v0.51.282`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051282--2026-06-05--Release-IX-stage-3544--surface-memoryskill-saves-in-Activity-summary)

[Compare Source](nesquena/hermes-webui@v0.51.281...v0.51.282)

##### Added

- **The collapsed Activity summary now shows when the agent saved a memory or updated a skill** — e.g. "Activity: 2 tools, 1 memory saved, 1 skill updated" — so persistent-state changes are visible at a glance without expanding the group. Detection matches the real tool action vocabularies (`memory`: add/replace count as saves, `remove` excluded; `skill_manage`: create/patch/edit/write\_file count as updates, delete/remove\_file excluded), and only completed, non-errored calls are counted. The memory/skill counts are subtracted from the tool count so it reflects only non-memory/skill tools. Classification is stamped as durable `data-*` attributes so the suffix survives the live tool-call group's HTML snapshot/restore on session switch. Sessions with no memory/skill writes render the unchanged "Activity: N tools" label. ([#&#8203;3544](nesquena/hermes-webui#3544), [@&#8203;rodboev](https://github.com/rodboev); closes [#&#8203;3340](nesquena/hermes-webui#3340))

### [`v0.51.281`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051281--2026-06-05--Release-IW-stage-verdigris--Verdigris-emeraldbronze-skin)

[Compare Source](nesquena/hermes-webui@v0.51.280...v0.51.281)

##### Added

- **New "Verdigris" appearance skin** — a dark-only emerald/forest-green palette (`#&#8203;0F1714` background, `#&#8203;121D18` sidebar) with bronze-gold accents (`#C89A5A`), named for the green-bronze patina on aged copper. Selectable in Settings → Appearance and via `/theme verdigris`. Fully scoped under `:root.dark[data-skin="verdigris"]` (no bleed into the default appearance or other skins), with component-level accents for the new-chat button, scrollbar, tool cards, tree viewer, session badges/tags, diff blocks, MCP status, and image lightbox. ([#&#8203;3602](nesquena/hermes-webui#3602), [@&#8203;rodboev](https://github.com/rodboev); closes [#&#8203;3357](nesquena/hermes-webui#3357))

### [`v0.51.280`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051280--2026-06-05--Release-IV-stage-p3i--Windows-self-update-restart-fix)

[Compare Source](nesquena/hermes-webui@v0.51.279...v0.51.280)

##### Fixed

- **Self-update now restarts correctly on Windows.** `os.execv` does not replace the current process on Windows (it spawns a new one while the old keeps running), so the old process held port 8787 and the new process failed to bind ("address already in use"), surfacing as "Update failed" after the timeout. On Windows the restart now launches a detached new process (`subprocess.Popen` with `DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP`) and exits the old one immediately to release the port, plus a bounded bind-retry loop in `server_bind()` (up to 10s) to ride out the `SO_EXCLUSIVEADDRUSE` teardown window. POSIX behavior is unchanged (still `os.execv`). ([#&#8203;3647](nesquena/hermes-webui#3647), [@&#8203;jja881](https://github.com/jja881))

### [`v0.51.279`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051279--2026-06-05--Release-IU-stage-p3h--preserve-Activitystreaming-turn-on-mid-stream-scroll)

[Compare Source](nesquena/hermes-webui@v0.51.278...v0.51.279)

##### Fixed

- **Loading earlier messages during an active stream no longer wipes the Activity panel or the current streaming turn.** Two causes: (1) the message merge/dedup keys didn't include `tool_calls`, so assistant messages invoking *different* tools with identical empty content and same-second timestamps collapsed into one — dropping every state.db tool-call after the first the sidecar registered; (2) `_syncToolCallsForLoadedMessages` cleared `S.toolCalls` while `S.busy` blocked the `renderMessages` rebuild. `tool_calls` is now part of the merge/dedup/visible keys (with a preservation branch so distinct tool invocations within the sidecar timestamp window aren't skipped), and the frontend keeps the live tool-call/streaming state when paging in history. ([#&#8203;3665](nesquena/hermes-webui#3665), [@&#8203;mysoul12138](https://github.com/mysoul12138); fixes [#&#8203;3346](nesquena/hermes-webui#3346))

### [`v0.51.278`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051278--2026-06-05--Release-IT-stage-p3g--repair-inline-PDF-preview)

[Compare Source](nesquena/hermes-webui@v0.51.277...v0.51.278)

##### Fixed

- **Inline PDF preview in chat now renders again.** The PDF.js loader previously created a `<script>` with both `src` and `textContent` set (the latter is ignored when `src` is present), so PDF.js never initialized and the preview hung on the spinner before degrading to a download link. It now loads PDF.js via a blob module script that sets the worker source, passes `isEvalSupported:false` to harden the parser, and revokes the blob URL on load. CSP gains `blob:` in `script-src` and a scoped `worker-src blob: 'self' https://cdn.jsdelivr.net` to permit the worker. ([#&#8203;3652](nesquena/hermes-webui#3652), [@&#8203;xx77yy](https://github.com/xx77yy); closes [#&#8203;3649](nesquena/hermes-webui#3649))

</details>

---

### Configuration

📅 **Schedule**: 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 [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL3BhdGNoIl19-->

Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/856
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Using the teal and gold theme from Hermes agent's dashboard for the "nous" skin

2 participants