Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

MemoryProof

Prove what your AI forgot.

English · 简体中文

CI statusLive MemoryProof matrixLatest releaseApache-2.0 license

Rust stablePython 3.11 or newerLocal-first privacySHA-256 evidencev1.0.4

🧪 Try it in 60 seconds · 🔍 See the proof · 🧭 Open the live matrix

MemoryProof: a synthetic canary leaves an observable memory graph while a verification ring and evidence ledger record the boundary

MemoryProof is an open-source memory assurance toolkit for AI agents. It tests a question that a successful DELETE response cannot answer:

Can the information still be observed through any path the backend exposes?

It creates isolated synthetic canaries, runs deterministic before/after probes, checks raw and derived boundaries, and emits an offline evidence bundle that developers can review, verify, and run in CI.

Important

DELETE 200 OK is an API response. MemoryProof tests the stronger, observable claim: the canary is no longer retrievable through the configured boundary.

Why MemoryProof?

Agent memory is rarely one table. A single fact can be copied into a raw record, summary, embedding, graph node, cache, block, or working context. A delete endpoint may remove one representation while another still answers a search query.

MemoryProof makes that gap concrete with a controlled experiment:

🧾 What an API may report🕳️ What can remain🔬 What MemoryProof records
DELETE 200 OKA summary still contains the canaryDeterministic pre/post probes
Raw row is goneAn index, vector, or graph edge still recalls itDerived-artifact inspection
One block was detachedAnother Agent path can still leak the factOptional black-box Agent query
“Delete all” was acceptedAn unrelated control subject disappeared tooIsolation and scope assertions

The goal is not to assign a vendor a simplistic score. The goal is to make what was checked, what passed, and what cannot be observed explicit.

The proof in one screen

flowchart LR
A["Scenario + synthetic canaries"] --> B["Rust runner"]
B --> C["Versioned NDJSON adapter"]
C --> D["Mem0 · Letta · Zep"]
B --> E["Before probes"]
D --> F["Erase / isolate"]
F --> G["Settle + after probes"]
E --> H["Evidence bundle"]
G --> H
H --> I["HTML · JUnit · CI · Matrix"]
Loading
  1. Seed a canary that is unique, synthetic, and safe to send to a test namespace.
  2. Prove the precondition: the target canary is observable before deletion.
  3. Erase or isolate only resources owned by this run.
  4. Wait for asynchronous writes to settle; a timeout becomes UNKNOWN, not a false pass.
  5. Probe raw, derived, Agent, and control paths with deterministic rules.
  6. Seal the evidence with sorted SHA-256 checksums and a bundle hash.

The difference it makes

❌ “Trust the endpoint”✅ MemoryProof
EvidenceA green HTTP responseA portable bundle with events, results, report, JUnit, and hashes
CoverageThe object named in the delete callEvery observable boundary advertised by the adapter
SafetyA script may delete the wrong dataSynthetic canaries plus target/control isolation
Regression testingA one-off manual checkA locked scenario in local runs and pull requests
UncertaintyMissing APIs become “probably fine”UNKNOWN, SKIP, and OUT OF SCOPE stay visible

A failure is a useful result

The repository includes a deliberately leaky backend. It deletes the raw item but leaves a derived artifact. MemoryProof must fail at the derived boundary:

status: FAIL
profile: erasure.derived
probe: target-derived-after
reason: the unique canary is still observable in a derived artifact

This is the core experience: an ambiguous memory concern becomes a named, reproducible, reviewable regression.

Quickstart

Requirements: Rust stable and Python 3.11+.

Run from source

git clone https://github.com/Hughhhhcoder/MemoryProof.git
cd MemoryProof
cargo run -- adapters list
cargo run -- run examples/reference-clean.yml

The clean reference scenario exits 0 and writes a bundle under .memoryproof/runs/. Verify and open it offline:

cargo run -- verify .memoryproof/runs/<run-id>
open .memoryproof/runs/<run-id>/report.html # macOS# xdg-open .memoryproof/runs/<run-id>/report.html # Linux

Now run the intentionally leaky backend:

cargo run -- run examples/reference-leaky.yml

It exits 1: the raw item disappears, but a derived artifact remains observable. That failure is expected and demonstrates the check is working.

Use the released binary or container

Download a platform binary from Releases, or run the GHCR image. Each binary archive includes the dependency-free Python adapter modules; if you keep them in a different location, set MEMORYPROOF_ADAPTER_ROOT to that archive's python/ directory.

docker run --rm -v "$PWD":/workspace \
ghcr.io/hughhhhcoder/memoryproof:1 \
run /workspace/examples/reference-clean.yml \
--output /workspace/.memoryproof/runs

For compatibility with the original v0.1 project, the forgetproof binary name and forgetproof Python import path remain available during the migration window.

Suites and profiles

MemoryProof is an umbrella with two suites:

SuiteWhat it answersProfiles
🧹 ErasureDid an owned memory boundary stop exposing the target?erasure.object, erasure.scope, erasure.derived, erasure.agent
🧱 IsolationCan one subject be read without leaking another subject’s memory?isolation.read, isolation.search, isolation.agent

The human-facing legacy names FP-Object, FP-Scope, FP-Derived, and FP-Agent are accepted when loading v0.1 scenarios. New scenarios use the stable names above.

Every assertion is one of:

StatusMeaning
PASSThe required observable check passed.
FAILA probe found the target, a forbidden derivative, or a scope violation.
SKIPThe selected profile is not required or is intentionally not executed.
UNKNOWNThe adapter cannot expose enough information to make the claim.
ERRORThe scenario, protocol, precondition, or execution failed.

There is no aggregate score. A capability boundary should be readable, not averaged away.

What it can—and cannot—prove

✅ It can show🚫 It does not claim
A target was observable before erase.Provider logs were deleted.
A configured API no longer returns the target.Backups or physical storage were wiped.
A visible summary, graph, index, or Agent path still leaks it.A model’s weights were unlearned.
A control subject stayed intact—or was accidentally deleted.Anything outside the adapter’s observable boundary.
The evidence bundle was not modified after creation.The identity of the person who produced the bundle.

These boundaries are part of the product, not a footnote. Reports explicitly separate proved, not observed, and out of scope.

Supported adapters

AdapterModesCoverage in v1
reference-cleanlocalFull erasure and isolation reference behavior
reference-leakylocalDeliberate derived-artifact residue
reference-overdeletelocalDeliberate control-subject deletion
mem0OSS / platform / cloudObject, scope, search, optional raw/derived inspection; async settle
lettaself-hosted / cloudTemporary Agent, core block, archival passage, scope delete, optional query
zepself-hosted / cloudEpisode, temporary user/thread, user scope, search, graph inspection

Remote access is opt-in. Credentials are read from environment variables and are never written into scenarios or evidence:

MEM0_BASE_URL=https://... MEM0_API_KEY=... \
cargo run -- run examples/mem0.yml --allow-network

Adapters communicate with the Rust runner through the versioned memoryproof.adapter/v1 NDJSON protocol. Third-party adapters can implement the same contract without linking to the Rust binary.

Evidence you can review in a pull request

Each run emits an offline-readable package:

manifest.json format, run, adapter mode, protocol, and declared files
scenario.lock.json redacted, frozen scenario snapshot
scenario.lock.yml the same frozen snapshot in the requested YAML form
events.ndjson ordered method journal with safe request IDs
results.json machine-readable assertions and profile states
report.html single-file bilingual report
junit.xml CI-native test report
checksums.sha256 per-file SHA-256 integrity list
bundle.hash hash of the checksum manifest

Use memoryproof doctor --allow-network only when a provider endpoint is intentionally reachable, and use memoryproof expand ... --allow-network only when probe generation is configured to call a non-loopback OpenAI-compatible endpoint. The generated probes are frozen before a run; the model never makes the final pass/fail decision.

By default, payloads are reduced to hashes, lengths, types, and safe structural summaries. --allow-network authorizes a remote backend; it does not disable redaction.

GitHub Actions

The repository ships a Docker-based action that uploads the evidence bundle even when the test fails:

name: Memory assuranceon:
pull_request:
jobs:
memoryproof:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: Hughhhhcoder/MemoryProof@v1with:
scenario: examples/reference-clean.yml

Use a leaky or vendor-specific scenario in a separate job when you want the PR to fail on a known regression. The action exposes bundle-path, status, and exit-code outputs and writes a short job summary.

Scenario and adapter contract

The stable scenario API is memoryproof.dev/v1. A scenario contains:

  • an adapter and non-sensitive configuration references;
  • isolated target and control subjects;
  • synthetic target/control fixtures;
  • settle policy for asynchronous backends;
  • an erase intent such as object_delete or subject_erase;
  • deterministic probes and selected profiles;
  • a privacy policy for redacted evidence.

The adapter protocol methods are hello, capabilities, prepare, ingest, settle, probe, erase, inspect, agent_query, cleanup, and close. stdout is reserved for protocol frames; adapter logs go to stderr. A capability that is not implemented must become SKIP or UNKNOWN, never a fabricated pass.

Credentialed provider runs

The checked-in *-adapter-contract evidence uses deterministic local mocks. For a real Mem0, Letta, or Zep deployment, use the opt-in credentialed provider workflow. It reads API keys from GitHub Secrets, requires --allow-network, uploads a reviewed artifact, and never commits remote evidence automatically.

Build and contribute

cargo fmt --all
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo clippy --workspace --all-targets --all-features -- -D warnings
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo test --workspace -- --test-threads=2
PYTHONPATH=python python3 -m unittest discover -s python/tests -v

Please read CONTRIBUTING.md, SECURITY.md, and their 中文版本 before opening a pull request. MemoryProof is Apache-2.0 licensed and follows the DCO sign-off workflow.

Learn more

Migration from ForgetProof

MemoryProof is the new umbrella name for the project formerly published as ForgetProof. The v0.1 evidence format and compatibility binary remain readable, while new scenarios and releases use memoryproof.dev/v1 and the memoryproof command. If you have an old GitHub Action reference, update Hughhhhcoder/ForgetProof@v0.1.0 to Hughhhhcoder/MemoryProof@v1; GitHub does not redirect Action references after a repository rename.

About

Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - Hughhhhcoder/MemoryProof: Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents. · GitHub
Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

MemoryProof

Prove what your AI forgot.

English · 简体中文

CI statusLive MemoryProof matrixLatest releaseApache-2.0 license

Rust stablePython 3.11 or newerLocal-first privacySHA-256 evidencev1.0.4

🧪 Try it in 60 seconds · 🔍 See the proof · 🧭 Open the live matrix

MemoryProof: a synthetic canary leaves an observable memory graph while a verification ring and evidence ledger record the boundary

MemoryProof is an open-source memory assurance toolkit for AI agents. It tests a question that a successful DELETE response cannot answer:

Can the information still be observed through any path the backend exposes?

It creates isolated synthetic canaries, runs deterministic before/after probes, checks raw and derived boundaries, and emits an offline evidence bundle that developers can review, verify, and run in CI.

Important

DELETE 200 OK is an API response. MemoryProof tests the stronger, observable claim: the canary is no longer retrievable through the configured boundary.

Why MemoryProof?

Agent memory is rarely one table. A single fact can be copied into a raw record, summary, embedding, graph node, cache, block, or working context. A delete endpoint may remove one representation while another still answers a search query.

MemoryProof makes that gap concrete with a controlled experiment:

🧾 What an API may report🕳️ What can remain🔬 What MemoryProof records
DELETE 200 OKA summary still contains the canaryDeterministic pre/post probes
Raw row is goneAn index, vector, or graph edge still recalls itDerived-artifact inspection
One block was detachedAnother Agent path can still leak the factOptional black-box Agent query
“Delete all” was acceptedAn unrelated control subject disappeared tooIsolation and scope assertions

The goal is not to assign a vendor a simplistic score. The goal is to make what was checked, what passed, and what cannot be observed explicit.

The proof in one screen

flowchart LR
A["Scenario + synthetic canaries"] --> B["Rust runner"]
B --> C["Versioned NDJSON adapter"]
C --> D["Mem0 · Letta · Zep"]
B --> E["Before probes"]
D --> F["Erase / isolate"]
F --> G["Settle + after probes"]
E --> H["Evidence bundle"]
G --> H
H --> I["HTML · JUnit · CI · Matrix"]
Loading
  1. Seed a canary that is unique, synthetic, and safe to send to a test namespace.
  2. Prove the precondition: the target canary is observable before deletion.
  3. Erase or isolate only resources owned by this run.
  4. Wait for asynchronous writes to settle; a timeout becomes UNKNOWN, not a false pass.
  5. Probe raw, derived, Agent, and control paths with deterministic rules.
  6. Seal the evidence with sorted SHA-256 checksums and a bundle hash.

The difference it makes

❌ “Trust the endpoint”✅ MemoryProof
EvidenceA green HTTP responseA portable bundle with events, results, report, JUnit, and hashes
CoverageThe object named in the delete callEvery observable boundary advertised by the adapter
SafetyA script may delete the wrong dataSynthetic canaries plus target/control isolation
Regression testingA one-off manual checkA locked scenario in local runs and pull requests
UncertaintyMissing APIs become “probably fine”UNKNOWN, SKIP, and OUT OF SCOPE stay visible

A failure is a useful result

The repository includes a deliberately leaky backend. It deletes the raw item but leaves a derived artifact. MemoryProof must fail at the derived boundary:

status: FAIL
profile: erasure.derived
probe: target-derived-after
reason: the unique canary is still observable in a derived artifact

This is the core experience: an ambiguous memory concern becomes a named, reproducible, reviewable regression.

Quickstart

Requirements: Rust stable and Python 3.11+.

Run from source

git clone https://github.com/Hughhhhcoder/MemoryProof.git
cd MemoryProof
cargo run -- adapters list
cargo run -- run examples/reference-clean.yml

The clean reference scenario exits 0 and writes a bundle under .memoryproof/runs/. Verify and open it offline:

cargo run -- verify .memoryproof/runs/<run-id>
open .memoryproof/runs/<run-id>/report.html # macOS# xdg-open .memoryproof/runs/<run-id>/report.html # Linux

Now run the intentionally leaky backend:

cargo run -- run examples/reference-leaky.yml

It exits 1: the raw item disappears, but a derived artifact remains observable. That failure is expected and demonstrates the check is working.

Use the released binary or container

Download a platform binary from Releases, or run the GHCR image. Each binary archive includes the dependency-free Python adapter modules; if you keep them in a different location, set MEMORYPROOF_ADAPTER_ROOT to that archive's python/ directory.

docker run --rm -v "$PWD":/workspace \
ghcr.io/hughhhhcoder/memoryproof:1 \
run /workspace/examples/reference-clean.yml \
--output /workspace/.memoryproof/runs

For compatibility with the original v0.1 project, the forgetproof binary name and forgetproof Python import path remain available during the migration window.

Suites and profiles

MemoryProof is an umbrella with two suites:

SuiteWhat it answersProfiles
🧹 ErasureDid an owned memory boundary stop exposing the target?erasure.object, erasure.scope, erasure.derived, erasure.agent
🧱 IsolationCan one subject be read without leaking another subject’s memory?isolation.read, isolation.search, isolation.agent

The human-facing legacy names FP-Object, FP-Scope, FP-Derived, and FP-Agent are accepted when loading v0.1 scenarios. New scenarios use the stable names above.

Every assertion is one of:

StatusMeaning
PASSThe required observable check passed.
FAILA probe found the target, a forbidden derivative, or a scope violation.
SKIPThe selected profile is not required or is intentionally not executed.
UNKNOWNThe adapter cannot expose enough information to make the claim.
ERRORThe scenario, protocol, precondition, or execution failed.

There is no aggregate score. A capability boundary should be readable, not averaged away.

What it can—and cannot—prove

✅ It can show🚫 It does not claim
A target was observable before erase.Provider logs were deleted.
A configured API no longer returns the target.Backups or physical storage were wiped.
A visible summary, graph, index, or Agent path still leaks it.A model’s weights were unlearned.
A control subject stayed intact—or was accidentally deleted.Anything outside the adapter’s observable boundary.
The evidence bundle was not modified after creation.The identity of the person who produced the bundle.

These boundaries are part of the product, not a footnote. Reports explicitly separate proved, not observed, and out of scope.

Supported adapters

AdapterModesCoverage in v1
reference-cleanlocalFull erasure and isolation reference behavior
reference-leakylocalDeliberate derived-artifact residue
reference-overdeletelocalDeliberate control-subject deletion
mem0OSS / platform / cloudObject, scope, search, optional raw/derived inspection; async settle
lettaself-hosted / cloudTemporary Agent, core block, archival passage, scope delete, optional query
zepself-hosted / cloudEpisode, temporary user/thread, user scope, search, graph inspection

Remote access is opt-in. Credentials are read from environment variables and are never written into scenarios or evidence:

MEM0_BASE_URL=https://... MEM0_API_KEY=... \
cargo run -- run examples/mem0.yml --allow-network

Adapters communicate with the Rust runner through the versioned memoryproof.adapter/v1 NDJSON protocol. Third-party adapters can implement the same contract without linking to the Rust binary.

Evidence you can review in a pull request

Each run emits an offline-readable package:

manifest.json format, run, adapter mode, protocol, and declared files
scenario.lock.json redacted, frozen scenario snapshot
scenario.lock.yml the same frozen snapshot in the requested YAML form
events.ndjson ordered method journal with safe request IDs
results.json machine-readable assertions and profile states
report.html single-file bilingual report
junit.xml CI-native test report
checksums.sha256 per-file SHA-256 integrity list
bundle.hash hash of the checksum manifest

Use memoryproof doctor --allow-network only when a provider endpoint is intentionally reachable, and use memoryproof expand ... --allow-network only when probe generation is configured to call a non-loopback OpenAI-compatible endpoint. The generated probes are frozen before a run; the model never makes the final pass/fail decision.

By default, payloads are reduced to hashes, lengths, types, and safe structural summaries. --allow-network authorizes a remote backend; it does not disable redaction.

GitHub Actions

The repository ships a Docker-based action that uploads the evidence bundle even when the test fails:

name: Memory assuranceon:
pull_request:
jobs:
memoryproof:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: Hughhhhcoder/MemoryProof@v1with:
scenario: examples/reference-clean.yml

Use a leaky or vendor-specific scenario in a separate job when you want the PR to fail on a known regression. The action exposes bundle-path, status, and exit-code outputs and writes a short job summary.

Scenario and adapter contract

The stable scenario API is memoryproof.dev/v1. A scenario contains:

  • an adapter and non-sensitive configuration references;
  • isolated target and control subjects;
  • synthetic target/control fixtures;
  • settle policy for asynchronous backends;
  • an erase intent such as object_delete or subject_erase;
  • deterministic probes and selected profiles;
  • a privacy policy for redacted evidence.

The adapter protocol methods are hello, capabilities, prepare, ingest, settle, probe, erase, inspect, agent_query, cleanup, and close. stdout is reserved for protocol frames; adapter logs go to stderr. A capability that is not implemented must become SKIP or UNKNOWN, never a fabricated pass.

Credentialed provider runs

The checked-in *-adapter-contract evidence uses deterministic local mocks. For a real Mem0, Letta, or Zep deployment, use the opt-in credentialed provider workflow. It reads API keys from GitHub Secrets, requires --allow-network, uploads a reviewed artifact, and never commits remote evidence automatically.

Build and contribute

cargo fmt --all
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo clippy --workspace --all-targets --all-features -- -D warnings
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo test --workspace -- --test-threads=2
PYTHONPATH=python python3 -m unittest discover -s python/tests -v

Please read CONTRIBUTING.md, SECURITY.md, and their 中文版本 before opening a pull request. MemoryProof is Apache-2.0 licensed and follows the DCO sign-off workflow.

Learn more

Migration from ForgetProof

MemoryProof is the new umbrella name for the project formerly published as ForgetProof. The v0.1 evidence format and compatibility binary remain readable, while new scenarios and releases use memoryproof.dev/v1 and the memoryproof command. If you have an old GitHub Action reference, update Hughhhhcoder/ForgetProof@v0.1.0 to Hughhhhcoder/MemoryProof@v1; GitHub does not redirect Action references after a repository rename.

About

Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Hughhhhcoder/MemoryProof: Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents. · GitHub
Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

MemoryProof

