# CLAUDE.md — Hermes Web UI Development Guide ## Project Overview Hermes Web UI is a web dashboard for [Hermes Agent](https://github.com/EKKOLearnAI/hermes-web-ui), a multi-platform AI chat system. It provides session management, scheduled jobs, usage analytics, model configuration, channel management (Telegram, Discord, Slack, WhatsApp, etc.), an integrated terminal, and a streaming chat interface. The project is designed for **multi-agent extensibility** — Hermes is the first agent integration. All agent-specific code is namespaced under `hermes/` directories, so future agents can be added alongside without conflicts. **Tech stack:** - **Frontend:** Vue 3 (Composition API, ` ``` Key patterns: - Import Naive UI components directly from `naive-ui` - Use `useMessage()` for toast notifications - Use `useI18n()` for translations, access via `t('key.path')` - Scoped SCSS with `@use '@/styles/variables' as *` ### Vue Composables Shared composables live in `packages/client/src/composables/`: - `useKeyboard.ts` — keyboard shortcut handling - `useTheme.ts` — theme management (dark/light mode) ### Pinia Stores Use setup store syntax (function passed to `defineStore`): ```ts import { defineStore } from 'pinia' import { ref } from 'vue' export const useMyStore = defineStore('myStore', () => { const items = ref([]) const loading = ref(false) async function fetchItems() { loading.value = true try { items.value = await apiCall() } finally { loading.value = false } } return { items, loading, fetchItems } }) ``` Existing stores in `packages/client/src/stores/hermes/`: `app`, `chat`, `jobs`, `models`, `settings`, `usage`, `gateways`, `profiles`. ### API Layer Agent-specific API modules live in `api/{agent}/`. The shared base `api/client.ts` provides: - `request(path, options)` — typed fetch wrapper with automatic `Authorization: Bearer` header and global 401 handling (clears token, redirects to login) - `getApiKey()` / `setApiKey()` / `clearApiKey()` — token management via `localStorage` - `getBaseUrlValue()` — configurable server URL from `localStorage` ```ts // packages/client/src/api/hermes/sessions.ts import { request } from '../client' export async function fetchSessions(source?: string, limit?: number): Promise { const params = new URLSearchParams() if (source) params.set('source', source) if (limit) params.set('limit', String(limit)) const query = params.toString() const res = await request<{ sessions: SessionSummary[] }>(`/api/hermes/sessions${query ? `?${query}` : ''}`) return res.sessions } ``` **API path rules:** - Local BFF endpoints: `/api/hermes/{resource}` — handled by Koa routes, call Hermes CLI directly - Gateway proxy endpoints: `/api/hermes/v1/*`, `/api/hermes/jobs/*` — forwarded to upstream Hermes gateway - Shared endpoints: `/health`, `/upload`, `/webhook` — no agent prefix ### i18n Eight locales in `packages/client/src/i18n/locales/`: `en`, `zh`, `de`, `es`, `fr`, `ja`, `ko`, `pt`. Flat nested object structure organized by feature section: ```ts // en.ts export default { chat: { emptyState: 'Start a conversation with Hermes Agent', inputPlaceholder: 'Type a message...', sessions: 'Sessions', // ... }, common: { save: 'Save', cancel: 'Cancel', delete: 'Delete', // ... }, } ``` When adding new strings, add to all locale files. ### SCSS Styling - Global variables in `packages/client/src/styles/variables.scss` — import with `@use '@/styles/variables' as *` - Naive UI theme overrides in `packages/client/src/styles/theme.ts` - Code block styling in `packages/client/src/styles/code-block.scss` - Theme: "Pure Ink" (monochrome black/white/gray), no color accent - Mobile breakpoint: `$breakpoint-mobile: 768px` - Global resets and shared classes in `packages/client/src/styles/global.scss` - Component styles are always `