How do you connect a remote Hermes (on a different VM) to Paperclip's hermes_local adapter?
NickyDigital · 2026-05-24
Hi all — looking for guidance from anyone who has set up Hermes-as-Paperclip-employee with Hermes running on a separate machine from the Paperclip server.
Setup
\- Paperclip server: Docker (docker-server-1), running on VPS A. Node-based, server runs as node user inside the container.
\- Hermes: Running on a separate always-on VPS (VPS B). Configured with Manifest routing for LLM calls (same Manifest instance Paperclip uses).
\- Goal: Hire 2 Paperclip agents (Content + Support roles) as adaptertype=hermeslocal so they get the full Hermes toolset (30+ tools, FTS5 memory, 80+ skills, MCP, etc.) rather than the native opencodelocal runner.
What works
\- hermes-paperclip-adapter@0.2.0 is installed in /app/server/nodemodules/ on the Paperclip VPS.
\- hermeslocal is registered in server/src/adapters/registry.ts (confirmed via grep).
\- Creating an agent via the UI ("Add a new agent" → "Invite an external agent") works. The agent gets a joinrequest, my remote Hermes claims it, and work flows.
Where I’m stuck
Answers
Aron Prins · 2026-05-25
Nick — short answer up front, then the why, then the path I'd take for your 7-company shape.
1. No, there is no remote-Hermes mode for hermeslocal. The adapter is a local-process spawner — it forks your hermes CLI binary on the same host as the Paperclip server. The only "remote" knob is paperclipApiUrl, and that's for Hermes to call back to Paperclip, not for Paperclip to reach out to a remote Hermes. The Configuration Reference in the [adapter README](https://github.com/NousResearch/hermes-paperclip-adapter) is complete on this — there's no undocumented HTTP transport.
2. Yes, the intended pattern is co-located. hermeslocal is now an external adapter (feat/externalize-hermes-adapter in core's AGENTS.md), installed via the Adapter Plugin manager. The model is: install hermes-agent (pip install hermes-agent) on the Paperclip host, then load the adapter package via Board → Adapter Manager. Same-VPS, possibly same docker-compose, is exactly the shape the adapter is built for.
3. The race you're seeing is a side effect of the invite-an-external-agent flow. That flow creates a row whose adaptertype defaults to Paperclip's external/push shape — which on your build seems to land as opencodelocal. From there, Paperclip's heartbeat scheduler dutifully tries to run the local OpenCode runner on it, while your remote Hermes is simultaneously polling joinrequest → claim → work. Two runners, one slot. Flipping the row to hermeslocal won't fix it because, per (1), that adapter also tries to spawn a local binary — which you don't have inside the container. So both ends of the toggle are wrong for your topology.
What I'd recommend for a 7-company production install:
Co-locate Hermes on the Paperclip VPS. Bake pip install hermes-agent and the Python 3.10+ runtime into your Paperclip Dockerfile, install @henkey/hermes-paperclip-adapter (or the NousResearch/hermes-paperclip-adapter upstream) via the Adapter Plugin manager, and let hermeslocal drive Hermes as a child process per agent. This is the supported path and the one that gets you the full Hermes toolset (30+ tools, FTS5 memory, 80+ skills, MCP) under Paperclip orchestration without the runner race. If you really must keep Hermes on VPS B, do not try to make hermeslocal work remotely. Use the HTTP adapter ([docs/adapters/http.md](https://github.com/paperclipai/paperclip/blob/master/docs/adapters/http.md)) on the Paperclip side — Paperclip POSTs each run to your remote Hermes, your VPS-B wrapper invokes Hermes locally there, then calls back to PAPERCLIPAPIURL to report results. You lose the deep hermeslocal UI integration (structured transcript parsing, skills sync, model auto-detect from ~/.hermes/config.yaml), but you eliminate the race because Paperclip never tries to spawn anything locally for an http-adapter agent. The scripts/smoke/openclaw-gateway-e2e.sh flow in the repo is the closest worked example — walking it end-to-end will give you the exact request/response sequence to mirror on VPS B. There's no heartbeat.enabled=false per-agent flag that would safely silence Paperclip's runner while leaving the slot claimable. Pause works, but it stops everything including external claims, so it's not what you want either.
Given you're already comfortable modifying the Dockerfile, the co-located route is the recommended path. It's the supported one, gets you all the hermeslocal features, and the 7-company multiplexing is a single-host concern Paperclip handles natively (one agent per company, each with its own cwd).
Two follow-up details that'd help nail this down on your specific build: which Paperclip version are you on (paperclip --version), and is the opencodelocal default on the invite flow happening through the UI invite flow or through a direct POST /api/companies/.../join-requests/... call? The default landing as opencodelocal instead of "no adapter / wait for claim to declare" smells like either a fork-level patch or an older invite-flow behavior worth pinning down on your side before you commit to the Dockerfile change.
NickyDigital · 2026-05-25
@aronprins — Aron — thanks again for the steer on co-location. Wanted to close the loop publicly in case anyone else hits the same path. Quick post-mortem below.
A. What we did
Followed your Approach A from the original thread: baked Hermes into the Paperclip Docker image, registered hermeslocal via the bundled adapter, migrated 2 Pictor specialists to it (Content & SEO + Support & KB), and kept the other 5 agents on opencodelocal.
Concrete steps:
Backups — full pgdump, Dockerfile snapshot, git tag, container image commit
docker system prune -af + dropped a redundant backup image — ran out of disk twice during build, needed \~6-8 GB free for the final layer extract
Dockerfile changes (2 stanzas):
Added python3-pip python3-venv python3-full to the base apt-get install line
Added RUN python3 -m venv /opt/hermes-venv && /opt/hermes-venv/bin/pip install --no-cache-dir hermes-agent && ln -s /opt/hermes-venv/bin/hermes /usr/local/bin/hermes in the production stage
docker compose --env-file .env build server + up -d
David · 2026-05-28
@NickyDigital I cannot begin to tell you how wonderful your postmortem is and THANK YOU for the time you took to do it.
NickyDigital · 2026-05-28
Glad to hear it was helpful!
NickyDigital · 2026-05-25
Thanks @aronprins — this is exactly the clarity I needed. Two answers for you, then a question back.
1\. Paperclip version: 0.3.1 (both @paperclipai/server and @paperclipai/ui).
2\. Invite flow: UI flow ("Invite an external agent" → generate one-time onboarding prompt →
external agent claims its API key). DB-side this lands as a sequence of:
invite.created (actor: founder user)
join.requested (actor: invite-anon)
join.approved (actor: founder user)
new agents row created with adaptertype='opencodelocal'
No fork-level patches on my end — vanilla 0.3.1. So the UI invite default landing as
opencodelocal looks like upstream behavior on this version.