Skip to main content

hermes-pubky

Run a Hermes agent whose saved state lives on your own Pubky homeserver. The laptop becomes a working copy, but the agent belongs to you.

Why

Hermes keeps everything it knows in one directory on one machine: SOUL.md, your memories, its learned skills, your conversations. New laptop, fresh container, throwaway VM, and the agent starts from nothing. The usual alternative is a memory SaaS, which makes your agent portable by moving it into someone else's account.

This is a third option. The homeserver holds the authoritative copy of the agent, a local Hermes reconstructs a working copy, runs it, and saves changes back. What travels:

  • instructions (SOUL.md), user and agent memories
  • learned skills and their assets
  • allowlisted settings
  • the conversation database, including tool calls, compaction and rewind history
  • a designated workspace: notes, references, outputs

What stays on the machine: API keys, OAuth sessions, the Pubky grant itself, and anything else machine-specific.

Install

uv pip install hermes-pubky==0.2.0 "hermes-agent==0.19.0"
hermes-pubky agent init default
hermes-pubky run default

Needs Python 3.11–3.13, Hermes 0.19.0 exactly, and a Pubky homeserver on v0.11 or later. agent init asks Pubky Ring to authorize one scoped capability, then publishes the agent's first checkpoint.

On a second computer:

uv pip install hermes-pubky==0.2.0 "hermes-agent==0.19.0"
hermes-pubky agent attach pubky://<owner>/priv/hermes.pubky.app/v2/agents/default/head.json
hermes-pubky run default

Nothing is copied between machines. attach downloads the instructions, memories, skills, settings and conversation database; workspace documents are fetched when the agent asks for them. Every run saves a checkpoint when it ends, and the next run on any machine starts from the newest one.

Commands

hermes-pubky run <id> [--resume SESSION] [--offline] [--query TEXT]

hermes-pubky agent init <id> [--from-hermes-home PATH] [--workspace PATH]
hermes-pubky agent attach <pubky-uri>
hermes-pubky agent list
hermes-pubky agent status <id> [--json] [--offline]
hermes-pubky agent login <id>
hermes-pubky agent logout <id>
hermes-pubky agent sync <id> [--prefer local|remote]
hermes-pubky agent files <id> list|fetch|import|remove
hermes-pubky agent history <id>
hermes-pubky agent restore <id> <snapshot-id>

hermes-pubky template init|inspect|publish <directory>
hermes-pubky template adopt <agent-id> <pubky-uri>
hermes-pubky template update <agent-id>

agent sync seals whatever changed locally, including files added by hand or with agent files import, then publishes everything pending. agent logout revokes the grant at the homeserver and says so only when that succeeded.

Exit codes: 0 done, 1 usage, 2 saved locally but not yet on the homeserver, 3 conflict, 4 authorization needed, 5 quota, 6 integrity or unsupported runtime.

What it can reach

agent init requests one capability:

/priv/hermes.pubky.app/v2/agents/<id>/:rw

Read and write inside that agent's own directory. No root capability, no access to your other apps. The launcher also refuses paths outside that directory locally, before a request leaves the process, and keeps the grant out of the Hermes child's environment entirely.

Publishing a template needs its own separate capability under /pub/. An agent's grant can never publish.

A grant holds one session at a time. Authorize each computer with its own agent login rather than copying a grant between machines, or each will keep signing the other out.

Read this before you store anything

Your homeserver operator can read your agent. /priv is access-controlled, not encrypted. If you self-host, that operator is you, otherwise assume whoever runs your homeserver can read your instructions, memories and conversations. Credentials are never uploaded, but a conversation can contain anything you or a tool put in it.

One writer at a time. Read from as many machines as you like, but stop and sync on one before writing from another. If the homeserver's checkpoint moved while this machine has unsaved work, run stops before starting the agent, installs nothing over your work, and asks you to choose with agent sync --prefer local|remote; whichever side you drop is preserved under recovery/ first.

Offline works. Startup seals anything a previous run left unsaved, then refreshes from the homeserver with a five-second budget. Offline runs chain their checkpoints, survive restarts, and publish in order at the next sync, retrying with backoff capped at 60 seconds. A run that could not reach the homeserver exits 2 and says saved locally; not yet saved to homeserver. A run whose conversation database cannot be captured exits 6 and does not claim anything was saved.

A cold attach downloads the conversation database in full. It is streamed and reassembled on disk, never held in memory, but a large history takes time. Workspace documents stay remote until requested.

History is kept. Older checkpoints remain recoverable and count against your homeserver quota. Removing a file drops it from the current inventory, not from history; this is not secure erasure.

Not in 0.2: multi-device merge, client-side encryption, portable credentials, semantic retrieval, Windows wheels, and harnesses other than Hermes 0.19.0.

How it fits together

hermes-pubky run <id>
  -> read and verify the remote checkpoint
  -> materialize a dedicated HERMES_HOME and workspace
  -> start Hermes as a child, with HERMES_HOME set before it imports
       -> the in-process plugin reports changes and serves two workspace tools
  -> the supervisor owns the lock, the journal and every network call
  -> final capture and sync after the child exits

Storage is content-addressed. A checkpoint is an immutable snapshot document naming immutable objects; only head.json is mutable, and it moves last, after every object it names has been verified as recorded. The homeserver offers no conditional write, so this is ordering, not a lock: concurrent writers remain unsupported and are detected rather than merged.

Locally, the journal tracks one base: the checkpoint the working copy corresponds to. Sealing a checkpoint advances it, installing one advances it, publishing never does. That is what lets a second run continue the first and offline runs form a chain.

/priv/hermes.pubky.app/v2/agents/<id>/{head,snapshots/*,objects/*}.json
/pub/hermes.pubky.app/v2/templates/<id>/{head,snapshots/*,objects/*}.json

Markdown is stored as Markdown and JSON as JSON, so what is on your homeserver is readable there. Files over 1 MiB, and the database always, are split into 1 MiB chunks.

Development

uv venv --python 3.11 .venv
uv pip install --python .venv/bin/python maturin pytest "hermes-agent==0.19.0"
PYO3_PYTHON="$PWD/.venv/bin/python" .venv/bin/maturin develop

.venv/bin/pytest        # Python tests; the Hermes ones skip if it is absent
cargo test --lib        # Rust unit tests

tests/test_supervisor.py runs the whole launcher against a fake homeserver and a stand-in child: two runs in a row, an attach on a second machine, offline chains, a moved head over local edits, a corrupt database, a failed restore. Those are the scenarios that matter; the rest of the suite guards the wire format and the policy boundaries.

The end-to-end and acceptance suites need PostgreSQL for the homeserver and the well-known testnet ports free:

docker run -d --name hermes-pubky-pg \
  -e POSTGRES_USER=test_user -e POSTGRES_PASSWORD=test_pass -e POSTGRES_DB=postgres \
  -p 5432:5432 postgres:18-alpine

export TEST_PUBKY_CONNECTION_STRING="postgres://test_user:test_pass@localhost:5432/postgres?pubky-test=true"
cargo test --test v2 -- --ignored --test-threads=1

A real managed Hermes turn, against a local fake model so no credentials are needed:

python scripts/check_managed_hermes_integration.py

The full recovery scenario through the shipped command line, one agent across two machines, ending with the grant revoked (so each run needs a fresh fixture):

cargo run --example testnet_fixture > /tmp/fixture.json &
HERMES_PUBKY_TESTNET=1 python scripts/check_managed_handoff.py --fixture /tmp/fixture.json

Pinned upstream versions, changed only as a deliberate compatibility decision with tests to match:

Hermes hermes-agent==0.19.0, conversation schema 22
Pubky SDK v0.11.0 commit 6a14bdb8fa2e30ef4e4b241fcdd3992c453d2378

Cargo.lock is committed. tests/test_hermes_contract.py holds the upstream contract as executable tests and fails if the installed package drifts from it.

License

MIT

Metadata

Release files for hermes-pubky 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hermes-pubky 0.2.0
File Size Uploaded
hermes_pubky-0.2.0.tar.gz 188.9 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for hermes-pubky 0.2.0
File Interpreter ABI Platform
hermes_pubky-0.2.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 abi3 Linux glibc 2.17+ x86-64 Details
hermes_pubky-0.2.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.11 abi3 Linux glibc 2.17+ ARM64 Details
hermes_pubky-0.2.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl CPython 3.11 abi3 macOS 11.0+ ARM64, macOS 10.12+ universal2 (ARM64, x86-64), macOS 10.12+ x86-64 Details

Total release size: 17.5 MB

Release files / hermes_pubky-0.2.0.tar.gz

Download URL hermes_pubky-0.2.0.tar.gz
Size 188.9 kB
Tags Source
SHA-256 checksum
How to use checksums
902a60c0618ebc4bb8df369e45803b023e1e1a96356e536b3e0c0b116a09c1b8
BLAKE2b-256 checksum
How to use checksums
ffcedaf42d224599adcdd61ba47e97f7d8b8c31209f220f04cf62ac41392fd8e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / hermes_pubky-0.2.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL hermes_pubky-0.2.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 4.6 MB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
7ac8581893066c051e49a30bbb745c72e902dd6555bf386c5a22d71ace302479
BLAKE2b-256 checksum
How to use checksums
a68398ba5f4ec6976344afe5fe5c952c23121f06609aba483e4399deb69cca71
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / hermes_pubky-0.2.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL hermes_pubky-0.2.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 4.3 MB
Tags CPython 3.11 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
86846f2a32a42d557eb745ed12a64a090833685636601cfa1bfda53ef2708c6b
BLAKE2b-256 checksum
How to use checksums
492e7247c18da4c3ccb74677485f07b56d35f2f9da8fda6719a2b9173867586c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / hermes_pubky-0.2.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl

Download URL hermes_pubky-0.2.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Size 8.4 MB
Tags CPython 3.11 abi3 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
0ba0a34840b05ec0e7a46d6fc3f664e2c8e831c5d9867264a9601dd53a699d31
BLAKE2b-256 checksum
How to use checksums
820761c37157e454243a6b26ad797188670cdc0d2069c12f9656af07b428565f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.3

4 release files

0.2.2

4 release files

0.2.1

4 release files

This release

0.2.0 This release

4 release files

0.1.0

4 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page