Hermes Agent is a sophisticated autonomous agent that lives on your server, accessed via a terminal or messaging apps, that remembers what it learns and gets more capable the longer it runs.
Hermes WebUI is a lightweight, dark-themed web app interface in your browser for Hermes Agent.
Full parity with the CLI experience - everything you can do from a terminal,
you can do from this UI. No build step, no framework, no bundler. Just Python
and vanilla JS.
Layout: three-panel. Left sidebar for sessions and navigation, center for chat,
right for workspace file browsing. Model, profile, and workspace controls live in
the composer footer — always visible while composing. A circular context ring
shows token usage at a glance. All settings and session tools are in the
Hermes Control Center (launcher at the sidebar bottom).
Light mode with full profile support
Customize your settings, configure a password
Workspace file browser with inline preview
Session projects, tags, and tool call cards
This gives you nearly 1:1 parity with Hermes CLI from a convenient web UI which you can access securely through an SSH tunnel from your Hermes setup. Single command to start this up, and a single command to SSH tunnel for access on your computer. Every single part of the web UI uses your existing Hermes agent and existing models, without requiring any additional setup.
Why Hermes
Most AI tools reset every session. They don’t know who you are, what you worked on, or what
conventions your project follows. You re-explain yourself every time.
Hermes retains context across sessions, runs scheduled jobs while you’re offline, and gets
smarter about your environment the longer it runs. It uses your existing Hermes agent setup,
your existing models, and requires no additional configuration to start.
What makes it different from other agentic tools:
Persistent memory — user profile, agent notes, and a skills system that saves reusable
procedures; Hermes learns your environment and does not have to relearn it
Self-hosted scheduling — cron jobs that fire while you’re offline and deliver results to
Telegram, Discord, Slack, Signal, email, and more
10+ messaging platforms — the same agent available in the terminal is reachable from your phone
Self-improving skills — Hermes writes and saves its own skills automatically from experience;
no marketplace to browse, no plugins to install
Provider-agnostic — OpenAI, Anthropic, Google, DeepSeek, OpenRouter, and more
Orchestrates other agents — can spawn Claude Code or Codex for heavy coding tasks and bring
the results back into its own memory
Self-hosted — your conversations, your memory, your hardware
vs. the field(landscape is actively shifting — see HERMES.md for the full breakdown):
OpenClaw
Claude Code
Codex CLI
OpenCode
Hermes
Persistent memory (auto)
Yes
Partial†
Partial
Partial
Yes
Scheduled jobs (self-hosted)
Yes
No‡
No
No
Yes
Messaging app access
Yes (15+ platforms)
Partial (Telegram/Discord preview)
No
No
Yes (10+)
Web UI (self-hosted)
Dashboard only
No
No
Yes
Yes
Self-improving skills
Partial
No
No
No
Yes
Python / ML ecosystem
No (Node.js)
No
No
No
Yes
Provider-agnostic
Yes
No (Claude only)
Yes
Yes
Yes
Open source
Yes (MIT)
No
Yes
Yes
Yes
† Claude Code has CLAUDE.md / MEMORY.md project context and rolling auto-memory, but not full automatic cross-session recall ‡ Claude Code has cloud-managed scheduling (Anthropic infrastructure) and session-scoped /loop; no self-hosted cron
The closest competitor is OpenClaw — both are always-on, self-hosted, open-source agents
with memory, cron, and messaging. The key differences: Hermes writes and saves its own skills
automatically as a core behavior (OpenClaw’s skill system centers on a community marketplace);
Hermes is more stable across updates (OpenClaw has documented release regressions and ClawHub
has had security incidents involving malicious skills); and Hermes runs natively in the Python
ecosystem. See HERMES.md for the full side-by-side.
Quick start
Run the repo bootstrap:
git clone https://github.com/nesquena/hermes-webui.git hermes-webui
cd hermes-webui
python3 bootstrap.py
Or keep using the shell launcher:
./start.sh
For self-hosted VM or homelab installs, ctl.sh wraps the common daemon lifecycle commands without requiring fuser or pkill:
ctl.sh start runs the bootstrap in foreground/no-browser mode behind the daemon wrapper, writes logs to ~/.hermes/webui.log, and respects .env plus inline overrides such as HERMES_WEBUI_HOST=0.0.0.0 ./ctl.sh start.
The bootstrap will:
Detect Hermes Agent and, if missing, attempt the official installer (curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash).
Find or create a Python environment with the WebUI dependencies.
Start the web server and wait for /health.
Open the browser unless you pass --no-browser.
Drop you into a first-run onboarding wizard inside the WebUI.
Native Windows is not supported for this bootstrap yet. Use Linux, macOS, or WSL2.
For Windows / WSL auto-start at login, see docs/wsl-autostart.md.
A community-maintained native Windows guide is tracked in #1952.
If provider setup is still incomplete after install, the onboarding wizard will point you to finish it with hermes model instead of trying to replicate the full CLI setup in-browser.
For a step-by-step walkthrough of the wizard, provider choices, local model server Base URLs, and safe re-runs, see docs/onboarding.md.
Docker
Pre-built images (amd64 + arm64) are published to GHCR on every release.
For a comprehensive setup guide covering all 3 compose files, common failure modes, and bind-mount migration, see docs/docker.md. The README covers the 5-minute happy path.
5-minute quickstart (single container)
The simplest setup: one WebUI container that runs the agent in-process.
git clone https://github.com/nesquena/hermes-webui
cd hermes-webui
cp .env.docker.example .env
# Edit .env if your host UID isn't 1000 (e.g. macOS where UIDs start at 501)
docker compose up -d
# Open http://localhost:8787
The container auto-detects your UID/GID from the mounted ~/.hermes volume so files written by the agent stay readable by you on the host.
To enable password protection (required if you expose the port outside 127.0.0.1):
echo "HERMES_WEBUI_PASSWORD=change-me-to-something-strong" >> .env
docker compose up -d --force-recreate
Both compose files use named Docker volumes by default, which solves the UID/GID problem by construction. If you need bind mounts to share an existing host directory, see docs/docker.md for the full migration recipe.
Known limitation (#681): in the two-container setup, tools triggered from the WebUI run in the WebUI container, not the agent container. If you need git/node/etc. on the WebUI’s filesystem, either use the single-container setup, extend the WebUI Dockerfile, or use the community all-in-one image.
Note: By default, Docker Compose binds to 127.0.0.1 (localhost only).
To expose on a network, change the port to "8787:8787" in docker-compose.yml
and set HERMES_WEBUI_PASSWORD to enable authentication.
What start.sh discovers automatically
Thing
How it finds it
Hermes agent dir
HERMES_WEBUI_AGENT_DIR env, then ~/.hermes/hermes-agent, then sibling ../hermes-agent
Python executable
Agent venv first, then .venv in this repo, then system python3
State directory
HERMES_WEBUI_STATE_DIR env, then ~/.hermes/webui
Default workspace
HERMES_WEBUI_DEFAULT_WORKSPACE env, then ~/workspace, then state dir
Port
HERMES_WEBUI_PORT env or first argument, default 8787
If discovery finds everything, nothing else is required.
Overrides (only needed if auto-detection misses)
export HERMES_WEBUI_AGENT_DIR=/path/to/hermes-agent
export HERMES_WEBUI_PYTHON=/path/to/python
export HERMES_WEBUI_PORT=9000
export HERMES_WEBUI_AUTO_INSTALL=1 # enable auto-install of agent deps (disabled by default)
./start.sh
Bind address (0.0.0.0 for all IPv4, :: for all IPv6, ::1 for IPv6 loopback)
HERMES_WEBUI_PORT
8787
Port
HERMES_WEBUI_STATE_DIR
~/.hermes/webui
Where sessions and state are stored
HERMES_WEBUI_DEFAULT_WORKSPACE
~/workspace
Default workspace
HERMES_WEBUI_DEFAULT_MODEL
openai/gpt-5.4-mini
Default model
HERMES_WEBUI_PASSWORD
(unset)
Set to enable password authentication
HERMES_WEBUI_EXTENSION_DIR
(unset)
Optional local directory served at /extensions/; must point to an existing directory before extension injection is enabled
HERMES_WEBUI_EXTENSION_SCRIPT_URLS
(unset)
Optional comma-separated same-origin script URLs to inject; see WebUI Extensions
HERMES_WEBUI_EXTENSION_STYLESHEET_URLS
(unset)
Optional comma-separated same-origin stylesheet URLs to inject; see WebUI Extensions
HERMES_HOME
~/.hermes
Base directory for Hermes state (affects all paths)
HERMES_CONFIG_PATH
~/.hermes/config.yaml
Path to Hermes config file
Accessing from a remote machine
The server binds to 127.0.0.1 by default (loopback only). If you are running
Hermes on a VPS or remote server, use an SSH tunnel from your local machine:
Then open http://localhost:8787 in your local browser.
start.sh will print this command for you automatically when it detects you
are running over SSH.
Accessing on your phone with Tailscale
Tailscale is a zero-config mesh VPN built on
WireGuard. Install it on your server and your phone, and they join the same
private network – no port forwarding, no SSH tunnels, no public exposure.
The Hermes Web UI is fully responsive with a mobile-optimized layout
(hamburger sidebar, sidebar top tabs in the drawer, touch-friendly controls),
so it works well as a daily-driver agent interface from your phone.
Setup:
Install Tailscale on your server and
your iPhone/Android.
Start the WebUI listening on all interfaces with password auth enabled:
Open http://<server-tailscale-ip>:8787 in your phone’s browser
(find your server’s Tailscale IP in the Tailscale app or with
tailscale ip -4 on the server).
That’s it. Traffic is encrypted end-to-end by WireGuard, and password auth
protects the UI at the application level. You can add it to your home screen
for an app-like experience.
Tip: If using Docker, set HERMES_WEBUI_HOST=0.0.0.0 in your
docker-compose.yml environment (already the default) and set
HERMES_WEBUI_PASSWORD.
Manual launch (without start.sh)
If you prefer to launch the server directly:
cd /path/to/hermes-agent # or wherever sys.path can find Hermes modules
HERMES_WEBUI_PORT=8787 venv/bin/python /path/to/hermes-webui/server.py
Note: use the agent venv Python (or any Python environment that has the Hermes agent dependencies installed). System Python will be missing openai, httpx, and other required packages.
Health check:
curl http://127.0.0.1:8787/health
Running tests
Tests discover the repo and the Hermes agent dynamically – no hardcoded paths.
Tests run against an isolated server on port 8788 with a separate state directory.
Production data and real cron jobs are never touched. Current count: 3309 tests
across 100+ test files.
Features
Chat and agent
Streaming responses via SSE (tokens appear as they are generated)
Multi-provider model support – any Hermes API provider (OpenAI, Anthropic, Google, DeepSeek, Nous Portal, OpenRouter, MiniMax, Xiaomi MiMo, Z.AI); dynamic model dropdown populated from configured keys
Send a message while one is processing – it queues automatically
Edit any past user message inline and regenerate from that point
Retry the last assistant response with one click
Cancel a running task directly from the composer footer (Stop button next to Send)
Tool call cards inline – each shows the tool name, args, and result snippet; expand/collapse all toggle for multi-tool turns
Subagent delegation cards – child agent activity shown with distinct icon and indented border
Thinking/reasoning display – collapsible gold-themed cards for Claude extended thinking and o3 reasoning blocks
Approval card for dangerous shell commands (allow once / session / always / deny)
SSE auto-reconnect on network blips (SSH tunnel resilience)
File attachments persist across page reloads
Message timestamps (HH:MM next to each message, full date on hover)
Code block copy button with “Copied!” feedback
Syntax highlighting via Prism.js (Python, JS, bash, JSON, SQL, and more)
Safe HTML rendering in AI responses (bold, italic, code converted to markdown)
rAF-throttled token streaming for smoother rendering during long responses
Context usage indicator in composer footer – token count, cost, and fill bar (model-aware)
Sessions
Create, rename, duplicate, delete, search by title and message content
Session actions via ⋯ dropdown per session — pin, move to project, archive, duplicate, delete
Pin/star sessions to the top of the sidebar (gold indicator)
Archive sessions (hide without deleting, toggle to show)
Session projects – named groups with colors for organizing sessions
Session tags – add #tag to titles for colored chips and click-to-filter
Grouped by Today / Yesterday / Earlier in the sidebar (collapsible date groups)
Download as Markdown transcript, full JSON export, or import from JSON
Sessions persist across page reloads and SSH tunnel reconnects
Browser tab title reflects the active session name
CLI session bridge – CLI sessions from hermes-agent’s SQLite store appear in the sidebar with a gold “cli” badge; click to import with full history and reply normally
Token/cost display – input tokens, output tokens, estimated cost shown per conversation (toggle in Settings or /usage command)
Workspace file browser
Directory tree with expand/collapse (single-click toggles, double-click navigates)
Breadcrumb navigation with clickable path segments
Preview text, code, Markdown (rendered), and images inline
Edit, create, delete, and rename files; create folders
Binary file download (auto-detected from server)
File preview auto-closes on directory navigation (with unsaved-edit guard)
Git detection – branch name and dirty file count badge in workspace header
Right panel is drag-resizable
Syntax highlighted code preview (Prism.js)
Voice input
Microphone button in the composer (Web Speech API)
Tap to record, tap again or send to stop
Live interim transcription appears in the textarea
Auto-stops after ~2s of silence
Appends to existing textarea content (doesn’t replace)
Hidden when browser doesn’t support Web Speech API (Chrome, Edge, Safari)
Profiles
Profile chip in the composer footer – dropdown showing all profiles with gateway status and model info
Gateway status dots (green = running), model info, skill count per profile
Profiles management panel – create, switch, and delete profiles from the sidebar
Clone config from active profile on create
Optional custom endpoint fields on create – Base URL and API key written into the profile’s config.yaml at creation time, so Ollama, LMStudio, and other local endpoints can be configured without editing files manually
Seamless switching – no server restart; reloads config, skills, memory, cron, models
Per-session profile tracking (records which profile was active at creation)
Authentication and security
Optional password auth – off by default, zero friction for localhost
Enable via HERMES_WEBUI_PASSWORD env var or Settings panel
Signed HMAC HTTP-only cookie with 24h TTL
Minimal dark-themed login page at /login
Security headers on all responses (X-Content-Type-Options, X-Frame-Options, Referrer-Policy)
Spaces – add, rename, remove workspaces; quick-switch from topbar
Mobile responsive
Hamburger sidebar – slide-in overlay on mobile (<640px)
Sidebar top tabs stay available on mobile; no fixed bottom nav stealing chat height
Files slide-over panel from right edge
Touch targets minimum 44px on all interactive elements
Full-height chat/composer on phones without bottom-nav spacing
Desktop layout completely unchanged
Architecture
server.py HTTP routing shell + auth middleware (~154 lines)
api/
auth.py Optional password authentication, signed cookies (~201 lines)
config.py Discovery, globals, model detection, reloadable config (~1110 lines)
helpers.py HTTP helpers, security headers (~175 lines)
models.py Session model + CRUD + CLI bridge (~377 lines)
onboarding.py First-run onboarding wizard, OAuth provider support (~507 lines)
profiles.py Profile state management, hermes_cli wrapper (~411 lines)
routes.py All GET + POST route handlers (~2250 lines)
state_sync.py /insights sync — message_count to state.db (~113 lines)
streaming.py SSE engine, run_agent, cancel support (~660 lines)
updates.py Self-update check and release notes (~257 lines)
upload.py Multipart parser, file upload handler (~82 lines)
workspace.py File ops, workspace helpers, git detection (~288 lines)
static/
index.html HTML template (~600 lines)
style.css All CSS incl. mobile responsive, themes (~1050 lines)
ui.js DOM helpers, renderMd, tool cards, context indicator (~1740 lines)
workspace.js File preview, file ops, git badge (~286 lines)
sessions.js Session CRUD, collapsible groups, search, reload recovery (~800 lines)
messages.js send(), SSE handlers, live streaming, session recovery (~655 lines)
panels.js Cron, skills, memory, profiles, settings (~1438 lines)
commands.js Slash command autocomplete (~267 lines)
boot.js Mobile nav, voice input, boot IIFE (~524 lines)
tests/
conftest.py Isolated test server (port 8788)
61 test files 961 test functions
Dockerfile python:3.12-slim container image
docker-compose.yml Compose with named volume and optional auth
.github/workflows/ CI: multi-arch Docker build + GitHub Release on tag
State lives outside the repo at ~/.hermes/webui/ by default
(sessions, workspaces, settings, projects, last_workspace). Override with HERMES_WEBUI_STATE_DIR.
Docs
HERMES.md – why Hermes, mental model, and detailed comparison to Claude Code / Codex / OpenCode / Cursor
ROADMAP.md – feature roadmap and sprint history
ARCHITECTURE.md – system design, all API endpoints, implementation notes
TESTING.md – manual browser test plan and automated coverage reference
CHANGELOG.md – release notes per sprint
SPRINTS.md – forward sprint plan with CLI + Claude parity targets
THEMES.md – theme system documentation, custom theme guide
docs/onboarding.md – first-run wizard, provider setup, local model server Base URLs, and safe re-runs
docs/troubleshooting.md – diagnostic flows for common failures (e.g. “AIAgent not available”)
Contributors
Hermes WebUI is built with help from the open-source community. Every PR — whether merged directly, absorbed into a batch release, or salvaged from a larger proposal — shapes the project, and we’re grateful to everyone who has taken the time to contribute.
130 contributors have shipped code that landed in a release tag as of v0.51.44. The full credit roll lives in CONTRIBUTORS.md. The highlights:
Top contributors (by PR count, including absorbed/batch-released work)
See CONTRIBUTORS.md for the full ranked list of all 130 contributors, including everyone with one or two PRs and the special-thanks roll for design and architectural contributions.
Notable contributions
@franksong2702 — Most prolific external contributor (92 PRs, v0.49.3 → v0.51.44)
Across the longest tenure of any external contributor: the session title guard (#301), breadcrumb workspace navigation (#302), embedded workspace terminal (#1099), worktree-backed session creation (#2053), onboarding documentation (#2052), composer footer container queries, streaming-session sidebar exemption (#1327), session sidecar repair, cron output preservation (#1295), profile default workspace persistence, and a long tail of polish across mobile/responsive, the session sidebar, and the workspace state machine.
@Michaelyklam — Most prolific contributor of recent releases (81 PRs, v0.50.240 → v0.51.40)
Production Docker hardening (#1921, drops sudo-capable staging user), profile-scoped skills endpoints (#1903), gateway PID resolution under profile-scoped HERMES_HOME (#1901), profile-aware AIAgent cache (#1898/#1904), backslash LaTeX delimiters (#1848), Codex quota error surfacing (#1770), shell-route HTML 503 (#1836), stale Kanban client recovery (#1828), context auto-compression toast lifetime (#1988), /goal command (#1866), Kanban detail-view scrolling (#1916), CLI session tool metadata preservation (#1778), Traditional Chinese kanban locale backfill (#1979).
@bergeouss — Provider management UI + Docker hardening (61 PRs, v0.48.0 → v0.51.18)
Provider management UI for adding/editing custom providers from Settings, OAuth provider status detection (#1552), two-container Docker setup, profile isolation hardening (per-profile .env secrets), the bulk of what users see when they touch Settings → Providers, Reveal-in-Finder context menu (#1551), gateway status card (#1552), auto-assign session to active project filter (#1550), “What’s new?” link in update banner (#1549), OpenRouter free-tier live fetch (#1548), credential pool 401 self-heal (#1553), inline provider chip + group model count in model picker (#1644).
@ai-ag2026 — Session recovery + audit infrastructure (49 PRs, v0.50.279 → v0.51.44)
Autonomous-AI contributor (Hermes Agent-driven) focused on durability: state.db-backed sidecar reconciliation (#2041), orphan .json.bak recovery on startup (#2035), read-only session recovery audit endpoints (#2036, #2040), active run lifecycle in /health (#2039), crash-safe turn-journal RFC at docs/rfcs/turn-journal.md (#2042), fork-session compression lineage isolation (#2014).
@dso2ng — Session lineage + diagnostics (21 PRs, v0.50.227 → v0.51.37)
/api/session/lineage-report/<sid> endpoint for bounded session graph diagnostics (#2012), stale Mermaid render error cleanup (#1337), and a long tail of frontend reliability fixes around session loading.
@jasonjcwu — Composer + transcript polish (13 PRs, v0.50.227 → v0.51.43)
Sidebar collapse via active-rail click (#2054, fuses #1884 + #1924), composer chip lightbox (#1758), title fixes for tool-heavy first turns, and a string of frontend polish fixes.
@aronprins — v0.50.0 UI overhaul (PR #242, plus 9 follow-ups)
The biggest single contribution to the project: a complete UI redesign that moved model/profile/workspace controls into the composer footer, replaced the gear-icon settings panel with the Hermes Control Center (tabbed modal), removed the activity bar in favor of inline composer status, redesigned the session list with a ⋯ action dropdown, and added the workspace panel state machine. Plus chat transcript redesign (#587), sidebar declutter (#584), three-column layout refactor (#899), light/dark theme + accent skins (#627), and shared confirm()/prompt() dialog replacement (PR #251 extracted from #242).
@iRonin — Security hardening sprint (PRs #196–#204)
Six consecutive, focused security PRs: session memory leak fix (expired token pruning), CSP + Permissions-Policy headers, 30-second slow-client connection timeout, optional HTTPS/TLS support via environment variables, upstream branch tracking fix for self-update, and CLI session support in the file-browser API. The kind of focused, high-quality security work that makes a self-hosted tool trustworthy.
@Jordan-SkyLF — Live streaming + session recovery (PRs #366, #367, #394–#397)
Six interlocking improvements: workspace fallback resolution, live reasoning cards that upgrade the generic thinking spinner to a real-time reasoning display, durable session state recovery via localStorage so in-flight tool cards survive a page reload, plus relative time labels and imported-session timestamp preservation.
@JKJameson — Composer + session polish (10 PRs)
Persistent composer draft per session (#1956), and a long tail of polish across the composer and session sidebar.
@gabogabucho — Spanish locale + onboarding wizard
Full Spanish (es) locale covering all UI strings, plus the one-shot bootstrap onboarding wizard that guides new users through provider setup on first launch.
@deboste — Reverse-proxy auth + mobile responsive layout (PRs #3, #4, #5)
Three of the very first community PRs: fixed EventSource/fetch to use URL origin for reverse-proxy setups, corrected model provider routing from config, and added mobile responsive layout with dvh viewport fix. Early foundation work.
@indigokarasu — Visual redesign proposal (PR #213)
A CSS-only redesign of the full UI — proper design tokens, an icon rail sidebar replacing the emoji tab strip, consistent form cards, breadcrumb nav, and 7 built-in themes as custom properties. The PR didn’t merge as-is but shaped the design language and theme architecture that shipped in v0.50.0.
@zenc-cp — Anti-hallucination guard for the ReAct loop (PR #133)
A three-layer approach (ephemeral anti-hallucination prompt, live token filtering, session-history cleanup) that the streaming pipeline still uses.
@Hinotoi-agent — Profile + session security (PRs #351, #2048)
Profile .env secret isolation fix (PR #351) preventing API key leakage between profiles, and session-import workspace validation (PR #2048) blocking a crafted-JSON file-read against /.
@Sanjays2402 — Endless-scroll + Start-jump race fix (PR #1949)
A generation-token + mutex pair fixing the v0.51.30 race between endless-scroll prefetch and Start-jump’s _ensureAllMessagesLoaded. The naive same-flag-check approach (proposed in #1942 and #1962) was a no-op for the post-await race — Sanjays2402’s fix was the correct shape.
@fxd-jason — Real-time approval + clarify via SSE (PRs #1350, #1355)
Replaced 1.5s HTTP polling with SSE long-connections for both approval and clarify, cutting latency from up to 1.5s to near-instant. Got all the correctness details right (atomic subscribe + snapshot, notify-inside-lock, head-of-queue payload, trailing event re-emission).
@happy5318 — Custom provider model dedup (PR #1947)
Fixed the same model from different named custom providers being silently deduplicated in the picker, with Opus catching a race in the original tests that needed augmentation.
@NocGeek — Streaming scroll + manual cron output persistence (7 PRs)
Streaming scroll viewport stability when tool/queue cards insert (#1360), manual cron-run output and metadata persistence (#1372, split from held #1352).
@DavidSchuchert — German translation (PR #190)
Complete German locale (de) covering all UI strings, settings labels, commands, and system messages — and stress-tested the i18n system, exposing several elements that weren’t yet translatable and getting them fixed as part of the same PR.
@Bobby9228 — Mobile Profiles button (PR #265)
Added the Profiles entry to the mobile navigation flow, making profile switching reachable on phones.
@kevin-ho — OLED theme (PR #168)
The 7th built-in theme: pure black backgrounds with warm accents tuned to reduce burn-in risk.
@andrewy-wizard — Chinese localization (PR #177)
Initial Simplified Chinese (zh) locale. One of the first non-English locales.
@DelightRun — session_search fix for WebUI sessions (PR #356)
Tracked down the missing SessionDB injection in the streaming path that was silently breaking the tool for every WebUI session.
@lawrencel1ng — Bandit security fixes (PR #354)
Systematic bandit-scan fixes: URL scheme validation before urlopen, MD5 usedforsecurity=False, and 40+ bare except: pass blocks replaced with proper logging.
@shaoxianbilly — Unicode filename downloads (PR #378)
Proper Content-Disposition with RFC 5987 filename*=UTF-8''... encoding so non-ASCII filenames download without crashing.
@lx3133584 — CSRF fix for reverse proxy (PR #360)
A real-world blocker for anyone hosting behind Nginx Proxy Manager or similar on a port other than 80/443.
@betamod — Security audit (PR #171)
A comprehensive CSRF / SSRF / XSS / env-race-condition audit that shipped in v0.39.0.
@TaraTheStar — Bot name + thinking blocks + login refactor (PRs #132, #176, #181)
Configurable assistant display name, thinking/reasoning block display, and a login page refactor.
Hermes Web UI
Hermes Agent is a sophisticated autonomous agent that lives on your server, accessed via a terminal or messaging apps, that remembers what it learns and gets more capable the longer it runs.
Hermes WebUI is a lightweight, dark-themed web app interface in your browser for Hermes Agent. Full parity with the CLI experience - everything you can do from a terminal, you can do from this UI. No build step, no framework, no bundler. Just Python and vanilla JS.
Layout: three-panel. Left sidebar for sessions and navigation, center for chat, right for workspace file browsing. Model, profile, and workspace controls live in the composer footer — always visible while composing. A circular context ring shows token usage at a glance. All settings and session tools are in the Hermes Control Center (launcher at the sidebar bottom).
Light mode with full profile support
Customize your settings, configure a password
Workspace file browser with inline preview
Session projects, tags, and tool call cards
This gives you nearly 1:1 parity with Hermes CLI from a convenient web UI which you can access securely through an SSH tunnel from your Hermes setup. Single command to start this up, and a single command to SSH tunnel for access on your computer. Every single part of the web UI uses your existing Hermes agent and existing models, without requiring any additional setup.
Why Hermes
Most AI tools reset every session. They don’t know who you are, what you worked on, or what conventions your project follows. You re-explain yourself every time.
Hermes retains context across sessions, runs scheduled jobs while you’re offline, and gets smarter about your environment the longer it runs. It uses your existing Hermes agent setup, your existing models, and requires no additional configuration to start.
What makes it different from other agentic tools:
vs. the field (landscape is actively shifting — see HERMES.md for the full breakdown):
† Claude Code has CLAUDE.md / MEMORY.md project context and rolling auto-memory, but not full automatic cross-session recall
‡ Claude Code has cloud-managed scheduling (Anthropic infrastructure) and session-scoped
/loop; no self-hosted cronThe closest competitor is OpenClaw — both are always-on, self-hosted, open-source agents with memory, cron, and messaging. The key differences: Hermes writes and saves its own skills automatically as a core behavior (OpenClaw’s skill system centers on a community marketplace); Hermes is more stable across updates (OpenClaw has documented release regressions and ClawHub has had security incidents involving malicious skills); and Hermes runs natively in the Python ecosystem. See HERMES.md for the full side-by-side.
Quick start
Run the repo bootstrap:
Or keep using the shell launcher:
For self-hosted VM or homelab installs,
ctl.shwraps the common daemon lifecycle commands without requiringfuserorpkill:ctl.sh startruns the bootstrap in foreground/no-browser mode behind the daemon wrapper, writes logs to~/.hermes/webui.log, and respects.envplus inline overrides such asHERMES_WEBUI_HOST=0.0.0.0 ./ctl.sh start.The bootstrap will:
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash)./health.--no-browser.If provider setup is still incomplete after install, the onboarding wizard will point you to finish it with
hermes modelinstead of trying to replicate the full CLI setup in-browser. For a step-by-step walkthrough of the wizard, provider choices, local model server Base URLs, and safe re-runs, seedocs/onboarding.md.Docker
Pre-built images (amd64 + arm64) are published to GHCR on every release.
For a comprehensive setup guide covering all 3 compose files, common failure modes, and bind-mount migration, see
docs/docker.md. The README covers the 5-minute happy path.5-minute quickstart (single container)
The simplest setup: one WebUI container that runs the agent in-process.
The container auto-detects your UID/GID from the mounted
~/.hermesvolume so files written by the agent stay readable by you on the host.To enable password protection (required if you expose the port outside
127.0.0.1):Manual
docker run(no compose)Build locally
Multi-container setups
If you want the agent and WebUI in separate containers (for isolation, or because you’re already running an agent gateway elsewhere):
Both compose files use named Docker volumes by default, which solves the UID/GID problem by construction. If you need bind mounts to share an existing host directory, see
docs/docker.mdfor the full migration recipe.Common failure modes
PermissionErrorat startupUID=$(id -u)in.env.env: permission denied(#1389)fix_credential_permissions()enforced 0600HERMES_SKIP_CHMOD=1in.env/workspacemountUID=$(id -u)in.envgit: command not foundin chathermes-agent-srcvolume misconfigured.hermesfailskeep-idlimitationFor the deep dive on each of these, see
docs/docker.md.What start.sh discovers automatically
HERMES_WEBUI_AGENT_DIRenv, then~/.hermes/hermes-agent, then sibling../hermes-agent.venvin this repo, then systempython3HERMES_WEBUI_STATE_DIRenv, then~/.hermes/webuiHERMES_WEBUI_DEFAULT_WORKSPACEenv, then~/workspace, then state dirHERMES_WEBUI_PORTenv or first argument, default8787If discovery finds everything, nothing else is required.
Overrides (only needed if auto-detection misses)
Or inline:
Full list of environment variables:
HERMES_WEBUI_AGENT_DIRHERMES_WEBUI_PYTHONHERMES_WEBUI_HOST127.0.0.10.0.0.0for all IPv4,::for all IPv6,::1for IPv6 loopback)HERMES_WEBUI_PORT8787HERMES_WEBUI_STATE_DIR~/.hermes/webuiHERMES_WEBUI_DEFAULT_WORKSPACE~/workspaceHERMES_WEBUI_DEFAULT_MODELopenai/gpt-5.4-miniHERMES_WEBUI_PASSWORDHERMES_WEBUI_EXTENSION_DIR/extensions/; must point to an existing directory before extension injection is enabledHERMES_WEBUI_EXTENSION_SCRIPT_URLSHERMES_WEBUI_EXTENSION_STYLESHEET_URLSHERMES_HOME~/.hermesHERMES_CONFIG_PATH~/.hermes/config.yamlAccessing from a remote machine
The server binds to
127.0.0.1by default (loopback only). If you are running Hermes on a VPS or remote server, use an SSH tunnel from your local machine:Example:
Then open
http://localhost:8787in your local browser.start.shwill print this command for you automatically when it detects you are running over SSH.Accessing on your phone with Tailscale
Tailscale is a zero-config mesh VPN built on WireGuard. Install it on your server and your phone, and they join the same private network – no port forwarding, no SSH tunnels, no public exposure.
The Hermes Web UI is fully responsive with a mobile-optimized layout (hamburger sidebar, sidebar top tabs in the drawer, touch-friendly controls), so it works well as a daily-driver agent interface from your phone.
Setup:
http://<server-tailscale-ip>:8787in your phone’s browser (find your server’s Tailscale IP in the Tailscale app or withtailscale ip -4on the server).That’s it. Traffic is encrypted end-to-end by WireGuard, and password auth protects the UI at the application level. You can add it to your home screen for an app-like experience.
Manual launch (without start.sh)
If you prefer to launch the server directly:
Note: use the agent venv Python (or any Python environment that has the Hermes agent dependencies installed). System Python will be missing
openai,httpx, and other required packages.Health check:
Running tests
Tests discover the repo and the Hermes agent dynamically – no hardcoded paths.
Or using the agent venv explicitly:
Tests run against an isolated server on port 8788 with a separate state directory. Production data and real cron jobs are never touched. Current count: 3309 tests across 100+ test files.
Features
Chat and agent
Sessions
⋯dropdown per session — pin, move to project, archive, duplicate, delete/usagecommand)Workspace file browser
Voice input
Profiles
config.yamlat creation time, so Ollama, LMStudio, and other local endpoints can be configured without editing files manuallyAuthentication and security
HERMES_WEBUI_PASSWORDenv var or Settings panel/loginThemes
/themecommand:root[data-theme="name"]CSS block and it works — see THEMES.mdSettings and configuration
/usagecommand)Slash commands
/in the composer for autocomplete dropdown/help,/clear,/compress [focus topic],/compact(alias),/model <name>,/workspace <name>,/new,/usage,/themePanels
Mobile responsive
Architecture
State lives outside the repo at
~/.hermes/webui/by default (sessions, workspaces, settings, projects, last_workspace). Override withHERMES_WEBUI_STATE_DIR.Docs
HERMES.md– why Hermes, mental model, and detailed comparison to Claude Code / Codex / OpenCode / CursorROADMAP.md– feature roadmap and sprint historyARCHITECTURE.md– system design, all API endpoints, implementation notesTESTING.md– manual browser test plan and automated coverage referenceCHANGELOG.md– release notes per sprintSPRINTS.md– forward sprint plan with CLI + Claude parity targetsTHEMES.md– theme system documentation, custom theme guidedocs/onboarding.md– first-run wizard, provider setup, local model server Base URLs, and safe re-runsdocs/troubleshooting.md– diagnostic flows for common failures (e.g. “AIAgent not available”)Contributors
Hermes WebUI is built with help from the open-source community. Every PR — whether merged directly, absorbed into a batch release, or salvaged from a larger proposal — shapes the project, and we’re grateful to everyone who has taken the time to contribute.
130 contributors have shipped code that landed in a release tag as of v0.51.44. The full credit roll lives in
CONTRIBUTORS.md. The highlights:Top contributors (by PR count, including absorbed/batch-released work)
v0.49.3→v0.51.44v0.50.240→v0.51.40v0.48.0→v0.51.18v0.50.279→v0.51.44v0.50.227→v0.51.37v0.50.227→v0.51.43v0.44.0→v0.50.233v0.50.233→v0.51.31v0.44.0→v0.50.270v0.50.233→v0.51.5See
CONTRIBUTORS.mdfor the full ranked list of all 130 contributors, including everyone with one or two PRs and the special-thanks roll for design and architectural contributions.Notable contributions
@franksong2702 — Most prolific external contributor (92 PRs,
v0.49.3→v0.51.44) Across the longest tenure of any external contributor: the session title guard (#301), breadcrumb workspace navigation (#302), embedded workspace terminal (#1099), worktree-backed session creation (#2053), onboarding documentation (#2052), composer footer container queries, streaming-session sidebar exemption (#1327), session sidecar repair, cron output preservation (#1295), profile default workspace persistence, and a long tail of polish across mobile/responsive, the session sidebar, and the workspace state machine.@Michaelyklam — Most prolific contributor of recent releases (81 PRs,
v0.50.240→v0.51.40) Production Docker hardening (#1921, drops sudo-capable staging user), profile-scoped skills endpoints (#1903), gateway PID resolution under profile-scoped HERMES_HOME (#1901), profile-aware AIAgent cache (#1898/#1904), backslash LaTeX delimiters (#1848), Codex quota error surfacing (#1770), shell-route HTML 503 (#1836), stale Kanban client recovery (#1828), context auto-compression toast lifetime (#1988),/goalcommand (#1866), Kanban detail-view scrolling (#1916), CLI session tool metadata preservation (#1778), Traditional Chinese kanban locale backfill (#1979).@bergeouss — Provider management UI + Docker hardening (61 PRs,
v0.48.0→v0.51.18) Provider management UI for adding/editing custom providers from Settings, OAuth provider status detection (#1552), two-container Docker setup, profile isolation hardening (per-profile.envsecrets), the bulk of what users see when they touch Settings → Providers, Reveal-in-Finder context menu (#1551), gateway status card (#1552), auto-assign session to active project filter (#1550), “What’s new?” link in update banner (#1549), OpenRouter free-tier live fetch (#1548), credential pool 401 self-heal (#1553), inline provider chip + group model count in model picker (#1644).@ai-ag2026 — Session recovery + audit infrastructure (49 PRs,
v0.50.279→v0.51.44) Autonomous-AI contributor (Hermes Agent-driven) focused on durability:state.db-backed sidecar reconciliation (#2041), orphan.json.bakrecovery on startup (#2035), read-only session recovery audit endpoints (#2036, #2040), active run lifecycle in/health(#2039), crash-safe turn-journal RFC atdocs/rfcs/turn-journal.md(#2042), fork-session compression lineage isolation (#2014).@dso2ng — Session lineage + diagnostics (21 PRs,
v0.50.227→v0.51.37)/api/session/lineage-report/<sid>endpoint for bounded session graph diagnostics (#2012), stale Mermaid render error cleanup (#1337), and a long tail of frontend reliability fixes around session loading.@jasonjcwu — Composer + transcript polish (13 PRs,
v0.50.227→v0.51.43) Sidebar collapse via active-rail click (#2054, fuses #1884 + #1924), composer chip lightbox (#1758), title fixes for tool-heavy first turns, and a string of frontend polish fixes.@aronprins —
v0.50.0UI overhaul (PR #242, plus 9 follow-ups) The biggest single contribution to the project: a complete UI redesign that moved model/profile/workspace controls into the composer footer, replaced the gear-icon settings panel with the Hermes Control Center (tabbed modal), removed the activity bar in favor of inline composer status, redesigned the session list with a⋯action dropdown, and added the workspace panel state machine. Plus chat transcript redesign (#587), sidebar declutter (#584), three-column layout refactor (#899), light/dark theme + accent skins (#627), and sharedconfirm()/prompt()dialog replacement (PR #251 extracted from #242).@iRonin — Security hardening sprint (PRs #196–#204) Six consecutive, focused security PRs: session memory leak fix (expired token pruning), CSP + Permissions-Policy headers, 30-second slow-client connection timeout, optional HTTPS/TLS support via environment variables, upstream branch tracking fix for self-update, and CLI session support in the file-browser API. The kind of focused, high-quality security work that makes a self-hosted tool trustworthy.
@Jordan-SkyLF — Live streaming + session recovery (PRs #366, #367, #394–#397) Six interlocking improvements: workspace fallback resolution, live reasoning cards that upgrade the generic thinking spinner to a real-time reasoning display, durable session state recovery via
localStorageso in-flight tool cards survive a page reload, plus relative time labels and imported-session timestamp preservation.@JKJameson — Composer + session polish (10 PRs) Persistent composer draft per session (#1956), and a long tail of polish across the composer and session sidebar.
@gabogabucho — Spanish locale + onboarding wizard Full Spanish (
es) locale covering all UI strings, plus the one-shot bootstrap onboarding wizard that guides new users through provider setup on first launch.@deboste — Reverse-proxy auth + mobile responsive layout (PRs #3, #4, #5) Three of the very first community PRs: fixed EventSource/fetch to use URL origin for reverse-proxy setups, corrected model provider routing from config, and added mobile responsive layout with dvh viewport fix. Early foundation work.
@indigokarasu — Visual redesign proposal (PR #213) A CSS-only redesign of the full UI — proper design tokens, an icon rail sidebar replacing the emoji tab strip, consistent form cards, breadcrumb nav, and 7 built-in themes as custom properties. The PR didn’t merge as-is but shaped the design language and theme architecture that shipped in v0.50.0.
@zenc-cp — Anti-hallucination guard for the ReAct loop (PR #133) A three-layer approach (ephemeral anti-hallucination prompt, live token filtering, session-history cleanup) that the streaming pipeline still uses.
@Hinotoi-agent — Profile + session security (PRs #351, #2048) Profile
.envsecret isolation fix (PR #351) preventing API key leakage between profiles, and session-import workspace validation (PR #2048) blocking a crafted-JSON file-read against/.@Sanjays2402 — Endless-scroll + Start-jump race fix (PR #1949) A generation-token + mutex pair fixing the v0.51.30 race between endless-scroll prefetch and Start-jump’s
_ensureAllMessagesLoaded. The naive same-flag-check approach (proposed in #1942 and #1962) was a no-op for the post-await race — Sanjays2402’s fix was the correct shape.@fxd-jason — Real-time approval + clarify via SSE (PRs #1350, #1355) Replaced 1.5s HTTP polling with SSE long-connections for both approval and clarify, cutting latency from up to 1.5s to near-instant. Got all the correctness details right (atomic subscribe + snapshot, notify-inside-lock, head-of-queue payload, trailing event re-emission).
@happy5318 — Custom provider model dedup (PR #1947) Fixed the same model from different named custom providers being silently deduplicated in the picker, with Opus catching a race in the original tests that needed augmentation.
@NocGeek — Streaming scroll + manual cron output persistence (7 PRs) Streaming scroll viewport stability when tool/queue cards insert (#1360), manual cron-run output and metadata persistence (#1372, split from held #1352).
@DavidSchuchert — German translation (PR #190) Complete German locale (
de) covering all UI strings, settings labels, commands, and system messages — and stress-tested the i18n system, exposing several elements that weren’t yet translatable and getting them fixed as part of the same PR.@Bobby9228 — Mobile Profiles button (PR #265) Added the Profiles entry to the mobile navigation flow, making profile switching reachable on phones.
@kevin-ho — OLED theme (PR #168) The 7th built-in theme: pure black backgrounds with warm accents tuned to reduce burn-in risk.
@andrewy-wizard — Chinese localization (PR #177) Initial Simplified Chinese (
zh) locale. One of the first non-English locales.@DelightRun —
session_searchfix for WebUI sessions (PR #356) Tracked down the missingSessionDBinjection in the streaming path that was silently breaking the tool for every WebUI session.@lawrencel1ng — Bandit security fixes (PR #354) Systematic bandit-scan fixes: URL scheme validation before
urlopen, MD5usedforsecurity=False, and 40+ bareexcept: passblocks replaced with proper logging.@shaoxianbilly — Unicode filename downloads (PR #378) Proper
Content-Dispositionwith RFC 5987filename*=UTF-8''...encoding so non-ASCII filenames download without crashing.@lx3133584 — CSRF fix for reverse proxy (PR #360) A real-world blocker for anyone hosting behind Nginx Proxy Manager or similar on a port other than 80/443.
@betamod — Security audit (PR #171) A comprehensive CSRF / SSRF / XSS / env-race-condition audit that shipped in v0.39.0.
@TaraTheStar — Bot name + thinking blocks + login refactor (PRs #132, #176, #181) Configurable assistant display name, thinking/reasoning block display, and a login page refactor.
Repo