- name
- hermes-studio-dashboard
- description
- Web dashboard for Hermes Agent with multi-platform AI chat, session management, scheduled jobs, and usage analytics
- triggers
- ["set up hermes studio web interface","install hermes web ui dashboard","configure hermes studio channels","manage hermes agent profiles","create hermes scheduled jobs","integrate telegram discord with hermes","deploy hermes studio docker","connect models to hermes dashboard"]
# Hermes Studio Dashboard
> Skill by [ara.so](https://ara.so) — Hermes Skills collection.
Hermes Studio is a comprehensive web dashboard and desktop application for [Hermes Agent](https://github.com/NousResearch/hermes-agent). It provides a unified control plane for managing AI agent conversations, platform integrations (Telegram, Discord, Slack, WhatsApp, Matrix, Feishu, WeChat, WeCom), session management, scheduled automation, model configuration, and usage analytics. Built with TypeScript and Vue3, it runs as a self-hosted local runtime, npm CLI package, or Docker container.
## Installation
### Desktop App (Recommended)
Download the native installer for Windows, macOS, or Linux from [GitHub Releases](https://github.com/EKKOLearnAI/hermes-web-ui/releases/latest).
Hermes data location:
- **Windows**: `%LOCALAPPDATA%\hermes` (fallback: `%APPDATA%\hermes`)
- **macOS/Linux**: `~/.hermes`
### NPM CLI
```bash
npm install -g hermes-web-ui
# Start the server
hermes-web-ui start
# Start with custom port
hermes-web-ui start --port 3001
# Start with custom Hermes home
HERMES_HOME=/custom/path hermes-web-ui start
```
### Docker
```bash
docker pull ekkolearnai/hermes-studio:latest
docker run -d \
--name hermes-studio \
-p 3000:3000 \
-v ~/.hermes:/root/.hermes \
-v ~/.hermes-web-ui:/root/.hermes-web-ui \
-e AUTH_TOKEN=your-secure-token \
ekkolearnai/hermes-studio:latest
```
Access at `http://localhost:3000`
## Core Architecture
Hermes Studio runs a Node.js backend (`packages/server`) that:
- Bridges to Hermes Agent Python runtime via HTTP and Socket.IO
- Manages its own SQLite database for Web UI sessions, users, jobs, Kanban tasks
- Reads Hermes `state.db` for historical agent sessions (read-only)
- Writes platform credentials to `~/.hermes/.env`
- Writes channel behavior config to `~/.hermes/config.yaml`
The Vue3 frontend (`packages/client`) connects via REST API and Socket.IO for real-time chat streaming.
## Authentication
### Default Credentials
First login after fresh install:
- **Username**: `admin`
- **Password**: `123456`
**Important**: Change default credentials immediately after first login via Settings → Account Management.
### Token-Based Auth
Set a custom auth token:
```bash
export AUTH_TOKEN=my-secure-token-123
hermes-web-ui start
```
Or in Docker:
```bash
docker run -d \
-e AUTH_TOKEN=my-secure-token-123 \
-p 3000:3000 \
ekkolearnai/hermes-studio:latest
```
### CLI Maintenance
```bash
# Clear login IP locks
hermes-web-ui clear-login-locks
# Clear locks and restart server
hermes-web-ui clear-login-locks --restart
# Reset admin account to admin/123456
hermes-web-ui reset-default-login
```
## Profile Management
Hermes Studio supports multiple isolated profiles, each with its own:
- Configuration and credentials
- Session history and cache
- Models, providers, skills, plugins
- Scheduled jobs and usage metrics
- Uploaded files
### Creating Profiles
```typescript
// Via API: POST /api/hermes/profiles
const response = await fetch('http://localhost:3000/api/hermes/profiles', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
name: 'production-bot',
description: 'Production customer support agent'
})
});
```
### Switching Profiles
```typescript
// Via API: POST /api/hermes/profiles/switch
await fetch('http://localhost:3000/api/hermes/profiles/switch', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
profileName: 'production-bot'
})
});
```
### Exporting/Importing Profiles
```bash
# Export creates ~/.hermes/profiles/{profile-name}.tar.gz
# Import via Web UI: Profiles → Import Profile → select .tar.gz file
```
## Chat Integration
### Real-Time Chat via Socket.IO
```typescript
import { io } from 'socket.io-client';
const socket = io('http://localhost:3000', {
auth: { token: process.env.AUTH_TOKEN }
});
// Start chat run
socket.emit('chat-run', {
sessionId: 'session-uuid',
message: 'What is the weather in San Francisco?',
profile: 'default',
model: 'gpt-4'
});
// Listen for streaming chunks
socket.on('chat-chunk', (data) => {
console.log('Chunk:', data.chunk);
console.log('Tool calls:', data.toolCalls);
});
// Listen for completion
socket.on('chat-complete', (data) => {
console.log('Final response:', data.response);
console.log('Usage:', data.usage);
});
// Listen for errors
socket.on('chat-error', (error) => {
console.error('Error:', error.message);
});
```
### REST API Chat
```typescript
// Create session
const sessionResponse = await fetch('http://localhost:3000/api/hermes/sessions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
name: 'Customer Support Chat',
profile: 'default'
})
});
const { sessionId } = await sessionResponse.json();
// Send message (non-streaming)
const chatResponse = await fetch('http://localhost:3000/api/hermes/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
sessionId,
message: 'Help me debug this Python error',
profile: 'default',
model: 'claude-3-5-sonnet-20241022'
})
});
const result = await chatResponse.json();
console.log(result.response);
```
## Platform Channel Configuration
### Telegram Bot
```typescript
// Configure via API: POST /api/hermes/channels/telegram
await fetch('http://localhost:3000/api/hermes/channels/telegram', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
enabled: true,
botToken: process.env.TELEGRAM_BOT_TOKEN,
mentionControl: 'required', // 'required' | 'optional' | 'none'
reactions: true,
freeResponseChats: ['123456789'] // Chat IDs for always-respond
})
});
```
Writes to `~/.hermes/.env`:
```bash
TELEGRAM_BOT_TOKEN=your-token-here
```
And `~/.hermes/config.yaml`:
```yaml
telegram:
enabled: true
mention_control: required
reactions: true
free_response_chats:
- 123456789
```
### Discord Bot
```typescript
await fetch('http://localhost:3000/api/hermes/channels/discord', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
enabled: true,
botToken: process.env.DISCORD_BOT_TOKEN,
mentionControl: 'required',
autoThread: true,
reactions: true,
allowedChannels: ['1234567890123456789'],
ignoredChannels: []
})
});
```
### Slack Bot
```typescript
await fetch('http://localhost:3000/api/hermes/channels/slack', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
enabled: true,
botToken: process.env.SLACK_BOT_TOKEN,
appToken: process.env.SLACK_APP_TOKEN,
mentionControl: 'optional',
handleBotMessages: false
})
});
```
### WhatsApp
```typescript
await fetch('http://localhost:3000/api/hermes/channels/whatsapp', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
enabled: true,
mentionControl: 'none',
mentionPattern: '@bot'
})
});
```
### Matrix
```typescript
await fetch('http://localhost:3000/api/hermes/channels/matrix', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
enabled: true,
accessToken: process.env.MATRIX_ACCESS_TOKEN,
homeserver: 'https://matrix.org',
autoThread: true,
dmMentionThreads: true
})
});
```
## Model Management
### Add Custom Provider
```typescript
// POST /api/hermes/providers
await fetch('http://localhost:3000/api/hermes/providers', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
name: 'local-ollama',
baseUrl: 'http://localhost:11434/v1',
apiKey: 'ollama', // Ollama doesn't require real key
type: 'custom'
})
});
```
### Fetch Available Models
```typescript
// GET /api/hermes/providers/{providerId}/models
const response = await fetch(
`http://localhost:3000/api/hermes/providers/${providerId}/models`,
{
headers: { 'Authorization': `Bearer ${process.env.AUTH_TOKEN}` }
}
);
const models = await response.json();
// [{ id: 'llama3.2', name: 'Llama 3.2', ... }, ...]
```
### Set Default Model
```typescript
// PATCH /api/hermes/settings
await fetch('http://localhost:3000/api/hermes/settings', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
defaultModel: 'gpt-4o',
defaultProvider: 'openai'
})
});
```
## Scheduled Jobs (Cron)
### Create Cron Job
```typescript
// POST /api/hermes/jobs
await fetch('http://localhost:3000/api/hermes/jobs', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.AUTH_TOKEN}`
},
body: JSON.stringify({
name: 'Daily Report',
cronExpression: '0 9 * * *', // 9 AM daily
profile: 'default',
task: 'Generate and email daily analytics report',
enabled: true
})
});
```
Voir sur GitHub