Skip to main content

MemFabric

CI PyPI

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

memfabric-0.2.1.tar.gz (41.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

memfabric-0.2.1-py3-none-any.whl (38.2 kB view details)

Uploaded Python 3

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

Hashes for memfabric-0.2.1.tar.gz
Algorithm Hash digest
SHA256 a72e2f9aeb03bc2dd0283a6868204d202ef22f19f0e7b0bd2b0ee2f1bf9d33c1
MD5 7e533a3eb556073471329497841f76b0
BLAKE2b-256 a2d692d1f8ff17670833d42159b2b58d78e9f9c5af8070de1a7c486d87844422

See more details on using hashes here.

Provenance

The following attestation bundles were made for memfabric-0.2.1.tar.gz:

Publisher: publish.yml on vamsi981/memfabric

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for memfabric-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0e91498346eb6e300e029139cf8c69437446881c9e0b34a7fd1ba3b955d72cc6
MD5 ce5e9ac00d3266bb5babdfcd887adc81
BLAKE2b-256 7df898becde9b5139ba546615d1e9c568134ace55361d6b2ce5995927a722dd5

See more details on using hashes here.

Provenance

The following attestation bundles were made for memfabric-0.2.1-py3-none-any.whl:

Publisher: publish.yml on vamsi981/memfabric

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page