Windows 原生安裝指南 — 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 專屬開關。
如果你只是想安裝,首頁或安裝頁上的一行命令就夠了。等到有什麼讓你困惑時再回來看這一頁。
如果你更想要一個真正的 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
| 參數 | 默認值 | 用途 |
|---|---|---|
-Branch | main | 克隆指定分支(用於測試 PR) |
-NoVenv | 關閉 | 跳過 venv 創建(高級用法——你自己管理 Python) |
-SkipSetup | 關閉 | 跳過安裝後的 hermes setup 嚮導 |
-HermesHome | %LOCALAPPDATA%\hermes | 覆蓋數據目錄 |
-InstallDir | %LOCALAPPDATA%\hermes\hermes-agent | 覆蓋代碼目錄 |
安裝器到底做了什麼
從上到下依次執行:
- 引導
uv—— Astral 的高性能 Python 管理器。安裝到%USERPROFILE%\.local\bin。 - 通過
uv安裝 Python 3.11。不需要預先安裝任何 Python。 - 安裝 Node.js 22(優先 winget,否則從可移植 Node tarball 解壓到
%LOCALAPPDATA%\hermes\node)。用於 browser tool 和 WhatsApp 橋接。 - 安裝可移植版 Git —— 如果 PATH 上已經有
git,安裝器會直接複用;否則會從官方git-for-windowsrelease 下載一個精簡、自包含的 PortableGit(約 45 MB)到%LOCALAPPDATA%\hermes\git。無需管理員權限,不寫入 Windows 安裝註冊表,不會干擾機器上的其他東西。 - 克隆倉庫到
%LOCALAPPDATA%\hermes\hermes-agent,並在內部創建 virtualenv。 - 分級
uv pip install—— 先嚐試.[all],如果某個git+https依賴在被限流的 GitHub 上抽風,會回退到逐步縮小的依賴集合([messaging,dashboard,ext]→[messaging]→.)。避免"一個依賴出問題就掉到裸裝"這種失敗模式。 - 基於
.env自動安裝消息平臺 SDK —— 如果存在TELEGRAM_BOT_TOKEN/DISCORD_BOT_TOKEN/SLACK_BOT_TOKEN/SLACK_APP_TOKEN/WHATSAPP_ENABLED,會運行python -m ensurepip --upgrade和針對性的pip install調用,確保每個平臺的 SDK 都能真正 import。 - 設置
HERMES_GIT_BASH_PATH指向解析到的bash.exe,這樣 Hermes 在新的 shell 裡也能確定性地找到 bash。 - 把
%LOCALAPPDATA%\hermes\bin加入 User PATH —— 在你打開新終端後,hermes命令就能直接使用。 - 運行
hermes setup—— 正常的首次運行嚮導(模型、provider、toolset)。可用-SkipSetup跳過。
能力矩陣
除了 Dashboard 內嵌終端面板之外,所有功能在 Windows 上都原生可用。
| 功能 | Windows 原生 | WSL2 |
|---|---|---|
CLI(hermes chat、hermes setup、hermes 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 的解析順序:
- 設置了
HERMES_GIT_BASH_PATH環境變量時優先使用它。 %LOCALAPPDATA%\hermes\git\usr\bin\bash.exe(安裝器自帶的 PortableGit)。%LOCALAPPDATA%\hermes\git\bin\bash.exe(舊版 Git-for-Windows 佈局)。- 系統的 Git-for-Windows 安裝(
%ProgramFiles%\Git\bin\bash.exe等)。 - 兜底: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::main、hermes_cli/main.py::main、gateway/run.py::main)都會在很早期調用它。它會:
- 通過
kernel32.SetConsoleCP/SetConsoleOutputCP把控制檯代碼頁切到 CP_UTF8(65001)。 - 把
sys.stdout/sys.stderr/sys.stdin重新配置為 UTF-8,且errors='replace'。 - 設置
PYTHONIOENCODING=utf-8和PYTHONUTF8=1(用setdefault,所以用戶顯式設置的值優先),讓 Python 子進程也繼承 UTF-8。 - 如果
EDITOR和VISUAL都沒設置,則設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
幕後發生的事情:
schtasks /Create /SC ONLOGON /RL LIMITED /TN HermesGateway—— 註冊一個登錄時以標準(非提權)權限運行的任務。無 UAC 彈窗。- 如果 schtasks 被組策略禁用,會回退到把一個
start /min cmd.exe /d /c <wrapper>快捷方式寫入%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup。效果一樣,做法稍粗糙。 - 通過
pythonw.exe以 detached 方式啟動 gateway——而不是python.exe。pythonw.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,可以手動用 nssm 或 sc 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 總是解析到.CMDwrapper。不要手動調用 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 | /edit 和 Ctrl-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。