v2.25.0 · MIT · zero dependencies

Agent memory that keeps a
corrected fact corrected.

The self-correcting memory layer for AI agents — zero dependencies, with an MCP server. Value-ranked recall, consolidation, and a first-class correction and erasure channel — measured, not assumed.

Quickstart — running in a minute

01 — correction

Corrections retire the old fact. They don't erase history.

When db::region changes from us-east to eu-west, the stale block dims and slides to a retired side-rail — still auditable, no longer asserted. Recall returns the current value; the chain remembers that it ever changed.

02 — the attack

“actually, go back to what we had.”

A revert is an authority action, not a sentence an attacker can type. An unsigned content-path request to resurrect a retired value shatters against authorization_required. This is the whole thesis: the value channel cannot mint a reversion.

03 — erasure

Deletion collapses a block into a signed tombstone.

A forget_subject seals the block into a cryptographic ghost. Then the ErasureAuditor sweeps the surrounding vector-cloud, checking whether the erased content is still reconstructible from what's left. Erasure you can actually verify.

the correction channel

Store a fact. Correct it. It stays corrected.

inspeximus — correction that sticks

        

new in 2.5.0

Is this memory still true — and may it still act?

Two questions most memory layers cannot answer at all. A stored fact can be perfectly recorded and quietly wrong, because the thing it describes has changed since.

check_sources()

Re-reads each record’s origin and compares a fingerprint stamped at write time: FRESH, DRIFTED, ORPHANED, UNCHECKABLE. When nothing is checkable it reports ok = false and says it verified nothing — a clean report over an empty scope is the failure it exists to prevent.

Four coverage numbers, kept apart

Can the evidence point back to an origin? Can that origin be re-read? Can deletions be detected? Is the record bound to a context? We measured our own store at 98.3% populated and 0.01% re-fetchable — one collapsed number would have called that fully covered.

Current-state applicability

Historical truth is not current authority. evaluate_applicability() asks whether evidence may drive an action here, now — the branch moved, the policy changed, the tenant differs, the window expired — and returns REVALIDATE instead of letting stale evidence acquire present authority.

Implements a vendor-neutral contract with a second, independent implementation: both agree on every case of its frozen fixture, including the reasons. Absence of historical context is not permission to assume continuity.

measured, not assumed

Cross-system correction integrity

Does a correction stick after the value is contested? One open, adversarial cut — revert success over 20 trials, with 95% Wilson intervals.

Every store is read through one shared judge, gpt-4o-mini at temperature 0.0, so the comparison is symmetric. The judge is part of the instrument, and it is not deterministic. Re-measured 2026-08-22: the store returns byte-identical contexts every time, while the judge scored those same contexts 0.75 in 26 of 30 runs, 0.70 twice and 0.80 twice, mean 0.7500, a ±0.05 band. Read the bar as that mode, not as a point. Among newer judges that hold the same temperature the figure moves to 0.80, inside that band, while two that refuse it score as high as 1.00 on a different instrument. No judge on any model ever answered that the superseded value was current, so the band is the model declining to commit on an ambiguous context, not disagreement about the revert. Judge-sensitivity probe.

inspeximus
0.75
mem0
0.20
Graphiti
0.00

Honest scope: this is a narrow adversarial cut, not a general memory-quality score. A separate run on each vendor’s own native configuration (n=30) measures the neighbouring question — does a corrected fact come back? inspeximus 0%, Graphiti 13.3%, mem0 46.7%; with our guard disabled we resurrect 100% of the time, which is how you can tell the number is the mechanism and not the benchmark being kind to us. mem0 measured at 2.0.11 (2026-07) and not re-run since. Run it yourself — the harness is open.

the surface

A memory layer with a correction spine

Clean, value-ranked recall

Retrieval ordered by earned value, not just recency or cosine. A write-admission gate (admit) rejects junk and near-duplicates before they bloat the store, and why_recalled shows exactly why a memory surfaced.

Correction, erasure & time-travel

A first-class channel: revert, retract_lineage, echo_guard, forget_subject. And a read-path review trigger — observe() reopens a settled fact on a corroborated contradiction, recall marks it under_review so the agent can hedge, and a steward resolves it. Bitemporal as_of reconstructs what the agent believed at any moment.

Tamper-evident receipts

Every write is hash-chained. verify_writes and anchor catch a history rewrite by a key-holder.

Poison-resistant influence

Corroboration-gated influence with recall(influence_only=True) so one laundered write can't dominate the answer. credit_requires_warrant closes the self-graded loop (a memory can't vouch for itself), and grounds can be Ed25519-signed so forged corroboration counts zero.

Cross-store erasure audit

DeletionManifest plus ErasureAuditor: an adversarial check that erased content isn't reconstructible across the fan-out — including the soft-delete residue a 200 OK leaves in Qdrant, pgvector, and S3.

Adapters & multi-tenancy

Adapters for OpenAI Agents, AutoGen, LangGraph, LangChain, LlamaIndex, CrewAI, Haystack, Google ADK, and Pydantic AI — 13 of 13 verified against current upstream, 0 recorded broken, counts published in docs/integration_conformance.json rather than implied. Fail-closed tenant isolation with a PII floor scopes every cross-record operation.

model context protocol

73 tools any MCP host can call

Point Claude, Cursor, or any MCP agent at inspeximus and it gets a real memory with a correction channel — no glue code.

Claude Code — one command
claude mcp add inspeximus -e INSPEXIMUS_PATH=~/.inspeximus_memory.json -- uvx --from "inspeximus[mcp]" inspeximus-mcp
claude_desktop_config.json
{
  "mcpServers": {
    "inspeximus": {
      "command": "uvx",
      "args": ["--from", "inspeximus[mcp]", "inspeximus-mcp"]
    }
  }
}

langgraph

A checkpointer and a store, drop-in

Listed in LangChain’s own integrations tables. InspeximusStore implements BaseStore and InspeximusSaver implements the checkpointer interface, so an existing graph swaps one line and keeps its corrections.

Install

Two packages, either alone:

pip
pip install langgraph-checkpoint-inspeximus langgraph-store-inspeximus

Store

Hand it to a graph anywhere a BaseStore goes. Keyed supersession means a corrected value replaces the old one instead of ranking beside it.

python
from inspeximus.integrations.langgraph import InspeximusStore

store = InspeximusStore(path="memory.json")
graph = builder.compile(store=store)

Checkpointer

The same store backs graph state, so a thread’s history and its long-term memory share one file and one erasure path.

python
from inspeximus.integrations.langgraph import InspeximusSaver

graph = builder.compile(checkpointer=InspeximusSaver(path="state.json"))

Parity is measured, not claimed

store_audit.py runs the same operation scripts against LangGraph’s own InMemoryStore and against InspeximusStore and requires identical observable results, operation by operation. It has a falsification mode that swallows the writes, and CI fails if that mode comes back green — an audit that cannot fail is a demo.

governance

Deletion you can actually verify

CT-style anchor

An RFC 6962 signed tree head over the write log. anchor() plus verify_consistency() catches a key-holder who rewrites history.

Authenticated erasure + proof

forget_subject is bound to an Ed25519 principal with a decision basis, and compliance_receipt() emits a signed, verifiable proof-of-erasure — the artifact a DPO hands a regulator under GDPR Art. 17.

Reconstruction audit

The ErasureAuditor asks the adversarial question: after deletion, is the content still reconstructible? It catches the soft-delete residue a 200 OK leaves behind — Qdrant points under the optimizer threshold, pgvector dead tuples, an S3 delete-marker over a live version.

Did the bytes actually go?

inspeximus residue --root ./deployment --value alice@example.com answers for your stack, and for stores we did not write — a vector database, a sqlite history, a JSONL trace. It separates a retained row from an unreclaimed page (a storage property, not a vendor defect) from a plain file nothing will ever reclaim. Exits non-zero, so it drops into a CI job or a DSAR runbook as a gate. It never prints the value you asked it to hunt.

Crypto-shred erasure

Store encrypted at rest with opt-in AES-256-GCM (standard crypto, key never persisted), so shred() destroys the key and makes the store — and every backup of it — provably unrecoverable. NIST SP 800-88 cryptographic-erase, beside the tombstone and reconstruction proofs.

Honest scope: inspeximus has no RCE or ReDoS surface (JSON-only, no pickle/eval/subprocess) and uses constant-time HMAC, with two documented residuals in SECURITY.md.