Prove what your AI forgot.

English · 简体中文

CI statusLive MemoryProof matrixLatest releaseApache-2.0 license

Rust stablePython 3.11 or newerLocal-first privacySHA-256 evidencev1.0.4

🧪 Try it in 60 seconds · 🔍 See the proof · 🧭 Open the live matrix

MemoryProof: a synthetic canary leaves an observable memory graph while a verification ring and evidence ledger record the boundary

MemoryProof is an open-source memory assurance toolkit for AI agents. It tests a question that a successful DELETE response cannot answer:

Can the information still be observed through any path the backend exposes?

It creates isolated synthetic canaries, runs deterministic before/after probes, checks raw and derived boundaries, and emits an offline evidence bundle that developers can review, verify, and run in CI.

Important

DELETE 200 OK is an API response. MemoryProof tests the stronger, observable claim: the canary is no longer retrievable through the configured boundary.

Why MemoryProof?

Agent memory is rarely one table. A single fact can be copied into a raw record, summary, embedding, graph node, cache, block, or working context. A delete endpoint may remove one representation while another still answers a search query.

MemoryProof makes that gap concrete with a controlled experiment:

🧾 What an API may report🕳️ What can remain🔬 What MemoryProof records
DELETE 200 OKA summary still contains the canaryDeterministic pre/post probes
Raw row is goneAn index, vector, or graph edge still recalls itDerived-artifact inspection
One block was detachedAnother Agent path can still leak the factOptional black-box Agent query
“Delete all” was acceptedAn unrelated control subject disappeared tooIsolation and scope assertions

The goal is not to assign a vendor a simplistic score. The goal is to make what was checked, what passed, and what cannot be observed explicit.

The proof in one screen

flowchart LR
A["Scenario + synthetic canaries"] --> B["Rust runner"]
B --> C["Versioned NDJSON adapter"]
C --> D["Mem0 · Letta · Zep"]
B --> E["Before probes"]
D --> F["Erase / isolate"]
F --> G["Settle + after probes"]
E --> H["Evidence bundle"]
G --> H
H --> I["HTML · JUnit · CI · Matrix"]
Loading
  1. Seed a canary that is unique, synthetic, and safe to send to a test namespace.
  2. Prove the precondition: the target canary is observable before deletion.
  3. Erase or isolate only resources owned by this run.
  4. Wait for asynchronous writes to settle; a timeout becomes UNKNOWN, not a false pass.
  5. Probe raw, derived, Agent, and control paths with deterministic rules.
  6. Seal the evidence with sorted SHA-256 checksums and a bundle hash.

The difference it makes

❌ “Trust the endpoint”✅ MemoryProof
EvidenceA green HTTP responseA portable bundle with events, results, report, JUnit, and hashes
CoverageThe object named in the delete callEvery observable boundary advertised by the adapter
SafetyA script may delete the wrong dataSynthetic canaries plus target/control isolation
Regression testingA one-off manual checkA locked scenario in local runs and pull requests
UncertaintyMissing APIs become “probably fine”UNKNOWN, SKIP, and OUT OF SCOPE stay visible

A failure is a useful result

The repository includes a deliberately leaky backend. It deletes the raw item but leaves a derived artifact. MemoryProof must fail at the derived boundary:

status: FAIL
profile: erasure.derived
probe: target-derived-after
reason: the unique canary is still observable in a derived artifact

This is the core experience: an ambiguous memory concern becomes a named, reproducible, reviewable regression.

Quickstart

Requirements: Rust stable and Python 3.11+.

Run from source

git clone https://github.com/Hughhhhcoder/MemoryProof.git
cd MemoryProof
cargo run -- adapters list
cargo run -- run examples/reference-clean.yml

The clean reference scenario exits 0 and writes a bundle under .memoryproof/runs/. Verify and open it offline:

cargo run -- verify .memoryproof/runs/<run-id>
open .memoryproof/runs/<run-id>/report.html # macOS# xdg-open .memoryproof/runs/<run-id>/report.html # Linux

Now run the intentionally leaky backend:

cargo run -- run examples/reference-leaky.yml

It exits 1: the raw item disappears, but a derived artifact remains observable. That failure is expected and demonstrates the check is working.

Use the released binary or container

Download a platform binary from Releases, or run the GHCR image. Each binary archive includes the dependency-free Python adapter modules; if you keep them in a different location, set MEMORYPROOF_ADAPTER_ROOT to that archive's python/ directory.

docker run --rm -v "$PWD":/workspace \
ghcr.io/hughhhhcoder/memoryproof:1 \
run /workspace/examples/reference-clean.yml \
--output /workspace/.memoryproof/runs

For compatibility with the original v0.1 project, the forgetproof binary name and forgetproof Python import path remain available during the migration window.

Suites and profiles

MemoryProof is an umbrella with two suites:

SuiteWhat it answersProfiles
🧹 ErasureDid an owned memory boundary stop exposing the target?erasure.object, erasure.scope, erasure.derived, erasure.agent
🧱 IsolationCan one subject be read without leaking another subject’s memory?isolation.read, isolation.search, isolation.agent

The human-facing legacy names FP-Object, FP-Scope, FP-Derived, and FP-Agent are accepted when loading v0.1 scenarios. New scenarios use the stable names above.

Every assertion is one of:

StatusMeaning
PASSThe required observable check passed.
FAILA probe found the target, a forbidden derivative, or a scope violation.
SKIPThe selected profile is not required or is intentionally not executed.
UNKNOWNThe adapter cannot expose enough information to make the claim.
ERRORThe scenario, protocol, precondition, or execution failed.

There is no aggregate score. A capability boundary should be readable, not averaged away.

What it can—and cannot—prove

✅ It can show🚫 It does not claim
A target was observable before erase.Provider logs were deleted.
A configured API no longer returns the target.Backups or physical storage were wiped.
A visible summary, graph, index, or Agent path still leaks it.A model’s weights were unlearned.
A control subject stayed intact—or was accidentally deleted.Anything outside the adapter’s observable boundary.
The evidence bundle was not modified after creation.The identity of the person who produced the bundle.

These boundaries are part of the product, not a footnote. Reports explicitly separate proved, not observed, and out of scope.

Supported adapters

AdapterModesCoverage in v1
reference-cleanlocalFull erasure and isolation reference behavior
reference-leakylocalDeliberate derived-artifact residue
reference-overdeletelocalDeliberate control-subject deletion
mem0OSS / platform / cloudObject, scope, search, optional raw/derived inspection; async settle
lettaself-hosted / cloudTemporary Agent, core block, archival passage, scope delete, optional query
zepself-hosted / cloudEpisode, temporary user/thread, user scope, search, graph inspection

Remote access is opt-in. Credentials are read from environment variables and are never written into scenarios or evidence:

MEM0_BASE_URL=https://... MEM0_API_KEY=... \
cargo run -- run examples/mem0.yml --allow-network

Adapters communicate with the Rust runner through the versioned memoryproof.adapter/v1 NDJSON protocol. Third-party adapters can implement the same contract without linking to the Rust binary.

Evidence you can review in a pull request

Each run emits an offline-readable package:

manifest.json format, run, adapter mode, protocol, and declared files
scenario.lock.json redacted, frozen scenario snapshot
scenario.lock.yml the same frozen snapshot in the requested YAML form
events.ndjson ordered method journal with safe request IDs
results.json machine-readable assertions and profile states
report.html single-file bilingual report
junit.xml CI-native test report
checksums.sha256 per-file SHA-256 integrity list
bundle.hash hash of the checksum manifest

Use memoryproof doctor --allow-network only when a provider endpoint is intentionally reachable, and use memoryproof expand ... --allow-network only when probe generation is configured to call a non-loopback OpenAI-compatible endpoint. The generated probes are frozen before a run; the model never makes the final pass/fail decision.

By default, payloads are reduced to hashes, lengths, types, and safe structural summaries. --allow-network authorizes a remote backend; it does not disable redaction.

GitHub Actions

The repository ships a Docker-based action that uploads the evidence bundle even when the test fails:

name: Memory assuranceon:
pull_request:
jobs:
memoryproof:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: Hughhhhcoder/MemoryProof@v1with:
scenario: examples/reference-clean.yml

Use a leaky or vendor-specific scenario in a separate job when you want the PR to fail on a known regression. The action exposes bundle-path, status, and exit-code outputs and writes a short job summary.

Scenario and adapter contract

The stable scenario API is memoryproof.dev/v1. A scenario contains:

  • an adapter and non-sensitive configuration references;
  • isolated target and control subjects;
  • synthetic target/control fixtures;
  • settle policy for asynchronous backends;
  • an erase intent such as object_delete or subject_erase;
  • deterministic probes and selected profiles;
  • a privacy policy for redacted evidence.

The adapter protocol methods are hello, capabilities, prepare, ingest, settle, probe, erase, inspect, agent_query, cleanup, and close. stdout is reserved for protocol frames; adapter logs go to stderr. A capability that is not implemented must become SKIP or UNKNOWN, never a fabricated pass.

Credentialed provider runs

The checked-in *-adapter-contract evidence uses deterministic local mocks. For a real Mem0, Letta, or Zep deployment, use the opt-in credentialed provider workflow. It reads API keys from GitHub Secrets, requires --allow-network, uploads a reviewed artifact, and never commits remote evidence automatically.

Build and contribute

cargo fmt --all
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo clippy --workspace --all-targets --all-features -- -D warnings
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo test --workspace -- --test-threads=2
PYTHONPATH=python python3 -m unittest discover -s python/tests -v

Please read CONTRIBUTING.md, SECURITY.md, and their 中文版本 before opening a pull request. MemoryProof is Apache-2.0 licensed and follows the DCO sign-off workflow.

Learn more

Migration from ForgetProof

MemoryProof is the new umbrella name for the project formerly published as ForgetProof. The v0.1 evidence format and compatibility binary remain readable, while new scenarios and releases use memoryproof.dev/v1 and the memoryproof command. If you have an old GitHub Action reference, update Hughhhhcoder/ForgetProof@v0.1.0 to Hughhhhcoder/MemoryProof@v1; GitHub does not redirect Action references after a repository rename.

About

Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Hughhhhcoder/MemoryProof: Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents. · GitHub
Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

MemoryProof

Prove what your AI forgot.

