The refresh claimed "Full translation coverage across all non-English locales (no English fallback strings)", but measuring i18n.js directly falsifies it: full-sentence keys are English-identical in several locales (e.g. gateway_start_success: 'Gateway start completed.' appears verbatim in 4+ locale blocks) -- ~30/1574 keys for Czech (~2%), 66 for Polish, 140 for Vietnamese, 243 for Turkish (~15%). These are genuine untranslated fallbacks on recently added keys, consistent with the repo's documented add-keys-with-English-fallback convention. Reword the line to the accurate shape (near-full coverage, measured fallback tail, backfilled by periodic translation passes) so the accuracy refresh stays accurate.
26 KiB
Hermes Web UI — Roadmap
Web companion to the Hermes Agent CLI. Same workflows, browser-native.
This roadmap tracks the whole ecosystem: the web app, the native clients that wrap it (macOS, Windows/Linux, Android, iOS), the extension system, and the autonomous maintenance framework that runs the project.
Version, test count, and release history are derived live, not stamped here (they drift every release). For the current numbers:
- Version + history:
git tag --sort=-v:refname | head+ CHANGELOG.md- Test count:
pytest tests/ --collect-only -q
Status snapshot
| Surface | Status |
|---|---|
| Hermes CLI parity | ✅ Complete — every CLI workflow has a web equivalent |
| Streaming + tool transparency | ✅ Live tool cards, reasoning cards, approval prompts, clarify, cancel, steer |
| Multi-provider model support | ✅ Any provider configured in config.yaml shows in the picker + live custom-endpoint discovery |
| Sessions + projects + search | ✅ CRUD, content search, projects, tags, archive, fork, import, batch ops, CLI bridge |
| Mobile + Docker + auth | ✅ Hamburger nav, slide-overs, PWA install, password auth, GHCR images |
| Auxiliary surfaces | ✅ Workspace tree + edit + terminal, cron CRUD, skills CRUD, memory write, MCP server UI |
| Visual polish | ✅ Light / dark / system × 21 skins, Mermaid, KaTeX, syntax highlighting, Transparent Stream |
| Internationalization | ✅ 15 locales with key-parity guards + CJK/RTL/IME handling |
| Gateway integration | ✅ Live external sessions (Telegram, Discord, Slack, WeChat/Weixin, Signal, SMS) + cross-channel handoff |
| Extension system | ✅ Opt-in loader, capability surface (themes / TTS / nav / sidecars), one-click gallery, vetted library repo |
| Native clients | ✅ macOS (Swift), Windows + Linux + macOS (Rust/Tauri), Android, iOS — each in its own repo |
| Autonomous maintenance | ✅ Self-running triage / review / release pipeline; generalized publicly as StewardOS |
Remaining gaps and forward work live in Forward Work below. The short version: the original CLI-parity + Claude-parity vision is done, and the work has shifted from "reach parity" to "harden reliability + widen distribution."
Architecture
| Layer | Files | Status |
|---|---|---|
| Python server | server.py + api/ modules |
Thin HTTP shell + auth middleware over the api/ business logic (config, sessions, streaming, profiles, routes, onboarding, workspace, updates, upload, extensions) |
| HTML template | static/index.html |
Served from disk |
| CSS | static/style.css |
Themes + skins, mobile responsive, KaTeX, table styles |
| JavaScript | static/{ui,sessions,messages,workspace,panels,boot,commands,icons,i18n,login,onboarding,extension_settings}.js |
Vanilla-JS modules served as static files — no bundler |
| Service worker | static/sw.js |
Offline shell cache, version-pinned assets |
| Docker | Dockerfile, docker-compose.yml |
python:3.12-slim, multi-arch (amd64+arm64), HEALTHCHECK |
| CI/CD | .github/workflows/ |
ruff lint + sharded pytest + Playwright browser + Docker smoke on every PR; auto-release + GHCR publish on tag push |
| Test isolation | tests/_pytest_port.py |
Per-worktree port + state-dir derivation, no collisions |
Per-file line counts drift every release; see
ARCHITECTURE.mdfor the current module map andgit ls-filesfor exact sizes.
Feature parity checklist
Chat and streaming
- Send messages, get SSE-streaming responses
- Composer-scoped model picker (per-conversation model selection)
- Rich provider-grouped, searchable model picker everywhere (composer + Preferences default-model)
- Multi-provider API support — OpenAI, Anthropic, Google, OpenRouter, xAI, GLM, DeepSeek, Mistral, MiniMax, Kimi, OpenCode, Nous Portal, custom OpenAI-compatible endpoints
- Live custom-endpoint model discovery (Ollama, LM Studio, vLLM via
/v1/models) - Add a self-hosted provider (Ollama / LM Studio) from Settings — no
config.yamledit - Free-form OpenRouter model name (autocomplete + custom input)
- Tool progress shown inline via live tool cards
- Approval card for dangerous commands (Allow once / session / always, Deny)
- Approval polling + SSE-pushed approval events
- Clarify dialog — agent can ask blocking clarifying questions
- Subagent delegation cards in tool view
- INFLIGHT guard: switch sessions mid-request without losing response
- Session restores from localStorage on page load
- Reconnect banner if page reloaded mid-stream
- SSE auto-reconnect with extended backoff ladder + full-session poll fallback
- Token / cost estimate per message and per session
- Context usage indicator (compact ring badge in composer footer)
- Auto-compaction handling +
/compactcommand - One-click recovery from "context compression exhausted" (focused continuation)
- rAF-throttled token rendering (smooth, no DOM thrash)
- Cancel / stop button in composer footer
- Reasoning effort selector (low / medium / high / xhigh) +
/reasoning - Pure-text streaming with crash-recovery — partial messages restored from localStorage on reload
- Default message mode on a busy turn: Queue / Interrupt / Steer (new installs default to Steer)
- Steer a live turn with attachments (files uploaded + scoped to the owning session)
- Transparent Stream mode — chronological worklog with per-word fade-in (respects reduced-motion)
Conversation controls
- Copy message to clipboard (hover icon on each bubble)
- Edit last user message and regenerate
- Regenerate last response
- Clear conversation (truncation-watermarked so cleared history cannot resurrect)
- Branch / fork conversation from any message point (turn-boundary aligned on compacted sessions)
- Pure-text + tool-call streams both recover
Sessions
- Create session (+ button or Cmd/Ctrl+K)
- Load session (click in sidebar)
- Delete session (hover trash, toast undo, fallback)
- Auto-title from first user message + adaptive title refresh (configurable cadence)
- LLM-generated titles via auxiliary route (configurable model)
- Rename session inline (double-click, Enter saves, Escape cancels)
- Title search (live filter)
- Content search (full-text across all sessions)
- Date group headers (Today / Yesterday / Earlier) with collapsible groups
- Pin / star sessions to top
- Duplicate session
- Import / Export session as JSON (full messages + metadata)
- Download as Markdown transcript
- Tags (
#tagextraction + filter chips) - Archive sessions (hidden by default, "Show N archived" toggle)
- Projects / folders (chip filter bar, "Unassigned" filter)
- Per-session profile tracking
- Per-session toolset override (
/toolsets) - Batch select mode (multi-select, bulk delete / move / archive)
- CLI session bridge — read CLI/agent sessions from state.db, surface running ones live, import as WebUI sessions
- Fork a read-only cron (scheduled-job) session into an editable chat
- Stable sidebar grouping (fork / compaction / subagent clusters don't reshuffle on refresh)
- Cross-device recency re-sort (a reactivated conversation bumps to top even in a background tab)
Workspace and files
- Add workspace with path validation (existing directory, follows symlinks)
- Remove / rename workspace
- Quick-switch from topbar dropdown
- Sidebar live workspace display (name + path)
- New sessions inherit last-used workspace
- Browse workspace directory tree with type icons
- Tree view with expand / collapse + lazy load (#22)
- Breadcrumb navigation in subdirectories
- Preview text / code (read-only)
- Preview markdown (rendered + tables + Mermaid + KaTeX)
- Preview images (PNG, JPG, GIF, SVG, WEBP, AVIF inline)
- Preview PDF / SVG / audio / video / Excalidraw / CSV / JSON / YAML
- Edit files inline (Edit button, Enter saves, Escape cancels)
- Create / rename / delete files and folders (in current directory)
- Drag-drop / click / clipboard paste upload
- Archive upload (zip / tar) with extraction
- Copy absolute + relative file path
- Syntax highlighted code preview (Prism.js, language-aware)
- File preview auto-close on directory navigation
- Right panel resizable (drag inner edge)
- Embedded workspace terminal (
/api/terminal/{start,input,output}) - Git branch + dirty status badge in workspace header
Cron jobs
- List all cron jobs (Tasks sidebar tab)
- View job details (prompt, schedule, last run, output)
- Run / pause / resume / delete
- Create job from UI (name, schedule, prompt, delivery target)
- Edit job inline (full create-form parity, including skills)
- Skill picker in create + edit forms
- No-cron-syntax schedule builder (frequency presets + time / day pickers, inline expression preview)
- Cron run history viewer (expandable per job)
- Cron completion alerts (toast + badge)
- Run-status tracking with live watch mode
Skills
- List all skills grouped by category
- Search / filter by name, description, category
- View full SKILL.md content
- View skill linked files
- Create / edit / delete skill
/skillsslash command
Memory
- View personal notes (MEMORY.md) rendered as markdown
- View user profile (USER.md) rendered as markdown
- Last-modified timestamp per section
- Add / edit memory entries inline
Profiles
- Multi-profile support — create, switch, delete (#28)
- Topbar profile picker with gateway-status dots
- Profile management panel (full CRUD)
- Seamless switching (no server restart, refreshes models / skills / memory / cron / workspace + forces config reload)
- Profile-local workspace storage
- First-run onboarding wizard with provider config (OpenRouter / Anthropic / OpenAI / Custom)
- In-app OAuth for Codex and Claude
- Concurrent per-profile isolation (context-local home override so parallel workers can't clobber each other)
Configuration
- Settings panel (default model, default workspace, send key, theme, skin, voice, font size)
- Searchable settings
- Send key preference (Enter or Ctrl+Enter)
- Password authentication (off by default)
- Per-session toolset override
- Personality config via
config.yaml - Reasoning effort persistence
Notifications
- Cron job completion alerts
- Background agent error banner
- Approval pending badge
- Provider / model mismatch toast warning
Slash commands
- Command registry + autocomplete dropdown
- Built-ins:
/help,/clear,/model,/workspace,/new,/usage,/theme,/compact,/queue,/interrupt,/steer,/goal,/btw,/reasoning,/skills,/toolsets - Transparent pass-through for unrecognized commands
Security
- Password auth with signed HMAC HTTP-only cookies (24h TTL)
- Security headers (X-Content-Type-Options, X-Frame-Options, Referrer-Policy)
- CSRF protection (scheme-aware, port-normalized for reverse proxies)
- CORS preflight echoes allowlisted origin only — never wildcard
- PBKDF2 password hashing
- Rate limiting on auth endpoints
- Session ID validation
- SSRF guard on
/api/models/live,cfg_base_url,custom_providers[] - ENV_LOCK around env mutations
- XSS sanitization on all rendered HTML
- HMAC-signed signing keys (random per install)
- Skills path-traversal guard
- Secure cookie flags (HttpOnly, SameSite, Secure when HTTPS)
- Error message sanitization (no stack traces in responses)
- POST body size limit (20MB)
- Upload path-traversal guard
- Credential redaction in API responses
- Profile
.envsecret isolation on switch - Open-redirect guard on
?next=login param (bounded decode, collapses login-loop chains) - Auto-install gate (opt-in via
HERMES_WEBUI_AUTO_INSTALL=1)
Visual / UX
- 3 base modes — Light, Dark, System (auto-sync)
- 21 skins layered on the base mode — default, ares, catppuccin, charizard, codex, geist-contrast, github, graphite, hepburn, mono, neon, neon-paint, neon-soft, nous, poseidon, sienna, sisyphus, slate, terracotta, verdigris, zeus
- 2-axis appearance model (base mode + skin) for community theme contributions
- Mermaid diagram rendering (with fit / fullscreen toolbar)
- KaTeX math rendering with fence-before-math fix
- Syntax highlighting (Prism.js, language-aware, YAML newline preservation)
- Markdown image syntax
and inline MEDIA: tokens render as<img> - Plain URL auto-linking
- Inline markdown in table cells (bold, italic, code, links)
- Code block copy button
- Tool card expand / collapse toggle
- Collapsible thinking / reasoning cards (Claude extended thinking, o3 reasoning tokens)
- Message timestamps (subtle, full date on hover)
- Chat header (model, icon, TPS badge, timestamp) scales with text-size preference
- Empty composer hides send button (icon-circle with pop-in animation)
- Pluggable Lucide SVG icons (no emoji rendering inconsistencies)
- Composer-centric controls (v0.50.0 UI overhaul)
- Hermes Control Center modal (centralized actions)
- Workspace panel state machine (defaults closed, opens for browsing / preview)
- Three-panel desktop layout keeps a readable conversation floor when resizing
- PWA manifest + service worker (offline shell)
- Favicon (SVG + PNG + ICO)
- Branded onboarding wizard
Voice
- Voice input via Web Speech API (push-to-talk dictation)
- Hands-free voice mode (turn-based conversation, opt-in via Settings → Preferences)
- TTS playback of responses (configurable voice, rate, pitch)
Mobile
- Hamburger sidebar (slide-in overlay)
- Bottom navigation bar (5-tab iOS-style)
- Files slide-over (right panel as slide-over)
- 44px minimum touch targets
- Container queries on composer
- Android Chrome compatibility fixes
- PWA installation (manifest + icons + Android support)
- Streaming-scroll hardening — off-screen height retention, native scroll-anchoring, no jump-to-top on iOS/Android
- Mobile drawer surfaces dashboard link + extension nav-actions
Internationalization
- 15 locales — English, Italian, Japanese, Russian, Spanish, German, Chinese (zh + zh-Hant), Portuguese, Korean, French, Czech, Turkish, Polish, Vietnamese
- Near-full translation coverage across non-English locales — a small English-fallback tail remains on recently added keys (measured ~2% for Czech up to ~15% for Turkish), backfilled by periodic translation passes
- Key-parity test ensures every locale has every key
- Right-to-left and CJK input (IME composition fixes)
Gateway integration
- Real-time gateway sessions in sidebar (Telegram, Discord, Slack, WeChat/Weixin, Signal, SMS) via SSE + DB polling
- Cross-channel handoff dock — composer-docked flyout summarizing the live external session
- Transcript-summary card at 10+ rounds
- Sidebar dedup keying on per-conversation identity (distinct chats from same platform stay separate)
- Gateway session sync skips dup / delete options for external sessions
- LLM Gateway routing metadata display — assistant turns and session metadata show the served model/provider, failover path, and model-switch warnings (#732)
- Gateway status card in Settings (#1457)
- Gateway approval-runs API opt-in (documented)
MCP integration
- MCP server management UI (System Settings → MCP Servers)
- Add / edit / delete MCP server entries
Extension system
- Opt-in extension loader — serve local static assets, inject same-origin CSS/JS into the app shell
- One-click install from an in-app gallery (Settings → Extensions) into a WebUI-managed state-dir directory (no restart, no env vars)
- Manifest contract (
extensions.json) for bundled / multi-extension installs - Capability surface — register custom themes (skins), register custom TTS engines, add nav-actions, declare loopback sidecars, embed an external web app in an iframe tab
- Per-extension settings schema + owned storage
- Consented extension sidecar proxy path (no arbitrary backend route registration)
- Status + diagnostics endpoint
- Trust model documented — extensions run with full session authority; install only vetted/self-authored
- Vetted, versioned library repo with CI safety gates — hermes-webui/hermes-webui-extensions ("in the registry == vetted")
- Core repo bundles zero extensions — clean client-side extensions are migrated to the library repo, not merged into core
Distribution
- Docker support (multi-arch amd64 + arm64, HEALTHCHECK, UID/GID auto-detect)
- Two-container Docker compose (webui + agent)
- GHCR auto-publish on tag push
- Subpath mount support (reverse proxy at
/hermes/) - PWA installable from any browser
- Native macOS app — universal Intel + Apple Silicon, signed + notarized DMG, Sparkle 2 auto-update
- Native Windows + Linux + macOS desktop app — Rust/Tauri, per-platform installers
- Native Android app — Play-ready APK/AAB releases
- Native iOS app — iPhone client (connects over Tailscale)
See Native clients for the per-repo detail.
Native clients
The web app is the engine; a small fleet of native shells wrap it so Hermes runs as a real app on every platform. Each lives in its own repo with its own versioning and release cadence — none is a fork of the WebUI source.
| Client | Platforms | Tech | Repo |
|---|---|---|---|
| Hermes for Mac | macOS (Intel + Apple Silicon) | Swift + WKWebView, SSH tunnel, Sparkle 2 auto-update, signed + notarized DMG | hermes-webui/hermes-swift-mac |
| Hermes Desktop | Windows + Linux + macOS | Rust / Tauri (WebView2 / WebKitGTK), per-platform installers | hermes-webui/hermes-desktop-rust |
| Hermes for Android | Android | Native Android, Play-ready releases | hermes-webui/hermes-android |
| Hermes for iOS | iOS (iPhone) | Native Swift, connects over Tailscale (QR / hostname pairing) | hermes-webui/hermes-swift-ios |
One server, every client: run the WebUI on one machine and reach it from web, desktop, and phone. Live versions and release notes are on each repo's Releases page — this table intentionally carries no version numbers (they drift per repo).
Autonomous project maintenance
Hermes WebUI is maintained by an autonomous agent system: inbound issues and PRs are triaged, deep-reviewed (multi-model gate + full test suite + browser QA), released, and closed with attribution — largely without manual steering. The project-agnostic distillation of that system is published as an open framework so any maintainer can adopt it:
- StewardOS — nesquena/steward-os · docs at nesquena.github.io/steward-os. Roles, autonomy bands, the security spine, issue/PR/quality-gate lifecycles, and reusable skills — harness-agnostic (no specific agent runtime required).
StewardOS is the generalization; the WebUI's own operating procedures are the source. This is the reason contributor PRs get same-day deep review and the release cadence runs multiple ships per day.
Forward work
Most of the original forward-work list has shipped. What remains is either an
open feature request under active consideration or an explicitly-deferred concept.
Issue state drifts — re-derive with gh issue list --repo nesquena/hermes-webui.
Open candidates (feature requests under active consideration)
| Theme | Tracking | Why |
|---|---|---|
| Lightweight in-app Canvas editing | #1255 | Text canvas for prompt drafting / shared notes |
| Provider / Model source-of-truth alignment | #1240 | Reconcile WebUI vs CLI vs Gateway provider resolution |
| Built-in SearXNG web search | #1037 | Lightweight search tool with on / off toggle |
Sunset legacy LMSTUDIO_API_KEY env var |
#1502 | Alias stays for one minor cycle, then removed |
| Native MCP server expose | #733 | Hermes WebUI as an MCP server for direct agent integration |
| Teams / agents management panel | #719 | Editable names, roles, assignments |
| WebUI profile ↔ Hermes runtime model alignment | #749 | Design parity between WebUI profiles and the runtime model |
| Add agent / replace model modals | #698 | Dedicated modals for agent + model management |
Backlog (deferred, listed for visibility)
- Insights / monitoring suite — data tabs / live integration (#722), monitor dashboard concepts (#721)
- Code execution inline cells — Jupyter-style cell rendering inside chat
- Sharing / public conversation URLs — requires hosted backend with access control (out of scope for self-host)
Intentionally not planned
- Full SwiftUI/native rewrite of the frontend — the WebView shells already get ~95% of native benefit at a fraction of the maintenance cost
- App Store distribution for the desktop apps — sandboxing breaks the local-server model
- Real-time multi-user collaboration — single-user assumption throughout
- Multi-tenant / white-label hosting — the project is single-user / multi-profile, not multi-tenant
- Anthropic / Claude proprietary features — Projects AI memory, Claude artifacts sync (not reproducible)
Note: a plugin/extension marketplace was once "not planned" — that gap is now filled by the extension system + the vetted library repo, which cover the customization surface without a heavyweight dependency system.
Sprint history
Per-version detail lives in CHANGELOG.md. The table below is a high-level chronology of major sprint themes; individual PR / fix detail lives in CHANGELOG to keep this file readable.
| Range | Theme | Highlights |
|---|---|---|
| Sprints 1–6 | Foundations + workspace | server / static split, JS module split, workspace CRUD, file editor, message queue + INFLIGHT, isolated test environment |
| Sprint 7 | Wave 2 core | Cron / skill / memory CRUD, session content search, health endpoint, git init |
| Sprint 8 | Daily-driver finish line | Edit + regenerate, regenerate last response, clear conversation, Prism.js, queue + INFLIGHT polish |
| Sprints 9–10 | Codebase health + operational polish | app.js → 6 modules, server.py → api/ modules, tool card UX, background task cancel, regression tests |
| Sprint 11 | Multi-provider models + streaming | Dynamic model dropdown, smooth scroll pinning, routes extracted to api/routes.py |
| Sprint 12 | Settings + reliability + session QoL | Settings panel, SSE auto-reconnect, pin sessions, JSON import |
| Sprint 13 | Alerts + polish | Cron alerts, background error banner, session duplicate, browser tab title |
| Sprint 14 | Visual polish + workspace ops | Mermaid, message timestamps, file rename, folder create, session tags, archive |
| Sprint 15 | Session projects + code copy | Projects / folders, code copy button, tool card expand / collapse |
| Sprint 16 | Sidebar visual polish | SVG icons, action dropdown, pin indicator, project border, safe HTML rendering |
| Sprint 17 | Workspace polish + slash commands | Breadcrumb nav, slash command autocomplete, send key setting (#26) |
| Sprint 18 | Thinking display + workspace tree | File preview auto-close, thinking / reasoning cards, expandable directory tree (#22) |
| Sprint 19 | Auth + security hardening | Password auth, login page, security headers, body limit (#23) |
| Sprint 20 | Voice input + send button | Web Speech API voice, send button polish |
| Sprint 21 | Mobile responsive + Docker | Hamburger sidebar, mobile nav, slide-over files, Docker support (#21, #7) |
| Sprint 22 | Multi-profile support | Profile picker, management panel, seamless switching, per-session tracking (#28) |
| Sprint 23 | Agentic transparency | Token / cost display, subagent cards, skill picker in cron, profile-local storage |
| Sprint 24 | Web polish | rAF streaming, git detection, collapsible date groups, context ring (#80–#83) |
| Sprint 25 | macOS desktop application | Native Swift + WKWebView shell, universal DMG, Sparkle 2 auto-update |
| Sprint 26 | Pluggable themes | Light / Slate / Solarized / Monokai / Nord, settings unsaved-changes guard, /theme |
| Sprint 27 | Theme polish | 30+ hardcoded colors → CSS variables, light theme final polish |
| Sprint 28 | Security hardening | Env race fix, random signing key, upload traversal, PBKDF2 |
| Sprints 29–32 | Model routing + custom endpoints + reasoning | Model routing by provider prefix, custom endpoint URL fix, OLED theme, top-level reasoning, message_count sync |
| Sprint 33 | Approval card + Lucide icons | Approval prompt surfaced, emoji → SVG, login CSP fix, update diagnostics |
| Sprint 34 | v0.50.0 UI overhaul | Composer-centric controls, Control Center modal, workspace state machine, collapsible date groups, rAF throttle, context ring |
| Sprints 35–37 | Onboarding + i18n | First-run wizard, provider config, Spanish locale, Docker two-container, mobile Profiles button |
| Sprints 38–40 | Session + UI polish | Five-bug clean-up, sidebar timestamp, test port isolation |
| Sprints 41–42 | Renderer hardening + KaTeX + handoff | Context ring live usage, renderMd link / image / code stash chain, MEDIA: image rendering, gateway handoff foundation |
| Sprints 43+ | Continuous contributor sprints | Custom providers, more locales, IME fixes, model-switch toast, approval queue multi-slot, profile polish, font-size CSS, contributor wave |
| Ongoing | Ecosystem expansion + reliability | Extension system + library, Rust/Android/iOS native clients, StewardOS, gateway platform expansion (Signal/SMS/WeChat), Transparent Stream, mobile scroll hardening, session-load perf, test-isolation flake elimination |
Versioning conventions
- Patch (
v0.51.X) — small batches, contributor PR releases, hotfixes - Minor (
v0.X.0) — sprint completion, new feature surface, architecture milestone - Major (
v1.0.0) — declared when the feature surface stabilizes and reliability across all clients reaches steady state
Per-version detail and contributor attribution live in CHANGELOG.md.