Skip to main content
khora.integrations.langgraph.KhoraStore implements LangGraph’s BaseStore interface so a StateGraph can use khora as its long-term semantic memory in one line:
The adapter wraps Khora.remember / Khora.recall / Khora.forget and maps LangGraph’s (tuple[str, ...], str, dict) item shape onto khora documents. Each (namespace_root, user_id) pair gets a deterministic khora namespace_id (UUID5), so a second KhoraStore over the same user sees the same memory.

Scope (v0.13)

  • KhoraStore: semantic long-term memory store. Shipped.
  • KhoraCheckpointer: NOT shipped. LangGraph’s PostgresSaver (in langgraph-postgres) already covers the opaque-blob checkpoint surface and khora offers no differentiator there. Revisit only if a single-DB-dependency story matters to a real user.

Install

This pulls langgraph>=1.0,<2.0. The adapter is also registered under the khora.integrations entry-point group, so discover() returns it without any explicit registration.

Constructor

Method semantics

All 6 async methods are first-class. Sync variants (put, get, search, delete, list_namespaces, batch) bridge through khora.integrations._sync.run_sync, which runs the coroutine on a dedicated daemon-thread loop and blocks the caller. From inside a graph node (already on an event loop) prefer the async methods; use the sync ones from a notebook or sync script.
  • aputKhora.remember with external_id derived from (flat_namespace, key). Overwriting an existing item deletes the previous document first so chunks don’t accumulate.
  • agetKhora.storage.get_document_by_external_id then project metadata back to a LangGraph Item. Returns None for foreign documents (no lg_namespace in metadata).
  • asearch(query=...)Khora.recall then map chunks to SearchItem. Without query, falls back to a list_documents scan. filter is applied client-side (exact match only in v1).
  • adeleteKhora.forget. Missing keys are a silent no-op, matching InMemoryStore semantics.
  • alist_namespaces: list documents in the bound khora namespace and aggregate distinct lg_namespace tuples. O(N_documents) scan, acceptable for bounded LangGraph workloads. Track a dedicated table at >= O(10⁴) docs.
  • abatch → serial dispatch over the per-op methods.

Ignored kwargs

  • ttl (per-item): khora has no per-item TTL. The adapter accepts it to satisfy the interface and emits one RuntimeWarning per KhoraStore instance. Use Khora.forget_session for bulk cleanup.
  • index=False: khora always embeds. The adapter accepts the kwarg and emits one RuntimeWarning per KhoraStore instance. Items remain retrievable.

Quickstart

example.py
The block above is enforced byte-identical against examples/integrations/langgraph/example.py by tools/check_examples_drift.py (CI gate).

Limits and future work

  • Filter operators ($gt, $lt, …): v1 supports exact match only. Operator support is a clean addition behind a feature flag.
  • alist_namespaces SQL pushdown - the current O(N) scan is fine for typical workloads but not for hot multi-tenant deployments. A SELECT DISTINCT metadata->'lg_namespace' helper on the storage layer would fix it.
  • Checkpointer: explicit non-goal (see “Scope” above).