Claude
Skills
Sign in
Back

hermes-web-ui

Included with Lifetime
$97 forever

```markdown

Design

What this skill does

```markdown
---
name: hermes-web-ui
description: Web dashboard for Hermes Agent — multi-platform AI chat, session management, scheduled jobs, usage analytics & channel configuration
triggers:
  - set up hermes web ui dashboard
  - configure hermes agent channels
  - add telegram discord slack to hermes
  - manage hermes chat sessions
  - schedule cron jobs for hermes agent
  - view hermes usage analytics and costs
  - integrate hermes web ui into my project
  - build custom hermes agent dashboard
---

# Hermes Web UI

> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.

Full-featured Vue 3 web dashboard for [Hermes Agent](https://github.com/NousResearch/hermes-agent). Provides AI chat with streaming, multi-platform channel configuration (Telegram, Discord, Slack, WhatsApp, Matrix, Feishu, WeChat, WeCom), usage analytics, cron job scheduling, skill browsing, log viewing, and an integrated web terminal.

---

## Installation

### Global npm (Recommended)

```bash
npm install -g hermes-web-ui
hermes-web-ui start
# Open http://localhost:8648
```

### One-line Setup (Debian/Ubuntu/macOS)

```bash
bash <(curl -fsSL https://raw.githubusercontent.com/EKKOLearnAI/hermes-web-ui/main/scripts/setup.sh)
```

### WSL

```bash
bash <(curl -fsSL https://raw.githubusercontent.com/EKKOLearnAI/hermes-web-ui/main/scripts/setup.sh)
hermes-web-ui start
```

---

## CLI Commands

| Command | Description |
|---|---|
| `hermes-web-ui start` | Start in background (daemon mode) on port 8648 |
| `hermes-web-ui start --port 9000` | Start on a custom port |
| `hermes-web-ui stop` | Stop the background process |
| `hermes-web-ui restart` | Restart the background process |
| `hermes-web-ui status` | Check if running |
| `hermes-web-ui update` | Update to latest version and restart |
| `hermes-web-ui -v` | Print version number |
| `hermes-web-ui -h` | Show help |

---

## Architecture

```
Browser → BFF (Koa, :8648) → Hermes Gateway (:8642)
                ↓
           Hermes CLI (sessions, logs, version)
                ↓
           ~/.hermes/config.yaml   (channel behavior)
           ~/.hermes/auth.json     (credential pool)
           ~/.hermes/.env          (platform credentials)
```

- **Frontend:** Vue 3 + TypeScript + Vite + Naive UI + Pinia + Vue Router + vue-i18n + SCSS + markdown-it + highlight.js
- **BFF:** Koa 2 server — proxies to Hermes on `:8642`, manages configs, SSE streaming, file uploads, WeChat QR login, model discovery, log reading, static serving
- **Terminal:** node-pty + @xterm/xterm over WebSocket

All Hermes-specific code lives under `hermes/` directories (`api/`, `components/`, `views/`, `stores/`) for multi-agent extensibility.

---

## Development Setup

```bash
git clone https://github.com/EKKOLearnAI/hermes-web-ui.git
cd hermes-web-ui
npm install
npm run dev
# Frontend: http://localhost:5173
# BFF:      http://localhost:8648
```

```bash
npm run build   # outputs to dist/
```

---

## Configuration Files

### `~/.hermes/config.yaml` — Channel Behavior

```yaml
api_server:
  host: 0.0.0.0
  port: 8642

telegram:
  enabled: true
  require_mention: false
  reactions: true
  free_response_chats: ["@my_chat"]

discord:
  enabled: true
  require_mention: true
  auto_thread: true
  reactions: true
  channel_allowlist: []
  channel_ignorelist: []

slack:
  enabled: false
  require_mention: true
  handle_bot_messages: false

whatsapp:
  enabled: false
  require_mention: true
  mention_patterns: ["@hermes"]

matrix:
  enabled: false
  homeserver: "https://matrix.org"
  auto_thread: false
  dm_mention_threads: true
```

### `~/.hermes/auth.json` — Credential Pool

```json
{
  "providers": [
    {
      "name": "openai",
      "base_url": "https://api.openai.com/v1",
      "api_key": "$OPENAI_API_KEY",
      "models": ["gpt-4o", "gpt-4o-mini"]
    },
    {
      "name": "custom",
      "base_url": "https://my-provider.example.com/v1",
      "api_key": "$CUSTOM_API_KEY"
    }
  ]
}
```

### `~/.hermes/.env` — Platform Credentials

```bash
TELEGRAM_BOT_TOKEN=$TELEGRAM_BOT_TOKEN
DISCORD_BOT_TOKEN=$DISCORD_BOT_TOKEN
SLACK_BOT_TOKEN=$SLACK_BOT_TOKEN
SLACK_APP_TOKEN=$SLACK_APP_TOKEN
FEISHU_APP_ID=$FEISHU_APP_ID
FEISHU_APP_SECRET=$FEISHU_APP_SECRET
WECOM_BOT_ID=$WECOM_BOT_ID
WECOM_BOT_SECRET=$WECOM_BOT_SECRET
```

---

## Frontend — Key Patterns

### API Client (BFF proxy calls)

```typescript
// packages/client/src/hermes/api/chat.ts
import axios from 'axios'

const BASE = '/api/hermes'

export async function sendMessage(
  sessionId: string,
  content: string,
  model?: string
): Promise<void> {
  const response = await fetch(`${BASE}/chat/${sessionId}/stream`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ content, model }),
  })

  const reader = response.body!.getReader()
  const decoder = new TextDecoder()

  while (true) {
    const { done, value } = await reader.read()
    if (done) break
    const chunk = decoder.decode(value)
    // parse SSE lines
    for (const line of chunk.split('\n')) {
      if (line.startsWith('data: ')) {
        const data = JSON.parse(line.slice(6))
        // handle delta, tool_call, done events
      }
    }
  }
}
```

### Pinia Store — Sessions

```typescript
// packages/client/src/hermes/stores/sessions.ts
import { defineStore } from 'pinia'
import axios from 'axios'

interface Session {
  id: string
  name: string
  source: string
  model: string
  createdAt: string
}

export const useSessionStore = defineStore('sessions', {
  state: () => ({
    sessions: [] as Session[],
    activeSessionId: null as string | null,
  }),
  actions: {
    async fetchSessions() {
      const { data } = await axios.get('/api/hermes/sessions')
      this.sessions = data
    },
    async createSession(name: string, model: string) {
      const { data } = await axios.post('/api/hermes/sessions', { name, model })
      this.sessions.unshift(data)
      this.activeSessionId = data.id
      return data
    },
    async deleteSession(id: string) {
      await axios.delete(`/api/hermes/sessions/${id}`)
      this.sessions = this.sessions.filter(s => s.id !== id)
      if (this.activeSessionId === id) this.activeSessionId = null
    },
    async renameSession(id: string, name: string) {
      await axios.patch(`/api/hermes/sessions/${id}`, { name })
      const s = this.sessions.find(s => s.id === id)
      if (s) s.name = name
    },
  },
  getters: {
    sessionsBySource: (state) => {
      return state.sessions.reduce((acc, s) => {
        ;(acc[s.source] ??= []).push(s)
        return acc
      }, {} as Record<string, Session[]>)
    },
  },
})
```

### Vue Component — Streaming Chat Message

```vue
<!-- packages/client/src/hermes/components/ChatMessage.vue -->
<template>
  <div class="message" :class="role">
    <div v-if="role === 'assistant'" class="content">
      <div v-html="renderedMarkdown" />
      <ToolCallExpander
        v-for="call in toolCalls"
        :key="call.id"
        :call="call"
      />
      <span v-if="streaming" class="cursor">▋</span>
    </div>
    <div v-else class="content">{{ content }}</div>
    <div class="meta">
      <n-tag size="small">{{ model }}</n-tag>
      <span v-if="tokens">{{ tokens }} tokens</span>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import MarkdownIt from 'markdown-it'
import hljs from 'highlight.js'

const md = new MarkdownIt({
  highlight: (str, lang) => {
    if (lang && hljs.getLanguage(lang)) {
      return hljs.highlight(str, { language: lang }).value
    }
    return ''
  },
})

const props = defineProps<{
  role: 'user' | 'assistant'
  content: string
  model?: string
  tokens?: number
  toolCalls?: Array<{ id: string; name: string; args: unknown; result: unknown }>
  streaming?: boolean
}>()

const renderedMarkdown = computed(() => md.render(props.content))
</script>
```

### Cron Job Management

```typescript
// packages/client/src/hermes/api/jobs.ts
import axios from 'axi
Files: 1
Size: 16.4 KB
Complexity: 18/100
Category: Design

Related in Design