跳到主要内容

Windows 原生安装指南 — Early Beta

Early BETA

原生 Windows 支持仍处于 early beta 阶段。它能装、能跑,并通过了我们的 Windows footgun lint,但还没有像 Linux/macOS/WSL2 那样经历过同等规模的实战考验。请预期会有一些粗糙的边缘——尤其是子进程处理、路径细节和非 ASCII 控制台输出方面。遇到问题时请提交 issue,并附上复现步骤。如果你今天就需要一套久经考验的配置,请改用 WSL2 下的 Linux/macOS 安装器

Hermes 在 Windows 10 和 Windows 11 上原生运行——不需要 WSL,不需要 Cygwin,也不需要 Docker。这一页是深入说明:哪些功能原生可用、哪些只能在 WSL 下用、安装器实际上做了什么,以及你可能需要调整的 Windows 专属开关。

如果你只是想安装,首页安装页上的一行命令就够了。等到有什么让你困惑时再回来看这一页。

想用 WSL?

如果你更想要一个真正的 POSIX 环境(比如使用 Dashboard 内嵌终端、fork 语义、Linux 风格的文件监听等),请参见 Windows (WSL2) 指南。两者可以干净地共存:原生数据存放在 %LOCALAPPDATA%\hermes 下,WSL 数据存放在 ~/.hermes 下。

一行命令安装

打开 PowerShell(或 Windows Terminal),运行:

irm https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.ps1 | iex

不需要管理员权限。安装器会把 Hermes 安装到 %LOCALAPPDATA%\hermes\,并把 hermes 加入你的 User PATH——安装完成后请打开一个新的终端窗口。

安装器选项(要传参数必须使用 scriptblock 形式):

& ([scriptblock]::Create((irm https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.ps1))) -NoVenv -SkipSetup -Branch main
参数默认值用途
-Branchmain克隆指定分支(用于测试 PR)
-NoVenv关闭跳过 venv 创建(高级用法——你自己管理 Python)
-SkipSetup关闭跳过安装后的 hermes setup 向导
-HermesHome%LOCALAPPDATA%\hermes覆盖数据目录
-InstallDir%LOCALAPPDATA%\hermes\hermes-agent覆盖代码目录

安装器到底做了什么

从上到下依次执行:

  1. 引导 uv —— Astral 的高性能 Python 管理器。安装到 %USERPROFILE%\.local\bin
  2. 通过 uv 安装 Python 3.11。不需要预先安装任何 Python。
  3. 安装 Node.js 22(优先 winget,否则从可移植 Node tarball 解压到 %LOCALAPPDATA%\hermes\node)。用于 browser tool 和 WhatsApp 桥接。
  4. 安装可移植版 Git —— 如果 PATH 上已经有 git,安装器会直接复用;否则会从官方 git-for-windows release 下载一个精简、自包含的 PortableGit(约 45 MB)到 %LOCALAPPDATA%\hermes\git。无需管理员权限,不写入 Windows 安装注册表,不会干扰机器上的其他东西。
  5. 克隆仓库%LOCALAPPDATA%\hermes\hermes-agent,并在内部创建 virtualenv。
  6. 分级 uv pip install —— 先尝试 .[all],如果某个 git+https 依赖在被限流的 GitHub 上抽风,会回退到逐步缩小的依赖集合([messaging,dashboard,ext][messaging].)。避免"一个依赖出问题就掉到裸装"这种失败模式。
  7. 基于 .env 自动安装消息平台 SDK —— 如果存在 TELEGRAM_BOT_TOKEN / DISCORD_BOT_TOKEN / SLACK_BOT_TOKEN / SLACK_APP_TOKEN / WHATSAPP_ENABLED,会运行 python -m ensurepip --upgrade 和针对性的 pip install 调用,确保每个平台的 SDK 都能真正 import。
  8. 设置 HERMES_GIT_BASH_PATH 指向解析到的 bash.exe,这样 Hermes 在新的 shell 里也能确定性地找到 bash。
  9. %LOCALAPPDATA%\hermes\bin 加入 User PATH —— 在你打开新终端后,hermes 命令就能直接使用。
  10. 运行 hermes setup —— 正常的首次运行向导(模型、provider、toolset)。可用 -SkipSetup 跳过。

能力矩阵

除了 Dashboard 内嵌终端面板之外,所有功能在 Windows 上都原生可用。

