A temporal knowledge-graph long-term memory for Hermes Agent, packaged as a signed
AXP v0.3 extension
(mintbot.ai/graph-memory).
Graph Memory remembers more than isolated sentences. It extracts entities such as people, projects, decisions, topics, and artifacts; stores the relationships between them; tracks when facts become valid or are superseded; and recalls relevant subgraphs by meaning rather than exact wording.
Hermes turn / explicit memory write
│
▼
user's active Hermes model
(proxy, Codex, Claude, BYOK, ...)
entity + relationship extraction
│
▼
Graphiti temporal graph
┌──────┴──────┐
▼ ▼
embedded Ladybug local FastEmbed
graph store semantic vectors
- Extraction follows the model/provider currently selected in Hermes. The
extension creates a tool-free nested agent with
skip_memory=True, avoiding recursion and avoiding a second credential configuration. - Embeddings and reranking run locally with
BAAI/bge-small-en-v1.5through FastEmbed/ONNX. There is no embeddings API cost or data egress. - LadybugDB, the actively maintained continuation of Kuzu, runs in-process and
stores one profile-scoped database at
$HERMES_HOME/graph-memory/graph.lbug. An existinggraph.kuzustore is migrated automatically through KuzuEXPORT DATABASE→ LadybugIMPORT DATABASE; the legacy store is retained as a backup. The archived Kuzu wheel is not a runtime dependency; if it is unavailable during migration, the helper fetcheskuzu==0.11.3into an ephemeraluvenvironment used only for the export process. There is no Docker container, port, database daemon, or password to operate. Ladybug's FTS extension is downloaded once fromextension.ladybugdb.comand loaded locally on each startup.
- Automatic extraction after each primary conversation turn (configurable).
- Automatic relevant-memory injection before model calls.
memory_query: explicit semantic/relationship/history search.memory_write: confirmed durable graph write.- Mirroring of Hermes built-in memory add/replace/remove operations with temporal supersession/removal events.
- Pre-compression and delegation-result ingestion.
- Clean shutdown that serializes and drains pending writes.
Graph Memory is a signed AXP v0.3
package with the extension id mintbot.ai/graph-memory. Point your host at
the manifest (agent-extension.json — served from the publisher's site or
attached to every GitHub release) and it will show the consent card, verify the
artifact digest and the ed25519 signature, run the Hermes lifecycle hooks in
its sandbox, and keep the extension updated from GitHub releases.
Automated hooks support first installs, inactive-provider replacement, and active upgrades through Hermes' public plugin installer. Activation is verified, not inferred from exit status. Failed activation attempts retain recovery snapshots and restore the prior plugin/selection where feasible; this is not an atomic runtime rollback.
What the consent card shows, and why:
| declared | why |
|---|---|
network_egress PyPI, Hugging Face, extension.ladybugdb.com |
Hermes PM stages the pinned dependencies before publishing an active replacement; the FastEmbed model and the LadybugDB extension are fetched on first use |
filesystem config:rw, hermes:plugins:rw, cache:rw |
the Hermes home (config.yaml, the venv, the graph database under HERMES_HOME/graph-memory), the provider package, the pip cache |
root: false |
not needed — the install prefix comes from the host (AXP_PREFIX) |
signed by mintbot.ai-graph-memory-2026 |
ed25519:m5vaq2/BLL372gVnVljTkdS+TeYjkpyduQ7/zk/gHbk= — pinned on first install; later releases must be signed by this key or a properly announced rotation |
Entity extraction calls whatever model Hermes already has selected, through Hermes itself: the extension holds no credentials and no API key of its own.
Run ./install.sh or ./upgrade.sh from the verified artifact. The hook stages
those exact bytes as a pinned local Git source and snapshots the previous plugin,
config, memory provider, and disabled-plugin list before calling native
hermes plugins install file://... --ref <sha> --force --yes-deps. It adds
--enable for first/inactive installs and --no-enable for active upgrades.
Do not run the hook with sudo to change profiles.
The hook checks installed source bytes, reads back memory.provider and
plugins.disabled, and runs hermes memory status through its health hook.
Exit zero alone is not success. On failure it attempts to reinstall the old
plugin through the same native installer and restore selection with
hermes config set, then reads back the result. Recovery files remain in the
printed cache directory, including the prior config for manual inspection.
A failed first activation can leave an installed, unselected tree; no old tree
exists to restore. Interrupted commands require inspecting the retained files.
Hermes owns dependency preparation and publication. The hook never runs pip,
patches Hermes, or restores code by copying it over a changed runtime. Native
recovery can fail; neither dependency-runtime identity, graph data, nor changes
to already-running sessions can be rolled back atomically. New sessions use the
selected provider. Git and a Hermes CLI exposing --yes-deps are required.
The local source is ephemeral and the recorded commit is pinned: use AXP hooks
for later upgrades, not hermes plugins update on that source. Lifecycle scripts
are copied to the prefix only after verification; a filesystem failure then
retains recovery inputs but does not undo native publication. Serialize lifecycle
operations and configuration changes for a profile.
See lifecycle safety for the reviewed upstream
contract, test boundaries, and release-qualification requirements.
A non-root install also works; lifecycle scripts are stored under
$HERMES_HOME/extensions/graph-memory instead of /opt/graph-memory. The
scripts honour the AXP host contract (AXP_PREFIX, AXP_CACHE_DIR,
AXP_PURGE, AXP_FROM_VERSION) and fall back to these defaults when the
variables are absent.
To remove: uninstall.sh (keeps the graph database; AXP_PURGE=1 uninstall.sh
deletes it too). Uninstall reads hermes config get memory.provider --json on
Hermes' runtime and verifies a native config set before deleting an active
provider. System Python needs only its standard JSON module, not PyYAML. Missing
Hermes, malformed responses, read failures, or stderr warnings (including
last-known-good fallbacks) stop removal, even with purge. An unrelated provider
is not changed.
Run:
hermes memory setup graph-memoryThe defaults are:
memory:
provider: graph-memory
graph-memory:
embedding_model: BAAI/bge-small-en-v1.5
ingest_turns: all # or explicit-only
recall_limit: 8No second LLM key is requested. Extraction resolves the active Hermes runtime on every call, so a later model/provider switch is picked up automatically.
./healthcheck.sh # provider installed + active + deps import
./upgrade.sh # idempotent reinstall; sees AXP_FROM_VERSION
./uninstall.sh # keeps the graph database
AXP_PURGE=1 ./uninstall.sh # also deletes long-term memoryhermes backup already includes the graph because it lives under HERMES_HOME.
LadybugDB is the active continuation of the archived Kuzu project. The
extension pins the tested pair graphiti-core==0.29.3 and ladybug==0.18.3.
Local embeddings use fastembed>=0.9.0,<0.10, qualified with Hermes' Python
3.14 runtime and Pillow 12.3.0 (required by browser-harness).
An isolated compatibility adapter binds Graphiti's Kuzu-named operation layer
to Ladybug's maintained Python API; the archived kuzu wheel is not installed.
The adapter boundary can be replaced by a future native Graphiti Ladybug driver
without changing the Hermes provider contract or on-disk graph.
Ladybug also allows one process to own a database at a time. Do not run a CLI and gateway concurrently against the same Hermes profile while this provider is active. Different Hermes profiles have separate databases and are isolated.
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements-dev.txt
pytest -qThe integration test exercises the real Ladybug/FastEmbed stack. A live extraction
test additionally uses whichever Hermes model/provider is currently selected.
tests/test_axp_manifest.py validates the manifest against the AXP schema and
reference implementation from a sibling ../agent-extension checkout (or
$AXP_SPEC_DIR).
Releases are cut with the axp CLI from the
agent-extension repo
(pip install -e ../agent-extension). The publisher key never enters this
repository; it lives on the release machine only.
AXP_SIGNING_KEY=/path/to/mintbot.ai-graph-memory.key scripts/release.sh 0.2.0First add a ## v<version> heading and release notes to CHANGELOG.md.
The script validates that heading, stamps plugin.yaml and the manifest's
changelog URL before building the deterministic artifact (which includes
CHANGELOG.md), then lets axp release write the version, digests, dates and
signature and verifies it. A failed release may leave local stamped metadata;
review/revert it before retrying. No release is published automatically. Then:
git commit -am "release v0.2.0" && git tag v0.2.0 && git push --tags
gh release create v0.2.0 dist/graph-memory-0.2.0.tar.gz agent-extension.json --notes-file CHANGELOG.mdBoth assets matter: hosts on the github update source read the signed
agent-extension.json release asset, and the tarball must be byte-identical to
the digest inside it (the build is deterministic, so a rebuild from the tag
reproduces it). Key rotation follows AXP section 8.3: publish one release with
signing.next_key, then one dual-signed release under the new key.
agent-extension-keys.json is the AXP section 8.5 key directory for
mintbot.ai: the public keys the publisher currently signs with, one entry per
key, optionally restricted to named extensions. It is served at
https://mintbot.ai/.well-known/agent-extension-keys.json, so hosts can tell a
legitimate rotation (the new key is listed) from a compromised manifest (it is
not), and release.sh refuses to cut a release whose signing key is missing
from it. Re-deploy the file whenever a key is added, rotated or revoked
("revoked": true keeps a retired key listed so hosts can tell "replaced"
from "never ours").
MIT — see LICENSE.