psy-core: Tamper-Evident Audit Trails for AI Agent Memory
AI agents that remember things across sessions are more useful. They pick up your preferences, notice patterns in what you ask for, and get smarter over time. They also get harder to debug. When your agent starts calling you "bud" in every reply, you have no idea which interaction taught it that. When a skill silently regresses, you can't easily find the patch that broke it.
psy-core is a TypeScript library that sits between your agent and its memory system, recording a cryptographically verifiable trail of every write operation. It does not replace your memory provider. It wraps it.
At 8 GitHub stars and published April 2026, psy-core is a young project. But it solves a problem most agent builders are only starting to recognize: agents that self-improve across sessions are also agents that self-corrupt. Without receipts, good luck figuring out when.
What It Captures
psy-core records paired events for every memory write. Before the call, it writes an intent row — what the agent is about to do. After the call, it writes a result row — what actually happened. Each row feeds into a local SQLite hash chain sealed by HMAC.
The adapters cover seven surfaces:
| Adapter | What It Wraps |
|---|---|
| Anthropic Memory | @anthropic-ai/sdk memory tool |
| Letta | @letta-ai/letta-client blocks |
| Mastra | @mastra/core memory class |
| Mem0 | mem0ai SDK calls |
| LangChain | Chat message history |
| LangGraph | Checkpointers |
| Hermes Agent | memory and skill_manage tools |
The Hermes adapter (psy-core-hermes, Python package on PyPI) is the one that matters most for our setup. It watches ~/.hermes/memories/ and ~/.hermes/skills/, streaming canonical JSONL envelopes into the same psy ingest pipe that the Node adapters use. All events land in the same chain. All chains verify with the same CLI.
How the Chain Works
The hash chain is simple by design. Each row contains a canonical JSON payload plus a reference to the hash of the previous row. Once written, any edit, deletion, or reordering changes the hash and breaks the chain. A separate sealed head pointer — signed by HMAC with a local key — records the latest tail coordinate.
Running psy verify --all checks three things: the active database, any rotated archive files, and the sealed head. If they agree, the log has not been tampered with.
An orphan row is a meaningful signal. If the agent writes an intent but dies before recording the result, verification surfaces it. You can see what the agent tried and failed to do. A silent failure becomes a visible one.
What Stays Out
psy-core is not a universal observability layer. It captures the durable memory paths: MEMORY.md writes, USER.md updates, skill_manage calls. It does not capture session_search (read-only), todo (task state), session summaries, or gateway transport events. External MemoryProvider tools — Honcho, RetainDB, whatever else — are out of scope.
This boundary is intentional. psy-core-hermes wants to be the audit witness for Hermes's native learning loop. If your app also calls Mem0 or Letta directly from TypeScript, use the dedicated Node adapters in the root psy-core package instead.
Installation for Hermes Agent
Three commands:
pip install psy-core-hermes
psy-core-hermes trust-layer --actor-id you@example.com
hermes
The trust-layer command writes the plugin config into ~/.hermes/config.yaml, installs a local Hermes skill at ~/.hermes/skills/devops/psy-core-trust-layer/SKILL.md, runs a diagnostic check, and verifies the audit chain. After that, restart Hermes and you are auditing.
Watch live events in another terminal:
psy tail
Query by actor:
psy query --actor you@example.com
Rank skills by churn to find what keeps getting patched:
psy-core-hermes skill-stats
The Competitive Landscape
This is a narrow niche. Searching for "agent memory audit tamper-evident" across GitHub returns exactly one project — psy-core. There are adjacent ideas: on-chain context anchoring (z1labs/mcp-contextstore-contract, 5 stars), deterministic oversight kernels. None wrap the same seven memory surfaces with the same verification model.
The closest thing to a competitor is the built-in session search that Hermes already provides. But session search shows you what the agent said. psy-core shows you what the agent wrote to durable state. The two are complementary.
What to Watch For
psy-core needs Node.js. The psy CLI is a Node binary published to npm. If you are in a Python-only environment, the Hermes adapter falls back to npx -y psy-core@latest psy ingest, which works but adds startup latency.
The project is eight days old (initial commit: April 27, 2026). The code is clean — strict TypeScript, 22 test files with vitest, cross-language E2E CI — but there has been exactly zero time for real-world stress testing. Expect edge cases around rapid skill edits and filesystem watcher race conditions.
Payload capture is off by default. You will not see the full content of every memory write in the audit log unless you enable it. This is a reasonable privacy default, but it means psy tail without payload capture shows timestamps and operation types, not what changed.
Verdict
For agents that persist state and self-modify — which is Hermes's entire value proposition — an audit trail is not a nice-to-have. It is table stakes for debugging at scale. psy-core is the only tool in this category that ships a native Hermes adapter. The code is solid. The design is honest about what it does and does not cover.
Two things would make it better: a Python-native audit store so the Node dependency goes away, and payload-by-default with configurable redaction. Until then, it works. I installed it.
Sources: psy-core GitHub, psy-core-hermes PyPI, psy-core npm