hermes-desktop-companion

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Hermes Desktop Companion

Hermes桌面配套工具

Skill by ara.so — Hermes Skills collection.
Hermes Desktop is a native Electron-based desktop application for installing, configuring, and interacting with Hermes Agent — a self-improving AI assistant with tool use, multi-platform messaging, and closed learning loop. It provides a GUI alternative to CLI management with streaming chat, session management, profile switching, skill installation, memory editing, and gateway configuration.
ara.so开发的Skill——Hermes Skills合集。
Hermes Desktop是一款基于Electron的原生桌面应用,用于安装、配置并与Hermes Agent交互——这是一款具备工具调用、多平台消息功能和闭环学习能力的自我改进型AI助手。它提供了CLI管理的GUI替代方案,支持流式聊天、会话管理、配置文件切换、Skill安装、记忆编辑和网关配置。

What It Does

功能介绍

  • Guided installation: First-run wizard installs Hermes Agent to
    ~/.hermes
    with dependency resolution
  • Local or remote mode: Run Hermes locally on
    127.0.0.1:8642
    or connect to remote API server
  • Multi-provider support: OpenRouter, Anthropic, OpenAI, Google Gemini, xAI Grok, Nous Portal, Qwen, MiniMax, Hugging Face, Groq, and local OpenAI-compatible endpoints
  • Streaming chat UI: SSE-based real-time chat with tool progress, markdown rendering, syntax highlighting, token usage tracking
  • 22 slash commands:
    /new
    ,
    /clear
    ,
    /fast
    ,
    /web
    ,
    /image
    ,
    /browse
    ,
    /code
    ,
    /shell
    ,
    /usage
    ,
    /help
    ,
    /tools
    ,
    /skills
    ,
    /model
    ,
    /memory
    ,
    /persona
    ,
    /version
    ,
    /compact
    ,
    /compress
    ,
    /undo
    ,
    /retry
    ,
    /debug
    ,
    /status
  • Profile management: Multiple isolated Hermes environments with separate configs
  • 14 toolsets: Web search, browser automation, terminal, file ops, code execution, vision, image gen, TTS, skills, memory, session search, clarify, delegation, MoA, task planning
  • Memory system: View/edit entries, user profile memory, capacity tracking, multiple providers (Honcho, Hindsight, Mem0, RetainDB, Supermemory, ByteRover)
  • 16 messaging gateways: Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Mattermost, Email, SMS, iMessage, DingTalk, Feishu, WeCom, WeChat, Webhooks, Home Assistant
  • Session search: Full-text search (SQLite FTS5) across conversation history
  • Scheduled tasks: Cron job builder with 15 delivery targets
  • Hermes Office (Claw3d): Visual 3D interface with adapter management
  • 引导式安装:首次运行向导会将Hermes Agent安装到
    ~/.hermes
    ,并自动解决依赖问题
  • 本地或远程模式:在
    127.0.0.1:8642
    本地运行Hermes,或连接到远程API服务器
  • 多提供商支持:支持OpenRouter、Anthropic、OpenAI、Google Gemini、xAI Grok、Nous Portal、Qwen、MiniMax、Hugging Face、Groq以及本地OpenAI兼容端点
  • 流式聊天UI:基于SSE的实时聊天,支持工具进度展示、Markdown渲染、语法高亮、Token使用追踪
  • 22条斜杠命令
    /new
    /clear
    /fast
    /web
    /image
    /browse
    /code
    /shell
    /usage
    /help
    /tools
    /skills
    /model
    /memory
    /persona
    /version
    /compact
    /compress
    /undo
    /retry
    /debug
    /status
  • 配置文件管理:多个独立的Hermes环境,各环境配置相互隔离
  • 14套工具集:网页搜索、浏览器自动化、终端、文件操作、代码执行、视觉识别、图像生成、TTS、技能、记忆、会话搜索、问题澄清、任务委派、MoA、任务规划
  • 记忆系统:查看/编辑条目、用户配置文件记忆、容量追踪、多提供商支持(Honcho、Hindsight、Mem0、RetainDB、Supermemory、ByteRover)
  • 16种消息网关:Telegram、Discord、Slack、WhatsApp、Signal、Matrix、Mattermost、邮件、SMS、iMessage、钉钉、飞书、企业微信、微信、Webhooks、Home Assistant
  • 会话搜索:基于SQLite FTS5的对话历史全文搜索
  • 定时任务:支持15种交付目标的Cron任务构建器
  • Hermes Office(Claw3d):带适配器管理的可视化3D界面

Installation

安装方法

Download Pre-built Binaries

下载预构建二进制文件

Download from GitHub Releases:
PlatformFile
macOS
.dmg
Linux (any)
.AppImage
Debian/Ubuntu
.deb
Fedora/RHEL
.rpm
Windows
.exe
(NSIS installer)
GitHub Releases下载:
平台文件
macOS
.dmg
Linux(通用)
.AppImage
Debian/Ubuntu
.deb
Fedora/RHEL
.rpm
Windows
.exe
(NSIS安装器)

macOS Installation

macOS安装

bash
undefined
bash
undefined

After installing the .dmg, remove quarantine attribute

安装.dmg后,移除隔离属性

xattr -cr "/Applications/Hermes Agent.app"

Or right-click → **Open** → confirm in dialog.
xattr -cr "/Applications/Hermes Agent.app"

或右键点击 → **打开** → 在弹窗中确认。

Windows Installation

Windows安装

Download
.exe
from releases. Windows SmartScreen will warn (unsigned) — click "More info" → "Run anyway".
Future winget support:
powershell
winget install NousResearch.HermesDesktop
从发布页面下载
.exe
文件。Windows SmartScreen会发出警告(未签名)——点击“更多信息”→“仍要运行”。
未来将支持winget:
powershell
winget install NousResearch.HermesDesktop

Linux Installation

Linux安装

AppImage (universal):
bash
chmod +x hermes-desktop-*.AppImage
./hermes-desktop-*.AppImage
Debian/Ubuntu:
bash
sudo dpkg -i hermes-desktop-*.deb
sudo apt-get install -f  # Fix dependencies if needed
Fedora/RHEL:
bash
sudo dnf install ./hermes-desktop-*.rpm --nogpgcheck
AppImage(通用):
bash
chmod +x hermes-desktop-*.AppImage
./hermes-desktop-*.AppImage
Debian/Ubuntu:
bash
sudo dpkg -i hermes-desktop-*.deb
sudo apt-get install -f  # 如有需要,修复依赖
Fedora/RHEL:
bash
sudo dnf install ./hermes-desktop-*.rpm --nogpgcheck

WSL Passwordless Sudo (if installer stalls)

WSL免密码sudo(若安装器停滞)

bash
echo "$USER ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/hermes-install
bash
echo "$USER ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/hermes-install

Re-run installer, then:

重新运行安装器,完成后执行:

sudo rm /etc/sudoers.d/hermes-install
undefined
sudo rm /etc/sudoers.d/hermes-install
undefined

First-Run Setup

首次运行设置

  1. Choose deployment mode:
    • Local: Installs Hermes to
      ~/.hermes
      , runs on
      127.0.0.1:8642
    • Remote: Connect to existing Hermes API server (requires URL + API key)
  2. Local mode: Installer checks for Git, uv, Python 3.11+, then runs official Hermes install script
  3. Configure provider: Select from OpenRouter, Anthropic, OpenAI, Google, xAI, Nous Portal, Qwen, MiniMax, Hugging Face, Groq, or custom local endpoint
  4. Enter credentials: API keys are saved to Hermes config files (not stored by desktop app)
  5. Launch workspace: Main UI opens with Chat, Sessions, Agents, Skills, Memory, Tools, etc.
  1. 选择部署模式:
    • 本地:将Hermes安装到
      ~/.hermes
      ,在
      127.0.0.1:8642
      运行
    • 远程:连接到已有的Hermes API服务器(需要URL + API密钥)
  2. 本地模式:安装器会检查Git、uv、Python 3.11+,然后运行官方Hermes安装脚本
  3. 配置提供商:从OpenRouter、Anthropic、OpenAI、Google、xAI、Nous Portal、Qwen、MiniMax、Hugging Face、Groq或自定义本地端点中选择
  4. 输入凭证:API密钥会保存到Hermes配置文件中(不会被桌面应用存储)
  5. 启动工作区:主UI打开,包含聊天、会话、Agent、Skills、记忆、工具等模块

Configuration

配置说明

Provider Configuration

提供商配置

Settings → Provider Config:
typescript
// Example: OpenRouter setup
{
  provider: "openrouter",
  apiKey: process.env.OPENROUTER_API_KEY,
  model: "anthropic/claude-3.5-sonnet",
  baseUrl: "https://openrouter.ai/api/v1"
}

// Example: Local Ollama
{
  provider: "openai",
  apiKey: "not-needed",
  model: "llama3.1:8b",
  baseUrl: "http://localhost:11434/v1"
}
设置 → 提供商配置:
typescript
// 示例:OpenRouter配置
{
  provider: "openrouter",
  apiKey: process.env.OPENROUTER_API_KEY,
  model: "anthropic/claude-3.5-sonnet",
  baseUrl: "https://openrouter.ai/api/v1"
}

// 示例:本地Ollama
{
  provider: "openai",
  apiKey: "not-needed",
  model: "llama3.1:8b",
  baseUrl: "http://localhost:11434/v1"
}

Remote Mode Configuration

远程模式配置

First run:
  • Choose "Remote" mode
  • Enter API URL:
    https://your-hermes-server.com
  • Enter API key (from remote Hermes
    /api/keys
    )
  • App validates connection before proceeding
首次运行:
  • 选择“远程”模式
  • 输入API URL:
    https://your-hermes-server.com
  • 输入API密钥(来自远程Hermes的
    /api/keys
  • 应用会先验证连接,再继续下一步

Profile (Agent) Management

配置文件(Agent)管理

Agents screen:
  • Create new profile: Creates isolated
    ~/.hermes/profiles/<name>
    directory
  • Switch profile: Restarts Hermes with new profile context
  • Delete profile: Removes profile directory and data
bash
undefined
Agent界面:
  • 创建新配置文件:创建独立的
    ~/.hermes/profiles/<name>
    目录
  • 切换配置文件:使用新配置文件上下文重启Hermes
  • 删除配置文件:移除配置文件目录及数据
bash
undefined

Profiles stored at:

配置文件存储路径:

~/.hermes/profiles/ ├── default/ │ ├── config.yaml │ ├── SOUL.md │ ├── memory.db │ └── sessions.db └── work/ └── ...
undefined
~/.hermes/profiles/ ├── default/ │ ├── config.yaml │ ├── SOUL.md │ ├── memory.db │ └── sessions.db └── work/ └── ...
undefined

Memory Provider Configuration

记忆提供商配置

Memory screen → Configure Providers:
typescript
// Example: Honcho
{
  provider: "honcho",
  apiKey: process.env.HONCHO_API_KEY,
  appId: "hermes-desktop",
  userId: "user-123"
}

// Example: Mem0
{
  provider: "mem0",
  apiKey: process.env.MEM0_API_KEY,
  userId: "user-123"
}
记忆界面 → 配置提供商:
typescript
// 示例:Honcho
{
  provider: "honcho",
  apiKey: process.env.HONCHO_API_KEY,
  appId: "hermes-desktop",
  userId: "user-123"
}

// 示例:Mem0
{
  provider: "mem0",
  apiKey: process.env.MEM0_API_KEY,
  userId: "user-123"
}

Gateway Configuration

网关配置

Gateway screen → Select platform → Configure:
Telegram:
yaml
enabled: true
bot_token: ${TELEGRAM_BOT_TOKEN}
allowed_users: [123456789]
Discord:
yaml
enabled: true
token: ${DISCORD_BOT_TOKEN}
channel_ids: [1234567890123456789]
Email (IMAP/SMTP):
yaml
enabled: true
imap_server: imap.gmail.com
imap_port: 993
smtp_server: smtp.gmail.com
smtp_port: 587
username: ${EMAIL_USERNAME}
password: ${EMAIL_APP_PASSWORD}
WhatsApp (via Baileys):
yaml
enabled: true
session_path: ~/.hermes/whatsapp-session
qr_code_callback: true
网关界面 → 选择平台 → 配置:
Telegram:
yaml
enabled: true
bot_token: ${TELEGRAM_BOT_TOKEN}
allowed_users: [123456789]
Discord:
yaml
enabled: true
token: ${DISCORD_BOT_TOKEN}
channel_ids: [1234567890123456789]
邮件(IMAP/SMTP):
yaml
enabled: true
imap_server: imap.gmail.com
imap_port: 993
smtp_server: smtp.gmail.com
smtp_port: 587
username: ${EMAIL_USERNAME}
password: ${EMAIL_APP_PASSWORD}
WhatsApp(通过Baileys):
yaml
enabled: true
session_path: ~/.hermes/whatsapp-session
qr_code_callback: true

Chat Interface Usage

聊天界面使用

Basic Chat

基础聊天

Type naturally or use slash commands:
> What's the weather in San Francisco?
[Hermes uses web search tool, returns answer]

> /web latest news on AI regulation
[Forces web search, streams results]

> /image a cyberpunk city at sunset
[Generates image via FAL.ai or configured provider]
自然输入或使用斜杠命令:
> 旧金山的天气如何?
[Hermes使用网页搜索工具,返回结果]

> /web AI监管的最新消息
[强制触发网页搜索,流式返回结果]

> /image 日落时分的赛博朋克城市
[通过FAL.ai或已配置的提供商生成图像]

Slash Commands

斜杠命令

CommandDescription
/new
Start new conversation
/clear
Clear current chat
/fast
Switch to faster model
/web <query>
Force web search
/image <prompt>
Generate image
/browse <url>
Browse and extract from URL
/code <task>
Execute code task
/shell <command>
Run shell command
/usage
Show token usage stats
/help
List all commands
/tools
Show enabled tools
/skills
List installed skills
/model [name]
Get/set current model
/memory [query]
Search memory
/persona
Show current persona
/version
Show Hermes version
/compact
Compress chat history
/compress
Deep compress with MoA
/undo
Remove last message
/retry
Retry last message
/debug
Toggle debug mode
/status
Show system status
命令描述
/new
开始新对话
/clear
清空当前聊天
/fast
切换到更快的模型
/web <query>
强制网页搜索
/image <prompt>
生成图像
/browse <url>
浏览并提取URL内容
/code <task>
执行代码任务
/shell <command>
运行Shell命令
/usage
显示Token使用统计
/help
列出所有命令
/tools
显示已启用的工具
/skills
列出已安装的Skill
/model [name]
获取/设置当前模型
/memory [query]
搜索记忆内容
/persona
显示当前角色设定
/version
显示Hermes版本
/compact
压缩聊天历史
/compress
通过MoA深度压缩
/undo
删除上一条消息
/retry
重试上一条消息
/debug
切换调试模式
/status
显示系统状态

Token Usage Tracking

Token使用追踪

Bottom of chat shows live counts:
📊 Prompt: 1,234 tokens • Completion: 567 tokens • Cost: $0.0123
Use
/usage
for detailed breakdown:
> /usage
Session Usage:
  Total Prompt Tokens: 12,345
  Total Completion Tokens: 5,678
  Total Cost: $0.123
  Messages: 15
聊天界面底部显示实时统计:
📊 提示词: 1,234 tokens • 回复: 567 tokens • 费用: $0.0123
使用
/usage
查看详细 breakdown:
> /usage
会话使用情况:
  总提示词Token: 12,345
  总回复Token: 5,678
  总费用: $0.123
  消息数: 15

Skills Management

Skills管理

Installing Skills

安装Skills

Skills screen:
  1. Browse bundled skills (pre-installed with Hermes)
  2. Or install from GitHub:
    Repository: username/repo-name
    Branch: main (optional)
  3. Click Install
Skills界面:
  1. 浏览内置Skill(随Hermes预安装)
  2. 或从GitHub安装:
    Repository: username/repo-name
    Branch: main(可选)
  3. 点击 安装

Skill Structure

Skill结构

Skills are markdown files with YAML frontmatter:
markdown
---
name: web-search-expert
description: Expert at web searching and information retrieval
triggers:
  - "search the web for"
  - "find information about"
  - "look up"
---
Skills是带有YAML前置元数据的Markdown文件:
markdown
---
name: web-search-expert
description: 擅长网页搜索和信息检索
triggers:
  - "search the web for"
  - "find information about"
  - "look up"
---

Web Search Expert

网页搜索专家

Use the web_search tool to find current information...
使用web_search工具查找最新信息...

Examples

示例

When user asks: "What's the latest on GPT-5?"
  1. Use web_search with query "GPT-5 latest news"
  2. Summarize findings
  3. Cite sources
undefined
当用户提问: "GPT-5的最新动态是什么?"
  1. 使用web_search工具,查询词为"GPT-5 latest news"
  2. 总结搜索结果
  3. 标注来源
undefined

Editing Skills

编辑Skills

Skills screen → Click skill → Edit:
  • Modify triggers, description, or content
  • Changes saved to
    ~/.hermes/skills/<name>/SKILL.md
Skills界面 → 点击Skill → 编辑:
  • 修改触发词、描述或内容
  • 更改会保存到
    ~/.hermes/skills/<name>/SKILL.md

Memory System

记忆系统

Viewing Memory

查看记忆

Memory screen:
  • Memory Entries: List of stored facts/context
  • User Profile: Persistent user information
  • Capacity: Current usage vs. limit
记忆界面:
  • 记忆条目: 已存储的事实/上下文列表
  • 用户配置文件: 持久化的用户信息
  • 容量: 当前使用量与上限对比

Adding Memory

添加记忆

Chat naturally — Hermes auto-saves important context:
> My name is Alice and I prefer Python over JavaScript
[Hermes stores to memory automatically]

> What's my name?
[Hermes retrieves: "Alice"]
Or explicit:
> Remember I'm working on a TypeScript project called Hermes Desktop
[Hermes: ✓ Stored to memory]
自然聊天即可——Hermes会自动保存重要上下文:
> 我叫Alice,比起JavaScript我更喜欢Python
[Hermes自动保存到记忆中]

> 我叫什么名字?
[Hermes检索到: "Alice"]
或手动添加:
> 记住我正在开发一个名为Hermes Desktop的TypeScript项目
[Hermes: ✓ 已存储到记忆]

Editing Memory Entries

编辑记忆条目

Memory screen:
  1. Click entry to view
  2. Edit content or delete
  3. Save changes
记忆界面:
  1. 点击条目查看详情
  2. 编辑内容或删除
  3. 保存更改

Memory Providers

记忆提供商

Configured in Memory screen → Configure Providers:
  • Honcho: Managed memory service
  • Hindsight: Self-hosted memory
  • Mem0: Personalized AI memory
  • RetainDB: Vector memory DB
  • Supermemory: Context-aware memory
  • ByteRover: Local memory store
记忆界面 → 配置提供商中设置:
  • Honcho: 托管式记忆服务
  • Hindsight: 自托管记忆
  • Mem0: 个性化AI记忆
  • RetainDB: 向量记忆数据库
  • Supermemory: 上下文感知记忆
  • ByteRover: 本地记忆存储

Session Management

会话管理

Searching Sessions

搜索会话

Sessions screen:
  • Search bar: Full-text search (SQLite FTS5) across all conversations
  • Date groups: Conversations grouped by Today, Yesterday, Last 7 Days, Last 30 Days, Older
typescript
// Example: Search sessions programmatically (if extending app)
import { searchSessions } from './main/database';

const results = await searchSessions('typescript error handling');
// Returns: [{ id, title, timestamp, snippet, profileId }, ...]
会话界面:
  • 搜索栏: 基于SQLite FTS5的所有对话全文搜索
  • 日期分组: 对话按今日、昨日、最近7天、最近30天、更早分组
typescript
// 示例:扩展应用时程序化搜索会话
import { searchSessions } from './main/database';

const results = await searchSessions('typescript error handling');
// 返回: [{ id, title, timestamp, snippet, profileId }, ...]

Resuming Sessions

恢复会话

  1. Sessions screen → Click conversation
  2. Chat loads with full history
  3. Continue conversation from last message
  1. 会话界面 → 点击对话
  2. 加载完整聊天历史
  3. 从最后一条消息继续对话

Deleting Sessions

删除会话

Right-click session → Delete or click trash icon.
右键点击会话 → 删除 或点击垃圾桶图标。

Tools Management

工具管理

Tools screen → Enable/disable toolsets:
ToolsetCapabilities
webExa/Tavily search, Firecrawl scraping
browserPlaywright automation, screenshot, PDF
terminalShell command execution
fileRead, write, list, move files
codePython execution in sandbox
visionImage analysis (GPT-4V, Claude Vision)
imageGeneration via FAL.ai/DALL-E
ttsText-to-speech synthesis
skillsInstall/manage skills
memoryStore/retrieve context
sessionSearch past conversations
clarifyAsk clarifying questions
delegationMulti-agent task delegation
moaMixture-of-Agents synthesis
planningBreak down complex tasks
Example enabling web tool:
yaml
undefined
工具界面 → 启用/禁用工具集:
工具集功能
webExa/Tavily搜索、Firecrawl爬取
browserPlaywright自动化、截图、PDF生成
terminalShell命令执行
file文件读写、列出、移动
code沙箱中执行Python代码
vision图像分析(GPT-4V、Claude Vision)
image通过FAL.ai/DALL-E生成图像
tts文本转语音合成
skills安装/管理Skill
memory存储/检索上下文
session搜索过往对话
clarify提出澄清问题
delegation多Agent任务委派
moa多Agent混合合成
planning拆解复杂任务
启用web工具示例:
yaml
undefined

~/.hermes/profiles/default/config.yaml

~/.hermes/profiles/default/config.yaml

tools: web: enabled: true exa_api_key: ${EXA_API_KEY} tavily_api_key: ${TAVILY_API_KEY}
undefined
tools: web: enabled: true exa_api_key: ${EXA_API_KEY} tavily_api_key: ${TAVILY_API_KEY}
undefined

Scheduled Tasks

定时任务

Schedules screenCreate Task:
yaml
name: "Daily standup summary"
schedule: "0 9 * * 1-5"  # 9 AM weekdays
task: "Summarize yesterday's GitHub activity and send to Slack"
delivery:
  type: slack
  channel: "#standup"
Schedule types:
  • Minutes: Every N minutes
  • Hourly: Every N hours
  • Daily: Specific time daily
  • Weekly: Specific day/time weekly
  • Custom: Full cron expression
Delivery targets: Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Email, SMS, Webhook, Home Assistant, File, Terminal, Memory, Chat (in-app), Desktop Notification
计划任务界面创建任务:
yaml
name: "每日站会总结"
schedule: "0 9 * * 1-5"  # 工作日上午9点
task: "总结昨天的GitHub活动并发送到Slack"
delivery:
  type: slack
  channel: "#standup"
计划类型:
  • 分钟级: 每N分钟执行一次
  • 小时级: 每N小时执行一次
  • 每日: 每日特定时间执行
  • 每周: 每周特定日期/时间执行
  • 自定义: 完整Cron表达式
交付目标: Telegram、Discord、Slack、WhatsApp、Signal、Matrix、邮件、SMS、Webhook、Home Assistant、文件、终端、记忆、聊天(应用内)、桌面通知

Development Setup

开发环境设置

Prerequisites

前置要求

bash
node --version  # v18+ recommended
npm --version   # v9+
bash
node --version  # 推荐v18+
npm --version   # v9+

Clone and Install

克隆并安装依赖

bash
git clone https://github.com/fathah/hermes-desktop.git
cd hermes-desktop
npm install
bash
git clone https://github.com/fathah/hermes-desktop.git
cd hermes-desktop
npm install

Development Mode

开发模式

bash
npm run dev
This starts:
  • Vite dev server for React UI
  • Electron main process with hot reload
  • TypeScript watch compiler
bash
npm run dev
该命令会启动:
  • 用于React UI的Vite开发服务器
  • 带热重载的Electron主进程
  • TypeScript监视编译器

Project Structure

项目结构

hermes-desktop/
├── src/
│   ├── main/          # Electron main process
│   │   ├── index.ts   # Entry point, IPC handlers
│   │   ├── database.ts # SQLite sessions/memory
│   │   ├── installer.ts # Hermes install logic
│   │   └── updater.ts  # Auto-update
│   ├── preload/       # Electron preload script
│   │   └── index.ts   # IPC bridge to renderer
│   └── renderer/      # React UI
│       ├── App.tsx
│       ├── screens/   # Chat, Sessions, Tools, etc.
│       ├── components/
│       └── lib/       # SSE parser, utils
├── electron.vite.config.ts
├── package.json
└── resources/         # Icons, installers
hermes-desktop/
├── src/
│   ├── main/          # Electron主进程
│   │   ├── index.ts   # 入口文件,IPC处理器
│   │   ├── database.ts # SQLite会话/记忆数据库
│   │   ├── installer.ts # Hermes安装逻辑
│   │   └── updater.ts  # 自动更新
│   ├── preload/       # Electron预加载脚本
│   │   └── index.ts   # 渲染进程的IPC桥接
│   └── renderer/      # React UI
│       ├── App.tsx
│       ├── screens/   # 聊天、会话、工具等界面
│       ├── components/
│       └── lib/       # SSE解析器、工具函数
├── electron.vite.config.ts
├── package.json
└── resources/         # 图标、安装器资源

IPC Communication Pattern

IPC通信模式

Renderer → Main:
typescript
// src/renderer/lib/api.ts
export async function sendChatMessage(message: string, profileId: string) {
  return window.electron.ipcRenderer.invoke('chat:send', { message, profileId });
}
Main handler:
typescript
// src/main/index.ts
ipcMain.handle('chat:send', async (event, { message, profileId }) => {
  const response = await fetch('http://127.0.0.1:8642/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ message, profile: profileId })
  });
  // Stream SSE events back to renderer
});
渲染进程 → 主进程:
typescript
// src/renderer/lib/api.ts
export async function sendChatMessage(message: string, profileId: string) {
  return window.electron.ipcRenderer.invoke('chat:send', { message, profileId });
}
主进程处理器:
typescript
// src/main/index.ts
ipcMain.handle('chat:send', async (event, { message, profileId }) => {
  const response = await fetch('http://127.0.0.1:8642/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ message, profile: profileId })
  });
  // 将SSE事件流式返回给渲染进程
});

SSE Streaming Implementation

SSE流式实现

typescript
// src/renderer/lib/sse-parser.ts
export class SSEParser {
  private buffer = '';

  parse(chunk: string): SSEEvent[] {
    this.buffer += chunk;
    const lines = this.buffer.split('\n');
    this.buffer = lines.pop() || '';
    
    const events: SSEEvent[] = [];
    let currentEvent: Partial<SSEEvent> = {};
    
    for (const line of lines) {
      if (line.startsWith('event:')) {
        currentEvent.event = line.slice(7).trim();
      } else if (line.startsWith('data:')) {
        currentEvent.data = line.slice(6).trim();
      } else if (line === '') {
        if (currentEvent.event) {
          events.push(currentEvent as SSEEvent);
        }
        currentEvent = {};
      }
    }
    
    return events;
  }
}
Usage in Chat:
typescript
// src/renderer/screens/Chat.tsx
const parser = new SSEParser();

fetch('http://127.0.0.1:8642/chat', {
  method: 'POST',
  body: JSON.stringify({ message })
}).then(async (response) => {
  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);
    const events = parser.parse(chunk);
    
    for (const event of events) {
      if (event.event === 'content') {
        appendContent(JSON.parse(event.data).text);
      } else if (event.event === 'tool_start') {
        showToolProgress(JSON.parse(event.data));
      } else if (event.event === 'usage') {
        updateTokenCount(JSON.parse(event.data));
      }
    }
  }
});
typescript
// src/renderer/lib/sse-parser.ts
export class SSEParser {
  private buffer = '';

  parse(chunk: string): SSEEvent[] {
    this.buffer += chunk;
    const lines = this.buffer.split('\n');
    this.buffer = lines.pop() || '';
    
    const events: SSEEvent[] = [];
    let currentEvent: Partial<SSEEvent> = {};
    
    for (const line of lines) {
      if (line.startsWith('event:')) {
        currentEvent.event = line.slice(7).trim();
      } else if (line.startsWith('data:')) {
        currentEvent.data = line.slice(6).trim();
      } else if (line === '') {
        if (currentEvent.event) {
          events.push(currentEvent as SSEEvent);
        }
        currentEvent = {};
      }
    }
    
    return events;
  }
}
聊天中的使用:
typescript
// src/renderer/screens/Chat.tsx
const parser = new SSEParser();

fetch('http://127.0.0.1:8642/chat', {
  method: 'POST',
  body: JSON.stringify({ message })
}).then(async (response) => {
  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);
    const events = parser.parse(chunk);
    
    for (const event of events) {
      if (event.event === 'content') {
        appendContent(JSON.parse(event.data).text);
      } else if (event.event === 'tool_start') {
        showToolProgress(JSON.parse(event.data));
      } else if (event.event === 'usage') {
        updateTokenCount(JSON.parse(event.data));
      }
    }
  }
});