功能Windows 原生WSL2
CLI(hermes chathermes setuphermes gateway、…)
交互式 TUI(hermes --tui
消息 Gateway(Telegram、Discord、Slack、WhatsApp,15+ 平台)
Cron 调度器
Browser tool(通过 Node 驱动 Chromium)
MCP servers(stdio 和 HTTP)
本地 Ollama / LM Studio / llama-server✓(通过 WSL 网络)
Web Dashboard(会话、任务、指标、配置)
Dashboard /chat 内嵌终端面板✗(需要 POSIX PTY)
登录时自启动✓(schtasks)✓(systemd)

Dashboard 的 /chat 标签页通过 POSIX PTY(ptyprocess)嵌入了一个真实终端。原生 Windows 没有等价原语;Python 的 pywinpty / Windows ConPTY 理论上可以工作,但需要一份独立实现——目前作为后续工作处理。Dashboard 的其他部分都原生可用——只有这一个标签页会显示"请改用 WSL2"的提示。

Hermes 在 Windows 上是怎么跑 shell 命令的

Hermes 的 terminal tool 通过 Git Bash 来执行命令,和 Claude Code 是同一套策略。这避免了重写每一个工具就能填平 POSIX-vs-Windows 的鸿沟。

bash.exe 的解析顺序:

  1. 设置了 HERMES_GIT_BASH_PATH 环境变量时优先使用它。
  2. %LOCALAPPDATA%\hermes\git\usr\bin\bash.exe(安装器自带的 PortableGit)。
  3. %LOCALAPPDATA%\hermes\git\bin\bash.exe(旧版 Git-for-Windows 布局)。
  4. 系统的 Git-for-Windows 安装(%ProgramFiles%\Git\bin\bash.exe 等)。
  5. 兜底:MSYS2、Cygwin 或任何在 PATH 上的 bash.exe

安装器会显式设置 HERMES_GIT_BASH_PATH,这样新启动的 PowerShell 不必重复探测。如果你想让 Hermes 用某个特定的 bash——比如系统的 Git Bash 或通过软链指向 WSL 内的 bash——可以覆盖这个变量。

坑点: MinGit 的目录结构和完整版 Git-for-Windows 不一样——bash 在 usr\bin\bash.exe,不是 bin\bash.exe。Hermes 两个位置都会检查。如果你手动解压 MinGit zip,记得选非 busybox 版本(MinGit-*-64-bit.zip,不是 MinGit-*-busybox*.zip)——busybox 构建只带 ash 而不是 bash,coreutils 也大多缺失。

Windows 上的 UTF-8 控制台

Python 在 Windows 上默认的 stdio 使用控制台的当前代码页(通常是 cp1252 或 cp437)。Hermes 的横幅、斜杠命令列表、tool feed、Rich 面板和 skill 描述里都包含 Unicode。如果不做处理,任何一处都可能报 UnicodeEncodeError: 'charmap' codec can't encode character…

修复在 hermes_cli/stdio.py::configure_windows_stdio() 里完成,每个入口点(cli.py::mainhermes_cli/main.py::maingateway/run.py::main)都会在很早期调用它。它会:

  1. 通过 kernel32.SetConsoleCP / SetConsoleOutputCP 把控制台代码页切到 CP_UTF8(65001)。
  2. sys.stdout / sys.stderr / sys.stdin 重新配置为 UTF-8,且 errors='replace'
  3. 设置 PYTHONIOENCODING=utf-8PYTHONUTF8=1(用 setdefault,所以用户显式设置的值优先),让 Python 子进程也继承 UTF-8。
  4. 如果 EDITORVISUAL 都没设置,则设 EDITOR=notepad(参见下面的 Editor 一节)。

幂等。在非 Windows 上是 no-op。

关掉它: 在环境里设 HERMES_DISABLE_WINDOWS_UTF8=1 会回退到旧的 cp1252 stdio 路径。用于二分定位编码 bug 时有用;正常使用基本不需要。

编辑器(Ctrl-X Ctrl-E/edit

#21561 之前,在 Windows 上按 Ctrl-X Ctrl-E 或输入 /edit 会静默无效。prompt_toolkit 内置了一份 POSIX 绝对路径的兜底列表(/usr/bin/nano/usr/bin/pico/usr/bin/vi、…),在 Windows 上永远解析不到——哪怕装了完整的 Git for Windows。

Hermes 的 Windows stdio 垫片现在会把 EDITOR=notepad 设成默认值。Notepad 随每个 Windows 安装一起出货,并且能作为阻塞式编辑器使用——subprocess.call(["notepad", file]) 会一直阻塞到窗口关闭。

用户的覆盖仍然优先(在 setdefault 之前会先检查):

编辑器PowerShell 命令
VS Code$env:EDITOR = "code --wait"
Notepad++$env:EDITOR = "'C:\Program Files\Notepad++\notepad++.exe' -multiInst -nosession"
Neovim$env:EDITOR = "nvim"
Helix$env:EDITOR = "hx"

VS Code 上的 --wait 参数至关重要——没有它,编辑器会立即返回,Hermes 拿到的是个空 buffer。

把它写进 PowerShell profile,让设置永久生效:

# 在 $PROFILE 里
$env:EDITOR = "code --wait"

或者在系统设置里把它设成 User 环境变量,这样每个新开的 shell 都能看到。

在 CLI 里用 Ctrl+Enter 换行

Windows Terminal 会把 Ctrl+Enter 作为一个独立的按键序列透传过来。Hermes 把它绑定为"插入换行",让你能在 CLI 里组合多行 prompt,而不必退回到 Esc-然后-Enter。在 Windows Terminal、VS Code 集成终端,以及任何遵守 VT 转义序列的现代 Windows 控制台里都能用。

在老式 cmd.exe 控制台里,Ctrl+Enter 会被折叠成普通 Enter——这种情况下用 Esc Enter,或者升级到 Windows Terminal(免费,Windows 11 默认安装)。

让 Gateway 在 Windows 登录时自动启动

hermes gateway install 在 Windows 上使用 Scheduled Tasks,并以 Startup 文件夹作为兜底——不需要管理员权限。

安装

hermes gateway install

幕后发生的事情:

  1. schtasks /Create /SC ONLOGON /RL LIMITED /TN HermesGateway —— 注册一个登录时以标准(非提权)权限运行的任务。无 UAC 弹窗。
  2. 如果 schtasks 被组策略禁用,会回退到把一个 start /min cmd.exe /d /c <wrapper> 快捷方式写入 %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup。效果一样,做法稍粗糙。
  3. 通过 pythonw.exe 以 detached 方式启动 gateway——而不是 python.exepythonw.exe 没有附带控制台,因此能免疫来自兄弟进程的 CTRL_C_EVENT 广播(这是个真实问题,过去曾经在你 Ctrl+C 同进程组里任何东西时把 gateway 顺带杀死)。

启动时使用的 flag:DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW | CREATE_BREAKAWAY_FROM_JOB

管理

hermes gateway status      # 合并视图:schtasks + Startup 文件夹 + 运行中 PID
hermes gateway start # 立即启动计划任务
hermes gateway stop # SIGTERM 的等价(通过 psutil 调 TerminateProcess)
hermes gateway restart
hermes gateway uninstall # 移除 schtasks 项、Startup 快捷方式、pid 文件

hermes gateway status 是幂等的——连着调一千次也绝不会意外杀掉 gateway。(PR #21561 之前它确实会静默杀掉,因为 os.kill(pid, 0) 在 C 层和 CTRL_C_EVENT 撞到一起——如果你想了解前因后果,请看下面"进程管理内部细节"。)

为什么不用 Windows Service?

服务需要管理员权限来安装,并且把 gateway 的生命周期绑定到机器开机,而不是用户登录。典型的 Hermes 用户想要的是:登录 → gateway 可用,登出 → gateway 退出。Scheduled Tasks 正好做到了这一点,且不需要提权。如果你确实想要一个 service,可以手动用 nssmsc create——但你大概率并不需要。

数据目录布局

路径内容
%LOCALAPPDATA%\hermes\hermes-agent\Git 检出 + venv。可以放心 Remove-Item -Recurse 然后重装。
%LOCALAPPDATA%\hermes\git\PortableGit(仅在安装器自动配置时存在)。
%LOCALAPPDATA%\hermes\node\可移植 Node.js(仅在安装器自动配置时存在)。
%LOCALAPPDATA%\hermes\bin\hermes.cmd 垫片,已加入 User PATH。
%USERPROFILE%\.hermes\你的配置、auth、skills、会话、日志。重装也不会动它。

这种切分是有意为之:%LOCALAPPDATA%\hermes 是可丢弃的基础设施(你可以整个删掉,一行命令再装回来)。%USERPROFILE%\.hermes 才是你的数据——配置、记忆、技能、会话历史——它的形状和 Linux 安装完全一致。把它在多台机器之间镜像,你的 Hermes 就跟着你走。

覆盖 HERMES_HOME 设置该环境变量指向其他数据目录。和 Linux 上行为相同。

Browser tool

Browser tool 通过 agent-browser(一个 Node helper)驱动 Chromium。在 Windows 上:

  • 安装器通过 npm 把 agent-browser 加到 PATH。
  • shutil.which("agent-browser", path=...) 会自动选到 .cmd 垫片——CreateProcessW 无法直接执行没有扩展名的 shebang 脚本,所以 Hermes 总是解析到 .CMD wrapper。不要手动调用 shebang 脚本本身,永远走 .cmd
  • Playwright Chromium 会在第一次运行时自动安装(npx playwright install chromium)。如果安装失败,hermes doctor 会把它报出来并给出修复提示。

在 Windows 上运行 Hermes —— 实践要点

安装后的 PATH

安装器通过 [Environment]::SetEnvironmentVariable%LOCALAPPDATA%\hermes\bin 加到了你的 User PATH。已经打开的终端拿不到这个变化——安装完成后请新开一个 PowerShell 窗口(或 Windows Terminal 标签页)。是关掉重开,而不是手动 $env:PATH += …,除非你清楚自己在做什么。

验证:

Get-Command hermes        # 应该输出 C:\Users\<你>\AppData\Local\hermes\bin\hermes.cmd
hermes --version

环境变量

Hermes 同时尊重 $env:X(进程级)和 User 环境变量(永久级,在系统属性 → 环境变量里设置)。把 API key 放到 %USERPROFILE%\.hermes\.env 里是常规做法——和 Linux 一致:

OPENROUTER_API_KEY=sk-or-...
TELEGRAM_BOT_TOKEN=...

不要把密钥放到 User 环境变量里,除非你确实希望每个 Windows 进程都能看到它(这通常不是你想要的)。

Windows 专属环境变量

这些只对 Windows 原生安装生效:

变量作用
HERMES_GIT_BASH_PATH覆盖 bash.exe 的解析。可以指向任意 bash——完整 Git-for-Windows、通过软链指向 WSL bash、MSYS2、Cygwin。安装器会自动设置。
HERMES_DISABLE_WINDOWS_UTF8设为 1 禁用 UTF-8 stdio 垫片,回退到 locale 代码页。用于二分定位编码 bug。
EDITOR / VISUAL/editCtrl-X Ctrl-E 使用的编辑器。两者都未设置时 Hermes 默认用 notepad

卸载

在 PowerShell 里:

hermes uninstall

这是干净路径——会移除 schtasks 项、Startup 文件夹快捷方式、hermes.cmd 垫片,删除 %LOCALAPPDATA%\hermes\hermes-agent\,并精简 User PATH。它不会动 %USERPROFILE%\.hermes\(你的配置、auth、skills、会话、日志),方便你之后重装。

要全部清干净:

hermes uninstall
Remove-Item -Recurse -Force "$env:USERPROFILE\.hermes"
Remove-Item -Recurse -Force "$env:LOCALAPPDATA\hermes"

hermes uninstall 子命令也能处理 schtasks 任务名不一样的情况(老版本可能注册了不同的名字)——它按安装路径而不是按硬编码任务名来搜。

进程管理内部细节

这部分是背景资料——除非你在排查"它把自己杀了"这种诡异问题,否则可以跳过。

在 Linux 和 macOS 上,POSIX 习惯用法 os.kill(pid, 0) 是一个 no-op 权限检查:"这个 PID 还活着吗?我能向它发信号吗?"在 Windows 上,Python 的 os.kill 会把 sig=0 映射到 CTRL_C_EVENT——它们在整数值 0 上撞车——并通过 GenerateConsoleCtrlEvent(0, pid) 路由出去,这个调用会向整个包含目标 PID 的控制台进程组广播 Ctrl+C。这就是 bpo-14484,从 2012 年就开着。它不会被修复,因为修了会破坏依赖当前行为的脚本。

后果:任何在 Windows 上通过 os.kill(pid, 0) 来"检查这个 PID 是否还活着"的代码路径,实际上都在静默杀掉目标。Hermes 把所有这样的位置(11 个文件里的 14 处)都迁移到了 gateway.status._pid_exists(),这个函数底层用的是 psutil.pid_exists()(在 Windows 上又会用 OpenProcess + GetExitCodeProcess——不发信号)。如果你写插件或补丁,请直接用 psutil.pid_exists()gateway.status._pid_exists()——绝不要用 os.kill(pid, 0)

scripts/check-windows-footguns.py 在 CI 里把这条规则强制执行:任何新的 os.kill(pid, 0) 调用都会让 Windows footguns (blocking) 检查失败,除非该行带 # windows-footgun: ok — <reason> 标记。

常见坑

安装完立刻报 hermes: command not found 打开一个新的 PowerShell 窗口。安装器把 %LOCALAPPDATA%\hermes\bin 加到了 User PATH,但已有的 shell 需要重启才能拿到新值。在此期间你可以用 & "$env:LOCALAPPDATA\hermes\bin\hermes.cmd" 直接执行。

运行某个工具时报 WinError 193: %1 is not a valid Win32 application 你触发了一次绕过 .cmd 垫片的 shebang 脚本调用。Hermes 通过 shutil.which(cmd, path=local_bin) 解析命令,这样 PATHEXT 才能选到 .CMD——如果你是通过硬编码路径调工具,请改用 .cmd 变体(比如 npx.cmd 而不是 npx)。

[scriptblock]::Create(...)The assignment expression is not valid 你下载的 install.ps1 带了 UTF-8 BOM。irm | iex 形式会自动剥掉 BOM;[scriptblock]::Create((irm ...)) 不会。改用简单的 irm | iex 形式重跑,或者手动下载脚本并用 [IO.File]::WriteAllText($path, $text, (New-Object Text.UTF8Encoding $false)) 保存为不带 BOM 的版本。

重启之后 Gateway 跑不起来。 看一眼 hermes gateway status——它会把 schtasks 项、Startup 文件夹快捷方式(如果有)和实时 PID 合并展示。如果 schtasks 已注册但没在跑,可能是组策略禁掉了 ONLOGON 触发器。运行 schtasks /Query /TN HermesGateway /V /FO LIST 看任务的失败原因,或者卸载后用 HERMES_GATEWAY_FORCE_STARTUP=1 重装回退到 Startup 文件夹路径。

设了 $env:EDITOR 之后 /edit 还是没反应。 你只是设到了当前进程;关掉再开一个 shell,或者在系统属性 → 环境变量里以 User scope 设置。在新 PowerShell 窗口里用 echo $env:EDITOR 验证。

Browser tool 起得来,但工具调用超时。 Chromium 在第一次运行时会自动安装。如果安装失败(GitHub 限流、Playwright CDN 抽风),运行 hermes doctor——它会指出缺失的 Chromium 并打印精确的 npx playwright install chromium 修复命令。

agent-browser 报奇怪的 Node 版本错误。 安装器在 %LOCALAPPDATA%\hermes\node 装了 Node 22,但你的 PATH 里可能有更老的系统 Node 18 排在前面。要么把 Hermes 的 node 目录在 PATH 里前移,要么在不需要其他 Node 的情况下卸载系统 Node。

中文 / 日语 / 阿拉伯字符在 CLI 里显示成 ? UTF-8 stdio 垫片没有生效。检查 HERMES_DISABLE_WINDOWS_UTF8 是否没有被设置(Get-ChildItem env:HERMES_DISABLE_WINDOWS_UTF8)。如果它确实是空的但仍然出现 ?,说明控制台宿主(极旧的 cmd.exe)根本不支持 UTF-8——切到 Windows Terminal。

Gateway 发不了 Telegram 图片——报 "BadRequest: payload contains invalid characters"。 这并非 Windows 特有,但有时候在 Windows 上首先暴露。通常是因为你的文件路径在 JSON body 里带了未转义的反斜杠。Telegram 应该收到的是 Hermes 标准化过的路径,而不是原始 Windows 路径——如果你在自定义插件里看到这个错误,请确认你传的是 Hermes 提供的路径,而不是来自用户输入的 str(Path(...))

git pull 之后出现"在另一台机器上能跑"的编码诡异问题。 如果你用非 UTF-8 编辑器(老版本 Windows 上的 Notepad、某些中文输入法)在 Windows 上编辑过 Hermes 配置或 skill,文件可能被存成了带 BOM 的版本。Hermes 在大多数配置读取时会容忍 utf-8-sig,但折叠 YAML 标量(description: >)里的 BOM 会让 YAML 解析静默失败。把文件重新存成不带 BOM 的纯 UTF-8。

接下来去哪里

  • 安装 —— 完整的安装页,覆盖 Linux/macOS/WSL2/Termux。
  • Windows (WSL2) 指南 —— 如果你想要 POSIX 语义或 Dashboard 终端面板。
  • CLI 参考 —— 每个 hermes 子命令。
  • FAQ —— 与 Windows 无关的常见问题。
  • 消息 Gateway —— 在 Windows 上跑 Telegram/Discord/Slack。