memory-unlocked 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- memory_unlocked-1.0.0/CHANGELOG.md +69 -0
- memory_unlocked-1.0.0/CODE_OF_CONDUCT.md +7 -0
- memory_unlocked-1.0.0/CONTRIBUTING.md +28 -0
- memory_unlocked-1.0.0/LICENSE +21 -0
- memory_unlocked-1.0.0/MANIFEST.in +10 -0
- memory_unlocked-1.0.0/PKG-INFO +247 -0
- memory_unlocked-1.0.0/README.md +221 -0
- memory_unlocked-1.0.0/ROADMAP.md +41 -0
- memory_unlocked-1.0.0/SECURITY.md +23 -0
- memory_unlocked-1.0.0/docs/architecture.md +86 -0
- memory_unlocked-1.0.0/docs/graph.md +112 -0
- memory_unlocked-1.0.0/docs/hermes.md +72 -0
- memory_unlocked-1.0.0/docs/install.md +98 -0
- memory_unlocked-1.0.0/docs/integrations.md +140 -0
- memory_unlocked-1.0.0/docs/privacy-and-redaction.md +93 -0
- memory_unlocked-1.0.0/docs/release-checklist.md +67 -0
- memory_unlocked-1.0.0/docs/schema.md +88 -0
- memory_unlocked-1.0.0/docs/student-quickstart.md +91 -0
- memory_unlocked-1.0.0/docs/threat-model.md +33 -0
- memory_unlocked-1.0.0/examples/evalset/README.md +13 -0
- memory_unlocked-1.0.0/examples/evalset/basic.json +28 -0
- memory_unlocked-1.0.0/examples/graph-basic/README.md +26 -0
- memory_unlocked-1.0.0/examples/hermes-basic/README.md +36 -0
- memory_unlocked-1.0.0/examples/sqlite-production/README.md +24 -0
- memory_unlocked-1.0.0/examples/team-memory/README.md +19 -0
- memory_unlocked-1.0.0/memory_unlocked/__init__.py +69 -0
- memory_unlocked-1.0.0/memory_unlocked/__main__.py +8 -0
- memory_unlocked-1.0.0/memory_unlocked/assembler.py +122 -0
- memory_unlocked-1.0.0/memory_unlocked/cli.py +502 -0
- memory_unlocked-1.0.0/memory_unlocked/evaluation.py +144 -0
- memory_unlocked-1.0.0/memory_unlocked/graph.py +570 -0
- memory_unlocked-1.0.0/memory_unlocked/mcp_server.py +458 -0
- memory_unlocked-1.0.0/memory_unlocked/models.py +145 -0
- memory_unlocked-1.0.0/memory_unlocked/ops.py +637 -0
- memory_unlocked-1.0.0/memory_unlocked/persistence.py +140 -0
- memory_unlocked-1.0.0/memory_unlocked/policy.py +208 -0
- memory_unlocked-1.0.0/memory_unlocked/ranking.py +208 -0
- memory_unlocked-1.0.0/memory_unlocked/render.py +91 -0
- memory_unlocked-1.0.0/memory_unlocked/serialize.py +88 -0
- memory_unlocked-1.0.0/memory_unlocked/sqlite_store.py +181 -0
- memory_unlocked-1.0.0/memory_unlocked/store.py +295 -0
- memory_unlocked-1.0.0/memory_unlocked.egg-info/PKG-INFO +247 -0
- memory_unlocked-1.0.0/memory_unlocked.egg-info/SOURCES.txt +59 -0
- memory_unlocked-1.0.0/memory_unlocked.egg-info/dependency_links.txt +1 -0
- memory_unlocked-1.0.0/memory_unlocked.egg-info/entry_points.txt +3 -0
- memory_unlocked-1.0.0/memory_unlocked.egg-info/requires.txt +4 -0
- memory_unlocked-1.0.0/memory_unlocked.egg-info/top_level.txt +1 -0
- memory_unlocked-1.0.0/pyproject.toml +48 -0
- memory_unlocked-1.0.0/scripts/smoke_release.py +202 -0
- memory_unlocked-1.0.0/setup.cfg +4 -0
- memory_unlocked-1.0.0/tests/test_assembler.py +90 -0
- memory_unlocked-1.0.0/tests/test_cli.py +148 -0
- memory_unlocked-1.0.0/tests/test_graph.py +212 -0
- memory_unlocked-1.0.0/tests/test_graph_public_surfaces.py +87 -0
- memory_unlocked-1.0.0/tests/test_mcp_server.py +282 -0
- memory_unlocked-1.0.0/tests/test_namespace_isolation.py +47 -0
- memory_unlocked-1.0.0/tests/test_persistence.py +153 -0
- memory_unlocked-1.0.0/tests/test_policy.py +121 -0
- memory_unlocked-1.0.0/tests/test_product_features.py +103 -0
- memory_unlocked-1.0.0/tests/test_release_contract.py +48 -0
- memory_unlocked-1.0.0/tests/test_serialize.py +81 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0 - Stable Local MCP for Students
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Stable local-per-installation contract: every new store starts with zero memories and has no connection to any maintainer or other student store.
|
|
8
|
+
- `memory-unlocked doctor` for version, backend, writability, scope, and aggregate-count diagnostics without exposing memory bodies.
|
|
9
|
+
- Student quickstart covering isolated SQLite setup, MCP binding, backup, restore, and deletion.
|
|
10
|
+
- Release-artifact smoke that verifies an empty initial store, nine MCP tools, same-scope recall, and cross-project isolation.
|
|
11
|
+
- MCP protocol negotiation through the official `2025-11-25` version while retaining support for `2024-11-05`, `2025-03-26`, and `2025-06-18` clients.
|
|
12
|
+
- Fail-closed JSON-RPC validation for malformed messages, invalid params, and notifications that must never receive responses.
|
|
13
|
+
- Linux Python 3.9-3.13, macOS Python 3.11, and Windows Python 3.11 CI coverage.
|
|
14
|
+
- Verified wheel/sdist publication workflow with checksums, GitHub release assets, and PyPI trusted publishing.
|
|
15
|
+
- Split, least-privilege release jobs with SHA-pinned GitHub Actions and a PyPI job that receives only verified wheel/sdist artifacts.
|
|
16
|
+
|
|
17
|
+
### Security
|
|
18
|
+
|
|
19
|
+
- The public package ships no database, memory export, environment file, private namespace, or hosted-service connection.
|
|
20
|
+
- Tenant/project remain process-bound MCP configuration and are never model-controlled tool arguments.
|
|
21
|
+
|
|
22
|
+
## 0.3.1 - Semantic Graph Layer
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- Deterministic public-safe semantic graph extraction.
|
|
27
|
+
- Relation vocabulary: `owns`, `routes_to`, `separate_from`, `uses_provider`, `fallback_provider`, `deploys_to`, `source_of_truth_for`, `sensitive_write`, `depends_on`, `supersedes`.
|
|
28
|
+
- Spanish/Spanglish extraction patterns including `usa`, `depende de`, `fuente de verdad`, `no mezclar`, `fallback a`.
|
|
29
|
+
- Nearest-subject fallback binding for `fallback_provider`.
|
|
30
|
+
- CLI commands: `graph` and `graph-context`.
|
|
31
|
+
- MCP tool: `memory_graph_context`.
|
|
32
|
+
- Graph docs and public example.
|
|
33
|
+
|
|
34
|
+
### Security
|
|
35
|
+
|
|
36
|
+
- Graph reports/context omit memory bodies.
|
|
37
|
+
- Entity/relation names pass secret/PII filters before emission.
|
|
38
|
+
- Graph extraction remains namespace-scoped and deterministic.
|
|
39
|
+
|
|
40
|
+
## 0.3.0 - Productization Preview
|
|
41
|
+
|
|
42
|
+
Memory Unlocked moves from an installable skeleton to a product-grade local agent memory toolkit.
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- SQLite backend via `--backend sqlite` / `MEMORY_UNLOCKED_BACKEND=sqlite`.
|
|
47
|
+
- Lifecycle states: `candidate`, `active`, `archived`, `rejected`.
|
|
48
|
+
- Governance commands: `audit`, `review`, `status`, `forget`.
|
|
49
|
+
- Token-budgeted context assembly via CLI `context --token-budget` and MCP `memory_context`.
|
|
50
|
+
- Offline eval harness: `memory-unlocked eval examples/evalset/basic.json`.
|
|
51
|
+
- Safer context rendering that treats memories as data, not instructions.
|
|
52
|
+
- Size limits and PII handling policy knobs.
|
|
53
|
+
- Public examples for Hermes, team memory, SQLite production, and evalsets.
|
|
54
|
+
|
|
55
|
+
### Security
|
|
56
|
+
|
|
57
|
+
- Recall logs redact secret-shaped queries.
|
|
58
|
+
- Rejected writes never persist the rejected content.
|
|
59
|
+
- Memory bodies are omitted from governance reports.
|
|
60
|
+
|
|
61
|
+
## 0.2.0
|
|
62
|
+
|
|
63
|
+
- CLI and MCP server.
|
|
64
|
+
- Durable JSONL storage.
|
|
65
|
+
- Secret policy gate and public docs.
|
|
66
|
+
|
|
67
|
+
## 0.1.0
|
|
68
|
+
|
|
69
|
+
- Public architecture skeleton, schema, examples, and tests.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
Be respectful, practical, and security-minded.
|
|
4
|
+
|
|
5
|
+
This project exists to help people build safer AI-agent memory. Contributions that harass people, expose private data, add backdoors, or intentionally weaken privacy/security are not welcome.
|
|
6
|
+
|
|
7
|
+
If you see a problem, use the repository's GitHub moderation/reporting tools or contact the maintainers through GitHub.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for improving Memory Unlocked.
|
|
4
|
+
|
|
5
|
+
## Local setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
python -m venv .venv
|
|
9
|
+
. .venv/bin/activate
|
|
10
|
+
python -m pip install -e '.[dev]'
|
|
11
|
+
python -m pytest -q
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Rules
|
|
15
|
+
|
|
16
|
+
1. Never commit `.env`, credentials, tokens, private customer data, internal domains, or realistic-looking secrets.
|
|
17
|
+
2. Add tests for policy, namespace isolation, persistence, and CLI/MCP behavior when touching those areas.
|
|
18
|
+
3. Keep core dependencies minimal; stdlib is preferred.
|
|
19
|
+
4. Public docs must use placeholders like `acme`, `billing`, `MEMORY_UNLOCKED_HOME`, and `[REDACTED]`.
|
|
20
|
+
5. Do not add telemetry or network calls to the core package without a clear opt-in.
|
|
21
|
+
|
|
22
|
+
## Pull request checklist
|
|
23
|
+
|
|
24
|
+
- [ ] `python -m pytest -q` passes
|
|
25
|
+
- [ ] `python -m compileall -q memory_unlocked` passes
|
|
26
|
+
- [ ] examples still use fake/public data only
|
|
27
|
+
- [ ] no generated caches or build artifacts committed
|
|
28
|
+
- [ ] changelog updated for user-visible changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Memory Unlocked contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
include CHANGELOG.md
|
|
2
|
+
include CODE_OF_CONDUCT.md
|
|
3
|
+
include CONTRIBUTING.md
|
|
4
|
+
include LICENSE
|
|
5
|
+
include README.md
|
|
6
|
+
include ROADMAP.md
|
|
7
|
+
include SECURITY.md
|
|
8
|
+
recursive-include docs *.md
|
|
9
|
+
recursive-include examples *.md *.json
|
|
10
|
+
recursive-include scripts *.py
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: memory-unlocked
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A privacy-first, scope-isolated local memory store for AI agents, with a CLI and an MCP server.
|
|
5
|
+
Author: Memory Unlocked contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Documentation, https://github.com/josenaicipa/memory-unlocked/tree/main/docs
|
|
8
|
+
Project-URL: Source, https://github.com/josenaicipa/memory-unlocked
|
|
9
|
+
Keywords: ai,agents,memory,privacy,namespace,mcp
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
24
|
+
Requires-Dist: ruff<1,>=0.14; extra == "dev"
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# Memory Unlocked
|
|
28
|
+
|
|
29
|
+
A **privacy-first, scoped local memory** for AI agents. Memory Unlocked gives
|
|
30
|
+
agents durable, project-scoped memory without leaking secrets or letting one
|
|
31
|
+
project's context bleed into another.
|
|
32
|
+
|
|
33
|
+
It is installable today as a dependency-free Python package with:
|
|
34
|
+
|
|
35
|
+
- durable local JSONL and SQLite stores,
|
|
36
|
+
- a practical CLI (`memory-unlocked`),
|
|
37
|
+
- a dependency-free MCP stdio server (`memory-unlocked-mcp`),
|
|
38
|
+
- lifecycle/governance commands for candidate review, archival, and forgetting,
|
|
39
|
+
- token-budgeted context assembly and offline recall/privacy evals,
|
|
40
|
+
- a deterministic semantic graph layer for typed agent context,
|
|
41
|
+
- audit events for writes, recalls, updates, forgets, and rejections,
|
|
42
|
+
- tests and CI for the privacy/scope guarantees.
|
|
43
|
+
|
|
44
|
+
The core stays deliberately small so teams can audit it, ship it locally, and
|
|
45
|
+
adapt it to their own database, vector index, or hosted service later.
|
|
46
|
+
|
|
47
|
+
**v1 local-isolation contract:** every installation starts with an empty local
|
|
48
|
+
store. It does not include sample memories, connect to a maintainer database, or
|
|
49
|
+
share data with any other installation. Each user owns their own JSONL/SQLite
|
|
50
|
+
files. See the [student quickstart](docs/student-quickstart.md).
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Why this exists
|
|
55
|
+
|
|
56
|
+
Long-running agents need to remember things between sessions — decisions,
|
|
57
|
+
conventions, gotchas, references. But naive "just dump everything into a vector
|
|
58
|
+
store" memory has two failure modes:
|
|
59
|
+
|
|
60
|
+
1. **Secret leakage** — credentials, tokens, customer data, and PII end up
|
|
61
|
+
persisted and later surfaced in unrelated contexts.
|
|
62
|
+
2. **Scope bleed** — memory from Project A contaminates answers about Project B.
|
|
63
|
+
|
|
64
|
+
Memory Unlocked treats both as first-class concerns. Every memory is scoped to a
|
|
65
|
+
namespace, every write passes a redaction/policy gate, and recall is filtered by
|
|
66
|
+
scope before anything reaches the model.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Who it is for
|
|
71
|
+
|
|
72
|
+
- Builders of multi-project agent systems who need **isolated** memory per scope.
|
|
73
|
+
- Teams that want **auditable, reviewable** writes instead of a black-box store.
|
|
74
|
+
- Anyone who wants a **readable reference architecture** they can port to their
|
|
75
|
+
own database, vector index, or MCP server.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Quickstart
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pipx install memory-unlocked
|
|
83
|
+
# or: uv tool install memory-unlocked
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
From source:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
git clone https://github.com/josenaicipa/memory-unlocked.git
|
|
90
|
+
cd memory-unlocked
|
|
91
|
+
python -m pip install -e '.[dev]'
|
|
92
|
+
python -m pytest -q
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Write and recall a memory from the CLI:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
memory-unlocked --path ./mem init
|
|
99
|
+
memory-unlocked --path ./mem write \
|
|
100
|
+
--tenant acme --project billing \
|
|
101
|
+
--title "Refunds run through the async queue" \
|
|
102
|
+
--body "Refund requests are enqueued and processed by a worker, not inline." \
|
|
103
|
+
--source docs/refunds.md \
|
|
104
|
+
--tags billing,architecture
|
|
105
|
+
memory-unlocked --path ./mem context \
|
|
106
|
+
--tenant acme --project billing --query refund --token-budget 200
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Review candidate memories and run governance/eval checks:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
memory-unlocked --path ./mem write \
|
|
113
|
+
--tenant acme --project billing \
|
|
114
|
+
--title "Candidate fact" --body "Needs human approval." \
|
|
115
|
+
--source docs/review.md --status candidate
|
|
116
|
+
memory-unlocked --path ./mem review --tenant acme --project billing
|
|
117
|
+
memory-unlocked --path ./mem audit --json
|
|
118
|
+
memory-unlocked eval examples/evalset/basic.json
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Use SQLite for a more production-like local backend:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
memory-unlocked --backend sqlite --path ./mem-sqlite init
|
|
125
|
+
memory-unlocked --backend sqlite --path ./mem-sqlite doctor
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Extract semantic graph context and the public-safe graph reports:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
memory-unlocked --path ./mem write \
|
|
132
|
+
--tenant acme --project billing \
|
|
133
|
+
--title "Graph demo" \
|
|
134
|
+
--body "Billing service owns refunds. Worker depends on Redis." \
|
|
135
|
+
--source docs/graph.md
|
|
136
|
+
memory-unlocked --path ./mem graph-context \
|
|
137
|
+
--tenant acme --project billing --token-budget 200
|
|
138
|
+
memory-unlocked --path ./mem graph-temporal \
|
|
139
|
+
--tenant acme --project billing --json
|
|
140
|
+
memory-unlocked --path ./mem graph-lineage \
|
|
141
|
+
--tenant acme --project billing --json
|
|
142
|
+
memory-unlocked --path ./mem graph-effective-backend \
|
|
143
|
+
--tenant acme --project billing --json
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The extra graph reports are read-only and public-safe: `graph-lineage` emits
|
|
147
|
+
opaque handles instead of raw memory ids/source refs, `graph-temporal` derives
|
|
148
|
+
relation validity from source-memory timestamps, and `graph-effective-backend`
|
|
149
|
+
returns the scoped graph as the canonical `memory_unlocked` backend payload for
|
|
150
|
+
agent/MCP consumers.
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
Run the MCP server for an agent runner:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
MEMORY_UNLOCKED_TENANT=acme \
|
|
157
|
+
MEMORY_UNLOCKED_PROJECT=billing \
|
|
158
|
+
MEMORY_UNLOCKED_HOME="$HOME/.memory_unlocked" \
|
|
159
|
+
memory-unlocked-mcp
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Use the core package directly:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from memory_unlocked import (
|
|
166
|
+
Memory, Source, Namespace, MemoryStore, ContextAssembler, PolicyError,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
store = MemoryStore()
|
|
170
|
+
|
|
171
|
+
store.add(Memory(
|
|
172
|
+
namespace=Namespace("acme", "billing"),
|
|
173
|
+
title="Refunds run through the async queue",
|
|
174
|
+
body="Refund requests are enqueued and processed by a worker, not inline.",
|
|
175
|
+
source=Source(kind="doc", ref="docs/refunds.md"),
|
|
176
|
+
tags=["billing", "architecture"],
|
|
177
|
+
))
|
|
178
|
+
|
|
179
|
+
# Recall is scope-filtered: only memories in the requested namespace come back.
|
|
180
|
+
assembler = ContextAssembler(store)
|
|
181
|
+
context = assembler.assemble(Namespace("acme", "billing"), query="refund")
|
|
182
|
+
print(context)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Writes that contain obvious secrets, or that lack a verifiable source, are
|
|
186
|
+
rejected at the gate:
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
store.add(Memory(
|
|
190
|
+
namespace=Namespace("acme", "billing"),
|
|
191
|
+
title="API key",
|
|
192
|
+
body="AWS_SECRET_ACCESS_KEY=AKIA...", # raises PolicyError
|
|
193
|
+
source=Source(kind="doc", ref="notes.md"),
|
|
194
|
+
))
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Core concepts
|
|
200
|
+
|
|
201
|
+
| Concept | What it is |
|
|
202
|
+
| --- | --- |
|
|
203
|
+
| **Memory** | One atomic fact, with a title, body, tags, and a required source. |
|
|
204
|
+
| **Source** | Provenance for a memory (a file, URL, ticket, or run id). No source → no write. |
|
|
205
|
+
| **Namespace** | A `tenant / project` scope. Recall never crosses namespaces. |
|
|
206
|
+
| **Policy / redaction** | A gate every write passes before it is stored. |
|
|
207
|
+
| **Context assembler** | Builds a scope-filtered, ranked context block for the agent. |
|
|
208
|
+
| **Event** | An append-only record of writes and recalls for auditability. |
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Privacy-first guardrails
|
|
213
|
+
|
|
214
|
+
These are the defaults, not opt-ins:
|
|
215
|
+
|
|
216
|
+
- **Never store secrets.** Writes are scanned for credential-shaped content and
|
|
217
|
+
rejected. See [`docs/privacy-and-redaction.md`](docs/privacy-and-redaction.md).
|
|
218
|
+
- **Every memory needs a source.** Unattributed claims are rejected so memory
|
|
219
|
+
stays verifiable.
|
|
220
|
+
- **Scope isolation by default.** A recall in `tenant/project` cannot return a
|
|
221
|
+
memory written under any other scope.
|
|
222
|
+
- **No raw transcripts, no PII, no customer/lead data.** Store durable, stable
|
|
223
|
+
facts — not transient progress or personal information.
|
|
224
|
+
- **Writes are reviewable.** Every write and recall emits an event so you can
|
|
225
|
+
audit what the memory fabric learned and surfaced.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Documentation
|
|
230
|
+
|
|
231
|
+
- [Install & CLI](docs/install.md) — package install, JSONL/SQLite stores, CLI commands.
|
|
232
|
+
- [Student quickstart](docs/student-quickstart.md) — isolated local setup starting with zero memories.
|
|
233
|
+
- [Hermes / MCP](docs/hermes.md) — run the MCP server and bind it to a project scope.
|
|
234
|
+
- [Semantic graph](docs/graph.md) — typed relation extraction and graph context.
|
|
235
|
+
- [Threat model](docs/threat-model.md) — public security boundaries and residual risk.
|
|
236
|
+
- [Release checklist](docs/release-checklist.md) — repeatable PyPI/release process.
|
|
237
|
+
- [Architecture](docs/architecture.md) — components, data flow, scope policy.
|
|
238
|
+
- [Privacy & redaction](docs/privacy-and-redaction.md) — what never to store and
|
|
239
|
+
the write-review flow.
|
|
240
|
+
- [Schema](docs/schema.md) — the canonical memory, source, link, and event shapes.
|
|
241
|
+
- [Integrations](docs/integrations.md) — MCP / HTTP / CLI patterns for agent runners.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Memory Unlocked
|
|
2
|
+
|
|
3
|
+
A **privacy-first, scoped local memory** for AI agents. Memory Unlocked gives
|
|
4
|
+
agents durable, project-scoped memory without leaking secrets or letting one
|
|
5
|
+
project's context bleed into another.
|
|
6
|
+
|
|
7
|
+
It is installable today as a dependency-free Python package with:
|
|
8
|
+
|
|
9
|
+
- durable local JSONL and SQLite stores,
|
|
10
|
+
- a practical CLI (`memory-unlocked`),
|
|
11
|
+
- a dependency-free MCP stdio server (`memory-unlocked-mcp`),
|
|
12
|
+
- lifecycle/governance commands for candidate review, archival, and forgetting,
|
|
13
|
+
- token-budgeted context assembly and offline recall/privacy evals,
|
|
14
|
+
- a deterministic semantic graph layer for typed agent context,
|
|
15
|
+
- audit events for writes, recalls, updates, forgets, and rejections,
|
|
16
|
+
- tests and CI for the privacy/scope guarantees.
|
|
17
|
+
|
|
18
|
+
The core stays deliberately small so teams can audit it, ship it locally, and
|
|
19
|
+
adapt it to their own database, vector index, or hosted service later.
|
|
20
|
+
|
|
21
|
+
**v1 local-isolation contract:** every installation starts with an empty local
|
|
22
|
+
store. It does not include sample memories, connect to a maintainer database, or
|
|
23
|
+
share data with any other installation. Each user owns their own JSONL/SQLite
|
|
24
|
+
files. See the [student quickstart](docs/student-quickstart.md).
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Why this exists
|
|
29
|
+
|
|
30
|
+
Long-running agents need to remember things between sessions — decisions,
|
|
31
|
+
conventions, gotchas, references. But naive "just dump everything into a vector
|
|
32
|
+
store" memory has two failure modes:
|
|
33
|
+
|
|
34
|
+
1. **Secret leakage** — credentials, tokens, customer data, and PII end up
|
|
35
|
+
persisted and later surfaced in unrelated contexts.
|
|
36
|
+
2. **Scope bleed** — memory from Project A contaminates answers about Project B.
|
|
37
|
+
|
|
38
|
+
Memory Unlocked treats both as first-class concerns. Every memory is scoped to a
|
|
39
|
+
namespace, every write passes a redaction/policy gate, and recall is filtered by
|
|
40
|
+
scope before anything reaches the model.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Who it is for
|
|
45
|
+
|
|
46
|
+
- Builders of multi-project agent systems who need **isolated** memory per scope.
|
|
47
|
+
- Teams that want **auditable, reviewable** writes instead of a black-box store.
|
|
48
|
+
- Anyone who wants a **readable reference architecture** they can port to their
|
|
49
|
+
own database, vector index, or MCP server.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Quickstart
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pipx install memory-unlocked
|
|
57
|
+
# or: uv tool install memory-unlocked
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
From source:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
git clone https://github.com/josenaicipa/memory-unlocked.git
|
|
64
|
+
cd memory-unlocked
|
|
65
|
+
python -m pip install -e '.[dev]'
|
|
66
|
+
python -m pytest -q
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Write and recall a memory from the CLI:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
memory-unlocked --path ./mem init
|
|
73
|
+
memory-unlocked --path ./mem write \
|
|
74
|
+
--tenant acme --project billing \
|
|
75
|
+
--title "Refunds run through the async queue" \
|
|
76
|
+
--body "Refund requests are enqueued and processed by a worker, not inline." \
|
|
77
|
+
--source docs/refunds.md \
|
|
78
|
+
--tags billing,architecture
|
|
79
|
+
memory-unlocked --path ./mem context \
|
|
80
|
+
--tenant acme --project billing --query refund --token-budget 200
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Review candidate memories and run governance/eval checks:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
memory-unlocked --path ./mem write \
|
|
87
|
+
--tenant acme --project billing \
|
|
88
|
+
--title "Candidate fact" --body "Needs human approval." \
|
|
89
|
+
--source docs/review.md --status candidate
|
|
90
|
+
memory-unlocked --path ./mem review --tenant acme --project billing
|
|
91
|
+
memory-unlocked --path ./mem audit --json
|
|
92
|
+
memory-unlocked eval examples/evalset/basic.json
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Use SQLite for a more production-like local backend:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
memory-unlocked --backend sqlite --path ./mem-sqlite init
|
|
99
|
+
memory-unlocked --backend sqlite --path ./mem-sqlite doctor
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Extract semantic graph context and the public-safe graph reports:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
memory-unlocked --path ./mem write \
|
|
106
|
+
--tenant acme --project billing \
|
|
107
|
+
--title "Graph demo" \
|
|
108
|
+
--body "Billing service owns refunds. Worker depends on Redis." \
|
|
109
|
+
--source docs/graph.md
|
|
110
|
+
memory-unlocked --path ./mem graph-context \
|
|
111
|
+
--tenant acme --project billing --token-budget 200
|
|
112
|
+
memory-unlocked --path ./mem graph-temporal \
|
|
113
|
+
--tenant acme --project billing --json
|
|
114
|
+
memory-unlocked --path ./mem graph-lineage \
|
|
115
|
+
--tenant acme --project billing --json
|
|
116
|
+
memory-unlocked --path ./mem graph-effective-backend \
|
|
117
|
+
--tenant acme --project billing --json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The extra graph reports are read-only and public-safe: `graph-lineage` emits
|
|
121
|
+
opaque handles instead of raw memory ids/source refs, `graph-temporal` derives
|
|
122
|
+
relation validity from source-memory timestamps, and `graph-effective-backend`
|
|
123
|
+
returns the scoped graph as the canonical `memory_unlocked` backend payload for
|
|
124
|
+
agent/MCP consumers.
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
Run the MCP server for an agent runner:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
MEMORY_UNLOCKED_TENANT=acme \
|
|
131
|
+
MEMORY_UNLOCKED_PROJECT=billing \
|
|
132
|
+
MEMORY_UNLOCKED_HOME="$HOME/.memory_unlocked" \
|
|
133
|
+
memory-unlocked-mcp
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Use the core package directly:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from memory_unlocked import (
|
|
140
|
+
Memory, Source, Namespace, MemoryStore, ContextAssembler, PolicyError,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
store = MemoryStore()
|
|
144
|
+
|
|
145
|
+
store.add(Memory(
|
|
146
|
+
namespace=Namespace("acme", "billing"),
|
|
147
|
+
title="Refunds run through the async queue",
|
|
148
|
+
body="Refund requests are enqueued and processed by a worker, not inline.",
|
|
149
|
+
source=Source(kind="doc", ref="docs/refunds.md"),
|
|
150
|
+
tags=["billing", "architecture"],
|
|
151
|
+
))
|
|
152
|
+
|
|
153
|
+
# Recall is scope-filtered: only memories in the requested namespace come back.
|
|
154
|
+
assembler = ContextAssembler(store)
|
|
155
|
+
context = assembler.assemble(Namespace("acme", "billing"), query="refund")
|
|
156
|
+
print(context)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Writes that contain obvious secrets, or that lack a verifiable source, are
|
|
160
|
+
rejected at the gate:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
store.add(Memory(
|
|
164
|
+
namespace=Namespace("acme", "billing"),
|
|
165
|
+
title="API key",
|
|
166
|
+
body="AWS_SECRET_ACCESS_KEY=AKIA...", # raises PolicyError
|
|
167
|
+
source=Source(kind="doc", ref="notes.md"),
|
|
168
|
+
))
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Core concepts
|
|
174
|
+
|
|
175
|
+
| Concept | What it is |
|
|
176
|
+
| --- | --- |
|
|
177
|
+
| **Memory** | One atomic fact, with a title, body, tags, and a required source. |
|
|
178
|
+
| **Source** | Provenance for a memory (a file, URL, ticket, or run id). No source → no write. |
|
|
179
|
+
| **Namespace** | A `tenant / project` scope. Recall never crosses namespaces. |
|
|
180
|
+
| **Policy / redaction** | A gate every write passes before it is stored. |
|
|
181
|
+
| **Context assembler** | Builds a scope-filtered, ranked context block for the agent. |
|
|
182
|
+
| **Event** | An append-only record of writes and recalls for auditability. |
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Privacy-first guardrails
|
|
187
|
+
|
|
188
|
+
These are the defaults, not opt-ins:
|
|
189
|
+
|
|
190
|
+
- **Never store secrets.** Writes are scanned for credential-shaped content and
|
|
191
|
+
rejected. See [`docs/privacy-and-redaction.md`](docs/privacy-and-redaction.md).
|
|
192
|
+
- **Every memory needs a source.** Unattributed claims are rejected so memory
|
|
193
|
+
stays verifiable.
|
|
194
|
+
- **Scope isolation by default.** A recall in `tenant/project` cannot return a
|
|
195
|
+
memory written under any other scope.
|
|
196
|
+
- **No raw transcripts, no PII, no customer/lead data.** Store durable, stable
|
|
197
|
+
facts — not transient progress or personal information.
|
|
198
|
+
- **Writes are reviewable.** Every write and recall emits an event so you can
|
|
199
|
+
audit what the memory fabric learned and surfaced.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Documentation
|
|
204
|
+
|
|
205
|
+
- [Install & CLI](docs/install.md) — package install, JSONL/SQLite stores, CLI commands.
|
|
206
|
+
- [Student quickstart](docs/student-quickstart.md) — isolated local setup starting with zero memories.
|
|
207
|
+
- [Hermes / MCP](docs/hermes.md) — run the MCP server and bind it to a project scope.
|
|
208
|
+
- [Semantic graph](docs/graph.md) — typed relation extraction and graph context.
|
|
209
|
+
- [Threat model](docs/threat-model.md) — public security boundaries and residual risk.
|
|
210
|
+
- [Release checklist](docs/release-checklist.md) — repeatable PyPI/release process.
|
|
211
|
+
- [Architecture](docs/architecture.md) — components, data flow, scope policy.
|
|
212
|
+
- [Privacy & redaction](docs/privacy-and-redaction.md) — what never to store and
|
|
213
|
+
the write-review flow.
|
|
214
|
+
- [Schema](docs/schema.md) — the canonical memory, source, link, and event shapes.
|
|
215
|
+
- [Integrations](docs/integrations.md) — MCP / HTTP / CLI patterns for agent runners.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## License
|
|
220
|
+
|
|
221
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Roadmap
|
|
2
|
+
|
|
3
|
+
Memory Unlocked is a safe, portable local memory layer for MCP-compatible AI agents.
|
|
4
|
+
|
|
5
|
+
## v1.0 - Stable Local MCP
|
|
6
|
+
|
|
7
|
+
- [x] Dependency-free CLI and MCP package
|
|
8
|
+
- [x] JSONL and SQLite local backends
|
|
9
|
+
- [x] Empty-by-default, local-per-installation student model
|
|
10
|
+
- [x] Process-bound tenant/project isolation
|
|
11
|
+
- [x] Lifecycle, review, audit, export, import, and forgetting
|
|
12
|
+
- [x] Offline recall/privacy eval harness
|
|
13
|
+
- [x] Deterministic public-safe semantic graph
|
|
14
|
+
- [x] Current MCP protocol negotiation with backward compatibility
|
|
15
|
+
- [x] Cross-platform CI and exact release-artifact smoke
|
|
16
|
+
- [x] Student quickstart, threat model, and privacy documentation
|
|
17
|
+
|
|
18
|
+
## v1.x - Optional Local Enhancements
|
|
19
|
+
|
|
20
|
+
- [ ] encrypted-at-rest local option
|
|
21
|
+
- [ ] signed export/import bundles
|
|
22
|
+
- [ ] richer duplicate merge workflow
|
|
23
|
+
- [ ] visual graph UI on top of the deterministic semantic graph
|
|
24
|
+
- [ ] additional MCP-client setup recipes
|
|
25
|
+
|
|
26
|
+
## Future Team/Hosted Layer
|
|
27
|
+
|
|
28
|
+
These are separate products and are not implied by the local v1 contract:
|
|
29
|
+
|
|
30
|
+
- [ ] Postgres backend with migrations
|
|
31
|
+
- [ ] authenticated multi-user service
|
|
32
|
+
- [ ] tenant authorization, RBAC, quotas, and deletion controls
|
|
33
|
+
- [ ] hosted dashboard and organization governance reports
|
|
34
|
+
|
|
35
|
+
## Non-goals
|
|
36
|
+
|
|
37
|
+
- Storing raw conversations by default.
|
|
38
|
+
- Becoming a generic vector database.
|
|
39
|
+
- Depending on paid embedding APIs for the core package.
|
|
40
|
+
- Connecting student installations to a maintainer/private database.
|
|
41
|
+
- Shipping private deployment details in the public repository.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
Memory Unlocked is designed to reject secrets and isolate agent memory by namespace.
|
|
4
|
+
|
|
5
|
+
## Reporting vulnerabilities
|
|
6
|
+
|
|
7
|
+
Use GitHub private vulnerability reporting / security advisories for this repository. Do not open a public issue containing exploit details or sensitive data.
|
|
8
|
+
|
|
9
|
+
## Supported versions
|
|
10
|
+
|
|
11
|
+
The latest minor release receives security fixes.
|
|
12
|
+
|
|
13
|
+
## Security design promises
|
|
14
|
+
|
|
15
|
+
- Namespace is selected by the operator/runtime, not by the model.
|
|
16
|
+
- Rejected writes do not store the rejected content.
|
|
17
|
+
- Governance reports omit memory bodies.
|
|
18
|
+
- Secret-shaped queries are redacted in audit events.
|
|
19
|
+
- The core package does not call external services.
|
|
20
|
+
|
|
21
|
+
## What not to submit
|
|
22
|
+
|
|
23
|
+
Please do not send real API keys, credentials, customer records, private internal URLs, or private conversation transcripts in issues, PRs, examples, or tests.
|