| name | hermes-web-ui-dashboard |
| description | Web dashboard for managing Hermes Agent multi-platform AI chat sessions, analytics, scheduled jobs, and platform channels |
| triggers | ["set up hermes web ui dashboard","manage hermes agent sessions","configure hermes platform channels","view hermes usage analytics","create hermes scheduled jobs","deploy hermes web interface","configure telegram discord slack for hermes","monitor hermes ai chat costs"] |
Hermes Web UI Dashboard
Skill by ara.so — Hermes Skills collection.
Hermes Web UI is a full-featured web dashboard for Hermes Agent. It provides AI chat session management, usage analytics, platform channel configuration (Telegram, Discord, Slack, WhatsApp, Matrix, Feishu, WeChat, WeCom), scheduled cron jobs, model management, file browsing, multi-profile support, and gateway control through a responsive Vue 3 interface.
Installation
Global npm Installation (Recommended)
npm install -g hermes-web-ui
hermes-web-ui start
Access at http://localhost:8648
Docker Compose
WEBUI_IMAGE=ekkoye8888/hermes-web-ui docker compose up -d
docker compose up -d --build
docker compose logs -f hermes-webui
Access at http://localhost:6060
Auto-Setup Script (Linux/macOS)
bash <(curl -fsSL https://raw.githubusercontent.com/EKKOLearnAI/hermes-web-ui/main/scripts/setup.sh)
Development Setup
git clone https://github.com/EKKOLearnAI/hermes-web-ui.git
cd hermes-web-ui
npm install
npm run dev
CLI Commands
hermes-web-ui start
hermes-web-ui start --port 9000
hermes-web-ui stop
hermes-web-ui restart
hermes-web-ui status
hermes-web-ui update
hermes-web-ui upgrade
hermes-web-ui -v
hermes-web-ui -h
Environment Variables
Configure the Web UI server (not Hermes Agent itself):
export PORT=8648
export BIND_HOST=0.0.0.0
export HERMES_WEB_UI_HOME=~/.hermes-web-ui
export UPLOAD_DIR=$HERMES_WEB_UI_HOME/upload
export CORS_ORIGINS=*
export AUTH_DISABLED=1
export AUTH_TOKEN=your-secret-token
export PROFILE=default
export LOG_LEVEL=info
export BRIDGE_LOG_LEVEL=info
export MAX_DOWNLOAD_SIZE=200MB
export MAX_EDIT_SIZE=10MB
export WORKSPACE_BASE=/opt/data/workspace
export GATEWAY_HOST=127.0.0.1
export HERMES_WEB_UI_STOP_GATEWAYS_ON_SHUTDOWN=true
Docker Environment Configuration
In docker-compose.yml:
services:
hermes-webui:
image: ekkoye8888/hermes-web-ui:latest
container_name: hermes-webui
ports:
- "6060:8648"
environment:
- PORT=8648
- BIND_HOST=0.0.0.0
- HERMES_WEB_UI_HOME=/app/data/hermes-web-ui
- AUTH_DISABLED=0
- PROFILE=default
- LOG_LEVEL=info
- MAX_DOWNLOAD_SIZE=200MB
- WORKSPACE_BASE=/app/data/workspace
volumes:
- ./hermes_data:/app/data
restart: unless-stopped
Architecture
Browser → BFF Server (Koa :8648) → Hermes Gateway (:8642)
↓
Hermes CLI (sessions, logs)
↓
~/.hermes/config.yaml (channel behavior)
~/.hermes/auth.json (credentials)
~/.hermes-web-ui/ (Web UI data)
BFF Layer Responsibilities:
- API proxy with path rewriting
- SSE streaming from Hermes Gateway
- File upload/download (local, Docker, SSH, Singularity backends)
- Session CRUD via Hermes CLI
- Config and credential management
- WeChat QR login via Tencent iLink API
- Model discovery from credential pool
- Skills and memory management
- Log reading and parsing
Frontend: Vue 3 + TypeScript + Vite + Naive UI + Pinia + Vue Router
Key Features & Usage
AI Chat Sessions
The Web UI maintains its own SQLite session database separate from Hermes' state.db:
import { io } from 'socket.io-client';
const socket = io('http://localhost:8648');
socket.emit('chat-run', {
sessionId: 'session-123',
message: 'Hello, Hermes!',
model: 'gpt-4',
profile: 'default'
});
socket.on('chat-delta', (data) => {
console.log('Streaming chunk:', data.content);
});
socket.on('chat-done', (data) => {
console.log('Response complete:', data);
});
Session Management:
- Sessions grouped by source (Telegram, Discord, Slack, etc.)
- Active sessions pinned to top with spinner
- Sessions sorted by latest message time
- Markdown rendering with syntax highlighting
- Tool call expansion (arguments/result)
- File upload and download support
- Ctrl+K global search across sessions
- Per-session model badge and token usage display
Platform Channel Configuration
Configure 8 platforms from a unified interface. Settings write to:
- Credentials →
~/.hermes/.env
- Behavior →
~/.hermes/config.yaml
Example Telegram Configuration:
telegram:
mention_control: true
reactions_enabled: true
free_response_chats:
- -1001234567890
TELEGRAM_BOT_TOKEN=your_bot_token_here
Supported Platforms:
- Telegram: Bot token, mention control, reactions, free-response chats
- Discord: Bot token, mention, auto-thread, reactions, channel allow/ignore
- Slack: Bot token, mention control, bot message handling
- WhatsApp: Enable/disable, mention control, mention patterns
- Matrix: Access token, homeserver, auto-thread, DM mention threads
- Feishu (Lark): App ID/Secret, mention control
- WeChat: QR code login (scan in browser)
- WeCom: Bot ID/Secret
The Web UI auto-restarts the gateway on config changes.
Model Management
Models are auto-discovered from ~/.hermes/auth.json credential pool:
{
"providers": [
{
"name": "openai",
"type": "openai",
"base_url": "https://api.openai.com/v1",
"api_key": "${OPENAI_API_KEY}",
"models": ["gpt-4", "gpt-3.5-turbo"]
},
{
"name": "anthropic",
"type": "anthropic",
"base_url": "https://api.anthropic.com/v1",
"api_key": "${ANTHROPIC_API_KEY}",
"models": ["claude-3-opus-20240229"]
}
]
}
Model Discovery API:
GET http://localhost:8648/api/models/providers/openai/models
Add Custom Provider:
const response = await fetch('http://localhost:8648/api/models/providers', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-auth-token'
},
body: JSON.stringify({
name: 'custom-llm',
type: 'openai-compatible',
base_url: 'https://api.custom-llm.com/v1',
api_key: process.env.CUSTOM_LLM_KEY,
models: ['custom-model-7b']
})
});
Usage Analytics
View token usage, session counts, estimated costs, and 30-day trends:
GET http://localhost:8648/api/analytics/usage
Response:
{
"totalTokens": 1500000,
"inputTokens": 800000,
"outputTokens": 700000,
"sessionCount": 245,
"dailyAverage": 8.2,
"estimatedCost": 12.45,
"cacheHitRate": 0.35,
"modelDistribution": {
"gpt-4": 60,
"claude-3-opus": 30,
"gpt-3.5-turbo": 10
},
"dailyTrend": [
{ "date": "2026-05-01", "tokens": 50000, "cost":
Scheduled Jobs (Cron)
Create and manage cron jobs for recurring tasks:
const job = await fetch('http://localhost:8648/api/cron/jobs', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
name: 'Daily Report',
schedule: '0 9 * * *',
command: 'hermes agent run --prompt "Generate daily summary"',
enabled: true
})
});
Cron Presets:
- Every hour:
0 * * * *
- Daily at 9 AM:
0 9 * * *
- Weekly Monday 9 AM:
0 9 * * 1
- Monthly 1st 9 AM:
0 9 1 * *
Job Operations:
GET /api/cron/jobs
PATCH /api/cron/jobs/:id/pause
PATCH /api/cron/jobs/:id/resume
POST /api/cron/jobs/:id/trigger
DELETE /api/cron/jobs/:id
Multi-Profile Management
Create isolated Hermes profiles with separate configs and caches:
const profile = await fetch('http://localhost:8648/api/profiles', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
name: 'production',
cloneFrom: 'default'
})
});
Gateway Management per Profile:
POST /api/profiles/:name/gateway/start
POST /api/profiles/:name/gateway/stop
GET /api/profiles/:name/gateway/status
File Browser
Browse and manage files on remote backends:
const files = await fetch('http://localhost:8648/api/files/list?path=/workspace', {
headers: { 'Authorization': `Bearer ${process.env.AUTH_TOKEN}` }
});
const formData = new FormData();
formData.append('file', fileBlob);
formData.append('path', '/workspace/data');
await fetch('http://localhost:8648/api/files/upload', {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.AUTH_TOKEN}` },
body: formData
});
GET /api/files/download?path=/workspace/output.txt
POST /api/files/mkdir
Content-Type: application/json
{ "path": "/workspace/new-dir" }
DELETE /api/files/delete?path=/workspace/old-file.txt
POST /api/files/rename
{ "oldPath": "/workspace/old.txt", "newPath": }
Supported Backends:
- Local filesystem
- Docker containers
- SSH remote hosts
- Singularity containers
Group Chat (Multi-Agent)
Create chat rooms with multiple agents and context compression:
import { io } from 'socket.io-client';
const socket = io('http://localhost:8648');
socket.emit('room-create', {
name: 'Engineering Team',
agents: [
{ name: 'CodeReviewer', profile: 'default' },
{ name: 'Architect', profile: 'production' }
]
});
socket.emit('room-message', {
roomId: 'room-123',
content: '@CodeReviewer can you review this function?',
userId: 'user-456'
});
socket.on('room-agent-reply', (data) => {
console.log(`${data.agentName}: ${data.message}`);
});
Features:
- @mention routing to specific agents
- Auto context compression when history exceeds token threshold
- Typing status and reply progress
- SQLite message persistence
- Invite code management
Authentication
cat ~/.hermes-web-ui/.token
curl -H "Authorization: Bearer your-token-here" \
http://localhost:8648/api/sessions
export AUTH_DISABLED=1
hermes-web-ui start
Username/Password Auth:
After initial token auth, set up username/password via Settings page. Credentials stored in Web UI database.
Web Terminal
Integrated terminal with multi-session support:
const ws = new WebSocket('ws://localhost:8648/terminal');
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'create',
cols: 80,
rows: 24
}));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'output') {
console.log(data.data);
}
};
ws.send(JSON.stringify({
type: 'input',
data: 'ls -la\n'
}));
ws.send(JSON.stringify({
type: 'resize',
cols: 120,
rows: 30
}));
Configuration Files
Hermes Config (~/.hermes/config.yaml)
api_server:
host: 127.0.0.1
port: 8642
cors_origins: ["*"]
telegram:
mention_control: true
reactions_enabled: true
free_response_chats: []
discord:
mention_required: true
auto_thread: true
reactions_enabled: true
allowed_channels: []
ignored_channels: []
memory:
enabled: true
max_chars: 10000
agent:
max_turns: 10
timeout: 300
enforce_tools: false
privacy:
redact_pii: false
Credentials (~/.hermes/auth.json)
{
"providers": [
{
"name": "openai",
"type": "openai",
"base_url": "https://api.openai.com/v1",
"api_key": "${OPENAI_API_KEY}",
"models": ["gpt-4", "gpt-3.5-turbo"]
}
]
}
Use environment variable references (${VAR_NAME}) instead of hardcoded keys.
Common Patterns
Starting Web UI with Custom Config
export PORT=9000
export LOG_LEVEL=debug
export AUTH_DISABLED=1
export HERMES_WEB_UI_HOME=/custom/path
hermes-web-ui start
Programmatic Chat Session
import { io, Socket } from 'socket.io-client';
class HermesChatClient {
private socket: Socket;
constructor(serverUrl = 'http://localhost:8648') {
this.socket = io(serverUrl);
}
sendMessage(sessionId: string, message: string, model = 'gpt-4'): Promise<string> {
return new Promise((resolve) => {
let fullResponse = '';
this.socket.emit('chat-run', {
sessionId,
message,
model,
profile: 'default'
});
this.socket.on('chat-delta', (data) => {
fullResponse += data.content;
});
this.socket.on('chat-done', () => {
resolve(fullResponse);
});
});
}
disconnect() {
..();
}
}
client = ();
response = client.(, );
.(response);
client.();
Batch Session Export
GET http://localhost:8648/api/sessions/export
Auto-Configure Platform on Startup
const configureTelegram = async () => {
const token = process.env.TELEGRAM_BOT_TOKEN;
if (!token) return;
await fetch('http://localhost:8648/api/platforms/telegram', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
bot_token: token,
mention_control: true,
reactions_enabled: true
})
});
};
Troubleshooting
Port Already in Use
lsof -ti:8648 | xargs kill -9
hermes-web-ui start --port 9000
Gateway Not Starting
GET http://localhost:8648/api/gateway/status
GET http://localhost:8648/api/logs?file=gateway.log
hermes-web-ui restart
Authentication Token Not Found
cat ~/.hermes-web-ui/.token
export AUTH_TOKEN=my-secret-token
hermes-web-ui restart
export AUTH_DISABLED=1
hermes-web-ui restart
Docker Volume Permissions
sudo chown -R $(id -u):$(id -g) ./hermes_data
docker compose run --user $(id -u):$(id -g) hermes-webui
Model Discovery Fails
cat ~/.hermes/auth.json | jq .
echo $OPENAI_API_KEY
curl -H "Authorization: Bearer $OPENAI_API_KEY" \
https://api.openai.com/v1/models
WebSocket Connection Errors
export CORS_ORIGINS=http:
hermes-web-ui restart
const socket = io('http://localhost:8648', {
path: '/socket.io/',
transports: ['websocket', 'polling']
});
Session Database Locked
hermes-web-ui restart
rm ~/.hermes-web-ui/sessions.db-wal
rm ~/.hermes-web-ui/sessions.db-shm
Update Fails
npm cache clean --force
npm install -g hermes-web-ui@latest
npm uninstall -g hermes-web-ui
npm install -g hermes-web-ui
Production Deployment
cat > /etc/systemd/system/hermes-web-ui.service <<EOF
[Unit]
Description=Hermes Web UI
After=network.target
[Service]
Type=simple
User=hermes
Environment="PORT=8648"
Environment="AUTH_DISABLED=0"
Environment="LOG_LEVEL=info"
ExecStart=/usr/bin/hermes-web-ui start
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable hermes-web-ui
sudo systemctl start hermes-web-ui
server {
listen 80;
server_name hermes.example.com;
location / {
proxy_pass http://127.0.0.1:8648;
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;
}
location /socket.io/ {
proxy_pass http://127.0.0.1:8648;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Resources: