Skip to main content

Tamper-evident memory audit log for Hermes Agent. Hash-chained, HMAC-sealed. Plain plugin observer that forwards every memory mutation to the psy-core audit chain.

Project description

psy-core-hermes

Audit receipts for Hermes Agent memory and skills. Keep the learning loop alive, but make every durable write inspectable.

PyPI PyPI Downloads Python License

PyPI | psy-core | Hermes example | Hermes Agent | Issues

psy-core-hermes is the Hermes Agent adapter for psy-core. Hermes is built to learn: it saves memories, updates user profiles, creates skills, and patches those skills as it gets better at recurring work. psy-core-hermes records those durable changes into a tamper-evident audit chain.

It does not replace Hermes memory. It does not become your MemoryProvider. It is a plugin observer that listens at the tool boundary, watches the file-backed memory directory, and streams canonical audit envelopes into psy ingest.

The result is simple: Hermes keeps improving, and you get a verifiable trail of what changed.

Quick Install

pip install psy-core-hermes
psy-core-hermes trust-layer --actor-id you@example.com

That command configures the plugin, installs the local Hermes skill psy-core-trust-layer, runs doctor, and runs psy verify --all.

Then restart Hermes:

hermes

Inside Hermes, ask:

Use the psy-core trust layer skill to verify my setup.

Use psy-core as the trust layer for Hermes's self-improvement loop. Hermes's magic is that it learns. psy-core's value is making that learning accountable.

In another terminal:

psy tail

When Hermes writes MEMORY.md, USER.md, or a skill file, you should see paired intent and result rows. Verify the chain at any time:

psy verify --all

The smaller psy-core-hermes init --actor-id you@example.com command is still available when you only want idempotent config insertion.

Why This Exists

Hermes memory is valuable because it persists. That persistence is also why it deserves an audit trail.

Use psy-core-hermes when you want to answer questions like:

  • What did Hermes just remember about this user?
  • Which session created or edited this skill?
  • Did a memory write fail, or did Hermes never attempt it?
  • Did a skill churn through several rapid patches after creation?
  • Has the audit log been edited, reordered, or truncated since it was written?

The adapter gives operators receipts without forcing Hermes into a new memory backend.

How It Works

Hermes Agent process                        psy-core audit process
--------------------                        ----------------------
pre_tool_call hook
  memory / skill intent  ----------------->  psy ingest writes intent row

Hermes executes the tool
  MEMORY.md / USER.md changes
  SKILL.md or skill file changes

filesystem watcher / post_tool_call ------>  psy ingest writes result row

                                             SQLite row is canonicalized
                                             row hash chains to previous row
                                             HMAC sealed head is advanced

The Python plugin owns observation. The Node psy CLI owns the canonical audit chain. That split keeps one verifier for every psy adapter, whether events originate from TypeScript, Python, or another language.

What Gets Captured

Hermes action psy operation Result confirmation
memory add to MEMORY.md or USER.md create Filesystem watcher
memory replace in MEMORY.md or USER.md str_replace Filesystem watcher
memory remove from MEMORY.md or USER.md delete Filesystem watcher
skill_manage create skill or file create post_tool_call
skill_manage edit or patch skill/file str_replace post_tool_call
skill_manage delete skill/file delete post_tool_call

Hermes handles the memory tool inside its agent loop, so there is no normal post-tool hook for memory writes. psy-core-hermes records the pre-tool intent and lets watchdog confirm the resulting file change.

What Stays Out of Scope

Surface Captured? Why
MEMORY.md and USER.md writes through the built-in memory tool Yes Core file-backed Hermes memory
Skills written through skill_manage Yes Durable procedural memory
External MemoryProvider tools such as Honcho, Mem0, Hindsight, RetainDB, Supermemory, and Byterover No Separate provider-specific memory surfaces
MemoryProvider lifecycle hooks No Becoming a provider would block users from running their chosen provider
session_search No Read-only lookup
todo No Task state, not memory
SessionDB summaries, trajectory JSONL, flush_memories() writes No No stable upstream hook today
Gateway transport events No Separate adapter surface

This boundary is intentional. psy-core-hermes should be the audit witness for Hermes's native durable memory paths, not a competing memory system.

If your app also calls Mem0, Letta, LangChain, or LangGraph directly, use the dedicated adapters in the root psy-core README.

