Security

What lnk-hermes installs and runs, beyond what Link's sandbox guarantees every harness (Link's Agents Security page).

Installing it

  • It runs Hermes's official installer, what hermes-agent.nousresearch.com/install.sh serves, pinned: the script comes from Hermes's repository at a release's commit, and runs only if its SHA-256 is the one in this adapter's source.
  • It installs that release with --commit, a git checkout, so the commit's hash is the code's.
  • It runs over HTTPS, in the home and the sandbox: it can download anything, but write only the home. Its code goes in its home (--dir) even for root, whom its installer would otherwise give /usr/local.
  • It brings its own Python, through uv, and Node, with no setup wizard and no service of its own. Its installer runs uv's installer from astral.sh unchecked.
  • Its Python packages come from its uv.lock, pinned by hash, unless that install fails and it resolves them afresh.
  • Hermes installs some packages on first use: its Anthropic SDK and each channel's library. This adapter installs those its settings need as it's configured, in the same sandbox as the install, so the running harness never needs a package registry for them. Hermes pins their versions, not their hashes.
  • A new Hermes release comes with a release of this adapter.

Running it

  • Link generates a key for Hermes's local API, on 127.0.0.1. Keys and channels' tokens go in ~/.hermes/.env in its home, never on a command line, each channel with your id or number as the only one allowed.
  • Its terminal's tools get a home of their own (terminal.home_mode profile) rather than reaching for your ~/.ssh and ~/.gitconfig.
  • Signal goes through a relay of this adapter's. Hermes speaks to signal-cli's HTTP daemon, which asks for no credential, so the daemon doesn't run: the relay answers Hermes on its port in the agent's block, only with the secret Link makes and keeps in Hermes's .env (SIGNAL_HTTP_URL, sent as Basic auth), compared in constant time. Behind it, signal-cli runs over its stdin and stdout, on no port. The relay takes its port before the gateway starts, and holds it until the gateway stops; if another program holds it, the agent doesn't start, so Hermes never talks to anything else there.
  • Known gap: on a Mac, anyone on the machine can reach the relay's port, on the loopback (on Linux behind its proxy it stays in the sandbox's own network). Without the secret they get nothing from it and send nothing through it: the relay reads a request's head, up to 64 KiB in 10 seconds, and answers 401 before reading any body, and it keeps at most 16 connections open that haven't shown the secret, closing the oldest when another comes. What they can still do is open connections faster than Hermes sends its head, and while they do, Hermes's connections to the relay can be closed too: the agent's Signal pauses until they stop. A body that comes with the secret is at most 64 MiB.
  • Its WhatsApp bridge asks for no credential, so where it's open you're asked first. Hermes starts it itself, on a port next to its API's, and reaches it over HTTP on the loopback with no way to send a secret or use a socket. Behind its proxy on Linux it stays in the sandbox's own network. On a Mac, and anywhere without its proxy (no sandbox, or lan), every user and program of the machine can reach it, and through it send as the agent's WhatsApp and read its messages; Hermes also takes whatever answers on that port for its bridge. Link tells lnk-hermes whether it runs behind its proxy, and where it doesn't, lnk-hermes needs names it, whatsapp-bridge, and Hermes with WhatsApp doesn't start until you allow it, in a terminal, with --yes, or with lnk agent hermes allow whatsapp-bridge. Taken back (deny whatsapp-bridge), it refuses to start, and says how to go on without WhatsApp.
  • Hermes ignores strangers rather than offering them a pairing.
  • With WhatsApp on your own number, it doesn't answer a mention in a group.

Its ports

Its API server, 8642 for main (another agent's is in its own block), its WhatsApp bridge (+1) and Signal's relay (+2): with a local model's, the only localhost ports the sandbox lets it connect to.

Outside its home

Unsandboxed, Hermes writes ~/.hermes, ~/.local/bin/hermes and its own service (the LaunchAgent ai.hermes.gateway, or the systemd unit hermes-gateway.service). lnk agent hermes show looks for these; lnk agent hermes remove removes them with its home. Its own service would run outside the sandbox, so lnk agent start stops it and moves it aside. The Python it installs through uv (~/.local/share/uv) is shared with other programs, so Link leaves it.