| name | hermes-webui-agent |
| description | Expert in deploying, configuring, and using Hermes WebUI—a web interface for Hermes Agent with persistent memory, scheduled jobs, and multi-platform messaging. |
| triggers | ["set up hermes web interface","configure hermes webui","run hermes agent from browser","deploy hermes with docker","troubleshoot hermes webui connection","create hermes scheduled job","access hermes from phone","configure hermes messaging apps"] |
Hermes WebUI Agent
Skill by ara.so — Hermes Skills collection.
Expert in deploying, configuring, and using Hermes WebUI—a lightweight web interface for Hermes Agent. This skill covers installation (native Python and Docker), configuration, SSH tunneling for remote access, messaging platform integration, scheduled jobs, workspace management, and troubleshooting common issues.
What Hermes WebUI Does
Hermes WebUI provides browser-based access to Hermes Agent, a self-hosted autonomous AI agent with:
- Persistent memory across sessions (user profiles, agent notes, self-improving skills)
- Scheduled jobs (cron-style tasks that run offline and deliver via Telegram, Discord, Slack, Signal, email)
- Messaging platform integration (10+ platforms)
- Provider-agnostic (OpenAI, Anthropic, Google, DeepSeek, OpenRouter, local models)
- Self-hosted (your conversations, your memory, your hardware)
The WebUI offers three-panel layout (sessions sidebar, chat center, workspace file browser), full CLI parity, and password protection for remote access.
Installation
Native Python (Recommended for Development)
git clone https://github.com/nesquena/hermes-webui.git
cd hermes-webui
python3 bootstrap.py
./start.sh
The bootstrap will:
- Detect or install Hermes Agent via the official installer
- Create/activate a Python venv with dependencies
- Start the web server on
http://localhost:8787
- Open the browser and show onboarding wizard
For self-hosted VM/homelab (daemon mode):
./ctl.sh start
./ctl.sh status
./ctl.sh logs --lines 100
./ctl.sh restart
./ctl.sh stop
The daemon writes logs to ~/.hermes/webui.log and PID to ~/.hermes/webui.pid.
Docker (Single Container - Simplest)
git clone https://github.com/nesquena/hermes-webui
cd hermes-webui
cp .env.docker.example .env
docker compose up -d
With password protection (required for network exposure):
echo "HERMES_WEBUI_PASSWORD=your-strong-password" >> .env
docker compose up -d --force-recreate
Docker (Multi-Container Setups)
Two-container (agent + WebUI isolated):
docker compose -f docker-compose.two-container.yml up -d
Three-container (agent + dashboard + WebUI):
docker compose -f docker-compose.three-container.yml up -d
Manual Docker Run
docker pull ghcr.io/nesquena/hermes-webui:latest
docker run -d \
-e WANTED_UID=$(id -u) \
-e WANTED_GID=$(id -g) \
-v ~/.hermes:/home/hermeswebui/.hermes \
-e HERMES_WEBUI_STATE_DIR=/home/hermeswebui/.hermes/webui \
-v ~/workspace:/workspace \
-p 127.0.0.1:8787:8787 \
ghcr.io/nesquena/hermes-webui:latest
Configuration
Environment Variables
Create .env in the project root or export variables:
HERMES_WEBUI_PORT=9000
HERMES_WEBUI_HOST=0.0.0.0
HERMES_WEBUI_PASSWORD=your-strong-password
HERMES_WEBUI_AGENT_DIR=/path/to/hermes-agent
HERMES_WEBUI_STATE_DIR=~/.hermes/webui
HERMES_WEBUI_DEFAULT_WORKSPACE=~/workspace
HERMES_WEBUI_PYTHON=/path/to/python
HERMES_WEBUI_AUTO_INSTALL=
HERMES_SKIP_CHMOD=1
SSH Tunnel for Remote Access
If running on a VM/server, access securely via SSH tunnel:
ssh -L 8787:localhost:8787 user@your-server.com
For persistent tunneling, use autossh:
autossh -M 0 -f -N -L 8787:localhost:8787 user@your-server.com
Daemon Lifecycle (ctl.sh)
HERMES_WEBUI_HOST=0.0.0.0 ./ctl.sh start
./ctl.sh status
./ctl.sh logs --lines 50
./ctl.sh restart
./ctl.sh stop
Key Commands and API
Starting the Server (Python)
from pathlib import Path
import subprocess
import sys
agent_dir = Path.home() / ".hermes" / "hermes-agent"
if not agent_dir.exists():
agent_dir = Path(__file__).parent.parent / "hermes-agent"
venv_python = agent_dir / "venv" / "bin" / "python"
if not venv_python.exists():
venv_python = Path(__file__).parent / ".venv" / "bin" / "python"
subprocess.run([
str(venv_python),
"-m", "hermes_webui.server",
"--port", "8787",
"--host", "127.0.0.1"
])
Server Module (hermes_webui/server.py)
import os
from pathlib import Path
from flask import Flask, render_template, request, jsonify
from werkzeug.security import check_password_hash, generate_password_hash
app = Flask(__name__)
PORT = int(os.getenv("HERMES_WEBUI_PORT", 8787))
HOST = os.getenv("HERMES_WEBUI_HOST", "127.0.0.1")
PASSWORD = os.getenv("HERMES_WEBUI_PASSWORD")
STATE_DIR = Path(os.getenv("HERMES_WEBUI_STATE_DIR", Path.home() / ".hermes" / "webui"))
AGENT_DIR = Path(os.getenv("HERMES_WEBUI_AGENT_DIR", Path.home() / ".hermes" / "hermes-agent"))
STATE_DIR.mkdir(parents=True, exist_ok=True)
@app.before_request
def check_auth():
if PASSWORD and request.endpoint not in ["login", "static"]:
auth = request.headers.get("Authorization")
if not auth or not check_password_hash(generate_password_hash(PASSWORD), auth):
return jsonify({"error": "Unauthorized"}), 401
@app.route("/")
def ():
render_template()
():
jsonify({: , : (AGENT_DIR), : (STATE_DIR)})
():
sessions_dir = STATE_DIR /
sessions = [s.name s sessions_dir.glob()] sessions_dir.exists() []
jsonify({: sessions})
__name__ == :
app.run(host=HOST, port=PORT, debug=)
Accessing the Agent in Python
import sys
from pathlib import Path
agent_dir = Path.home() / ".hermes" / "hermes-agent"
sys.path.insert(0, str(agent_dir))
from hermes.agent import Agent
from hermes.memory import Memory
agent = Agent(
memory=Memory(storage_dir=Path.home() / ".hermes" / "memory"),
workspace_dir=Path.home() / "workspace"
)
response = agent.send_message("List my recent projects")
print(response)
skills = agent.memory.get_skills()
for skill in skills:
print(f"Skill: {skill.name}, Uses: {skill.use_count}")
Common Patterns
Setting Up Scheduled Jobs
Scheduled jobs are configured via the Hermes Agent CLI, then accessible from WebUI:
cd ~/.hermes/hermes-agent
source venv/bin/activate
hermes schedule create \
--name "daily-summary" \
--cron "0 9 * * *" \
--prompt "Summarize my commits from yesterday and send to Telegram" \
--messenger telegram
From the WebUI, jobs appear in the Hermes Control Center (bottom sidebar launcher) under "Scheduled Jobs."
Messaging Platform Integration
Configure platforms via hermes messenger CLI:
hermes messenger add telegram --token "$TELEGRAM_BOT_TOKEN" --chat-id "$CHAT_ID"
hermes messenger add discord --webhook-url "$DISCORD_WEBHOOK_URL"
hermes messenger add slack --webhook-url "$SLACK_WEBHOOK_URL"
hermes messenger add signal --phone "+1234567890"
Reference in jobs or send messages:
from hermes.messengers import get_messenger
telegram = get_messenger("telegram")
telegram.send("Deployment complete! ✅")
Workspace File Browsing
The right panel in WebUI browses files from HERMES_WEBUI_DEFAULT_WORKSPACE. To switch workspaces mid-session:
POST /api/workspace/switch
{
"path": "/home/user/new-project"
}
Or via agent message:
Switch workspace to ~/new-project
Using Profiles
Profiles store user-specific context. Create via WebUI Control Center > Profiles or CLI:
hermes profile create work \
--name "Work Profile" \
--context "I'm a Python backend engineer working on FastAPI microservices. I prefer pytest for testing and Docker for deployment."
hermes profile activate work
From WebUI composer footer: dropdown shows active profile.
Troubleshooting
WebUI Can't Find Hermes Agent
Symptom: Hermes Agent not found error on startup.
Fix: Set explicit path:
export HERMES_WEBUI_AGENT_DIR=/path/to/hermes-agent
./start.sh
Or in .env:
HERMES_WEBUI_AGENT_DIR=/path/to/hermes-agent
Permission Denied (Docker)
Symptom: PermissionError writing to ~/.hermes or /workspace.
Fix: Set correct UID in .env:
id -u
UID=1000
Then recreate:
docker compose down
docker compose up -d
Password Not Working
Symptom: 401 Unauthorized even with correct password.
Fix: Check environment variable is set:
HERMES_WEBUI_PASSWORD=your-password
docker compose config | grep PASSWORD
Recreate container:
docker compose up -d --force-recreate
WebUI Shows Empty Workspace (Docker Two-Container)
Symptom: Workspace file browser is empty, but files exist on host.
Fix: This is architectural limitation #681. Tools run in WebUI container, not agent container. Use single-container setup:
docker compose -f docker-compose.yml up -d
Or extend WebUI Dockerfile to install needed tools:
FROM ghcr.io/nesquena/hermes-webui:latest
USER root
RUN apk add --no-cache git nodejs npm
USER hermeswebui
Model Provider Not Configured
Symptom: Onboarding wizard shows "Provider setup incomplete."
Fix: Complete setup via CLI:
cd ~/.hermes/hermes-agent
source venv/bin/activate
hermes model add openai --api-key "$OPENAI_API_KEY"
hermes model add anthropic --api-key "$ANTHROPIC_API_KEY"
hermes model add ollama --base-url http://localhost:11434
hermes model set-default gpt-4
Then refresh WebUI.
WSL Auto-Start Not Working
Symptom: WebUI doesn't start on Windows login.
Fix: See docs/wsl-autostart.md. Quick version:
- Create
start-hermes.vbs in shell:startup:
Set objShell = CreateObject("WScript.Shell")
objShell.Run "wsl -d Ubuntu -u yourusername -- /home/yourusername/hermes-webui/ctl.sh start", 0
- Ensure
ctl.sh is executable:
chmod +x ~/hermes-webui/ctl.sh
Health Check Fails
Symptom: /health returns 500 or connection refused.
Fix: Check logs:
tail -f ~/.hermes/webui.log
docker logs hermes-webui
./ctl.sh logs
Common causes:
- Agent directory not found (set
HERMES_WEBUI_AGENT_DIR)
- Port already in use (change
HERMES_WEBUI_PORT)
- Python venv corrupted (delete
.venv and re-run bootstrap.py)
Podman Shared .hermes Fails
Symptom: Permission issues with Podman 3.4.
Fix: Upgrade to Podman 4+ or use single-container setup. Podman 3.4's keep-id has known limitations with shared volumes.
Advanced Configuration
Custom Agent Orchestration
Hermes can spawn other agents (Claude Code, Codex) and bring results back:
from hermes.orchestration import spawn_agent
result = spawn_agent(
agent_type="claude-code",
task="Refactor authentication module to use JWT",
workspace="~/my-project"
)
agent.memory.add_note(f"Refactoring completed: {result.summary}")
From WebUI, trigger via message:
Spawn Claude Code to refactor the auth module
Custom Skills
Skills are auto-written by Hermes. To manually add:
cd ~/.hermes/hermes-agent
source venv/bin/activate
hermes skill create deploy-to-prod \
--description "Deploy current branch to production" \
--steps "1. Run tests\n2. Build Docker image\n3. Push to registry\n4. Update k8s deployment"
Skills appear in WebUI Control Center > Skills.
External Access (Production)
For production deployment behind a reverse proxy:
# Nginx config
server {
listen 443 ssl;
server_name hermes.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/hermes.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hermes.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8787;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Ensure password is set:
HERMES_WEBUI_PASSWORD=strong-password
HERMES_WEBUI_HOST=127.0.0.1
Summary
Hermes WebUI provides full-featured browser access to Hermes Agent with zero configuration beyond initial bootstrap. Key capabilities:
- Persistent memory across sessions
- Scheduled jobs with multi-platform delivery
- Self-improving skills
- Provider-agnostic model support
- Self-hosted with SSH tunnel or reverse proxy access
Install via bootstrap.py (native) or Docker Compose, configure via environment variables, and access via http://localhost:8787 or SSH tunnel. For production, use password protection and reverse proxy with HTTPS.