A privacy-first, scope-isolated local memory store for AI agents, with a CLI and an MCP server.
Project description
Memory Unlocked
A privacy-first, scoped local memory for AI agents. Memory Unlocked gives agents durable, project-scoped memory without leaking secrets or letting one project's context bleed into another.
It is installable today as a dependency-free Python package with:
- durable local JSONL and SQLite stores,
- a practical CLI (
memory-unlocked), - a dependency-free MCP stdio server (
memory-unlocked-mcp), - lifecycle/governance commands for candidate review, archival, and forgetting,
- token-budgeted context assembly and offline recall/privacy evals,
- a deterministic semantic graph layer for typed agent context,
- audit events for writes, recalls, updates, forgets, and rejections,
- tests and CI for the privacy/scope guarantees.
The core stays deliberately small so teams can audit it, ship it locally, and adapt it to their own database, vector index, or hosted service later.
v1 local-isolation contract: every installation starts with an empty local store. It does not include sample memories, connect to a maintainer database, or share data with any other installation. Each user owns their own JSONL/SQLite files. See the student quickstart.
Why this exists
Long-running agents need to remember things between sessions — decisions, conventions, gotchas, references. But naive "just dump everything into a vector store" memory has two failure modes:
- Secret leakage — credentials, tokens, customer data, and PII end up persisted and later surfaced in unrelated contexts.
- Scope bleed — memory from Project A contaminates answers about Project B.
Memory Unlocked treats both as first-class concerns. Every memory is scoped to a namespace, every write passes a redaction/policy gate, and recall is filtered by scope before anything reaches the model.
Who it is for
- Builders of multi-project agent systems who need isolated memory per scope.
- Teams that want auditable, reviewable writes instead of a black-box store.
- Anyone who wants a readable reference architecture they can port to their own database, vector index, or MCP server.
Quickstart
pipx install memory-unlocked
# or: uv tool install memory-unlocked
From source:
git clone https://github.com/josenaicipa/memory-unlocked.git
cd memory-unlocked
python -m pip install -e '.[dev]'
python -m pytest -q
Write and recall a memory from the CLI:
memory-unlocked --path ./mem init
memory-unlocked --path ./mem write \
--tenant acme --project billing \
--title "Refunds run through the async queue" \
--body "Refund requests are enqueued and processed by a worker, not inline." \
--source docs/refunds.md \
--tags billing,architecture
memory-unlocked --path ./mem context \
--tenant acme --project billing --query refund --token-budget 200
Review candidate memories and run governance/eval checks:
memory-unlocked --path ./mem write \
--tenant acme --project billing \
--title "Candidate fact" --body "Needs human approval." \
--source docs/review.md --status candidate
memory-unlocked --path ./mem review --tenant acme --project billing
memory-unlocked --path ./mem audit --json
memory-unlocked eval examples/evalset/basic.json
Use SQLite for a more production-like local backend:
memory-unlocked --backend sqlite --path ./mem-sqlite init
memory-unlocked --backend sqlite --path ./mem-sqlite doctor
Extract semantic graph context and the public-safe graph reports:
memory-unlocked --path ./mem write \
--tenant acme --project billing \
--title "Graph demo" \
--body "Billing service owns refunds. Worker depends on Redis." \
--source docs/graph.md
memory-unlocked --path ./mem graph-context \
--tenant acme --project billing --token-budget 200
memory-unlocked --path ./mem graph-temporal \
--tenant acme --project billing --json
memory-unlocked --path ./mem graph-lineage \
--tenant acme --project billing --json
memory-unlocked --path ./mem graph-effective-backend \
--tenant acme --project billing --json
The extra graph reports are read-only and public-safe: graph-lineage emits
opaque handles instead of raw memory ids/source refs, graph-temporal derives
relation validity from source-memory timestamps, and graph-effective-backend
returns the scoped graph as the canonical memory_unlocked backend payload for
agent/MCP consumers.
Run the MCP server for an agent runner:
MEMORY_UNLOCKED_TENANT=acme \
MEMORY_UNLOCKED_PROJECT=billing \
MEMORY_UNLOCKED_HOME="$HOME/.memory_unlocked" \
memory-unlocked-mcp
Use the core package directly:
from memory_unlocked import (
Memory, Source, Namespace, MemoryStore, ContextAssembler, PolicyError,
)
store = MemoryStore()
store.add(Memory(
namespace=Namespace("acme", "billing"),
title="Refunds run through the async queue",
body="Refund requests are enqueued and processed by a worker, not inline.",
source=Source(kind="doc", ref="docs/refunds.md"),
tags=["billing", "architecture"],
))
# Recall is scope-filtered: only memories in the requested namespace come back.
assembler = ContextAssembler(store)
context = assembler.assemble(Namespace("acme", "billing"), query="refund")
print(context)
Writes that contain obvious secrets, or that lack a verifiable source, are rejected at the gate:
store.add(Memory(
namespace=Namespace("acme", "billing"),
title="API key",
body="AWS_SECRET_ACCESS_KEY=AKIA...", # raises PolicyError
source=Source(kind="doc", ref="notes.md"),
))
Core concepts
| Concept | What it is |
|---|---|
| Memory | One atomic fact, with a title, body, tags, and a required source. |
| Source | Provenance for a memory (a file, URL, ticket, or run id). No source → no write. |
| Namespace | A tenant / project scope. Recall never crosses namespaces. |
| Policy / redaction | A gate every write passes before it is stored. |
| Context assembler | Builds a scope-filtered, ranked context block for the agent. |
| Event | An append-only record of writes and recalls for auditability. |
Privacy-first guardrails
These are the defaults, not opt-ins:
- Never store secrets. Writes are scanned for credential-shaped content and
rejected. See
docs/privacy-and-redaction.md. - Every memory needs a source. Unattributed claims are rejected so memory stays verifiable.
- Scope isolation by default. A recall in
tenant/projectcannot return a memory written under any other scope. - No raw transcripts, no PII, no customer/lead data. Store durable, stable facts — not transient progress or personal information.
- Writes are reviewable. Every write and recall emits an event so you can audit what the memory fabric learned and surfaced.
Documentation
- Install & CLI — package install, JSONL/SQLite stores, CLI commands.
- Student quickstart — isolated local setup starting with zero memories.
- Hermes / MCP — run the MCP server and bind it to a project scope.
- Semantic graph — typed relation extraction and graph context.
- Threat model — public security boundaries and residual risk.
- Release checklist — repeatable PyPI/release process.
- Architecture — components, data flow, scope policy.
- Privacy & redaction — what never to store and the write-review flow.
- Schema — the canonical memory, source, link, and event shapes.
- Integrations — MCP / HTTP / CLI patterns for agent runners.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file memory_unlocked-1.0.0.tar.gz.
File metadata
- Download URL: memory_unlocked-1.0.0.tar.gz
- Upload date:
- Size: 79.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9aaf95e374b57a4706431e29a0e8bdf5c4411bba15861d3f1beaa4a0c7cea0da
|
|
| MD5 |
3dca51786fd03d34122f7f0cb8b7e36a
|
|
| BLAKE2b-256 |
1d17cb37161977d833ec28bd7382e567936b38053b309d8ecac94d5690cf48d3
|
Provenance
The following attestation bundles were made for memory_unlocked-1.0.0.tar.gz:
Publisher:
publish.yml on josenaicipa/memory-unlocked
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
memory_unlocked-1.0.0.tar.gz -
Subject digest:
9aaf95e374b57a4706431e29a0e8bdf5c4411bba15861d3f1beaa4a0c7cea0da - Sigstore transparency entry: 2187107493
- Sigstore integration time:
-
Permalink:
josenaicipa/memory-unlocked@5f3c38c076251a2e3d5abc3307904ed88cba4db1 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/josenaicipa
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5f3c38c076251a2e3d5abc3307904ed88cba4db1 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file memory_unlocked-1.0.0-py3-none-any.whl.
File metadata
- Download URL: memory_unlocked-1.0.0-py3-none-any.whl
- Upload date:
- Size: 53.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4c555396a024999551a6c4ea90b672d9e41f8dfbc4df3392b6a42aa39bc26c34
|
|
| MD5 |
b60a651bdce283280b226078e3bf9eb5
|
|
| BLAKE2b-256 |
9597d556a0b8932be7c59c9f110520a8f35ca31be962c931546f0dd101e36a7b
|
Provenance
The following attestation bundles were made for memory_unlocked-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on josenaicipa/memory-unlocked
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
memory_unlocked-1.0.0-py3-none-any.whl -
Subject digest:
4c555396a024999551a6c4ea90b672d9e41f8dfbc4df3392b6a42aa39bc26c34 - Sigstore transparency entry: 2187107538
- Sigstore integration time:
-
Permalink:
josenaicipa/memory-unlocked@5f3c38c076251a2e3d5abc3307904ed88cba4db1 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/josenaicipa
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5f3c38c076251a2e3d5abc3307904ed88cba4db1 -
Trigger Event:
workflow_dispatch
-
Statement type: