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 | 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:
- Use
psy_binaryif configured. - Else use
psyif it is onPATH. - Else use
npx -y psy-core@0.5.1 psy ingest. - 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_pathprivate and mode0600. psy verify --allshould be part of any incident review involving memory changes.- Use
allow_anonymous: trueonly 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c71c7979703361acd1a341281e6c41fceb7349d064be3c622a1d29a517441e66
|
|
| MD5 |
25bbc08e65f961bfad3756fa34e19979
|
|
| BLAKE2b-256 |
b86bb9fefbed4c58c17f32fe628c59575cbf03eddaa43f306f2f998fc19556fa
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
psy_core_hermes-0.1.4.tar.gz -
Subject digest:
c71c7979703361acd1a341281e6c41fceb7349d064be3c622a1d29a517441e66 - Sigstore transparency entry: 1438444890
- Sigstore integration time:
-
Permalink:
jethros-projects/psy-core@4a0bb4340088f9ae27bddf92f1e5d2256da446e1 -
Branch / Tag:
refs/tags/psy-core-hermes-v0.1.4 - Owner: https://github.com/jethros-projects
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@4a0bb4340088f9ae27bddf92f1e5d2256da446e1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file psy_core_hermes-0.1.4-py3-none-any.whl.
File metadata
- Download URL: psy_core_hermes-0.1.4-py3-none-any.whl
- Upload date:
- Size: 42.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3412a6f83e3bbd69758c4a54128b2a3864ad901fb846f37af445b5bf29c881c5
|
|
| MD5 |
626528d1d52552accce318977497571f
|
|
| BLAKE2b-256 |
49cc813208446cb87ba3e8dae0de43900df94fe6d516bdc98eeb1b3f02a1acf6
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
psy_core_hermes-0.1.4-py3-none-any.whl -
Subject digest:
3412a6f83e3bbd69758c4a54128b2a3864ad901fb846f37af445b5bf29c881c5 - Sigstore transparency entry: 1438444971
- Sigstore integration time:
-
Permalink:
jethros-projects/psy-core@4a0bb4340088f9ae27bddf92f1e5d2256da446e1 -
Branch / Tag:
refs/tags/psy-core-hermes-v0.1.4 - Owner: https://github.com/jethros-projects
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@4a0bb4340088f9ae27bddf92f1e5d2256da446e1 -
Trigger Event:
push
-
Statement type: