saihm-langgraph
SAIHM long-term memory for LangGraph — a BaseStore your graph owns. Portable, encrypted, provably erasable.
SaihmStore is a drop-in langgraph.store.base.BaseStore — the interface LangGraph uses for long-term, cross-thread memory. Compile a graph with it and that graph gets memory the user actually owns: portable across models and frameworks, non-custodial (sealed client-side; Python never holds a key), and provably erasable (GDPR Art. 17 — delete crypto-shreds the cell, it does not merely hide it).
pip install saihm-langgraph # also needs Node.js >= 20 on PATH (see "How it works")
from typing import TypedDict
from langgraph.graph import StateGraph
from langgraph.store.base import BaseStore
from saihm_memory import SaihmStore
class State(TypedDict):
user: str
profile: dict
def node(state, *, store: BaseStore): # LangGraph injects the compiled store
store.put(("users", state["user"]), "profile", {"name": "Dana"})
return {"profile": store.get(("users", state["user"]), "profile").value}
builder = StateGraph(State)
builder.add_node("remember", node)
builder.set_entry_point("remember")
graph = builder.compile(store=SaihmStore()) # sandbox by default — no account, offline
print(graph.invoke({"user": "u1"})["profile"]) # -> {'name': 'Dana'}
SaihmStore implements the full BaseStore surface — get / put / search / delete /
list_namespaces, sync and async — on top of batch / abatch. Each (namespace, key) is
one encrypted SAIHM cell.
Why not just the built-in store?
An in-process store is only as portable as the process it runs in, and only as private as
whoever holds it. SAIHM changes the ownership model — same three lines of BaseStore, a
fundamentally different guarantee about who owns the memory:
- Yours across every model. The same memory opens under Claude, GPT, DeepSeek, Qwen, Kimi, or GLM — and under the LangChain, CrewAI, and AutoGen adapters. Switch models or frameworks and the agent's memory follows it. No migration, no re-embedding, no vendor lock-in.
- The store is blind. Every cell is sealed client-side with post-quantum cryptography (ML-DSA-65 / ML-KEM-768 / AES-256-GCM) before it ever leaves your process. The endpoint holds ciphertext it cannot read; Python never holds a key.
- Erasure you can prove.
deletedestroys the cell's key, so its ciphertext becomes unrecoverable noise — a cryptographic shred, not a soft-delete. That is GDPR Art. 17 built intostore.delete(...). On the hosted tier each shred is recorded in SAIHM's audit chain; in the offline sandbox the identical code path runs locally, with no external record. - Free to start, offline in seconds. Runs against a local blind sandbox with no account and no network; point it at the hosted free tier when you're ready to persist.
Give your graph long-term memory your users actually own — portable, private, and provably
forgettable — without leaving the BaseStore interface you already use.
How it works
All cryptography runs in a small Node sidecar (built on @saihm/mcp-server-pro, ML-DSA-65 / ML-KEM-768 / AES-256-GCM); Python drives it over MCP stdio and holds no keys — one audited crypto implementation, not a second one ported to Python. That is why Node.js ≥ 20 is required. The sidecar ships inside the wheel as source only; its Node dependencies are installed once into a per-user cache (~/.cache/saihm-langgraph) on first use, then reused offline.
- Sandbox (default): no configuration → a local, in-process blind endpoint (ciphertext only). Great for trying it with zero signup; memory lasts for the client's life.
- Live: set
SAIHM_ENDPOINT_URL+SAIHM_MASTER_SECRET_HEXand eitherSAIHM_TIER=FREE(free tier — runnpx -y @saihm/mcp-server-pro free-joinonce) orSAIHM_AUTH_HEADER(Pro; join at https://saihm.coti.global/join) → durable, hosted, blind memory.
Always close() the store (or use the client as a context manager); a dropped client is reaped on GC, but explicit close is cleaner.
Parity with InMemoryStore
Filter ($-operators) and namespace matching reuse LangGraph's own helpers, so results match the reference InMemoryStore exactly. Two documented differences, both from SAIHM being a blind store (the endpoint holds ciphertext only and cannot run a server-side vector index):
searchreturns matches newest-first withscore=None(no semantic ranking), whereInMemoryStorereturns insertion order.supports_ttlisFalse.
A cell written outside this adapter (e.g. by the LangChain, CrewAI, or AutoGen SAIHM adapters, or a raw remember) is left untouched — one owned store can hold facts from several adapters without collision.
Related
- Try it in your browser (offline, no signup): https://citw2.github.io/saihm-demos/
- Runnable end-to-end demo: https://github.com/citw2/saihm-langgraph
- Other adapters: LangChain/LlamaIndex · CrewAI · AutoGen
- What SAIHM is: https://saihm.coti.global
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 saihm_langgraph-0.1.0.tar.gz.
File metadata
- Download URL: saihm_langgraph-0.1.0.tar.gz
- Upload date:
- Size: 35.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0bb0296d2b58ddbd344fdc603020e2f871fdc508f31b43fe28a3eb3becd30cf
|
|
| MD5 |
18c5ea5a09fcef930262f1d6fec01393
|
|
| BLAKE2b-256 |
4e9eba391bfbed4439753cf12acba263339b68f1195849ea6f0e8750fdeb26a6
|
File details
Details for the file saihm_langgraph-0.1.0-py3-none-any.whl.
File metadata
- Download URL: saihm_langgraph-0.1.0-py3-none-any.whl
- Upload date:
- Size: 34.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b975e5cdc5b2a74a70146c055460b8fb8124e56f8fb066e5bc1d4fd1f492f0db
|
|
| MD5 |
8682165353bba5191e37a89668f5549a
|
|
| BLAKE2b-256 |
26210ceeb23bd22acd40e086fd3c5c5011fa1b3dbd122640a1fea8c858fa5c7a
|