Building for Production

生产环境构建

Build All Platforms (current OS)

构建所有平台(当前操作系统)

bash
npm run build
Output:
dist/
directory with installers
bash
npm run build
输出目录:
dist/
,包含安装器

Platform-Specific Builds

特定平台构建

bash
npm run build:win    # Windows .exe
npm run build:mac    # macOS .dmg
npm run build:linux  # .AppImage, .deb, .rpm
bash
npm run build:win    # Windows .exe
npm run build:mac    # macOS .dmg
npm run build:linux  # .AppImage, .deb, .rpm

Build Configuration

构建配置

Edit
electron-builder.yml
:
yaml
appId: com.nousresearch.hermesdesktop
productName: Hermes Agent
directories:
  output: dist
  buildResources: resources

mac:
  target:
    - dmg
    - zip
  category: public.app-category.productivity
  icon: resources/icon.icns

win:
  target:
    - nsis
  icon: resources/icon.ico

linux:
  target:
    - AppImage
    - deb
    - rpm
  category: Utility
  icon: resources/icon.png
编辑
electron-builder.yml
:
yaml
appId: com.nousresearch.hermesdesktop
productName: Hermes Agent
directories:
  output: dist
  buildResources: resources

mac:
  target:
    - dmg
    - zip
  category: public.app-category.productivity
  icon: resources/icon.icns

win:
  target:
    - nsis
  icon: resources/icon.ico

linux:
  target:
    - AppImage
    - deb
    - rpm
  category: Utility
  icon: resources/icon.png

Troubleshooting

故障排除

Installer Stalls on "Installing dependencies"

安装器在“安装依赖”步骤停滞

WSL: Grant temporary passwordless sudo (see Installation section)
General: Check logs in
~/.hermes/logs/install.log
:
bash
tail -f ~/.hermes/logs/install.log
WSL: 授予临时免密码sudo权限(见安装部分)
通用方法: 查看
~/.hermes/logs/install.log
日志:
bash
tail -f ~/.hermes/logs/install.log

"Connection refused" on 127.0.0.1:8642

127.0.0.1:8642
连接被拒绝

Hermes not running. Start manually:
bash
cd ~/.hermes
source venv/bin/activate
python -m hermes.server
Or restart from Settings → Restart Hermes.
Hermes未运行。手动启动:
bash
cd ~/.hermes
source venv/bin/activate
python -m hermes.server
或从设置 → 重启Hermes重启。

Remote mode connection fails

远程模式连接失败

  1. Verify URL is reachable:
    curl https://your-hermes-server.com/health
  2. Check API key in remote Hermes:
    hermes keys list
  3. Ensure firewall allows traffic
  1. 验证URL可访问:
    curl https://your-hermes-server.com/health
  2. 检查远程Hermes中的API密钥:
    hermes keys list
  3. 确保防火墙允许流量

Memory provider not connecting

记忆提供商连接失败

Check API keys in Memory → Configure Providers:
typescript
// Test Honcho connection
const response = await fetch('https://api.honcho.dev/apps', {
  headers: { 'Authorization': `Bearer ${process.env.HONCHO_API_KEY}` }
});
检查记忆 → 配置提供商中的API密钥:
typescript
// 测试Honcho连接
const response = await fetch('https://api.honcho.dev/apps', {
  headers: { 'Authorization': `Bearer ${process.env.HONCHO_API_KEY}` }
});

Gateway fails to send messages

网关无法发送消息

  1. View logs: Settings → View Logs → Select gateway
  2. Telegram: Verify bot token with
    @BotFather
    , check allowed_users IDs
  3. Discord: Ensure bot has
    SEND_MESSAGES
    permission in channel
  4. Email: Test SMTP credentials with
    telnet smtp.server.com 587
  1. 查看日志: 设置 → 查看日志 → 选择网关
  2. Telegram: 通过
    @BotFather
    验证机器人令牌,检查allowed_users ID
  3. Discord: 确保机器人在频道中拥有
    SEND_MESSAGES
    权限
  4. 邮件: 使用
    telnet smtp.server.com 587
    测试SMTP凭证

Skills not triggering

Skills未触发

  1. Check triggers in skill YAML frontmatter are specific
  2. Ensure skill is enabled: Skills screen → Check toggle
  3. Restart profile: Agents → Switch away and back
  1. 检查Skill的YAML前置元数据中的触发词是否明确
  2. 确保Skill已启用: Skills界面 → 检查开关
  3. 重启配置文件: Agent → 切换到其他配置文件再切回

Auto-update fails (Fedora RPM)

自动更新失败(Fedora RPM)

RPM builds don't support auto-update. Download new
.rpm
and reinstall:
bash
sudo dnf install ./hermes-desktop-<new-version>.rpm --nogpgcheck
RPM构建不支持自动更新。下载新的
.rpm
文件并重新安装:
bash
sudo dnf install ./hermes-desktop-<new-version>.rpm --nogpgcheck

Chat stuck on "Thinking..."

聊天卡在“思考中...”

  1. Check network:
    curl -I http://127.0.0.1:8642/health
  2. Check model provider API status (OpenRouter, Anthropic, etc.)
  3. View debug logs:
    /debug
    in chat or Settings → View Logs → Agent
  1. 检查网络:
    curl -I http://127.0.0.1:8642/health
  2. 检查模型提供商API状态(OpenRouter、Anthropic等)
  3. 查看调试日志: 在聊天中输入
    /debug
    设置 → 查看日志 → Agent

Session search returns no results

会话搜索无结果

Database index corrupt. Rebuild FTS5 index:
bash
cd ~/.hermes/profiles/default
sqlite3 sessions.db "DELETE FROM sessions_fts; INSERT INTO sessions_fts SELECT * FROM sessions;"
数据库索引损坏。重建FTS5索引:
bash
cd ~/.hermes/profiles/default
sqlite3 sessions.db "DELETE FROM sessions_fts; INSERT INTO sessions_fts SELECT * FROM sessions;"

macOS "App is damaged" error

macOS提示“应用已损坏”错误

Remove quarantine:
bash
xattr -cr "/Applications/Hermes Agent.app"
移除隔离属性:
bash
xattr -cr "/Applications/Hermes Agent.app"

Windows SmartScreen blocks installer

Windows SmartScreen阻止安装器

Click "More info" → "Run anyway" (app is not code-signed).
点击“更多信息”→“仍要运行”(应用未签名)。

Environment Variables

环境变量

bash
undefined
bash
undefined

LLM Providers

LLM提供商

OPENROUTER_API_KEY=sk-or-... ANTHROPIC_API_KEY=sk-ant-... OPENAI_API_KEY=sk-... GOOGLE_API_KEY=... XAI_API_KEY=...
OPENROUTER_API_KEY=sk-or-... ANTHROPIC_API_KEY=sk-ant-... OPENAI_API_KEY=sk-... GOOGLE_API_KEY=... XAI_API_KEY=...

Search/Web Tools

搜索/网页工具

EXA_API_KEY=... TAVILY_API_KEY=... FIRECRAWL_API_KEY=...
EXA_API_KEY=... TAVILY_API_KEY=... FIRECRAWL_API_KEY=...

Image Generation

图像生成

FAL_API_KEY=... REPLICATE_API_TOKEN=...
FAL_API_KEY=... REPLICATE_API_TOKEN=...

Memory Providers

记忆提供商

HONCHO_API_KEY=... MEM0_API_KEY=...
HONCHO_API_KEY=... MEM0_API_KEY=...

Messaging Gateways

消息网关

TELEGRAM_BOT_TOKEN=... DISCORD_BOT_TOKEN=... SLACK_BOT_TOKEN=... TWILIO_ACCOUNT_SID=... TWILIO_AUTH_TOKEN=...
TELEGRAM_BOT_TOKEN=... DISCORD_BOT_TOKEN=... SLACK_BOT_TOKEN=... TWILIO_ACCOUNT_SID=... TWILIO_AUTH_TOKEN=...

Email

邮件

EMAIL_USERNAME=... EMAIL_APP_PASSWORD=...
EMAIL_USERNAME=... EMAIL_APP_PASSWORD=...

Analytics

分析

WANDB_API_KEY=...

Store in `~/.hermes/.env` or OS-level environment.
WANDB_API_KEY=...

存储在`~/.hermes/.env`或操作系统级环境变量中。

Testing

测试

Run Tests

运行测试

bash
npm test
Test suites:
  • SSE parser: Validates event parsing, incomplete chunks, malformed data
  • IPC handlers: Mock Electron IPC, test chat/session/profile handlers
  • Preload API: Ensures all main process APIs are safely exposed
  • Installer utils: Dependency checking, path resolution
  • Constants: Validates config schema, provider definitions
bash
npm test
测试套件:
  • SSE解析器: 验证事件解析、不完整块处理、格式错误数据处理
  • IPC处理器: 模拟Electron IPC,测试聊天/会话/配置文件处理器
  • 预加载API: 确保所有主进程API安全暴露
  • 安装器工具: 依赖检查、路径解析
  • 常量: 验证配置 schema、提供商定义

Example Test

测试示例

typescript
// src/__tests__/sse-parser.test.ts
import { describe, it, expect } from 'vitest';
import { SSEParser } from '../renderer/lib/sse-parser';

describe('SSEParser', () => {
  it('parses complete events', () => {
    const parser = new SSEParser();
    const events = parser.parse('event: content\ndata: {"text":"Hello"}\n\n');
    
    expect(events).toHaveLength(1);
    expect(events[0].event).toBe('content');
    expect(JSON.parse(events[0].data).text).toBe('Hello');
  });
  
  it('buffers incomplete events', () => {
    const parser = new SSEParser();
    const events1 = parser.parse('event: content\n');
    const events2 = parser.parse('data: {"text":"Hi"}\n\n');
    
    expect(events1).toHaveLength(0);
    expect(events2).toHaveLength(1);
  });
});
typescript
// src/__tests__/sse-parser.test.ts
import { describe, it, expect } from 'vitest';
import { SSEParser } from '../renderer/lib/sse-parser';

describe('SSEParser', () => {
  it('解析完整事件', () => {
    const parser = new SSEParser();
    const events = parser.parse('event: content\ndata: {"text":"Hello"}\n\n');
    
    expect(events).toHaveLength(1);
    expect(events[0].event).toBe('content');
    expect(JSON.parse(events[0].data).text).toBe('Hello');
  });
  
  it('缓冲不完整事件', () => {
    const parser = new SSEParser();
    const events1 = parser.parse('event: content\n');
    const events2 = parser.parse('data: {"text":"Hi"}\n\n');
    
    expect(events1).toHaveLength(0);
    expect(events2).toHaveLength(1);
  });
});

Resources

资源

License

许可证

MIT License — see LICENSE
MIT许可证 — 详见LICENSE