English · 简体中文

CI statusLive MemoryProof matrixLatest releaseApache-2.0 license

Rust stablePython 3.11 or newerLocal-first privacySHA-256 evidencev1.0.4

🧪 Try it in 60 seconds · 🔍 See the proof · 🧭 Open the live matrix

MemoryProof: a synthetic canary leaves an observable memory graph while a verification ring and evidence ledger record the boundary

MemoryProof is an open-source memory assurance toolkit for AI agents. It tests a question that a successful DELETE response cannot answer:

Can the information still be observed through any path the backend exposes?

It creates isolated synthetic canaries, runs deterministic before/after probes, checks raw and derived boundaries, and emits an offline evidence bundle that developers can review, verify, and run in CI.

Important

DELETE 200 OK is an API response. MemoryProof tests the stronger, observable claim: the canary is no longer retrievable through the configured boundary.

Why MemoryProof?

Agent memory is rarely one table. A single fact can be copied into a raw record, summary, embedding, graph node, cache, block, or working context. A delete endpoint may remove one representation while another still answers a search query.

MemoryProof makes that gap concrete with a controlled experiment:

🧾 What an API may report🕳️ What can remain🔬 What MemoryProof records
DELETE 200 OKA summary still contains the canaryDeterministic pre/post probes
Raw row is goneAn index, vector, or graph edge still recalls itDerived-artifact inspection
One block was detachedAnother Agent path can still leak the factOptional black-box Agent query
“Delete all” was acceptedAn unrelated control subject disappeared tooIsolation and scope assertions

The goal is not to assign a vendor a simplistic score. The goal is to make what was checked, what passed, and what cannot be observed explicit.

The proof in one screen

flowchart LR
A["Scenario + synthetic canaries"] --> B["Rust runner"]
B --> C["Versioned NDJSON adapter"]
C --> D["Mem0 · Letta · Zep"]
B --> E["Before probes"]
D --> F["Erase / isolate"]
F --> G["Settle + after probes"]
E --> H["Evidence bundle"]
G --> H
H --> I["HTML · JUnit · CI · Matrix"]
Loading
  1. Seed a canary that is unique, synthetic, and safe to send to a test namespace.
  2. Prove the precondition: the target canary is observable before deletion.
  3. Erase or isolate only resources owned by this run.
  4. Wait for asynchronous writes to settle; a timeout becomes UNKNOWN, not a false pass.
  5. Probe raw, derived, Agent, and control paths with deterministic rules.
  6. Seal the evidence with sorted SHA-256 checksums and a bundle hash.

The difference it makes

❌ “Trust the endpoint”✅ MemoryProof
EvidenceA green HTTP responseA portable bundle with events, results, report, JUnit, and hashes
CoverageThe object named in the delete callEvery observable boundary advertised by the adapter
SafetyA script may delete the wrong dataSynthetic canaries plus target/control isolation
Regression testingA one-off manual checkA locked scenario in local runs and pull requests
UncertaintyMissing APIs become “probably fine”UNKNOWN, SKIP, and OUT OF SCOPE stay visible

A failure is a useful result

The repository includes a deliberately leaky backend. It deletes the raw item but leaves a derived artifact. MemoryProof must fail at the derived boundary:

status: FAIL
profile: erasure.derived
probe: target-derived-after
reason: the unique canary is still observable in a derived artifact

This is the core experience: an ambiguous memory concern becomes a named, reproducible, reviewable regression.

Quickstart

Requirements: Rust stable and Python 3.11+.

Run from source

git clone https://github.com/Hughhhhcoder/MemoryProof.git
cd MemoryProof
cargo run -- adapters list
cargo run -- run examples/reference-clean.yml

The clean reference scenario exits 0 and writes a bundle under .memoryproof/runs/. Verify and open it offline:

cargo run -- verify .memoryproof/runs/<run-id>
open .memoryproof/runs/<run-id>/report.html # macOS# xdg-open .memoryproof/runs/<run-id>/report.html # Linux

Now run the intentionally leaky backend:

cargo run -- run examples/reference-leaky.yml

It exits 1: the raw item disappears, but a derived artifact remains observable. That failure is expected and demonstrates the check is working.

Use the released binary or container

Download a platform binary from Releases, or run the GHCR image. Each binary archive includes the dependency-free Python adapter modules; if you keep them in a different location, set MEMORYPROOF_ADAPTER_ROOT to that archive's python/ directory.

docker run --rm -v "$PWD":/workspace \
ghcr.io/hughhhhcoder/memoryproof:1 \
run /workspace/examples/reference-clean.yml \
--output /workspace/.memoryproof/runs

For compatibility with the original v0.1 project, the forgetproof binary name and forgetproof Python import path remain available during the migration window.

Suites and profiles

MemoryProof is an umbrella with two suites:

SuiteWhat it answersProfiles
🧹 ErasureDid an owned memory boundary stop exposing the target?erasure.object, erasure.scope, erasure.derived, erasure.agent
🧱 IsolationCan one subject be read without leaking another subject’s memory?isolation.read, isolation.search, isolation.agent

The human-facing legacy names FP-Object, FP-Scope, FP-Derived, and FP-Agent are accepted when loading v0.1 scenarios. New scenarios use the stable names above.

Every assertion is one of:

StatusMeaning
PASSThe required observable check passed.
FAILA probe found the target, a forbidden derivative, or a scope violation.
SKIPThe selected profile is not required or is intentionally not executed.
UNKNOWNThe adapter cannot expose enough information to make the claim.
ERRORThe scenario, protocol, precondition, or execution failed.

There is no aggregate score. A capability boundary should be readable, not averaged away.

What it can—and cannot—prove

✅ It can show🚫 It does not claim
A target was observable before erase.Provider logs were deleted.
A configured API no longer returns the target.Backups or physical storage were wiped.
A visible summary, graph, index, or Agent path still leaks it.A model’s weights were unlearned.
A control subject stayed intact—or was accidentally deleted.Anything outside the adapter’s observable boundary.
The evidence bundle was not modified after creation.The identity of the person who produced the bundle.

These boundaries are part of the product, not a footnote. Reports explicitly separate proved, not observed, and out of scope.

Supported adapters

AdapterModesCoverage in v1
reference-cleanlocalFull erasure and isolation reference behavior
reference-leakylocalDeliberate derived-artifact residue
reference-overdeletelocalDeliberate control-subject deletion
mem0OSS / platform / cloudObject, scope, search, optional raw/derived inspection; async settle
lettaself-hosted / cloudTemporary Agent, core block, archival passage, scope delete, optional query
zepself-hosted / cloudEpisode, temporary user/thread, user scope, search, graph inspection

Remote access is opt-in. Credentials are read from environment variables and are never written into scenarios or evidence:

MEM0_BASE_URL=https://... MEM0_API_KEY=... \
cargo run -- run examples/mem0.yml --allow-network

Adapters communicate with the Rust runner through the versioned memoryproof.adapter/v1 NDJSON protocol. Third-party adapters can implement the same contract without linking to the Rust binary.

Evidence you can review in a pull request

Each run emits an offline-readable package:

manifest.json format, run, adapter mode, protocol, and declared files
scenario.lock.json redacted, frozen scenario snapshot
scenario.lock.yml the same frozen snapshot in the requested YAML form
events.ndjson ordered method journal with safe request IDs
results.json machine-readable assertions and profile states
report.html single-file bilingual report
junit.xml CI-native test report
checksums.sha256 per-file SHA-256 integrity list
bundle.hash hash of the checksum manifest

Use memoryproof doctor --allow-network only when a provider endpoint is intentionally reachable, and use memoryproof expand ... --allow-network only when probe generation is configured to call a non-loopback OpenAI-compatible endpoint. The generated probes are frozen before a run; the model never makes the final pass/fail decision.

By default, payloads are reduced to hashes, lengths, types, and safe structural summaries. --allow-network authorizes a remote backend; it does not disable redaction.

GitHub Actions

The repository ships a Docker-based action that uploads the evidence bundle even when the test fails:

name: Memory assuranceon:
pull_request:
jobs:
memoryproof:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: Hughhhhcoder/MemoryProof@v1with:
scenario: examples/reference-clean.yml

Use a leaky or vendor-specific scenario in a separate job when you want the PR to fail on a known regression. The action exposes bundle-path, status, and exit-code outputs and writes a short job summary.

Scenario and adapter contract

The stable scenario API is memoryproof.dev/v1. A scenario contains:

  • an adapter and non-sensitive configuration references;
  • isolated target and control subjects;
  • synthetic target/control fixtures;
  • settle policy for asynchronous backends;
  • an erase intent such as object_delete or subject_erase;
  • deterministic probes and selected profiles;
  • a privacy policy for redacted evidence.

The adapter protocol methods are hello, capabilities, prepare, ingest, settle, probe, erase, inspect, agent_query, cleanup, and close. stdout is reserved for protocol frames; adapter logs go to stderr. A capability that is not implemented must become SKIP or UNKNOWN, never a fabricated pass.

Credentialed provider runs

The checked-in *-adapter-contract evidence uses deterministic local mocks. For a real Mem0, Letta, or Zep deployment, use the opt-in credentialed provider workflow. It reads API keys from GitHub Secrets, requires --allow-network, uploads a reviewed artifact, and never commits remote evidence automatically.

Build and contribute

cargo fmt --all
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo clippy --workspace --all-targets --all-features -- -D warnings
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo test --workspace -- --test-threads=2
PYTHONPATH=python python3 -m unittest discover -s python/tests -v

Please read CONTRIBUTING.md, SECURITY.md, and their 中文版本 before opening a pull request. MemoryProof is Apache-2.0 licensed and follows the DCO sign-off workflow.

Learn more

Migration from ForgetProof

MemoryProof is the new umbrella name for the project formerly published as ForgetProof. The v0.1 evidence format and compatibility binary remain readable, while new scenarios and releases use memoryproof.dev/v1 and the memoryproof command. If you have an old GitHub Action reference, update Hughhhhcoder/ForgetProof@v0.1.0 to Hughhhhcoder/MemoryProof@v1; GitHub does not redirect Action references after a repository rename.

About

Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - Hughhhhcoder/MemoryProof: Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents. · GitHub
Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

MemoryProof

Prove what your AI forgot.

English · 简体中文

