Loading...
Loading...
Expert in deploying, configuring, and using Hermes WebUI—a web interface for Hermes Agent with persistent memory, scheduled jobs, and multi-platform messaging.
npx skill4agent add aradotso/hermes-skills hermes-webui-agentSkill by ara.so — Hermes Skills collection.
# Clone the repository
git clone https://github.com/nesquena/hermes-webui.git
cd hermes-webui
# Run bootstrap (auto-detects Hermes Agent, creates venv, starts server)
python3 bootstrap.py
# Or use the shell launcher
./start.shhttp://localhost:8787# Start as background daemon
./ctl.sh start
# Check status
./ctl.sh status
# View logs
./ctl.sh logs --lines 100
# Restart
./ctl.sh restart
# Stop
./ctl.sh stop~/.hermes/webui.log~/.hermes/webui.pidgit clone https://github.com/nesquena/hermes-webui
cd hermes-webui
# Copy and edit environment file
cp .env.docker.example .env
# If your host UID isn't 1000 (check with `id -u`), edit .env:
# UID=501 # macOS example
# Start
docker compose up -d
# Open http://localhost:8787echo "HERMES_WEBUI_PASSWORD=your-strong-password" >> .env
docker compose up -d --force-recreatedocker compose -f docker-compose.two-container.yml up -ddocker compose -f docker-compose.three-container.yml up -ddocker 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.env# Port (default: 8787)
HERMES_WEBUI_PORT=9000
# Bind host (default: 127.0.0.1 for local-only, 0.0.0.0 for network)
HERMES_WEBUI_HOST=0.0.0.0
# Password protection (required if HOST is 0.0.0.0)
HERMES_WEBUI_PASSWORD=your-strong-password
# Hermes Agent directory (auto-detected)
HERMES_WEBUI_AGENT_DIR=/path/to/hermes-agent
# State directory (sessions, logs, etc.)
HERMES_WEBUI_STATE_DIR=~/.hermes/webui
# Default workspace directory
HERMES_WEBUI_DEFAULT_WORKSPACE=~/workspace
# Python executable (auto-detected from agent venv)
HERMES_WEBUI_PYTHON=/path/to/python
# Disable auto-install of Hermes Agent
HERMES_WEBUI_AUTO_INSTALL=
# Skip chmod enforcement (Docker only, for .env permission issues)
HERMES_SKIP_CHMOD=1# On your local machine
ssh -L 8787:localhost:8787 user@your-server.com
# Then open http://localhost:8787 in your browserautosshautossh -M 0 -f -N -L 8787:localhost:8787 user@your-server.com# Start daemon (respects .env, inline overrides allowed)
HERMES_WEBUI_HOST=0.0.0.0 ./ctl.sh start
# Check status (PID, uptime, host:port, log path, /health)
./ctl.sh status
# Tail logs
./ctl.sh logs --lines 50
# Restart
./ctl.sh restart
# Stop
./ctl.sh stop# From bootstrap.py or manual start
from pathlib import Path
import subprocess
import sys
# Detect Hermes Agent directory
agent_dir = Path.home() / ".hermes" / "hermes-agent"
if not agent_dir.exists():
agent_dir = Path(__file__).parent.parent / "hermes-agent"
# Find Python from agent venv
venv_python = agent_dir / "venv" / "bin" / "python"
if not venv_python.exists():
venv_python = Path(__file__).parent / ".venv" / "bin" / "python"
# Start server
subprocess.run([
str(venv_python),
"-m", "hermes_webui.server",
"--port", "8787",
"--host", "127.0.0.1"
])#!/usr/bin/env python3
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__)
# Load config from environment
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)
# Password protection middleware
@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 index():
return render_template("index.html")
@app.route("/health")
def health():
return jsonify({"status": "ok", "agent_dir": str(AGENT_DIR), "state_dir": str(STATE_DIR)})
@app.route("/api/sessions", methods=["GET"])
def list_sessions():
sessions_dir = STATE_DIR / "sessions"
sessions = [s.name for s in sessions_dir.glob("*.json")] if sessions_dir.exists() else []
return jsonify({"sessions": sessions})
if __name__ == "__main__":
app.run(host=HOST, port=PORT, debug=False)# WebUI uses the Hermes Agent SDK
import sys
from pathlib import Path
# Add agent to 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
# Initialize agent with memory
agent = Agent(
memory=Memory(storage_dir=Path.home() / ".hermes" / "memory"),
workspace_dir=Path.home() / "workspace"
)
# Send a message
response = agent.send_message("List my recent projects")
print(response)
# Access skills
skills = agent.memory.get_skills()
for skill in skills:
print(f"Skill: {skill.name}, Uses: {skill.use_count}")# Create a cron job (from Hermes Agent directory)
cd ~/.hermes/hermes-agent
source venv/bin/activate
# Schedule a daily summary at 9 AM
hermes schedule create \
--name "daily-summary" \
--cron "0 9 * * *" \
--prompt "Summarize my commits from yesterday and send to Telegram" \
--messenger telegramhermes messenger# Telegram
hermes messenger add telegram --token "$TELEGRAM_BOT_TOKEN" --chat-id "$CHAT_ID"
# Discord
hermes messenger add discord --webhook-url "$DISCORD_WEBHOOK_URL"
# Slack
hermes messenger add slack --webhook-url "$SLACK_WEBHOOK_URL"
# Signal (requires signal-cli)
hermes messenger add signal --phone "+1234567890"from hermes.messengers import get_messenger
telegram = get_messenger("telegram")
telegram.send("Deployment complete! ✅")HERMES_WEBUI_DEFAULT_WORKSPACE# Via WebUI API
POST /api/workspace/switch
{
"path": "/home/user/new-project"
}Switch workspace to ~/new-projecthermes 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 workHermes Agent not foundexport HERMES_WEBUI_AGENT_DIR=/path/to/hermes-agent
./start.sh.envHERMES_WEBUI_AGENT_DIR=/path/to/hermes-agentPermissionError~/.hermes/workspace.env# Check your UID
id -u
# In .env
UID=1000 # Replace with your actual UIDdocker compose down
docker compose up -d# In .env
HERMES_WEBUI_PASSWORD=your-password
# Verify it's loaded
docker compose config | grep PASSWORDdocker compose up -d --force-recreatedocker compose -f docker-compose.yml up -dFROM ghcr.io/nesquena/hermes-webui:latest
USER root
RUN apk add --no-cache git nodejs npm
USER hermeswebuicd ~/.hermes/hermes-agent
source venv/bin/activate
# For OpenAI
hermes model add openai --api-key "$OPENAI_API_KEY"
# For Anthropic
hermes model add anthropic --api-key "$ANTHROPIC_API_KEY"
# For local model (Ollama)
hermes model add ollama --base-url http://localhost:11434
# Set default
hermes model set-default gpt-4docs/wsl-autostart.mdstart-hermes.vbsshell:startupSet objShell = CreateObject("WScript.Shell")
objShell.Run "wsl -d Ubuntu -u yourusername -- /home/yourusername/hermes-webui/ctl.sh start", 0ctl.shchmod +x ~/hermes-webui/ctl.sh/health# Native Python
tail -f ~/.hermes/webui.log
# Docker
docker logs hermes-webui
# ctl.sh daemon
./ctl.sh logsHERMES_WEBUI_AGENT_DIRHERMES_WEBUI_PORT.venvbootstrap.py.hermeskeep-idfrom hermes.orchestration import spawn_agent
# Spawn Claude Code for heavy refactoring
result = spawn_agent(
agent_type="claude-code",
task="Refactor authentication module to use JWT",
workspace="~/my-project"
)
# Result is stored in Hermes memory
agent.memory.add_note(f"Refactoring completed: {result.summary}")Spawn Claude Code to refactor the auth module# In Hermes Agent directory
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"# 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;
}
}HERMES_WEBUI_PASSWORD=strong-password
HERMES_WEBUI_HOST=127.0.0.1 # Keep local, proxy handles externalbootstrap.pyhttp://localhost:8787