/ engineering

Bringing Hermes to WebAssembly

Yev·May 6, 2026·5 min read·
#engineering
Bringing Hermes to WebAssembly

What's in this post?

We took Hermes Agent, developed by the folks at Nous Research, and brought it to WebAssembly in two different ways, detailed below, and share what our general takeaways from this experiment are.

Should I replace my Hermes with one of these?

Probably not. If doing things with Python in WebAssembly is of interest to you, then continue reading!

Where did Hermes come from?

Having taken the world by storm, OpenClaw is an AI assistant which uses the computer you run it on similarly to a person (so it can do more than just recite Wikipedia articles). Following this, Hermes was written in Python on top of mini-swe-agent (unlike OpenClaw which is written in TypeScript on top of pi).

Both are "general-purpose agents" which are really batteries-included coding agents. The "magic" of their utility comes from the assembling of the "harness" the agent sits inside of when handling users' prompts; which gives it the capability to do things like click around a browser or send an email.

Why WebAssembly?

I'm admittedly biased when it comes to WebAssembly but, having worked on multi-agent projects before, I was interested in seeing if WebAssembly would give a win with regard to isolation (ie spinning up multiple separate agents in parallel) or granular configurability (ie assembling agents precisely with certain tools for different "modes").

Additionally, since Hermes is written in Python, I wanted to see if eagerly compiling to WebAssembly would offer closer-to-native performance.

How to WASM Hermes

Pyodide

Run Hermes in pyodide yourself

This app serves an index.html with the full agent running client-side in Pyodide. To run the below command, you may need to install the vers CLI first.

vers run-commit f46a2b21-73fe-4835-ad79-8eccd523fc07 \
  --format json --wait \
  | sed -n 's/.*"vm_id"[: ]*"\([^"]*\)".*/https:\/\/\1.vm.vers.sh/p'

Public Vers VM Commit: f46a2b21-73fe-4835-ad79-8eccd523fc07

How it works with Pyodide

The first approach is by using Pyodide, a Python runtime that's ported to WebAssembly so Python programs can be interpreted and run in the browser. You can think of this as being similar to the approach that was taken with bringing Postgres to WebAssembly:

Postgres itself doesn't get run in WebAssembly but instead a Linux emulator in WASM runs a modified version of Postgres so the whole thing can actually work together inside a browser.

Hermes in Pyodide source

You can view and modify the source code here: https://github.com/hdresearch/hermes-pyodide

pywasm

Run Hermes in pywasm yourself

This app serves the hermes_agent.wasm binary. Hit the "Run" button in the UI to execute it live.

vers run-commit f83df1ac-0a53-4ca6-bc26-205584fe65a3 \
  --format json --wait \
  | sed -n 's/.*"vm_id"[: ]*"\([^"]*\)".*/https:\/\/\1.vm.vers.sh/p'

Public Vers VM Commit: f83df1ac-0a53-4ca6-bc26-205584fe65a3

How it works with py2wasm

This second approach works by using py2wasm, a Python-to-WebAssembly compiler and the pywasm split design keeps the security boundary clean:

The host extracts real schemas from the Hermes' ToolRegistry at startup before sending them to the WASM binary via init protocol. The LLM always sees the same parameter names as the actual handlers (ie path instead of file_path or old_string instead old_text).

Hermes in pywasm source

You can view and modify the soure code yourself here: https://github.com/hdresearch/hermes-pywasm

Benchmarks

Below are benchmarks obtained from running on a M4 macbook. As admitted earlier, this probably won't meaningfully replace running Hermes on your laptop. However, if porting the harness itself to alternative environments (ie a browser) is of interest to you, then you can see some of the tradeoffs between pyodide and py2wasm.

MetricNative PythonPyodide (browser)pywasm (WASI)
Cold start750 ms2–5 s110 ms
Single turn840 ms~850 ms100 ms
20-turn conversation3,280 ms~3,300 ms110 ms
50 parallel agents4,566 msN/A (browser)611 ms (wasmtime)
Worker pool throughput9 q/sN/A (browser)81 q/s (wasmtime)
Deployment size733 MB~20 MB + packages26 MB
Pip packages171171 (via Pyodide)0
Runs in browser⚠️ needs WASI polyfill
API key exposureserver-sideclient-sideStored in host

Takeaways

While the founder of Docker years ago suggested WASM+WASI was the missing sandboxing solution, it's evidently not a magic bullet considering the missing capabilities from a full-fledged computer or container. If having a full but branchable VM with incredibly fast startup times sounds like what you're looking for, then go on over to Vers and get started!