Skip to content

Set up Hermes with Vornik

Hermes Agent can use Vornik as a broker: when a request needs your mail, calendar or accounts, Hermes runs a workflow you chose on Vornik and gets back a short, schema-checked answer. Hermes never holds the credential. Vornik can also be Hermes's long-term memory.

This page covers the usual layout: Vornik and Hermes on one machine, each under its own OS user. It also works with Hermes on another machine (see the end of this page).

If you are Hermes, or another assistant, reading this

The steps run as vornik below need the operator's admin key and the operator's paired phone. Do not run them yourself. Give the operator the commands for their terminal, and wait for them to tell you the setup is done. Only the plugin install in step 4 runs as the Hermes user. Never ask for the admin key, never put it in your own environment or files, and never mint a key for yourself. A key you mint is a key you chose the limits of.

Two setups

Setup What Hermes can do Who decides what it can reach
Broker (the default) Run the workflows you allowed, within a budget, and read their answers You, once, when you grant its key
Admin (opt-in) Build its own projects, workflows and connections in its own namespace You, on your phone, for each change

Start with the broker. It gives Hermes the least: a fixed list of workflows, a spending cap, and answers whose shape you approved. Use the admin setup only when you want Hermes to build automations itself; it is described in Let your assistant set up Vornik.

Who runs what

In this guide vornik is the OS user Vornik runs as, and hermes is the OS user Hermes runs as. Use your own names.

Step Run as Why
Pair your phone, create projects, grant keys vornik (the operator) Needs the admin key and the daemon's config tree
Write Hermes's .env the operator, writing into hermes's home Hermes reads its tokens from there
Install and enable the plugin, check status hermes The plugin lives in Hermes's home

Hermes's user runs no vornikctl for the broker setup, and never needs the admin key. The operator writes Hermes's .env, but as the hermes user, so the file belongs to Hermes.

Broker setup

1. Two projects: the broker and the memory

The broker key and the memory key live in two different projects. A broker project (broker: true) refuses memory and skills on every key, so nothing Hermes delegates can be recalled later as raw text. Hermes's memory goes in an ordinary project whose key cannot delegate.

As vornik, scaffold the broker project into the daemon's config tree (by default ~/.config/vornik/configs; check vornikctl config show if you changed it). The broker-mail template reads mail and never writes:

vornikctl init project broker-mail --template broker-mail \
    --config-dir ~/.config/vornik/configs

It writes projects/broker-mail.yaml: broker: true, the daemon's google-workspace server narrowed to gmail_search, gmail_get and time_getCurrentDate and declared read-only, and mail-digest as its workflow. The full example, with the optional write path, is configs/examples/broker-mail.yaml in the Vornik source.

It narrows a google-workspace MCP server that must already be configured at the daemon level with your mail account; see Connect your tools (MCP). mail-digest and broker-swarm ship with Vornik (make install-config-assets installs them). To let Hermes also draft replies that you approve before they are sent, see Proposed writes.

Scaffold the memory project rather than writing it by hand:

vornikctl init project hermes-memory --config-dir ~/.config/vornik/configs \
    --display-name "Hermes memory"

Load both, and check that the daemon accepted them:

vornikctl config reload
vornikctl config reload-status
vornikctl project list            # expect broker-mail and hermes-memory

2. Two keys

Still as vornik:

# delegation only, to the workflows you name, within a budget
vornikctl companion grant -p broker-mail --client hermes \
    --workflows mail-digest --budget-usd 5
# memory only: this key can never delegate
vornikctl companion grant -p hermes-memory --client hermes \
    --memory-all --no-delegate

Each prints its secret once, as the .env line Hermes needs: VORNIK_BROKER_TOKEN=... for the broker key, VORNIK_MEMORY_TOKEN=... for the memory key, each with a VORNIK_URL=... line. Grant nothing else to a Hermes key:

  • no --skill-all or other skill flags: the knowledge-skill store is for coding assistants;
  • no companion-* workflows: those are developer workflows (reviews, ingest) for the coding-assistant companion, not for Hermes;
  • no memory flags on the broker key: grant refuses them on a broker project, and that refusal is the design.

The generic recipe in Companion plugin → Setting it up is for Claude Code and Codex; do not adapt it for Hermes.

3. Hand the keys to Hermes

Hermes loads $HERMES_HOME/.env (by default ~/.hermes/.env) into its environment every time it starts, including as a service (read in Hermes v2026.9.24, 0.21.5; if your Hermes is a different version and hermes vornik status shows the tokens unset, check its own docs on .env). Put the URL and both keys there, not in an export in some shell: a gateway started by systemd, or after a reboot, never sees a shell's exports.

From the operator's terminal, open the file in an editor as hermes, so the secrets go into neither Hermes's conversation nor your shell history:

sudo -u hermes -H sh -c 'umask 077; mkdir -p ~/.hermes; touch ~/.hermes/.env; chmod 600 ~/.hermes/.env; exec vi ~/.hermes/.env'

(sudo drops your EDITOR; put another editor in place of vi if you prefer.)

and paste the lines the two grant commands printed (one VORNIK_URL line is enough):

VORNIK_URL=http://localhost:8080
VORNIK_BROKER_TOKEN=<the broker-mail secret>
VORNIK_MEMORY_TOKEN=<the hermes-memory secret>

If Hermes runs with HERMES_HOME set to another directory (a service often does), edit .env there instead. Each Hermes profile has its own .env, and a gateway that serves several profiles gives each one only its own: put the lines in the .env of every profile that should reach Vornik (hermes -p <profile> config set VORNIK_URL … writes one line there). The plugin (0.21.5 and later) reads them through Hermes, never from the process environment.

http://localhost:8080 is right when both users are on the same machine and Vornik listens on its default port. Plain http is only acceptable on loopback; for any other host use https.

4. Install the plugin

As hermes:

hermes plugins install vornik-companion
hermes plugins enable vornik-companion
hermes config set memory.provider vornik-companion   # Vornik as long-term memory
hermes vornik status        # URL, which tokens are set, the daemon's capabilities
hermes memory status        # expect "installed" and "available"

For an existing installation, update the plugin separately after upgrading the daemon, then restart Hermes or its gateway so the process reloads its tools:

hermes plugins update vornik-companion

Restart Hermes (or its gateway) so it reads the new .env. Then ask it to list what it can run: it should name mail-digest and nothing else. To hand over a file from a completed task, Hermes also needs the plugin's vornik_list_artifacts and vornik_read_artifact tools; those appear only when the daemon advertises companion-artifact-read and the broker key is valid. To look into a task that seems stuck or failed, the plugin (0.21.0 or later) has vornik_task_logs and vornik_task_explain; they show step progress and closed error classes only, never the task's own text. From 0.21.1 they appear only when the daemon advertises companion-progress, so an older daemon does not offer calls it cannot answer.

Admin setup (opt-in)

Read Let your assistant set up Vornik first; it explains what an administering assistant can and cannot do. With Hermes on its own OS user, two things differ from that page.

Hermes's user needs its own vornikctl. Connect writes the path of the vornikctl it runs into Hermes's config, and Hermes runs that path every time it starts (the MCP bridge) and for every approval it sends to your phone. A vornikctl inside vornik's home is usually not executable by hermes, and the entry then fails at every start. Install a copy where hermes can run it and where it stays put, then always run that copy:

sudo install -m 0755 "$(command -v vornikctl)" /usr/local/bin/vornikctl

When you upgrade Vornik, replace the file at the same path; the recorded path then stays valid. Install a real file there, not a symlink: connect records the file --vornikctl /usr/local/bin/vornikctl (below) resolves to, and refuses a path the user it runs as cannot execute, instead of writing an entry that fails at every start.

Connect needs the admin key once, from your terminal. The sign-in from vornikctl auth login lives in vornik's home, so hermes's vornikctl is not signed in. Give the key to that one command only, typed by you, so it is in neither a command line nor a shell history, and not in anything Hermes can read:

read -rs K                                  # paste the admin key
# printf is a shell builtin: the key is in no command line, environment
# or history. The dry run reaches Vornik too, so it reads the key as well.
printf '%s\n' "$K" | sudo -u hermes -H /usr/local/bin/vornikctl agent connect hermes \
    --vornikctl /usr/local/bin/vornikctl --api-key-stdin --dry-run
printf '%s\n' "$K" | sudo -u hermes -H /usr/local/bin/vornikctl agent connect hermes \
    --vornikctl /usr/local/bin/vornikctl --api-key-stdin
unset K

--api-key-stdin refuses a terminal: a key typed there would be shown.

Do not run hermes vornik connect with the admin key in Hermes's own environment: it passes its environment to vornikctl, and that environment is Hermes's. Connect stores the assistant's own key in ~hermes/.config/vornik/agents/hermes.key, readable by hermes only; the admin key is not stored anywhere.

Hermes on another machine

The broker setup is the same, with two changes: VORNIK_URL is Vornik's https:// address (a tunnel or a reverse proxy with a certificate), and you carry the two secrets to the Hermes machine yourself: sign in there as the Hermes user and write .env with the same umask 077 and mode 600. For the admin setup, follow Vornik on another machine.

When it does not work

What you see Why Fix
hermes vornik status says a token is not set It was exported in a shell, not written to .env, or Hermes was not restarted Step 3, then restart Hermes
Hermes says it has no Vornik tools The daemon is older than the broker (no companion-broker capability), or Hermes hides plugin tools behind tool_search Check hermes vornik status; for small local models, hermes config set tools.tool_search.enabled off
Hermes cannot list or read completed-run files Its installed plugin may predate artifact tools, the daemon may lack companion-artifact-read, or the workflow may not approve those filenames Run hermes plugins update vornik-companion and restart Hermes; check hermes vornik status; ensure the workflow's approved broker.egress.artifacts names the files
vornikctl companion grant refuses --memory-all Memory on a broker project is refused by design Grant memory on the separate memory project
vornikctl companion grant says unauthorized It ran without the admin key, for example as hermes Run it as vornik, signed in
Admin setup: the Vornik MCP entry fails at every Hermes start The vornikctl path connect recorded is not executable by hermes (connect now refuses such a path) Install vornikctl in /usr/local/bin and connect again with --vornikctl /usr/local/bin/vornikctl (or hermes vornik connect --vornikctl /usr/local/bin/vornikctl)
Admin setup: connect says it cannot reach Vornik, or is unauthorized hermes's vornikctl has no admin key, or a different URL Pass the key as shown above; add --url if Vornik is not on localhost:8080
A memory note is refused Vornik refuses a note shorter than three words and ten characters ("Dr Novak"); the plugin tells Hermes nothing was stored Write the fact as a full sentence with its context ("My dentist is Dr Novak.")

More on the plugin itself, including what it does on your machine and how forgetting works, is on its catalog page in the Hermes plugin catalog and in the Companion plugin page.