Skip to main content

memstrand

PyPI Python License: MIT

Local-first typed memory for AI agents. Zero API keys.

Two strands, like DNA: one strand holds facts (vectors), the other holds relationships (graph). Every write joins them base-pair by base-pair — a memory is never stored without its connections, and never retrieved without its scope.

30-second demo

No Docker. No server. No LLM. pip install is the entire setup:

from memstrand import Category, Memory, Provenance

mem = Memory.in_memory()

# A fact scoped to one task...
mem.remember(
    "Playwright installed as an agent-testing task dependency",
    category=Category.fact,
    provenance=Provenance.explicit_statement,
    task_id="playwright-test",
)

# ...and a global preference
mem.remember(
    "Chiran prefers a natural, unstylized look in AI portraits",
    category=Category.preference,
    provenance=Provenance.explicit_statement,
    confidence=0.95,
)

# An unrelated session asks about testing setup.
# The Playwright fact does NOT leak across the task boundary:
for hit in mem.recall("testing setup"):
    print(hit["category"], "-", hit["content"])
# preference - Chiran prefers a natural, unstylized look in AI portraits

# Same query WITH the task scope sees it:
for hit in mem.recall("testing setup", task_id="playwright-test"):
    print(hit["category"], "-", hit["content"])
# fact - Playwright installed as an agent-testing task dependency

Typed. Scoped. Provenance on every atom. The hot path (remember/recall) never touches an LLM — embeddings are local ONNX, the graph is embedded Kuzu, sessions are SQLite.

Why

Flat vector memory has three failure modes, and every agent hits all three:

  1. No types — a preference, a decision, and a guess all look the same to cosine similarity.
  2. No scope — a fact learned while testing Playwright leaks into an unrelated Mac disk-cleanup session. (This actually happened. It's why this exists.)
  3. No provenance — nobody knows whether a memory was said, inferred, or corrected, or how confident the agent was.

memstrand fixes all three: every memory is typed (13 categories), scoped (session/task/host), and carries provenance (how it was learned, confidence, expiry).

Persistent setup

in_memory() is ephemeral — data dies with the process. For real use:

docker compose up -d          # Qdrant (vectors); Kuzu + SQLite are embedded, zero setup
pip install memstrand
mem = Memory()  # Docker Qdrant + on-disk Kuzu/SQLite

For the session-distillation pass (mem.improve()), point at any OpenAI-compatible local endpoint:

export MEMSTRAND_LLM_BASE_URL=http://localhost:8081/v1

Architecture

Seven layers, deterministic write routing, scoped retrieval:

Layer What lives there Scope
L0 working live transcript + task/host scope; outranks everything task
L1 session cache fast raw Q&A, no extraction, TTL'd session
L2 episodic distilled session learnings task + host
L3 semantic typed facts, vector-embedded global
L4 consolidated curated cross-session synthesis global
L5 graph typed edges over everything above global
L6 procedural action sequences, workflow patterns, lessons global

Write path (the session-commit loop): during a session, writes land in L1 with zero extraction cost. At session end (or pre-compact hook), an async distillation pass extracts Memanto-typed atoms via your local LLM, dedups by content hash, checks for conflicts — contradictions become contradicts edges, never deletions — and promotes into L2/L3/L5.

Read path: scope filter first (session/task/host is a hard filter, not a ranking signal), then tiered abstracts before full content, graph traversal for multi-hop, and a grounded_answer() primitive that answers only from stored memory.

Memory dynamics (stolen fair and square, see below): per-fact FSRS strength with a review queue, Hebbian edge weights (use strengthens, disuse decays), and replay consolidation that prunes weak edges but never facts.

How it compares

memstrand Mem0 Cognee raw vector RAG
Local-first, no API keys ✅ OSS self-host option ✅ ✅
Typed memory schema ✅ 13 categories ✅ notes ✅ ontology ❌
Scope enforcement (hard filter) ✅ ❌ ❌ ❌
Graph + vector joint writes ✅ ✅ ✅ ❌
Contradictions as edges, not deletes ✅ ❌ ✅ ❌

API

mem.remember(content, category=..., provenance=..., confidence=..., ttl_days=...)
mem.recall(query, session_id=..., task_id=..., limit=...)   # scope-aware
mem.improve(session_ids=[...])    # distill sessions → permanent memory (needs local LLM)
mem.forget(memory_id)             # provenance-chain cleanup, never silent
mem.grounded_answer(question)     # answer ONLY from stored memories

MCP server included: python -m memstrand.mcp_server exposes the same surface to Claude Code, Cursor, and friends over stdio.

Acceptance test

Any memory system should pass these three before you trust it (rubric adapted from a Cognee ad, because it was right):

  1. Remember me in a brand-new chat without re-pasting anything.
  2. Search by meaning, not keywords.
  3. Connect facts across sessions — and don't leak facts across unrelated tasks (the Playwright test).

Acknowledgments

Standing on shoulders, with credit:

  • Memanto (moorcheh-ai/memanto) — the 13-category typed schema, provenance, and confidence model. Their product is cloud-only; this is the schema reimplemented local-first.
  • Cognee (topoteretes/cognee) — the pipeline patterns: fast session cache → distillation, joint graph+vector writes, contradictions as additive edges.
  • ZenBrain (zensation-ai/zenbrain) — per-fact FSRS, deterministic write routing, replay consolidation, Hebbian edges.
  • Mem0 — the ADD/UPDATE/DELETE/NONE extraction resolution pattern.

Roadmap

  • Schema + store interfaces + scaffold
  • Session-commit distillation loop (extract → dedup → judge → promote)
  • Scoped retrieval (task/host hard filters; unscoped queries see globals only)
  • Graph neighbor hydration + Hebbian strengthen/decay
  • FSRS + replay consolidation pass (math is in pipeline/consolidate.py, not yet scheduled)
  • MCP server tools (remember/recall/forget)
  • memstrand import — adopt an existing Markdown memory file
  • Benchmarks: the 3-test rubric, automated (tests/test_memory_flow.py)

License

MIT — see LICENSE.

Metadata

Release files for memstrand 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for memstrand 0.1.1
File Interpreter ABI Platform
memstrand-0.1.1-py3-none-any.whl Python 3 none any Details

Release files / memstrand-0.1.1-py3-none-any.whl

Download URL memstrand-0.1.1-py3-none-any.whl
Size 23.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0b181b8a459fef5ce5b69d1346192fb5bc50bf3c9836e1bf8bf73f0ef7bc3ff0
BLAKE2b-256 checksum
How to use checksums
7c0accea142c0d21afed074609015b31130cd30622c0e07f4d057e9d1c8cebd9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

0.2.1

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

This release

0.1.1 This release

1 release file

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page