MemFabric
Temporal, permission-scoped memory for AI agents, in a single SQLite file.
Facts change. Most agent memory either overwrites the old fact and loses the history, or piles up contradictions that confuse retrieval. MemFabric does what temporal knowledge graphs do, but with zero infrastructure:
from memfabric import MemoryFabric
fabric = MemoryFabric() # one SQLite file, nothing else
fabric.remember("Project X runs on Azure AI",
subject="Project X", predicate="runs_on", object="Azure AI")
fabric.remember("Project X moved to Azure Foundry",
subject="Project X", predicate="runs_on", object="Azure Foundry")
for fact in fabric.history("Project X", "runs_on"):
print(fact.describe())
# [semantic] Project X runs on Azure AI (was true 2026-07-01 ... until 2026-08-14; ...)
# [semantic] Project X moved to Azure Foundry (since 2026-08-14; ...)
The old fact is superseded, not deleted. It keeps its validity window and a
superseded_by pointer, drops out of default recall, and stays queryable as
history. Only currently valid facts reach your prompts.
What it does
Facts are (subject, predicate, object) triples with valid_from and
valid_to timestamps, the same idea Graphiti uses, except the storage is
stdlib SQLite with FTS5. You don't run Neo4j, you don't run a vector service,
and no LLM is required for any core operation.
Every memory belongs to a (scope, scope_id) pair: user, session,
agent, team, project, or org. Recall takes a scope allowlist, and
memories outside it are invisible:
fabric.recall("how do we deploy?",
scopes=[(Scope.USER, "vamsi"), (Scope.TEAM, "platform")])
Retrieval is BM25 plus recency (plus vector search if you plug in an embedder), fused with Reciprocal Rank Fusion. Because none of that needs a model, recall is deterministic: you can write unit tests that assert exactly what your agent remembers. The offline suite runs in under 2 seconds.
When you do configure an LLM, ingest() turns conversation turns into
durable facts. Any provider works: Anthropic, OpenAI, an OpenAI-compatible
endpoint (Ollama, Groq, vLLM, OpenRouter, LM Studio), or your own class
implementing a 2-method protocol. Without a provider, turns are stored as
episodes and you add facts through remember().
There is also a Letta-style working memory (named blocks plus a recent-turn
buffer), a context assembler that packs everything into one budgeted
<memory_context> block for your prompt, and an MCP server (memfabric-mcp)
that exposes the whole thing to Claude Code, Claude Desktop, Cursor, or any
other MCP client.
Architecture
flowchart TD
Agent["Your agent or app"]
MCP["MCP clients<br/>Claude Code, Claude Desktop, Cursor"]
Agent --> API
MCP -->|memfabric-mcp| API
subgraph Fabric["MemFabric"]
API["MemoryFabric API<br/>remember / ingest / recall / history / build_context"]
WM["Working memory<br/>goal blocks + recent turns"]
subgraph WritePath["Write path"]
EX["Fact extraction<br/>optional LLM"]
NK["Canonical keys<br/>case, camelCase, typos"]
TS["Temporal supersede<br/>close valid_to, keep history"]
end
subgraph ReadPath["Read path"]
SC["Scope allowlist<br/>user / session / agent / team / project / org"]
KW["Keyword<br/>FTS5 + porter"]
VC["Vector<br/>pluggable embedder"]
RC["Recency"]
FU["Reciprocal Rank Fusion"]
RR["LLM rerank<br/>optional"]
CA["Context assembly<br/>memory_context block"]
end
API --> EX --> NK --> TS
API --> SC
SC --> KW & VC & RC --> FU --> RR --> CA
WM --> CA
end
subgraph Stores["MemoryStore protocol (pluggable)"]
DB[("SQLite file<br/>default, zero infra")]
M0[("Mem0<br/>optional adapter")]
GR[("Graphiti<br/>optional adapter")]
end
subgraph Providers["LLM providers (all optional)"]
AN["Anthropic"]
OA["OpenAI-compatible<br/>OpenAI, Ollama, Groq, vLLM, LM Studio"]
BY["Your own class<br/>extract + rerank"]
end
TS --> DB
ReadPath -.->|reads| DB
EX -.-> Providers
RR -.-> Providers
CA --> Agent
Dashed lines are optional dependencies: every solid-line path works with no LLM and no external service. The temporal mechanism at the heart of it:
flowchart LR
R["fabric.recall()<br/>current facts only"]
H["fabric.history()<br/>full chain"]
F1["Project X runs_on Azure AI<br/>valid until 14 Aug 2026"]
F2["Project X runs_on Azure Foundry<br/>valid since 14 Aug 2026"]
F1 -->|superseded_by| F2
R --> F2
H -.-> F1
H -.-> F2
What it is not (read this before filing issues)
Scopes are not security. The allowlist is an organizational primitive: your application decides which scopes a caller may pass, and nothing inside the library authenticates anyone. If you need enforced multi-tenant isolation, put MemFabric behind your API boundary (or run one DB per trust domain) and treat the allowlist as the enforcement point you control. Projects like Cognee enforce identity server-side; MemFabric deliberately stays a library.
Supersede matches canonical (subject, predicate) keys: case, punctuation,
camelCase, and predicate style are normalized ("Project X" / "ProjectX" /
"project_x" share one chain, as do "runs_on" / "RunsOn"), and a conservative
fuzzy layer catches close typos (disable with
LocalStore(fuzzy_subjects=False)). Genuinely different aliases are still
different subjects: "the postgres db" and "PG main" fork into separate
chains. Full entity resolution is not in the box.
It is built for thousands to hundreds of thousands of memories, not millions. Vector search (when you plug in an embedder) is brute-force cosine. For graph-scale workloads, use the Graphiti adapter and a real graph DB.
There is no automatic forgetting or decay yet. Invalid facts accumulate as history (that's the point), and episodes accumulate until you prune them.
The Mem0 and Graphiti adapters are experimental: thin mappings onto their APIs. Verify them against the versions you install.
Where it sits
| MemFabric | Graphiti | Mem0 | Cognee | |
|---|---|---|---|---|
| Temporal fact supersede | yes | yes (reference impl.) | no | no |
| Permission-scoped recall | allowlist, library-level | namespaces only | namespaces only | server-enforced ACL |
| Zero infrastructure | one SQLite file | needs Neo4j/FalkorDB | needs a vector DB | embedded mode available |
| Works with no LLM at all | yes | no | no | no |
| Scale ceiling | ~10^5 memories | graph-scale | large | large |
If you need graph-scale temporal reasoning, use Graphiti. If you need
server-enforced multi-user ACLs today, use Cognee. If you want temporal facts
plus scoped recall in a library you can pip install and unit-test with zero
services running, that's the niche this fills. MemFabric also wraps
Mem0 and
Graphiti as optional backends behind
the same API, so you can start on SQLite and graduate without rewriting.
Install
pip install memfabric # core: stdlib + pydantic only
pip install memfabric[anthropic] # + Claude extraction/rerank
pip install memfabric[openai] # + OpenAI or any OpenAI-compatible endpoint
pip install memfabric[mcp] # + MCP server
Quickstart
from memfabric import MemoryFabric, Scope
fabric = MemoryFabric(default_scope=(Scope.USER, "vamsi"))
# Facts with temporal tracking
fabric.remember("Deploys go through GitHub Actions",
subject="deploys", predicate="run_via", object="GitHub Actions",
scope=Scope.TEAM, scope_id="platform")
# Conversation ingestion (LLM extracts facts when configured)
fabric.ingest("We're migrating Project X to Azure Foundry", role="user")
# Permission-aware hybrid recall
hits = fabric.recall("deployment process",
scopes=[(Scope.USER, "vamsi"), (Scope.TEAM, "platform")])
# Prompt-ready context block
block = fabric.build_context("Project X status")
Run the full demo (works with zero configuration): python examples/demo.py
LLM providers
fabric = MemoryFabric(llm="ollama:llama3.1") # local, no API key
fabric = MemoryFabric(llm="anthropic:claude-opus-5")
fabric = MemoryFabric(llm="openai:gpt-5-mini")
# Any OpenAI-compatible endpoint
from memfabric.llms import OpenAICompatibleLLM
fabric = MemoryFabric(llm=OpenAICompatibleLLM(
model="llama-3.3-70b-versatile",
base_url="https://api.groq.com/openai/v1", api_key="gsk_..."))
# Bring your own: two methods, no subclassing
class MyLLM:
def extract(self, text, role="user"): ...
def rerank(self, query, texts): ...
fabric = MemoryFabric(llm=MyLLM())
The default (llm="auto") resolves from the environment: it checks the
MEMFABRIC_LLM spec first, then ANTHROPIC_API_KEY, then OPENAI_API_KEY,
and otherwise runs with no LLM. Anthropic uses native structured outputs.
The OpenAI-compatible provider uses prompt-based JSON with tolerant parsing,
so it behaves the same on hosted APIs and small local models. Verified
against local Ollama (gpt-oss).
MCP server
pip install memfabric[mcp]
claude mcp add memfabric -- memfabric-mcp
Environment: MEMFABRIC_DB (SQLite path), MEMFABRIC_SCOPE (default
user:default), MEMFABRIC_LLM (optional provider spec). Tools exposed:
remember, ingest, recall, history, build_context, forget.
Layout
memfabric/
├── fabric.py MemoryFabric facade (remember/ingest/recall/history/context)
├── types.py MemoryRecord, MemoryType, Scope, ScoredMemory
├── retrieval.py hybrid channels + Reciprocal Rank Fusion + rerank hook
├── working_memory.py Letta-style blocks + recent-turn buffer
├── assembly.py budgeted <memory_context> builder
├── mcp_server.py MCP server (memfabric-mcp)
├── llms/ model-agnostic LLM layer (optional)
└── stores/ LocalStore (SQLite) + Mem0/Graphiti adapters
Tests
python -m unittest discover tests -v # offline, no LLM, <2s
Roadmap
The short version, in order: reflect() consolidation (dedup, promotion, pruning), embedders out of the box with sqlite-vec ANN, lifecycle and scope hierarchies, an auth-enforcing server layer, a PostgreSQL backend, and a Graphiti graph channel. Milestone scope and acceptance criteria are in ROADMAP.md.
Credits
The design deliberately borrows from Graphiti (temporal invalidation), Mem0 (memory API shape), and Letta (working-memory blocks). The contribution is the combination, not the parts. Bug reports with failing tests are the most useful thing you can send.
License
Apache-2.0
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 memfabric-0.2.1.tar.gz.
File metadata
- Download URL: memfabric-0.2.1.tar.gz
- Upload date:
- Size: 41.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a72e2f9aeb03bc2dd0283a6868204d202ef22f19f0e7b0bd2b0ee2f1bf9d33c1
|
|
| MD5 |
7e533a3eb556073471329497841f76b0
|
|
| BLAKE2b-256 |
a2d692d1f8ff17670833d42159b2b58d78e9f9c5af8070de1a7c486d87844422
|
Provenance
The following attestation bundles were made for memfabric-0.2.1.tar.gz:
Publisher:
publish.yml on vamsi981/memfabric
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
memfabric-0.2.1.tar.gz -
Subject digest:
a72e2f9aeb03bc2dd0283a6868204d202ef22f19f0e7b0bd2b0ee2f1bf9d33c1 - Sigstore transparency entry: 2465828676
- Sigstore integration time:
-
Permalink:
vamsi981/memfabric@b2357ccf38ded86bce121a6bddb598281c6e79c7 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/vamsi981
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b2357ccf38ded86bce121a6bddb598281c6e79c7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file memfabric-0.2.1-py3-none-any.whl.
File metadata
- Download URL: memfabric-0.2.1-py3-none-any.whl
- Upload date:
- Size: 38.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0e91498346eb6e300e029139cf8c69437446881c9e0b34a7fd1ba3b955d72cc6
|
|
| MD5 |
ce5e9ac00d3266bb5babdfcd887adc81
|
|
| BLAKE2b-256 |
7df898becde9b5139ba546615d1e9c568134ace55361d6b2ce5995927a722dd5
|
Provenance
The following attestation bundles were made for memfabric-0.2.1-py3-none-any.whl:
Publisher:
publish.yml on vamsi981/memfabric
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
memfabric-0.2.1-py3-none-any.whl -
Subject digest:
0e91498346eb6e300e029139cf8c69437446881c9e0b34a7fd1ba3b955d72cc6 - Sigstore transparency entry: 2465828885
- Sigstore integration time:
-
Permalink:
vamsi981/memfabric@b2357ccf38ded86bce121a6bddb598281c6e79c7 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/vamsi981
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b2357ccf38ded86bce121a6bddb598281c6e79c7 -
Trigger Event:
push
-
Statement type: