Skip to content

Windows (WSL2) Guide

Hermes Agent is developed and tested on Linux and macOS. Native Windows is not supported — on Windows you run Hermes inside WSL2 (Windows Subsystem for Linux, version 2). That means there are effectively two computers in play: your Windows host, and a Linux VM managed by WSL. Most confusion comes from not being sure which one you’re on at any moment.

This guide covers the parts of that split that specifically affect Hermes: installing WSL2, getting files back and forth between Windows and Linux, networking in both directions, and the pitfalls people actually hit.

:::info 简体中文 A Chinese-language walkthrough of the minimum install path is maintained on this same page — switch via the language menu (top right) and select 简体中文. :::

Hermes assumes a POSIX environment: fork, /tmp, UNIX sockets, signal semantics, PTY-backed terminals, shells like bash/zsh, and tools like rg, git, ffmpeg that behave the way they do on Linux. Rewriting that for native Windows would be a full port — WSL2 gives you a real Linux kernel in a lightweight VM instead, and Hermes inside it is essentially identical to running on Ubuntu.

Practical consequences of this choice:

  • The Hermes CLI, gateway, sessions, memory, skills, and tool runtimes all live inside the Linux VM.
  • Windows programs (browsers, native apps, Chrome with your logged-in profile) live outside it.
  • Every time you want the two to talk — share files, open URLs, control Chrome, hit a local model server, expose the Hermes gateway to your phone — you cross a boundary. Those boundaries are what this guide is about.

From an Admin PowerShell or Windows Terminal:

Окно терминала
wsl --install

On a fresh Windows 10 22H2+ or Windows 11 box this installs the WSL2 kernel, the Virtual Machine Platform feature, and a default Ubuntu distro. Reboot when prompted. After reboot Ubuntu will open and ask for a Linux username + password — this is a new Linux user, unrelated to your Windows account.

Verify you’re actually on WSL2 (not legacy WSL1):

Окно терминала
wsl --list --verbose

You should see VERSION 2. If a distro shows VERSION 1, convert it:

Окно терминала
wsl --set-version Ubuntu 2
wsl --set-default-version 2

Hermes does not work reliably on WSL1 — WSL1 translates Linux syscalls on the fly and some behaviors (procfs, signals, network) diverge from real Linux.

Ubuntu (LTS) is what we test against. Debian works. Arch and NixOS work for people who want them, but the one-line installer assumes a Debian-derived apt system — see the Nix setup guide for that path.

The hermes gateway (and anything else you want to keep running) is easier to manage with systemd. On modern WSL, enable it once inside your distro:

Окно терминала
sudo tee /etc/wsl.conf >/dev/null <<'EOF'
[boot]
systemd=true
[interop]
enabled=true
appendWindowsPath=true
[automount]
options = "metadata,umask=22,fmask=11"
EOF

Then from PowerShell:

Окно терминала
wsl --shutdown

Reopen your WSL terminal. ps -p 1 -o comm= should print systemd.

The metadata mount option above is important — without it, files on /mnt/c/... can’t store real Linux permission bits, which breaks things like chmod +x on scripts under Windows paths.

Once you have a WSL2 shell open:

Окно терминала
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
source ~/.bashrc
hermes

The installer treats WSL2 as plain Linux — nothing WSL-specific is needed. See Installation for the full layout.

Filesystem: crossing the Windows ↔ WSL2 boundary

Section titled “Filesystem: crossing the Windows ↔ WSL2 boundary”

This is the part that trips up the most people. There are two filesystems, and where you put your files matters — for performance, correctness, and what tools can see.

DirectionPath insidePath you use
Windows disk, seen from WSLC:\Users\you\Documents/mnt/c/Users/you/Documents
WSL disk, seen from Windows/home/you/code\\wsl$\Ubuntu\home\you\code (or \\wsl.localhost\Ubuntu\... on newer builds)

Both are real, both work, but they are not the same filesystem — they’re bridged by a 9P network protocol under the hood. That has real performance and semantic consequences.

Rule of thumb: keep everything Linux-ish inside the Linux filesystem.

  • Your Hermes install (~/.hermes/) — Linux side. The installer already does this.
  • Your git repos that you work on from WSL — Linux side (~/code/..., ~/projects/...).
  • Your models, datasets, venvs — Linux side.

What you get by following this rule:

  • Fast I/O. Operations on /mnt/c/... go through 9P and are 10–100× slower than native ext4. git status on a 10k-file repo that feels instant under ~/code can take 15+ seconds under /mnt/c.
  • Correct permissions. Linux permission bits are a best-effort emulation on /mnt/c. Things like ssh refusing a key with “bad permissions” or chmod +x silently failing are common.
  • Reliable file watchers. inotify across 9P is flaky — file watchers (dev servers, test runners) routinely miss changes on /mnt/c.
  • No case-sensitivity surprises. Windows paths are case-insensitive by default; Linux is case-sensitive. Projects with both Readme.md and README.md behave differently depending which side you’re on.

Put things on /mnt/c only when you need a file to live on the Windows side — e.g., you want to open it from a Windows GUI app, or Windows Chrome’s DevTools MCP needs the current directory to be a Windows-reachable path.

From Windows → into WSL: easiest is to open Explorer and type \\wsl.localhost\Ubuntu in the address bar. You can then drag-drop into \home\<you>\.... Or from PowerShell:

Окно терминала
wsl cp /mnt/c/Users/you/Downloads/file.pdf ~/incoming/

From WSL → into Windows: copy to /mnt/c/Users/<you>/... and it shows up in Windows Explorer immediately:

Окно терминала
cp ~/reports/output.pdf /mnt/c/Users/you/Desktop/

Open a WSL file in a Windows app (GUI editor, browser, etc.): use explorer.exe or wslview:

Окно терминала
sudo apt install wslu # once — gives you wslview, wslpath, wslopen, etc.
wslview ~/reports/output.pdf # opens with the Windows default handler
explorer.exe . # opens the current WSL dir in Windows Explorer

Convert paths between the two universes:

Окно терминала
wslpath -w ~/code/project # → \\wsl.localhost\Ubuntu\home\you\code\project
wslpath -u 'C:\Users\you' # → /mnt/c/Users/you

If you edit files on the Windows side with a Windows editor, they may get CRLF line endings. When bash or Python on the Linux side reads them, shell scripts break with bad interpreter: /bin/bash^M and Python can fail on BOM’d .env files.

The fix is a sane git config inside WSL (not on Windows):

Окно терминала
git config --global core.autocrlf input
git config --global core.eol lf

For files that already have CRLF:

Окно терминала
sudo apt install dos2unix
dos2unix path/to/script.sh

Clone inside WSL. Always, unless you have a specific reason not to. A typical Hermes workflow (hermes chat, tool calls that rg/ripgrep the repo, file watchers, background gateway) will be dramatically faster and more reliable against ~/code/myrepo than /mnt/c/Users/you/myrepo.

One exception: MCP bridges that launch Windows binaries. If you’re using chrome-devtools-mcp through cmd.exe (see MCP guide: WSL → Windows Chrome), Windows may complain with a UNC warning if Hermes’s current working directory is ~. In that case, start Hermes from somewhere under /mnt/c/ so the Windows process has a drive-letter cwd.

WSL2 runs in a lightweight VM with its own network stack. That means localhost inside WSL is not the same as localhost on Windows — they’re two separate hosts from the network’s point of view. You need to decide, for each service, which direction traffic flows and pick the right bridge.

Two cases come up constantly.

Case 1 — Hermes in WSL talks to a service on Windows

Section titled “Case 1 — Hermes in WSL talks to a service on Windows”

Most common: you’re running Ollama, LM Studio, or a llama-server on Windows, and Hermes (inside WSL) needs to hit it.

The canonical how-to for this lives in the providers guide: WSL2 Networking for Local Models →

Short version:

  • Windows 11 22H2+: turn on mirrored networking mode (networkingMode=mirrored in %USERPROFILE%\.wslconfig, then wsl --shutdown). localhost then works in both directions.
  • Windows 10 or older builds: use the Windows host IP (the default gateway of WSL’s virtual network) and make sure the server on Windows binds to 0.0.0.0, not just 127.0.0.1. Windows Firewall usually also needs a rule for the port.

For the full table (Ollama / LM Studio / vLLM / SGLang bind addresses, firewall rule one-liners, dynamic IP helpers, Hyper-V firewall workaround), follow the link above — don’t duplicate it.

Case 2 — Something on Windows (or your LAN) talks to Hermes in WSL

Section titled “Case 2 — Something on Windows (or your LAN) talks to Hermes in WSL”

This is the reverse direction and is less documented elsewhere, but it’s what you need for:

  • Using the Hermes web dashboard from a Windows browser.
  • Using the API server (hermes api) from a Windows-side tool.
  • Testing a messaging gateway (Telegram, Discord, etc.) where the platform pings a local webhook URL — usually you’d use cloudflared/ngrok rather than raw port forwarding.

On Windows 11 22H2+ with mirrored mode enabled, there is nothing to do. A process in WSL that binds to 0.0.0.0:8080 (or even 127.0.0.1:8080) is reachable from a Windows browser at http://localhost:8080. WSL publishes the bind back to the host automatically.

On NAT mode (Windows 10 / older Windows 11), the default “localhost forwarding” in WSL2 will generally forward Linux-side 127.0.0.1 binds to Windows localhost, so a Hermes service started with --host 127.0.0.1 is usually reachable as http://localhost:PORT from Windows. If it isn’t:

  • Bind to 0.0.0.0 explicitly inside WSL.
  • Find the WSL VM’s IP with ip -4 addr show eth0 | grep inet and hit that from Windows.

Subcase 2b: from another device on your LAN (phone, tablet, another PC)

Section titled “Subcase 2b: from another device on your LAN (phone, tablet, another PC)”

This is the real pain. Traffic flows LAN device → Windows host → WSL VM, and you have to set up both hops:

  1. Bind on all interfaces inside WSL. A process listening on 127.0.0.1 will never be reachable from outside the VM. Use 0.0.0.0.

  2. Port-forward Windows → WSL VM. In mirrored mode this is automatic. In NAT mode you have to do it yourself, per port, in Admin PowerShell:

    Окно терминала
    # Grab the WSL VM's current IP (it changes on every WSL restart under NAT)
    $wslIp = (wsl hostname -I).Trim().Split(' ')[0]
    # Forward Windows port 8080 → WSL:8080
    netsh interface portproxy add v4tov4 `
    listenaddress=0.0.0.0 listenport=8080 `
    connectaddress=$wslIp connectport=8080
    # Allow it through Windows Firewall
    New-NetFirewallRule -DisplayName "Hermes WSL 8080" `
    -Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow

    Remove later with netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=8080.

  3. Point the LAN device at http://<windows-lan-ip>:8080.

Because the WSL VM IP drifts on each restart in NAT mode, a one-shot rule survives only until the next wsl --shutdown. For anything persistent, either use mirrored mode or put the port-proxy step in a script that runs at Windows login.

For webhooks from cloud messaging providers (Telegram setWebhook, Slack events, etc.), don’t fight port-forwarding — use cloudflared tunnels. See the webhooks guide.

Running Hermes services long-term on Windows

Section titled “Running Hermes services long-term on Windows”

The Hermes Tool Gateway and the API server are long-lived processes. In WSL2 you have a few options for keeping them up.

If you enabled systemd per the setup section above, hermes gateway and the API server work the way they do on any Linux machine. Use the gateway setup wizard:

Окно терминала
hermes gateway setup

It will offer to install a systemd user unit so the gateway comes up automatically when WSL starts.

WSL’s VM only stays alive while something is using it. To keep your gateway reachable without a terminal window open, boot a WSL process at Windows login via Task Scheduler:

  • Trigger: At log on (your user).
  • Action: Start a program
    • Program: C:\Windows\System32\wsl.exe
    • Arguments: -d Ubuntu --exec /bin/sh -c "sleep infinity"

That keeps the VM alive so the systemd-managed gateway stays running. On Windows 11, the newer wsl --install --no-launch + auto-start flows also work; the sleep infinity trick is the portable version.

WSL2 supports NVIDIA GPUs natively since WSL kernel 5.10.43+ — install the standard NVIDIA driver on Windows (do not install a Linux NVIDIA driver inside WSL), and nvidia-smi inside WSL will see the GPU. From there, CUDA toolkits, torch, vllm, sglang, and llama-server build against the real GPU as usual.

AMD ROCm and Intel Arc support inside WSL2 is still evolving and outside Hermes’s test matrix — it may work with current drivers but we don’t have a recipe to recommend.

If you’re running a Windows-native local-model server (Ollama for Windows, LM Studio) that already uses your GPU through Windows drivers, you don’t need WSL GPU passthrough at all — just follow Case 1 above and hit it over the network from WSL.

“Connection refused” to my Windows-hosted Ollama / LM Studio. See WSL2 Networking. Ninety percent of the time the server is bound to 127.0.0.1 and needs 0.0.0.0 (Ollama: OLLAMA_HOST=0.0.0.0), or you’re missing a firewall rule.

Massive slowness on git status / hermes chat in a repo. You’re probably working under /mnt/c/.... Move the repo to ~/code/... (Linux side). Order-of-magnitude faster.

bad interpreter: /bin/bash^M on scripts. CRLF line endings from a Windows editor. dos2unix script.sh, and set core.autocrlf input in your WSL git config.

“UNC paths are not supported” warning from Windows binaries launched via MCP. Hermes’s cwd is inside the Linux filesystem, and Windows cmd.exe doesn’t know what to do with it. Start Hermes from /mnt/c/... for that session, or use a wrapper that cds to a Windows-reachable path before invoking the Windows executable.

Clock drift after sleep/hibernate. WSL2’s clock can lag by minutes after the host resumes from sleep, which breaks anything cert-based (OAuth, HTTPS APIs). Fix it on demand:

Окно терминала
sudo hwclock -s

Or install ntpdate and run it at login.

DNS stops working after enabling mirrored mode, or when a VPN is connected. Mirrored mode proxies host network settings into WSL — if Windows DNS is funky (VPN split-tunnel, corporate resolver), WSL inherits that. Workaround: override resolv.conf manually (set generateResolvConf=false in /etc/wsl.conf, then write your own /etc/resolv.conf with 1.1.1.1 or your VPN’s DNS).

hermes not found after running the installer. The installer adds ~/.local/bin to your shell’s PATH via ~/.bashrc. You need to source ~/.bashrc (or open a new terminal) for it to take effect in the current session.

Windows Defender is slow on WSL files. Defender scans files via the 9P bridge when accessed from Windows, which magnifies the slowness of /mnt/c-style cross-boundary access. If you only touch WSL files from inside WSL, this doesn’t matter. If you use Windows tools against \\wsl$\... frequently, consider excluding the WSL distro path from real-time scanning.

Running out of disk. WSL2 stores its VM disk as a sparse VHDX under %LOCALAPPDATA%\Packages\.... It grows but doesn’t auto-shrink when you delete files. To reclaim space: wsl --shutdown, then from an Admin PowerShell run Optimize-VHD -Path <path-to-ext4.vhdx> -Mode Full (requires Hyper-V tools) — or the simpler diskpart path documented on the WSL docs.