Skip to main content
The examples/20_integrations/ tier shows the adapters from this section wired into real agent frameworks. Where the per-adapter reference pages document the contract, these scripts show the shape: a working graph, session, or crew you can copy and run. They complement the broader example tiers (basics → core APIs → workloads).
Each demo runs on the zero-infra embedded backend (pip install "khora[sqlite-lance]" + OPENAI_API_KEY) and accepts --config examples/khora.standard.yaml to switch to PostgreSQL + Neo4j. You’ll also need the framework itself installed (langgraph, openai-agents, or crewai).
The LangGraph and CrewAI adapters require a stable user_id of 8+ characters and reject empty, short, or "default" ids, a guardrail against silent cross-user reads. Derive it from your auth subject, not a placeholder.

LangGraph · KhoraStore

account_tree

01_langgraph.py

Long-term memory that survives the graph lifecycle · engine: vectorcypher
A two-node StateGraph (recall → respond) backed by KhoraStore. Before each reply the agent semantically searches prior turns; after it, it persists the new turn. The point: memory belongs to the store, not the graph. Drop the graph, rebuild it with the same store, and the history is still there.
from khora.integrations.langgraph import KhoraStore

store = KhoraStore(kb, user_id="alice-acme-prod")   # 8+ chars, never "default"
graph = build_graph(store)                           # builder.compile(store=store)

# inside a node — semantic search over previously stored items:
hits = await store.asearch(MEMORY_NS, query=user_msg, limit=3)

# persist the turn so future recalls can find it:
await store.aput(MEMORY_NS, turn_id, {"text": user_msg, "role": "user"})
Takeaway: KhoraStore implements LangGraph’s BaseStore (asearch / aput) over a khora namespace scoped to user_id, with VectorCypher handling entity and recency-aware recall. See the LangGraph reference for the full contract.

OpenAI Agents SDK · KhoraSession

resume

02_openai_agents.py

Resume a conversation days later
The defining memory-library demo: a user walks away and comes back tomorrow, and the agent still knows what they discussed. Two KhoraSession instances share one namespace under different session_id values (“Monday” and “Tuesday”). Memory written in one session is recallable from the other, because the namespace is the isolation boundary, the session is not.
from khora.integrations.openai_agents import KhoraSession
from khora.integrations.openai_agents.session import session_uuid

monday = KhoraSession(kb=kb, namespace=ns_id, session_id="conv-2026-05-19")
await monday.add_items([{"role": "user", "content": "I'm allergic to peanuts."}])

# A different session_id, the SAME namespace — yesterday's facts are reachable:
recall = await kb.recall("What food restrictions does the user have?", namespace=ns_id)

# GDPR-friendly cleanup — cascade-delete one session's documents + chunks:
await kb.forget_session(ns_id, session_uuid("conv-2026-05-19"))
Takeaway: the SDK’s session_id (any string) is mapped onto khora’s via UUID5, so ids round-trip cleanly. Use the namespace as the per-user boundary and forget_session to scope retention when a conversation ends. See the OpenAI Agents reference for khora_recall_tool and KhoraMemoryHooks.

CrewAI · KhoraMemory

groups

03_crewai_multi_agent.py

Shared vs. private memory across a crew · engine: vectorcypher
Two agents (researcher, writer) over three namespaces: one shared pool both read and write, plus a private notebook each. The shape agentic teams actually need (collaboration where it matters, isolation where it doesn’t) falls out of handing each agent a different KhoraMemory instance.
from khora.integrations.crewai import KhoraMemory

researcher_shared = KhoraMemory(kb=kb, namespace=shared_ns, user_id="agent-researcher-001", scope_root="/team")
writer_shared     = KhoraMemory(kb=kb, namespace=shared_ns, user_id="agent-writer-001",     scope_root="/team")
writer_private    = KhoraMemory(kb=kb, namespace=writer_ns, user_id="agent-writer-001",     scope_root="/scratch")

researcher_shared.remember("Customer interviews show 80% want self-hosted Postgres.",
                           scope="/team/findings", importance=0.9)

hits = writer_shared.recall("what do customers want?", limit=5)   # hit.score, hit.record.content
# writer_private.recall(...) sees none of the researcher's notes — the isolation guarantee.
Takeaway: KhoraMemory binds (kb, namespace, user_id) and plugs into CrewAI’s unified Memory. Same namespace + different user_id → shared storage, writes distinguished by user. Different namespaces → full isolation. See the CrewAI reference.

Other adapters

Google ADK (KhoraMemoryService) and LlamaIndex ship adapters with their own reference pages but don’t have a tier-20 walkthrough yet. Every adapter also has a per-framework smoke test under examples/integrations/<framework>/ that exercises the contract against a deterministic mock LLM.