CI statusLive MemoryProof matrixLatest releaseApache-2.0 license

Rust stablePython 3.11 or newerLocal-first privacySHA-256 evidencev1.0.4

🧪 Try it in 60 seconds · 🔍 See the proof · 🧭 Open the live matrix

MemoryProof: a synthetic canary leaves an observable memory graph while a verification ring and evidence ledger record the boundary

MemoryProof is an open-source memory assurance toolkit for AI agents. It tests a question that a successful DELETE response cannot answer:

Can the information still be observed through any path the backend exposes?

It creates isolated synthetic canaries, runs deterministic before/after probes, checks raw and derived boundaries, and emits an offline evidence bundle that developers can review, verify, and run in CI.

Important

DELETE 200 OK is an API response. MemoryProof tests the stronger, observable claim: the canary is no longer retrievable through the configured boundary.

Why MemoryProof?

Agent memory is rarely one table. A single fact can be copied into a raw record, summary, embedding, graph node, cache, block, or working context. A delete endpoint may remove one representation while another still answers a search query.

MemoryProof makes that gap concrete with a controlled experiment:

🧾 What an API may report🕳️ What can remain🔬 What MemoryProof records
DELETE 200 OKA summary still contains the canaryDeterministic pre/post probes
Raw row is goneAn index, vector, or graph edge still recalls itDerived-artifact inspection
One block was detachedAnother Agent path can still leak the factOptional black-box Agent query
“Delete all” was acceptedAn unrelated control subject disappeared tooIsolation and scope assertions

The goal is not to assign a vendor a simplistic score. The goal is to make what was checked, what passed, and what cannot be observed explicit.

The proof in one screen

flowchart LR
A["Scenario + synthetic canaries"] --> B["Rust runner"]
B --> C["Versioned NDJSON adapter"]
C --> D["Mem0 · Letta · Zep"]
B --> E["Before probes"]
D --> F["Erase / isolate"]
F --> G["Settle + after probes"]
E --> H["Evidence bundle"]
G --> H
H --> I["HTML · JUnit · CI · Matrix"]
Loading
  1. Seed a canary that is unique, synthetic, and safe to send to a test namespace.
  2. Prove the precondition: the target canary is observable before deletion.
  3. Erase or isolate only resources owned by this run.
  4. Wait for asynchronous writes to settle; a timeout becomes UNKNOWN, not a false pass.
  5. Probe raw, derived, Agent, and control paths with deterministic rules.
  6. Seal the evidence with sorted SHA-256 checksums and a bundle hash.

The difference it makes

❌ “Trust the endpoint”✅ MemoryProof
EvidenceA green HTTP responseA portable bundle with events, results, report, JUnit, and hashes
CoverageThe object named in the delete callEvery observable boundary advertised by the adapter
SafetyA script may delete the wrong dataSynthetic canaries plus target/control isolation
Regression testingA one-off manual checkA locked scenario in local runs and pull requests
UncertaintyMissing APIs become “probably fine”UNKNOWN, SKIP, and OUT OF SCOPE stay visible

A failure is a useful result

The repository includes a deliberately leaky backend. It deletes the raw item but leaves a derived artifact. MemoryProof must fail at the derived boundary:

status: FAIL
profile: erasure.derived
probe: target-derived-after
reason: the unique canary is still observable in a derived artifact

This is the core experience: an ambiguous memory concern becomes a named, reproducible, reviewable regression.

Quickstart

Requirements: Rust stable and Python 3.11+.

Run from source

git clone https://github.com/Hughhhhcoder/MemoryProof.git
cd MemoryProof
cargo run -- adapters list
cargo run -- run examples/reference-clean.yml

The clean reference scenario exits 0 and writes a bundle under .memoryproof/runs/. Verify and open it offline:

cargo run -- verify .memoryproof/runs/<run-id>
open .memoryproof/runs/<run-id>/report.html # macOS# xdg-open .memoryproof/runs/<run-id>/report.html # Linux

Now run the intentionally leaky backend:

cargo run -- run examples/reference-leaky.yml

It exits 1: the raw item disappears, but a derived artifact remains observable. That failure is expected and demonstrates the check is working.

Use the released binary or container

Download a platform binary from Releases, or run the GHCR image. Each binary archive includes the dependency-free Python adapter modules; if you keep them in a different location, set MEMORYPROOF_ADAPTER_ROOT to that archive's python/ directory.

docker run --rm -v "$PWD":/workspace \
ghcr.io/hughhhhcoder/memoryproof:1 \
run /workspace/examples/reference-clean.yml \
--output /workspace/.memoryproof/runs

For compatibility with the original v0.1 project, the forgetproof binary name and forgetproof Python import path remain available during the migration window.

Suites and profiles

MemoryProof is an umbrella with two suites:

SuiteWhat it answersProfiles
🧹 ErasureDid an owned memory boundary stop exposing the target?erasure.object, erasure.scope, erasure.derived, erasure.agent
🧱 IsolationCan one subject be read without leaking another subject’s memory?isolation.read, isolation.search, isolation.agent

The human-facing legacy names FP-Object, FP-Scope, FP-Derived, and FP-Agent are accepted when loading v0.1 scenarios. New scenarios use the stable names above.

Every assertion is one of:

StatusMeaning
PASSThe required observable check passed.
FAILA probe found the target, a forbidden derivative, or a scope violation.
SKIPThe selected profile is not required or is intentionally not executed.
UNKNOWNThe adapter cannot expose enough information to make the claim.
ERRORThe scenario, protocol, precondition, or execution failed.

There is no aggregate score. A capability boundary should be readable, not averaged away.

What it can—and cannot—prove

✅ It can show🚫 It does not claim
A target was observable before erase.Provider logs were deleted.
A configured API no longer returns the target.Backups or physical storage were wiped.
A visible summary, graph, index, or Agent path still leaks it.A model’s weights were unlearned.
A control subject stayed intact—or was accidentally deleted.Anything outside the adapter’s observable boundary.
The evidence bundle was not modified after creation.The identity of the person who produced the bundle.

These boundaries are part of the product, not a footnote. Reports explicitly separate proved, not observed, and out of scope.

Supported adapters

AdapterModesCoverage in v1
reference-cleanlocalFull erasure and isolation reference behavior
reference-leakylocalDeliberate derived-artifact residue
reference-overdeletelocalDeliberate control-subject deletion
mem0OSS / platform / cloudObject, scope, search, optional raw/derived inspection; async settle
lettaself-hosted / cloudTemporary Agent, core block, archival passage, scope delete, optional query
zepself-hosted / cloudEpisode, temporary user/thread, user scope, search, graph inspection

Remote access is opt-in. Credentials are read from environment variables and are never written into scenarios or evidence:

MEM0_BASE_URL=https://... MEM0_API_KEY=... \
cargo run -- run examples/mem0.yml --allow-network

Adapters communicate with the Rust runner through the versioned memoryproof.adapter/v1 NDJSON protocol. Third-party adapters can implement the same contract without linking to the Rust binary.

Evidence you can review in a pull request

Each run emits an offline-readable package:

manifest.json format, run, adapter mode, protocol, and declared files
scenario.lock.json redacted, frozen scenario snapshot
scenario.lock.yml the same frozen snapshot in the requested YAML form
events.ndjson ordered method journal with safe request IDs
results.json machine-readable assertions and profile states
report.html single-file bilingual report
junit.xml CI-native test report
checksums.sha256 per-file SHA-256 integrity list
bundle.hash hash of the checksum manifest

Use memoryproof doctor --allow-network only when a provider endpoint is intentionally reachable, and use memoryproof expand ... --allow-network only when probe generation is configured to call a non-loopback OpenAI-compatible endpoint. The generated probes are frozen before a run; the model never makes the final pass/fail decision.

By default, payloads are reduced to hashes, lengths, types, and safe structural summaries. --allow-network authorizes a remote backend; it does not disable redaction.

GitHub Actions

The repository ships a Docker-based action that uploads the evidence bundle even when the test fails:

name: Memory assuranceon:
pull_request:
jobs:
memoryproof:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: Hughhhhcoder/MemoryProof@v1with:
scenario: examples/reference-clean.yml

Use a leaky or vendor-specific scenario in a separate job when you want the PR to fail on a known regression. The action exposes bundle-path, status, and exit-code outputs and writes a short job summary.

Scenario and adapter contract

The stable scenario API is memoryproof.dev/v1. A scenario contains:

  • an adapter and non-sensitive configuration references;
  • isolated target and control subjects;
  • synthetic target/control fixtures;
  • settle policy for asynchronous backends;
  • an erase intent such as object_delete or subject_erase;
  • deterministic probes and selected profiles;
  • a privacy policy for redacted evidence.

The adapter protocol methods are hello, capabilities, prepare, ingest, settle, probe, erase, inspect, agent_query, cleanup, and close. stdout is reserved for protocol frames; adapter logs go to stderr. A capability that is not implemented must become SKIP or UNKNOWN, never a fabricated pass.

Credentialed provider runs

The checked-in *-adapter-contract evidence uses deterministic local mocks. For a real Mem0, Letta, or Zep deployment, use the opt-in credentialed provider workflow. It reads API keys from GitHub Secrets, requires --allow-network, uploads a reviewed artifact, and never commits remote evidence automatically.

Build and contribute

cargo fmt --all
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo clippy --workspace --all-targets --all-features -- -D warnings
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo test --workspace -- --test-threads=2
PYTHONPATH=python python3 -m unittest discover -s python/tests -v

Please read CONTRIBUTING.md, SECURITY.md, and their 中文版本 before opening a pull request. MemoryProof is Apache-2.0 licensed and follows the DCO sign-off workflow.

Learn more

Migration from ForgetProof

MemoryProof is the new umbrella name for the project formerly published as ForgetProof. The v0.1 evidence format and compatibility binary remain readable, while new scenarios and releases use memoryproof.dev/v1 and the memoryproof command. If you have an old GitHub Action reference, update Hughhhhcoder/ForgetProof@v0.1.0 to Hughhhhcoder/MemoryProof@v1; GitHub does not redirect Action references after a repository rename.

About

Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Hughhhhcoder/MemoryProof: Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents. · GitHub
Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

MemoryProof

Prove what your AI forgot.

English · 简体中文