Operator Quick Reference

Goal Command
Configure plugin, install skill, run doctor, and verify psy-core-hermes trust-layer --actor-id you@example.com
Install or refresh only the Hermes operating skill psy-core-hermes install-skill
Enable only the plugin in ~/.hermes/config.yaml psy-core-hermes init --actor-id you@example.com
Allow anonymous local testing psy-core-hermes init --allow-anonymous
Diagnose config, paths, Node, npx, and subprocess handshake psy-core-hermes doctor
Print a compact current status psy-core-hermes status
Inspect JSONL envelopes without spawning psy ingest psy-core-hermes dry-run < envelopes.jsonl
See live audit rows psy tail
Query by actor psy query --actor you@example.com
Verify chain integrity psy verify --all
Rank unstable skills by churn psy-core-hermes skill-stats

Install Details

psy-core-hermes is a Python package with a Hermes plugin entry point:

[project.entry-points."hermes_agent.plugins"]
psy = "psy_core.hermes.register"

After psy-core-hermes trust-layer --actor-id you@example.com, your Hermes config contains the plugin block plus explicit trust-layer paths:

plugins:
  enabled:
    - psy

  psy:
    enabled: true
    actor_id: you@example.com
    allow_anonymous: false
    db_path: ~/.hermes/psy/audit.db
    seal_key_path: ~/.hermes/psy/seal-key
    memories_dir: ~/.hermes/memories
    psy_core_version: 0.5.1

The command also writes:

~/.hermes/skills/devops/psy-core-trust-layer/SKILL.md

Useful bootstrap flags:

psy-core-hermes trust-layer --actor-id alice@example.com --no-verify
psy-core-hermes trust-layer --actor-id alice@example.com --psy-binary /usr/local/bin/psy
psy-core-hermes trust-layer --actor-id alice@example.com --no-payload-capture
psy-core-hermes trust-layer --allow-anonymous   # local experiments only

At runtime, the plugin starts the audit writer using this order:

  1. Use psy_binary if configured.
  2. Else use psy if it is on PATH.
  3. Else use npx -y psy-core@0.5.1 psy ingest.
  4. Else fail with an install diagnostic.

Most users only need pip install psy-core-hermes. Installing psy-core globally avoids the npx fallback:

npm i -g psy-core

Configuration

Full plugins.psy reference:

plugins:
  enabled:
    - psy

  psy:
    enabled: true

    # Identity
    actor_id: alice@acme.com          # required unless allow_anonymous: true
    tenant_id: acme                   # optional
    purpose: production-debug         # optional
    allow_anonymous: false

    # Storage; defaults shown for HERMES_HOME unset.
    db_path: ~/.hermes/psy/audit.db
    seal_key_path: ~/.hermes/psy/seal-key
    memories_dir: ~/.hermes/memories

    # Ingest subprocess
    psy_core_version: 0.5.1
    psy_binary: null
    schema_version_pin: "1.0.0"

    # Payload handling
    payload_capture: true
    redactor: default                 # default | none | "<dotted_path>"

    # Debugging
    dry_run: false
    log_level: info

HERMES_HOME changes the default base directory. Without it, paths resolve under ~/.hermes.

Identity Model

actor_id is required by default. This is deliberate: an audit log without a principal is only half a receipt.

If actor_id is missing, Hermes starts without the plugin hooks and prints:

psy-core-hermes: actor_id is required.
  Why:    audit events must attribute the session to a principal.
  Where:  ~/.hermes/config.yaml -> plugins.psy.actor_id
  Example:
    plugins:
      psy:
        actor_id: alice@acme.com
  Bypass: set allow_anonymous: true (not recommended in production).
  Docs:   https://github.com/jethros-projects/psy-core/blob/main/python/psy-core-hermes/README.md#identity-model

For local experiments, use:

psy-core-hermes init --allow-anonymous

For shared machines, hosted agents, or any real user data, set actor_id.

Skill Churn Reports

Hermes skills are procedural memory. A skill that is created once and reused may be healthy; a skill that is patched five times in an hour may be unstable. The audit chain can measure that because every skill write has a timestamp and an immutable order.

psy-core-hermes skill-stats

Example:

SKILL                            CREATE  PATCH  DEL  CHURN  RAPID  STATUS
deploy-runbook                        1      7    0   7.00      5  unstable
flaky-test-recovery                   1      4    0   4.00      4  unstable
release-checklist                     1      0    0   0.00      0  ok

legend: unstable = churn>=2.0 or 3+ rapid patches | short-lived = create+delete within 1 day

Useful views:

psy-core-hermes skill-stats --since 7d
psy-core-hermes skill-stats --actor alice@acme.com
psy-core-hermes skill-stats --top 10
psy-core-hermes skill-stats --skill-md-only
psy-core-hermes skill-stats --json

Library usage:

from datetime import timedelta
from pathlib import Path
from psy_core.hermes.skill_stats import compute_skill_stats

metrics = compute_skill_stats(
    Path.home() / ".hermes" / "psy" / "audit.db",
    actor_id="alice@acme.com",
    since=timedelta(days=7),
)

for skill in metrics:
    if skill.status == "unstable":
        print(skill.skill, skill.churn_ratio)

The stats path opens SQLite read-only.

Docs by Goal

Goal Where to go
Try the adapter quickly ../../examples/hermes-agent
Understand the core audit chain Root psy-core README
See generated Hermes config ../../examples/hermes-agent/hermes-config.yaml
Debug install issues psy-core-hermes doctor
Verify audit integrity psy verify --all
Report suspicious skill churn psy-core-hermes skill-stats

Versioning and Compatibility

This package version: psy-core-hermes 0.1.4

Pinned Node audit engine: psy-core 0.5.1

Audit schema: 1.0.0

Verified Hermes Agent contracts:

Contract Behavior
Plugin entry point group hermes_agent.plugins
Entry point value Module path psy_core.hermes.register
Hook signature Keyword-only tool_name, args, task_id, session_id, tool_call_id, and extras
Memory post-hook behavior Built-in memory bypasses post_tool_call; watcher confirms results
Memory args {action, target, content, old_text}
Skill args {action, name, content, old_string, new_string, file_path, file_content, ...}

Source verification covers Hermes Agent v0.11.0 (v2026.4.23) and v0.12.0 (v2026.4.30). The cross-language workflow also loads the plugin into a real Hermes PluginManager.

Security Notes

  • The adapter records durable memory writes; it does not approve or deny Hermes tool calls.
  • Payload capture is enabled by default for the Hermes adapter so memory content previews are useful. Built-in redaction catches common secret patterns, but it is not a DLP system.
  • The seal key protects tail verification. Keep seal_key_path private and mode 0600.
  • psy verify --all should be part of any incident review involving memory changes.
  • Use allow_anonymous: true only for local experiments.

Development

cd python/psy-core-hermes
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest
ruff check .
mypy src

Root audit-engine checks:

cd ../..
npm test
npm run typecheck
npm run build

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

psy_core_hermes-0.1.4.tar.gz (62.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

psy_core_hermes-0.1.4-py3-none-any.whl (42.5 kB view details)

Uploaded Python 3

File details

Details for the file psy_core_hermes-0.1.4.tar.gz.

File metadata

  • Download URL: psy_core_hermes-0.1.4.tar.gz
  • Upload date:
  • Size: 62.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for psy_core_hermes-0.1.4.tar.gz
Algorithm Hash digest
SHA256 c71c7979703361acd1a341281e6c41fceb7349d064be3c622a1d29a517441e66
MD5 25bbc08e65f961bfad3756fa34e19979
BLAKE2b-256 b86bb9fefbed4c58c17f32fe628c59575cbf03eddaa43f306f2f998fc19556fa

See more details on using hashes here.

Provenance

The following attestation bundles were made for psy_core_hermes-0.1.4.tar.gz:

Publisher: publish-pypi.yml on jethros-projects/psy-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file psy_core_hermes-0.1.4-py3-none-any.whl.

File metadata

File hashes

Hashes for psy_core_hermes-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 3412a6f83e3bbd69758c4a54128b2a3864ad901fb846f37af445b5bf29c881c5
MD5 626528d1d52552accce318977497571f
BLAKE2b-256 49cc813208446cb87ba3e8dae0de43900df94fe6d516bdc98eeb1b3f02a1acf6

See more details on using hashes here.

Provenance

The following attestation bundles were made for psy_core_hermes-0.1.4-py3-none-any.whl:

Publisher: publish-pypi.yml on jethros-projects/psy-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page