September 28, 2026

hermes-memory-pgvector 1.0: A Stable Memory Surface

hermes-memory-pgvector 1.0: A Stable Memory Surface

hermes-memory-pgvector 1.0.0 is out. It is the first release where we promise not to break the parts you script against. This post covers what the plugin is, what 1.0 guarantees, what the pre-release review turned up, and how to upgrade.

What it is

hermes-memory-pgvector is a Postgres + pgvector memory provider for hermes-agent. It is a shared memory layer for a fleet of cooperating agents, built on a Postgres instance and one embedding endpoint you probably already run.

The design rules have not changed since the first write-up:

  • Storage layer, not a memory model. Agents keep calling the built-in memory tool. The plugin mirrors those writes into Postgres and stores substantive chat turns for semantic search.
  • No LLM in the memory hot path. Embeddings are vector math. There is no deriver, no dialectic loop, no dream cycle.
  • Per-agent themes by default. Every row carries an agent_identity. Recall stays inside the current theme unless the agent asks for scope='all'.
  • Fail-soft. If the embed endpoint is down, writes degrade to text-only. If the writer queue is full, the write is dropped with a one-time warning. If the database is down, the plugin logs and skips. No exception reaches the agent loop.
  • Admin/runtime separation. DDL runs once as a superuser through hermes-pgvector migrate. The runtime role gets DML only.

What 1.0 means

From 1.0.0 the project follows semantic versioning on its public surface:

  • plugins.pgvector.* config keys
  • tool names and parameters (recall_memory, recall_conversation)
  • CLI commands, flags and exit codes
  • database table and column names
  • the pgvector provider name and the pip entry point

Within 1.x that surface may grow, but nothing on the list is renamed or removed, and no default changes behavior, without a 2.0. MemoryStore and the other Python classes and modules are internal and not covered. A released migration file is never edited in place; schema changes ship as a new numbered migration.

The support matrix is tested in CI on every push: Python 3.11, 3.12 and 3.13 against PostgreSQL 16, 17 and 18 with pgvector 0.5.0 or newer. An upstream hermes-agent conformance suite runs against a pinned ref, with a non-blocking weekly drift check against upstream main.

What the review found

1.0.0 is not a re-tag of the release candidate, which was never published to PyPI. Before release we ran a multi-pass, full-codebase review: several passes with parallel AI reviewer agents, where a finding needed a concrete reproduction or an independent check before anyone acted on it. 0.6.0 came out of an earlier 1.0-readiness review.

It found one High-severity bug, and it was a data-loss bug. hermes-pgvector remap --old X --new X --execute deleted every memory_entries row for theme X and exited 0. Each row conflicted with itself on the insert, then the delete removed the originals. remap now refuses blank or identical --old and --new with exit 1, including in dry-run.

The Medium and Low findings are worth a skim if you operate this in production:

  • identity_signature() read config frozen at startup, so edits to allowed_themes or identity_aliases did not reach cached gateway agents until a restart. It now re-reads config.yaml on change.
  • The on_session_end backstop could write multimodal user turns twice and could store large /skill scaffolding.
  • replace() with a blank old_text overwrote an arbitrary row.
  • The embed client accepted vectors containing NaN, Infinity or null. The database rejected them and the durable row was lost. They now degrade to a text-only row like any other embed failure.
  • backfill retried blank rows made of non-ASCII whitespace forever, and failed every row on SQL_ASCII databases.
  • An explicit --config that could not be read used to warn and silently fall back to the default DSN. It is now an error.
  • Telegram forum (topic) chats, LINE rooms and webhook sessions were not recognised as multi-party sessions, so their raw session keys, including a participant id, became themes of their own. They now land in the shared external-group bucket like other group traffic.

The test suite grew from 442 to more than 500 tests, including about 80 regression tests for these fixes. CI runs them against live Postgres 16, 17 and 18, and now fails on any skipped test, so a broken environment can no longer pass green.

Install and upgrade

pip install hermes-memory-pgvector
hermes-pgvector migrate --admin-dsn \
    "dbname=<your-memory-db> user=postgres host=/var/run/postgresql"
hermes config set memory.provider pgvector
hermes memory status

If you are coming from 0.6.0, there are no schema changes and no new migrations. Upgrade the package, restart, and read the 1.0.0 upgrade notes in the CHANGELOG. These change behavior:

  • remap refuses blank or identical --old/--new.
  • An explicit --config that cannot be read or parsed is now an error instead of a silent fallback to the default DSN.
  • Boolean config keys accept only 1/true/yes/on and 0/false/no/off. Blank or unrecognized values now mean the key's default.
  • prefetch_budget, prefetch_limit and min_similarity are clamped to their documented ranges.
  • New writes from Telegram forum, LINE room and webhook sessions go to the external-group theme; rows already written under their raw keys stay where they are.
  • Install backups now move to a hidden plugins/.pgvector.bak-<ts> directory. Remove any old visible pgvector.bak* directory so hermes-agent does not discover it as a second provider.

Coming from anything older than 0.6.0, read the 0.6.0 notes first, and follow the ordering rule there: upgrade the package on every host that writes to the database before you run migrate. docs/upgrading.md has the full procedure.

Links

The project is BSD-3-Clause, copyright Green Yoga Inc. Bug reports and focused PRs are welcome.