# Hermes Web UI -- Changelog > Living document. Updated at the end of every sprint. > Repository: https://github.com/nesquena/hermes-webui --- ## [v0.36] Self-Update Checker with One-Click Update *April 5, 2026 | 433 tests* ### Features - **Update checker.** Non-blocking background check on boot detects when the WebUI or hermes-agent git repos are behind upstream. Blue banner shows "WebUI: N updates, Agent: N updates available" with Update Now / Later. - **One-click update.** "Update Now" runs `git stash && git pull --ff-only && git stash pop` on each behind repo, then reloads the page. Concurrent update attempts blocked via lock. Dirty working trees safely stashed and restored. - **Settings toggle.** "Check for updates" checkbox in Settings panel. Persisted server-side. Disabled = no background fetch, no banner. - **30-minute cache.** Git fetch runs at most twice per hour regardless of tab count. Results cached server-side with TTL. - **Session-scoped dismissal.** "Later" dismisses banner for the current tab session (sessionStorage). New tabs get a fresh check. - **Test mode.** `?test_updates=1` URL param shows the banner with fake data (localhost only) for UI testing without needing to actually be behind. ### Architecture - New `api/updates.py`: `check_for_updates()`, `apply_update()`. Thread-safe caching with `_cache_lock`. Concurrent apply blocked with `_apply_lock`. Default branch auto-detected (master/main). - `api/routes.py`: `GET /api/updates/check`, `POST /api/updates/apply`. Simulate endpoint gated to 127.0.0.1. - `static/ui.js`: `_showUpdateBanner()`, `dismissUpdate()`, `applyUpdates()`. - `static/boot.js`: fire-and-forget check on boot (does not block UI). - `api/config.py`: `check_for_updates` in settings defaults + bool keys. - Docker safe: all git ops gated by `.git` directory existence check. --- ## [v0.35.1] Model dropdown fixes *April 5, 2026 | 433 tests* ### Bug Fixes - **Custom providers invisible in model dropdown (#117).** `cfg_base_url` was scoped inside a conditional block but referenced unconditionally, causing a `NameError` for users with a `base_url` in config.yaml. Fix: initialize to `''` before the block. (#118) - **Configured default model missing from dropdown (#116).** OpenRouter and other providers replaced the model list with a hardcoded fallback that didn't include `model.default` values like `openrouter/free` or custom local model names. Fix: after building all groups, inject the configured `default_model` at the top of its provider group if absent. (#119) --- ## [v0.35] Security hardening *April 5, 2026 | 433 tests* ### Security fixes - **ENV race condition (HIGH):** Two concurrent sessions could interleave `os.environ` writes, clobbering workspace and session keys. Fixed with a global `_ENV_LOCK` in `streaming.py` that serializes the env save/restore block across all sessions. (#108) - **Predictable signing key (MEDIUM):** Session cookies were signed with `sha256(STATE_DIR)` -- deterministic and forgeable if the install path is known. Now generates a cryptographically random 32-byte key on first startup, persisted to `STATE_DIR/.signing_key` (chmod 600). (#108) - **Upload path traversal (MEDIUM):** Filenames like `..` survived the `[^\w.\-]` sanitization regex because dots are allowed. Fixed by rejecting dot-only filenames and validating the resolved path stays within the workspace sandbox via `safe_resolve_ws()`. (#108) - **Weak password hashing (MEDIUM):** Bare SHA-256 with a predictable salt replaced with PBKDF2-SHA256 at 600k iterations (OWASP recommendation) using the random signing key as salt. No new dependencies (stdlib `hashlib.pbkdf2_hmac`). (#108) **Breaking change:** Existing session cookies and password hashes are invalidated on first restart after upgrade. Users with password auth enabled will need to re-set their password. --- ## [v0.34.3] Light theme final polish *April 5, 2026 | 433 tests* ### Bug Fixes - **Light theme: sidebar, role labels, chips, and interactive elements all broken.** Session titles were too faint, active session used washed-out gold, pin stars were near-invisible bright yellow, and all hover/border effects used dark-theme white `rgba(255,255,255,.XX)` values invisible on cream. Fixed with 46 scoped `[data-theme="light"]` selector overrides covering session items, role labels, project chips, topbar chips, composer, suggestions, tool cards, cron list, and more. (#105) - Active session now uses blue accent (`#2d6fa3`) for strong contrast. Pin stars use deep gold (`#996b15`). Role labels are solid and high contrast. --- ## [v0.34.2] Theme text colors *April 5, 2026 | 433 tests* ### Bug Fixes - **Light mode text unreadable.** Bold text was hardcoded white (invisible on cream), italic was light purple on cream, inline code had a dark box on a light background. Fixed by introducing 5 new per-theme CSS variables (`--strong`, `--em`, `--code-text`, `--code-inline-bg`, `--pre-text`) defined for every theme. (#102) - Also replaced remaining `rgba(255,255,255,.08)` border references with `var(--border)`, and darkened light theme `--code-bg` slightly for better contrast. --- ## [v0.34.1] Theme variable polish *April 5, 2026 | 433 tests* ### Bug Fixes - **All non-dark themes had broken surfaces, topbar, and dropdowns.** 30+ hardcoded dark-navy rgba/hex values in style.css were stuck on the Dark palette regardless of active theme. Fixed by introducing 7 new CSS variables (`--surface`, `--topbar-bg`, `--main-bg`, `--input-bg`, `--hover-bg`, `--focus-ring`, `--focus-glow`) defined per-theme, replacing every hardcoded reference. (#100) --- ## [v0.34] Sprint 26 -- Pluggable UI Themes *April 5, 2026 | 433 tests* ### Features - **6 built-in themes.** Dark (default), Light, Slate, Solarized Dark, Monokai, Nord. Defined as CSS variable overrides on `:root[data-theme="name"]` — the entire UI adapts automatically. - **Theme picker in Settings.** Dropdown with instant live preview. Changes apply immediately as you click through options. - **`/theme` slash command.** `/theme dark`, `/theme light`, etc. - **Theme persistence.** Saved server-side in `settings.json` and client-side in `localStorage` for flicker-free loading on page refresh. - **Flash prevention.** Inline `