A Hermes agent plugin written in Python that gives the agent the ability to run JavaScript files through a controlled Node.js process interface — plus the original web-UI plugin toolchain (scaffold / validate / build / test / pack) and the sandboxed host loader those artifacts run under.
Three deliverables in one repository:
- Native Hermes plugin (
plugin.yaml+hermes_js_plugin_builder/): seven tools registered via the officialregister(ctx)entry point —run_javascript,js_runtime_info,create_plugin,validate_plugin,build_plugin,test_plugin,pack_plugin. - Web-UI plugin spec (
docs/PLUGIN_SPEC.md+src/spec/): manifest format,activate/deactivatelifecycle,ctxhost API, RPC wire shapes. - Sandboxed host loader (
src/host/):PluginHostruns each web-UI plugin in aniframe sandbox="allow-scripts"(Worker fallback) with a permission-gatedpostMessageRPC bridge.
┌─────────────────────────────┐ ┌────────────────────────────────┐
│ Hermes agent (Python) │ │ Web UI (browser) │
│ │ │ │
│ plugin.yaml + register(ctx)│ │ PluginHost │
│ ├─ run_javascript ───────┼──node──┼─► executes .js/.mjs/.cjs file │
│ ├─ js_runtime_info │ │ │
│ ├─ create_plugin │ │ ├─ iframe sandbox │
│ ├─ validate_plugin │ │ │ └─ guest bootstrap │
│ ├─ build_plugin ──esbuild┼────────┼──►│ └─ plugin bundle │
│ ├─ test_plugin │ │ ▲ │
│ └─ pack_plugin ──► .hpkg │ │ └─ postMessage RPC bridge ───┘
└─────────────────────────────┘ └────────────────────────────────┘
The agent can execute arbitrary JavaScript files via run_javascript
(subprocess, never a shell) and produce web-UI plugin packages
(plugin.json + src/ + tests → bundled dist/ → .hpkg). A web UI embeds
PluginHost and loads the bundle — plugin code only ever runs inside the
sandbox and reaches host capabilities through declared permissions.
- Python ≥ 3.10 (the plugin itself; zero runtime dependencies)
- Node.js ≥ 20 on
PATH— required forrun_javascript,build_plugin,test_plugin, andjs_runtime_info. Override the binary with thenode_binaryplugin setting.
As a directory plugin:
git clone https://github.com/CommunityPokeOrg/hermes-js-plugin-builder \
~/.hermes/plugins/hermes-js-plugin-builder
hermes plugins enable hermes-js-plugin-builderOr as a pip package (registers the hermes_agent.plugins entry point):
pip install git+https://github.com/CommunityPokeOrg/hermes-js-plugin-builder
hermes plugins enable hermes-js-plugin-builderSee docs/HERMES_INTEGRATION.md for the full
loading contract, settings, and references to the official Hermes plugin
documentation.
| Tool | Input | Result |
|---|---|---|
run_javascript |
file (required .js/.mjs/.cjs), args?[], cwd?, timeout? (s, ≤600, default 30), env?{}, allow_outside_workdir? |
Exit code, stdout/stderr (64 KB caps), timeout/truncation flags, duration. |
js_runtime_info |
— | Node.js path + version; ok:false if Node is missing. |
create_plugin |
name, id?, template (basic|panel), outputDir?, description?, permissions?, force? |
Scaffolded web-UI plugin dir; refuses non-empty dirs without force. |
validate_plugin |
dir? |
Manifest schema check, entry existence, known permissions, forbidden-globals scan (eval, new Function → errors; document.write → warning). |
build_plugin |
dir?, outDir?, minify? |
esbuild ESM bundle dist/<id>.js + resolved dist/plugin.json (copies verbatim when the entry has no relative imports). |
test_plugin |
dir?, runner? (auto|vitest|node) |
Runs the plugin's tests; structured exit code, counts, output tail. |
pack_plugin |
dir?, outDir? |
Deterministic <id>-<version>.hpkg ZIP (manifest + dist/); auto-builds if needed. |
Every tool returns a JSON string of { ok: boolean, summary: string, details: object } and never raises on user errors.
run_javascript executes files through subprocess with an argument vector
(shell=False), stdin closed, a new process group (start_new_session=True),
and SIGKILL on the whole group at timeout. Additional guards:
- The interpreter is never selected from tool input —
noderesolves fromPATHor the operator-controllednode_binaryplugin setting only. - The child environment is scrubbed to a minimal base (
PATH,HOME, temp dirs, locale) plus explicitenventries; secrets and ambient variables are not forwarded. - Paths are confined to the working directory unless the caller (the agent,
with user-facing approval) sets
allow_outside_workdir. - Output and execution time are bounded (64 KB per stream, ≤600 s).
This is contained execution, not a security sandbox: the JavaScript file runs with the privileges of the Hermes process. Do not run untrusted code without an external sandbox (container, VM, seccomp profile).
python -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'
pytest -q # Python tests (48)
npm ci # eslint for the JS library surface
npm run lint
npm test # node --test tests-js/ (38)docs/HERMES_INTEGRATION.md— native plugin loading contract, install paths, settings, official doc references.docs/PLUGIN_SPEC.md— web-UI plugin manifest, lifecycle,ctxAPI, RPC wire format.docs/HOST_API.md—PluginHostAPI and sandbox model.
MIT — CommunityPokeOrg contributors.