CI statusLive MemoryProof matrixLatest releaseApache-2.0 license

Rust stablePython 3.11 or newerLocal-first privacySHA-256 evidencev1.0.4

🧪 Try it in 60 seconds · 🔍 See the proof · 🧭 Open the live matrix

MemoryProof: a synthetic canary leaves an observable memory graph while a verification ring and evidence ledger record the boundary

MemoryProof is an open-source memory assurance toolkit for AI agents. It tests a question that a successful DELETE response cannot answer:

Can the information still be observed through any path the backend exposes?

It creates isolated synthetic canaries, runs deterministic before/after probes, checks raw and derived boundaries, and emits an offline evidence bundle that developers can review, verify, and run in CI.

Important

DELETE 200 OK is an API response. MemoryProof tests the stronger, observable claim: the canary is no longer retrievable through the configured boundary.

Why MemoryProof?

Agent memory is rarely one table. A single fact can be copied into a raw record, summary, embedding, graph node, cache, block, or working context. A delete endpoint may remove one representation while another still answers a search query.

MemoryProof makes that gap concrete with a controlled experiment:

🧾 What an API may report🕳️ What can remain🔬 What MemoryProof records
DELETE 200 OKA summary still contains the canaryDeterministic pre/post probes
Raw row is goneAn index, vector, or graph edge still recalls itDerived-artifact inspection
One block was detachedAnother Agent path can still leak the factOptional black-box Agent query
“Delete all” was acceptedAn unrelated control subject disappeared tooIsolation and scope assertions

The goal is not to assign a vendor a simplistic score. The goal is to make what was checked, what passed, and what cannot be observed explicit.

The proof in one screen

flowchart LR
A["Scenario + synthetic canaries"] --> B["Rust runner"]
B --> C["Versioned NDJSON adapter"]
C --> D["Mem0 · Letta · Zep"]
B --> E["Before probes"]
D --> F["Erase / isolate"]
F --> G["Settle + after probes"]
E --> H["Evidence bundle"]
G --> H
H --> I["HTML · JUnit · CI · Matrix"]
Loading
  1. Seed a canary that is unique, synthetic, and safe to send to a test namespace.
  2. Prove the precondition: the target canary is observable before deletion.
  3. Erase or isolate only resources owned by this run.
  4. Wait for asynchronous writes to settle; a timeout becomes UNKNOWN, not a false pass.
  5. Probe raw, derived, Agent, and control paths with deterministic rules.
  6. Seal the evidence with sorted SHA-256 checksums and a bundle hash.

The difference it makes

❌ “Trust the endpoint”✅ MemoryProof
EvidenceA green HTTP responseA portable bundle with events, results, report, JUnit, and hashes
CoverageThe object named in the delete callEvery observable boundary advertised by the adapter
SafetyA script may delete the wrong dataSynthetic canaries plus target/control isolation
Regression testingA one-off manual checkA locked scenario in local runs and pull requests
UncertaintyMissing APIs become “probably fine”UNKNOWN, SKIP, and OUT OF SCOPE stay visible

A failure is a useful result

The repository includes a deliberately leaky backend. It deletes the raw item but leaves a derived artifact. MemoryProof must fail at the derived boundary:

status: FAIL
profile: erasure.derived
probe: target-derived-after
reason: the unique canary is still observable in a derived artifact

This is the core experience: an ambiguous memory concern becomes a named, reproducible, reviewable regression.

Quickstart

Requirements: Rust stable and Python 3.11+.

Run from source

git clone https://github.com/Hughhhhcoder/MemoryProof.git
cd MemoryProof
cargo run -- adapters list
cargo run -- run examples/reference-clean.yml

The clean reference scenario exits 0 and writes a bundle under .memoryproof/runs/. Verify and open it offline:

cargo run -- verify .memoryproof/runs/<run-id>
open .memoryproof/runs/<run-id>/report.html # macOS# xdg-open .memoryproof/runs/<run-id>/report.html # Linux

Now run the intentionally leaky backend:

cargo run -- run examples/reference-leaky.yml

It exits 1: the raw item disappears, but a derived artifact remains observable. That failure is expected and demonstrates the check is working.

Use the released binary or container

Download a platform binary from Releases, or run the GHCR image. Each binary archive includes the dependency-free Python adapter modules; if you keep them in a different location, set MEMORYPROOF_ADAPTER_ROOT to that archive's python/ directory.

docker run --rm -v "$PWD":/workspace \
ghcr.io/hughhhhcoder/memoryproof:1 \
run /workspace/examples/reference-clean.yml \
--output /workspace/.memoryproof/runs

For compatibility with the original v0.1 project, the forgetproof binary name and forgetproof Python import path remain available during the migration window.

Suites and profiles

MemoryProof is an umbrella with two suites:

SuiteWhat it answersProfiles
🧹 ErasureDid an owned memory boundary stop exposing the target?erasure.object, erasure.scope, erasure.derived, erasure.agent
🧱 IsolationCan one subject be read without leaking another subject’s memory?isolation.read, isolation.search, isolation.agent

The human-facing legacy names FP-Object, FP-Scope, FP-Derived, and FP-Agent are accepted when loading v0.1 scenarios. New scenarios use the stable names above.

Every assertion is one of:

StatusMeaning
PASSThe required observable check passed.
FAILA probe found the target, a forbidden derivative, or a scope violation.
SKIPThe selected profile is not required or is intentionally not executed.
UNKNOWNThe adapter cannot expose enough information to make the claim.
ERRORThe scenario, protocol, precondition, or execution failed.

There is no aggregate score. A capability boundary should be readable, not averaged away.

What it can—and cannot—prove

✅ It can show🚫 It does not claim
A target was observable before erase.Provider logs were deleted.
A configured API no longer returns the target.Backups or physical storage were wiped.
A visible summary, graph, index, or Agent path still leaks it.A model’s weights were unlearned.
A control subject stayed intact—or was accidentally deleted.Anything outside the adapter’s observable boundary.
The evidence bundle was not modified after creation.The identity of the person who produced the bundle.

These boundaries are part of the product, not a footnote. Reports explicitly separate proved, not observed, and out of scope.

Supported adapters

AdapterModesCoverage in v1
reference-cleanlocalFull erasure and isolation reference behavior
reference-leakylocalDeliberate derived-artifact residue
reference-overdeletelocalDeliberate control-subject deletion
mem0OSS / platform / cloudObject, scope, search, optional raw/derived inspection; async settle
lettaself-hosted / cloudTemporary Agent, core block, archival passage, scope delete, optional query
zepself-hosted / cloudEpisode, temporary user/thread, user scope, search, graph inspection

Remote access is opt-in. Credentials are read from environment variables and are never written into scenarios or evidence:

MEM0_BASE_URL=https://... MEM0_API_KEY=... \
cargo run -- run examples/mem0.yml --allow-network

Adapters communicate with the Rust runner through the versioned memoryproof.adapter/v1 NDJSON protocol. Third-party adapters can implement the same contract without linking to the Rust binary.

Evidence you can review in a pull request

Each run emits an offline-readable package:

manifest.json format, run, adapter mode, protocol, and declared files
scenario.lock.json redacted, frozen scenario snapshot
scenario.lock.yml the same frozen snapshot in the requested YAML form
events.ndjson ordered method journal with safe request IDs
results.json machine-readable assertions and profile states
report.html single-file bilingual report
junit.xml CI-native test report
checksums.sha256 per-file SHA-256 integrity list
bundle.hash hash of the checksum manifest

Use memoryproof doctor --allow-network only when a provider endpoint is intentionally reachable, and use memoryproof expand ... --allow-network only when probe generation is configured to call a non-loopback OpenAI-compatible endpoint. The generated probes are frozen before a run; the model never makes the final pass/fail decision.

By default, payloads are reduced to hashes, lengths, types, and safe structural summaries. --allow-network authorizes a remote backend; it does not disable redaction.

GitHub Actions

The repository ships a Docker-based action that uploads the evidence bundle even when the test fails:

name: Memory assuranceon:
pull_request:
jobs:
memoryproof:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: Hughhhhcoder/MemoryProof@v1with:
scenario: examples/reference-clean.yml

Use a leaky or vendor-specific scenario in a separate job when you want the PR to fail on a known regression. The action exposes bundle-path, status, and exit-code outputs and writes a short job summary.

Scenario and adapter contract

The stable scenario API is memoryproof.dev/v1. A scenario contains:

  • an adapter and non-sensitive configuration references;
  • isolated target and control subjects;
  • synthetic target/control fixtures;
  • settle policy for asynchronous backends;
  • an erase intent such as object_delete or subject_erase;
  • deterministic probes and selected profiles;
  • a privacy policy for redacted evidence.

The adapter protocol methods are hello, capabilities, prepare, ingest, settle, probe, erase, inspect, agent_query, cleanup, and close. stdout is reserved for protocol frames; adapter logs go to stderr. A capability that is not implemented must become SKIP or UNKNOWN, never a fabricated pass.

Credentialed provider runs

The checked-in *-adapter-contract evidence uses deterministic local mocks. For a real Mem0, Letta, or Zep deployment, use the opt-in credentialed provider workflow. It reads API keys from GitHub Secrets, requires --allow-network, uploads a reviewed artifact, and never commits remote evidence automatically.

Build and contribute

cargo fmt --all
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo clippy --workspace --all-targets --all-features -- -D warnings
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo test --workspace -- --test-threads=2
PYTHONPATH=python python3 -m unittest discover -s python/tests -v

Please read CONTRIBUTING.md, SECURITY.md, and their 中文版本 before opening a pull request. MemoryProof is Apache-2.0 licensed and follows the DCO sign-off workflow.

Learn more

Migration from ForgetProof

MemoryProof is the new umbrella name for the project formerly published as ForgetProof. The v0.1 evidence format and compatibility binary remain readable, while new scenarios and releases use memoryproof.dev/v1 and the memoryproof command. If you have an old GitHub Action reference, update Hughhhhcoder/ForgetProof@v0.1.0 to Hughhhhcoder/MemoryProof@v1; GitHub does not redirect Action references after a repository rename.

About

Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Hughhhhcoder/MemoryProof: Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents. · GitHub
Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

MemoryProof

Prove what your AI forgot.

English · 简体中文

CI statusLive MemoryProof matrixLatest releaseApache-2.0 license

Rust stablePython 3.11 or newerLocal-first privacySHA-256 evidencev1.0.4

🧪 Try it in 60 seconds · 🔍 See the proof · 🧭 Open the live matrix

MemoryProof: a synthetic canary leaves an observable memory graph while a verification ring and evidence ledger record the boundary

MemoryProof is an open-source memory assurance toolkit for AI agents. It tests a question that a successful DELETE response cannot answer:

Can the information still be observed through any path the backend exposes?

It creates isolated synthetic canaries, runs deterministic before/after probes, checks raw and derived boundaries, and emits an offline evidence bundle that developers can review, verify, and run in CI.

Important

DELETE 200 OK is an API response. MemoryProof tests the stronger, observable claim: the canary is no longer retrievable through the configured boundary.

Why MemoryProof?

Agent memory is rarely one table. A single fact can be copied into a raw record, summary, embedding, graph node, cache, block, or working context. A delete endpoint may remove one representation while another still answers a search query.

MemoryProof makes that gap concrete with a controlled experiment:

🧾 What an API may report🕳️ What can remain🔬 What MemoryProof records
DELETE 200 OKA summary still contains the canaryDeterministic pre/post probes
Raw row is goneAn index, vector, or graph edge still recalls itDerived-artifact inspection
One block was detachedAnother Agent path can still leak the factOptional black-box Agent query
“Delete all” was acceptedAn unrelated control subject disappeared tooIsolation and scope assertions

The goal is not to assign a vendor a simplistic score. The goal is to make what was checked, what passed, and what cannot be observed explicit.

The proof in one screen

flowchart LR
A["Scenario + synthetic canaries"] --> B["Rust runner"]
B --> C["Versioned NDJSON adapter"]
C --> D["Mem0 · Letta · Zep"]
B --> E["Before probes"]
D --> F["Erase / isolate"]
F --> G["Settle + after probes"]
E --> H["Evidence bundle"]
G --> H
H --> I["HTML · JUnit · CI · Matrix"]
Loading
  1. Seed a canary that is unique, synthetic, and safe to send to a test namespace.
  2. Prove the precondition: the target canary is observable before deletion.
  3. Erase or isolate only resources owned by this run.
  4. Wait for asynchronous writes to settle; a timeout becomes UNKNOWN, not a false pass.
  5. Probe raw, derived, Agent, and control paths with deterministic rules.
  6. Seal the evidence with sorted SHA-256 checksums and a bundle hash.

The difference it makes

❌ “Trust the endpoint”✅ MemoryProof
EvidenceA green HTTP responseA portable bundle with events, results, report, JUnit, and hashes
CoverageThe object named in the delete callEvery observable boundary advertised by the adapter
SafetyA script may delete the wrong dataSynthetic canaries plus target/control isolation
Regression testingA one-off manual checkA locked scenario in local runs and pull requests
UncertaintyMissing APIs become “probably fine”UNKNOWN, SKIP, and OUT OF SCOPE stay visible

A failure is a useful result

The repository includes a deliberately leaky backend. It deletes the raw item but leaves a derived artifact. MemoryProof must fail at the derived boundary:

status: FAIL
profile: erasure.derived
probe: target-derived-after
reason: the unique canary is still observable in a derived artifact

This is the core experience: an ambiguous memory concern becomes a named, reproducible, reviewable regression.

Quickstart

Requirements: Rust stable and Python 3.11+.

Run from source

git clone https://github.com/Hughhhhcoder/MemoryProof.git
cd MemoryProof
cargo run -- adapters list
cargo run -- run examples/reference-clean.yml

The clean reference scenario exits 0 and writes a bundle under .memoryproof/runs/. Verify and open it offline:

cargo run -- verify .memoryproof/runs/<run-id>
open .memoryproof/runs/<run-id>/report.html # macOS# xdg-open .memoryproof/runs/<run-id>/report.html # Linux

Now run the intentionally leaky backend:

cargo run -- run examples/reference-leaky.yml

It exits 1: the raw item disappears, but a derived artifact remains observable. That failure is expected and demonstrates the check is working.

Use the released binary or container

Download a platform binary from Releases, or run the GHCR image. Each binary archive includes the dependency-free Python adapter modules; if you keep them in a different location, set MEMORYPROOF_ADAPTER_ROOT to that archive's python/ directory.

docker run --rm -v "$PWD":/workspace \
ghcr.io/hughhhhcoder/memoryproof:1 \
run /workspace/examples/reference-clean.yml \
--output /workspace/.memoryproof/runs

For compatibility with the original v0.1 project, the forgetproof binary name and forgetproof Python import path remain available during the migration window.

Suites and profiles

MemoryProof is an umbrella with two suites:

SuiteWhat it answersProfiles
🧹 ErasureDid an owned memory boundary stop exposing the target?erasure.object, erasure.scope, erasure.derived, erasure.agent
🧱 IsolationCan one subject be read without leaking another subject’s memory?isolation.read, isolation.search, isolation.agent

The human-facing legacy names FP-Object, FP-Scope, FP-Derived, and FP-Agent are accepted when loading v0.1 scenarios. New scenarios use the stable names above.

Every assertion is one of:

StatusMeaning
PASSThe required observable check passed.
FAILA probe found the target, a forbidden derivative, or a scope violation.
SKIPThe selected profile is not required or is intentionally not executed.
UNKNOWNThe adapter cannot expose enough information to make the claim.
ERRORThe scenario, protocol, precondition, or execution failed.

There is no aggregate score. A capability boundary should be readable, not averaged away.

What it can—and cannot—prove

✅ It can show🚫 It does not claim
A target was observable before erase.Provider logs were deleted.
A configured API no longer returns the target.Backups or physical storage were wiped.
A visible summary, graph, index, or Agent path still leaks it.A model’s weights were unlearned.
A control subject stayed intact—or was accidentally deleted.Anything outside the adapter’s observable boundary.
The evidence bundle was not modified after creation.The identity of the person who produced the bundle.

These boundaries are part of the product, not a footnote. Reports explicitly separate proved, not observed, and out of scope.

Supported adapters

AdapterModesCoverage in v1
reference-cleanlocalFull erasure and isolation reference behavior
reference-leakylocalDeliberate derived-artifact residue
reference-overdeletelocalDeliberate control-subject deletion
mem0OSS / platform / cloudObject, scope, search, optional raw/derived inspection; async settle
lettaself-hosted / cloudTemporary Agent, core block, archival passage, scope delete, optional query
zepself-hosted / cloudEpisode, temporary user/thread, user scope, search, graph inspection

Remote access is opt-in. Credentials are read from environment variables and are never written into scenarios or evidence:

MEM0_BASE_URL=https://... MEM0_API_KEY=... \
cargo run -- run examples/mem0.yml --allow-network

Adapters communicate with the Rust runner through the versioned memoryproof.adapter/v1 NDJSON protocol. Third-party adapters can implement the same contract without linking to the Rust binary.

Evidence you can review in a pull request

Each run emits an offline-readable package:

manifest.json format, run, adapter mode, protocol, and declared files
scenario.lock.json redacted, frozen scenario snapshot
scenario.lock.yml the same frozen snapshot in the requested YAML form
events.ndjson ordered method journal with safe request IDs
results.json machine-readable assertions and profile states
report.html single-file bilingual report
junit.xml CI-native test report
checksums.sha256 per-file SHA-256 integrity list
bundle.hash hash of the checksum manifest

Use memoryproof doctor --allow-network only when a provider endpoint is intentionally reachable, and use memoryproof expand ... --allow-network only when probe generation is configured to call a non-loopback OpenAI-compatible endpoint. The generated probes are frozen before a run; the model never makes the final pass/fail decision.

By default, payloads are reduced to hashes, lengths, types, and safe structural summaries. --allow-network authorizes a remote backend; it does not disable redaction.

GitHub Actions

The repository ships a Docker-based action that uploads the evidence bundle even when the test fails:

name: Memory assuranceon:
pull_request:
jobs:
memoryproof:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: Hughhhhcoder/MemoryProof@v1with:
scenario: examples/reference-clean.yml

Use a leaky or vendor-specific scenario in a separate job when you want the PR to fail on a known regression. The action exposes bundle-path, status, and exit-code outputs and writes a short job summary.

Scenario and adapter contract

The stable scenario API is memoryproof.dev/v1. A scenario contains:

  • an adapter and non-sensitive configuration references;
  • isolated target and control subjects;
  • synthetic target/control fixtures;
  • settle policy for asynchronous backends;
  • an erase intent such as object_delete or subject_erase;
  • deterministic probes and selected profiles;
  • a privacy policy for redacted evidence.

The adapter protocol methods are hello, capabilities, prepare, ingest, settle, probe, erase, inspect, agent_query, cleanup, and close. stdout is reserved for protocol frames; adapter logs go to stderr. A capability that is not implemented must become SKIP or UNKNOWN, never a fabricated pass.

Credentialed provider runs

The checked-in *-adapter-contract evidence uses deterministic local mocks. For a real Mem0, Letta, or Zep deployment, use the opt-in credentialed provider workflow. It reads API keys from GitHub Secrets, requires --allow-network, uploads a reviewed artifact, and never commits remote evidence automatically.

Build and contribute

cargo fmt --all
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo clippy --workspace --all-targets --all-features -- -D warnings
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo test --workspace -- --test-threads=2
PYTHONPATH=python python3 -m unittest discover -s python/tests -v

Please read CONTRIBUTING.md, SECURITY.md, and their 中文版本 before opening a pull request. MemoryProof is Apache-2.0 licensed and follows the DCO sign-off workflow.

Learn more

Migration from ForgetProof

MemoryProof is the new umbrella name for the project formerly published as ForgetProof. The v0.1 evidence format and compatibility binary remain readable, while new scenarios and releases use memoryproof.dev/v1 and the memoryproof command. If you have an old GitHub Action reference, update Hughhhhcoder/ForgetProof@v0.1.0 to Hughhhhcoder/MemoryProof@v1; GitHub does not redirect Action references after a repository rename.

About

Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - Hughhhhcoder/MemoryProof: Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents. · GitHub
Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

MemoryProof

Prove what your AI forgot.

English · 简体中文

CI statusLive MemoryProof matrixLatest releaseApache-2.0 license

