Security
What lnk-hermes installs and runs, beyond what Link's sandbox
guarantees every harness (Link's Agents
Security
page).
Installing it
What the adapter runs to install Hermes, and what checks it.
Its installer, pinned
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.
A git checkout
It installs that release with --commit, a git checkout, so the
commit's hash is the code's.
In the home and the sandbox
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.
Its own Python and Node
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
They come from its uv.lock, pinned by hash, unless that install fails
and it resolves them afresh.
Packages on first use
Hermes installs some packages on first use: its Anthropic SDK and each connection'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.
Its updates
A new Hermes release comes with a release of this adapter, never fetched on its own, since the adapter pins its commit.
Running it
What it may do while it runs, and where its secrets are.
It asks for any program
--command '*', granted only once you allow it: it runs the Python it
installed in its home, which it can write, so no list of programs would
hold it.
Its local API
Hermes's local API, on 127.0.0.1, takes Link's key for each start, which only Link's bridge holds. It holds no connection's token: Link's bridge carries them.
Its keys and addresses
Keys go in ~/.hermes/.env in its home (600), never on a command line.
The model's address goes there too (LNK_HERMES_MODEL_URL, which holds
its proxy's secret for a model on this machine), named in its config by
variable (${LNK_HERMES_MODEL_URL}, which Hermes reads), and its tools'
addresses into config.yaml itself (600): none on the command line of
hermes config set.
Its API's key in lnk secret list
lnk secret list lists its API's key, the one Link hands it at each
start, in each agent's home.
Not listed: Hermes's own logins
~/.hermes/auth.json, which hermes login writes when you run it in
the agent's home yourself. Link never runs it nor relies on it: Link
hands Hermes its model's key, or a placeholder for its proxy, in
.env. One you made stays in the home, and moves with the agent
(lnk agent move).
Its terminal's home
Its terminal's tools get a home of their own (terminal.home_mode profile) rather than reaching for your ~/.ssh and ~/.gitconfig.
Its state at a switch
lnk agent use asks Hermes's hub for its state over ASP: its sessions,
files, skills and memory, read and written by its own SessionDB and
files in its home. What comes in is data, never instructions, and
confers no Link authority.
Its ports
Its endpoint, 8642 for main (another agent's is in its own block):
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).
Finding and removing them
lnk agent harness show --harness hermes looks for these; lnk agent harness delete --harness hermes deletes them with its home. Its own service
would run outside the sandbox, so lnk agent start stops it and moves
it aside.
What it leaves
The Python it installs through uv (~/.local/share/uv) is shared with
other programs, so Link leaves it.
Portable session archive
.hermes/link-imports.json holds exact imported ACP updates and their native
projection, mode 600. A native continuation exports the original updates
plus later work. Divergent history preserves both branches. Historical tool
calls become records without effects; thinking and unsupported metadata
remain archival and are named as omissions from live context.