aiGalen Guan

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