Rust stablePython 3.11 or newerLocal-first privacySHA-256 evidencev1.0.4

🧪 Try it in 60 seconds · 🔍 See the proof · 🧭 Open the live matrix

MemoryProof: a synthetic canary leaves an observable memory graph while a verification ring and evidence ledger record the boundary

MemoryProof is an open-source memory assurance toolkit for AI agents. It tests a question that a successful DELETE response cannot answer:

Can the information still be observed through any path the backend exposes?

It creates isolated synthetic canaries, runs deterministic before/after probes, checks raw and derived boundaries, and emits an offline evidence bundle that developers can review, verify, and run in CI.

Important

DELETE 200 OK is an API response. MemoryProof tests the stronger, observable claim: the canary is no longer retrievable through the configured boundary.

Why MemoryProof?

Agent memory is rarely one table. A single fact can be copied into a raw record, summary, embedding, graph node, cache, block, or working context. A delete endpoint may remove one representation while another still answers a search query.

MemoryProof makes that gap concrete with a controlled experiment:

🧾 What an API may report🕳️ What can remain🔬 What MemoryProof records
DELETE 200 OKA summary still contains the canaryDeterministic pre/post probes
Raw row is goneAn index, vector, or graph edge still recalls itDerived-artifact inspection
One block was detachedAnother Agent path can still leak the factOptional black-box Agent query
“Delete all” was acceptedAn unrelated control subject disappeared tooIsolation and scope assertions

The goal is not to assign a vendor a simplistic score. The goal is to make what was checked, what passed, and what cannot be observed explicit.

The proof in one screen

flowchart LR
A["Scenario + synthetic canaries"] --> B["Rust runner"]
B --> C["Versioned NDJSON adapter"]
C --> D["Mem0 · Letta · Zep"]
B --> E["Before probes"]
D --> F["Erase / isolate"]
F --> G["Settle + after probes"]
E --> H["Evidence bundle"]
G --> H
H --> I["HTML · JUnit · CI · Matrix"]
Loading
  1. Seed a canary that is unique, synthetic, and safe to send to a test namespace.
  2. Prove the precondition: the target canary is observable before deletion.
  3. Erase or isolate only resources owned by this run.
  4. Wait for asynchronous writes to settle; a timeout becomes UNKNOWN, not a false pass.
  5. Probe raw, derived, Agent, and control paths with deterministic rules.
  6. Seal the evidence with sorted SHA-256 checksums and a bundle hash.

The difference it makes

❌ “Trust the endpoint”✅ MemoryProof
EvidenceA green HTTP responseA portable bundle with events, results, report, JUnit, and hashes
CoverageThe object named in the delete callEvery observable boundary advertised by the adapter
SafetyA script may delete the wrong dataSynthetic canaries plus target/control isolation
Regression testingA one-off manual checkA locked scenario in local runs and pull requests
UncertaintyMissing APIs become “probably fine”UNKNOWN, SKIP, and OUT OF SCOPE stay visible

A failure is a useful result

The repository includes a deliberately leaky backend. It deletes the raw item but leaves a derived artifact. MemoryProof must fail at the derived boundary:

status: FAIL
profile: erasure.derived
probe: target-derived-after
reason: the unique canary is still observable in a derived artifact

This is the core experience: an ambiguous memory concern becomes a named, reproducible, reviewable regression.

Quickstart

Requirements: Rust stable and Python 3.11+.

Run from source

git clone https://github.com/Hughhhhcoder/MemoryProof.git
cd MemoryProof
cargo run -- adapters list
cargo run -- run examples/reference-clean.yml

The clean reference scenario exits 0 and writes a bundle under .memoryproof/runs/. Verify and open it offline:

cargo run -- verify .memoryproof/runs/<run-id>
open .memoryproof/runs/<run-id>/report.html # macOS# xdg-open .memoryproof/runs/<run-id>/report.html # Linux

Now run the intentionally leaky backend:

cargo run -- run examples/reference-leaky.yml

It exits 1: the raw item disappears, but a derived artifact remains observable. That failure is expected and demonstrates the check is working.

Use the released binary or container

Download a platform binary from Releases, or run the GHCR image. Each binary archive includes the dependency-free Python adapter modules; if you keep them in a different location, set MEMORYPROOF_ADAPTER_ROOT to that archive's python/ directory.

docker run --rm -v "$PWD":/workspace \
ghcr.io/hughhhhcoder/memoryproof:1 \
run /workspace/examples/reference-clean.yml \
--output /workspace/.memoryproof/runs

For compatibility with the original v0.1 project, the forgetproof binary name and forgetproof Python import path remain available during the migration window.

Suites and profiles

MemoryProof is an umbrella with two suites:

SuiteWhat it answersProfiles
🧹 ErasureDid an owned memory boundary stop exposing the target?erasure.object, erasure.scope, erasure.derived, erasure.agent
🧱 IsolationCan one subject be read without leaking another subject’s memory?isolation.read, isolation.search, isolation.agent

The human-facing legacy names FP-Object, FP-Scope, FP-Derived, and FP-Agent are accepted when loading v0.1 scenarios. New scenarios use the stable names above.

Every assertion is one of:

StatusMeaning
PASSThe required observable check passed.
FAILA probe found the target, a forbidden derivative, or a scope violation.
SKIPThe selected profile is not required or is intentionally not executed.
UNKNOWNThe adapter cannot expose enough information to make the claim.
ERRORThe scenario, protocol, precondition, or execution failed.

There is no aggregate score. A capability boundary should be readable, not averaged away.

What it can—and cannot—prove

✅ It can show🚫 It does not claim
A target was observable before erase.Provider logs were deleted.
A configured API no longer returns the target.Backups or physical storage were wiped.
A visible summary, graph, index, or Agent path still leaks it.A model’s weights were unlearned.
A control subject stayed intact—or was accidentally deleted.Anything outside the adapter’s observable boundary.
The evidence bundle was not modified after creation.The identity of the person who produced the bundle.

These boundaries are part of the product, not a footnote. Reports explicitly separate proved, not observed, and out of scope.

Supported adapters

AdapterModesCoverage in v1
reference-cleanlocalFull erasure and isolation reference behavior
reference-leakylocalDeliberate derived-artifact residue
reference-overdeletelocalDeliberate control-subject deletion
mem0OSS / platform / cloudObject, scope, search, optional raw/derived inspection; async settle
lettaself-hosted / cloudTemporary Agent, core block, archival passage, scope delete, optional query
zepself-hosted / cloudEpisode, temporary user/thread, user scope, search, graph inspection

Remote access is opt-in. Credentials are read from environment variables and are never written into scenarios or evidence:

MEM0_BASE_URL=https://... MEM0_API_KEY=... \
cargo run -- run examples/mem0.yml --allow-network

Adapters communicate with the Rust runner through the versioned memoryproof.adapter/v1 NDJSON protocol. Third-party adapters can implement the same contract without linking to the Rust binary.

Evidence you can review in a pull request

Each run emits an offline-readable package:

manifest.json format, run, adapter mode, protocol, and declared files
scenario.lock.json redacted, frozen scenario snapshot
scenario.lock.yml the same frozen snapshot in the requested YAML form
events.ndjson ordered method journal with safe request IDs
results.json machine-readable assertions and profile states
report.html single-file bilingual report
junit.xml CI-native test report
checksums.sha256 per-file SHA-256 integrity list
bundle.hash hash of the checksum manifest

Use memoryproof doctor --allow-network only when a provider endpoint is intentionally reachable, and use memoryproof expand ... --allow-network only when probe generation is configured to call a non-loopback OpenAI-compatible endpoint. The generated probes are frozen before a run; the model never makes the final pass/fail decision.

By default, payloads are reduced to hashes, lengths, types, and safe structural summaries. --allow-network authorizes a remote backend; it does not disable redaction.

GitHub Actions

The repository ships a Docker-based action that uploads the evidence bundle even when the test fails:

name: Memory assuranceon:
pull_request:
jobs:
memoryproof:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: Hughhhhcoder/MemoryProof@v1with:
scenario: examples/reference-clean.yml

Use a leaky or vendor-specific scenario in a separate job when you want the PR to fail on a known regression. The action exposes bundle-path, status, and exit-code outputs and writes a short job summary.

Scenario and adapter contract

The stable scenario API is memoryproof.dev/v1. A scenario contains:

  • an adapter and non-sensitive configuration references;
  • isolated target and control subjects;
  • synthetic target/control fixtures;
  • settle policy for asynchronous backends;
  • an erase intent such as object_delete or subject_erase;
  • deterministic probes and selected profiles;
  • a privacy policy for redacted evidence.

The adapter protocol methods are hello, capabilities, prepare, ingest, settle, probe, erase, inspect, agent_query, cleanup, and close. stdout is reserved for protocol frames; adapter logs go to stderr. A capability that is not implemented must become SKIP or UNKNOWN, never a fabricated pass.

Credentialed provider runs

The checked-in *-adapter-contract evidence uses deterministic local mocks. For a real Mem0, Letta, or Zep deployment, use the opt-in credentialed provider workflow. It reads API keys from GitHub Secrets, requires --allow-network, uploads a reviewed artifact, and never commits remote evidence automatically.

Build and contribute

cargo fmt --all
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo clippy --workspace --all-targets --all-features -- -D warnings
CARGO_NET_OFFLINE=true CARGO_TARGET_DIR=/tmp/memoryproof-target \
cargo test --workspace -- --test-threads=2
PYTHONPATH=python python3 -m unittest discover -s python/tests -v

Please read CONTRIBUTING.md, SECURITY.md, and their 中文版本 before opening a pull request. MemoryProof is Apache-2.0 licensed and follows the DCO sign-off workflow.

Learn more

Migration from ForgetProof

MemoryProof is the new umbrella name for the project formerly published as ForgetProof. The v0.1 evidence format and compatibility binary remain readable, while new scenarios and releases use memoryproof.dev/v1 and the memoryproof command. If you have an old GitHub Action reference, update Hughhhhcoder/ForgetProof@v0.1.0 to Hughhhhcoder/MemoryProof@v1; GitHub does not redirect Action references after a repository rename.

About

Test what your AI remembers. Prove what it forgot. Deterministic erasure and memory assurance tests for AI agents.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages