Deterministic, self-hosted long-term memory for AI agents.
Project description
🪢 ai-knot
The deterministic memory layer for AI agents.
No LLM on the read path or the write path. ai-knot keeps a self-hosted, MCP-native knowledge store, recalls only the few facts each turn needs, and does it deterministically — cheap, fast, and testable. Multi-agent, temporal, and air-gappable by default.
Fastest proof · Basic memory commands · Integrations · Examples · Benchmarks · Comparison · Open in Codespaces
No LLM on read or write · shared memory for teams of agents · one-line integration · Python · TypeScript · MCP · HTTP
pip install ai-knot && ai-knot demo — 30 seconds, no signup, no API key
Works with: Claude · OpenClaw · CrewAI · LangGraph · LlamaIndex · AutoGen · OpenAI Agents SDK · PydanticAI · Vercel AI SDK
Backends: SQLite · PostgreSQL · YAML | Surfaces: Python · TypeScript · CLI · MCP · HTTP · Browser inspector
Why another memory library? Most memory layers put an LLM in the loop — a model to extract on write, a model to rank on read — so every turn costs tokens and latency. ai-knot doesn't: recall is pure retrieval — $0 per call, milliseconds, fully offline, deterministic. It's built for teams of agents — shared memory with trust, provenance, and visibility, not one bag of vectors everyone writes to and poisons — and drops into your stack in one line: MCP, HTTP, or native adapters for Claude, LangGraph, CrewAI, LlamaIndex, AutoGen, OpenAI Agents, and PydanticAI. Quality holds up: 78% on LoCoMo with the optional embedding dial. See the benchmarks →
Self-hosted OSS — no cloud tier, no signup, no API key. New and pre-1.0 — a ⭐ helps others find it, and questions are welcome in Discussions.
At a glance
| If you care about… | ai-knot gives you… |
|---|---|
| recall that stays cheap and reproducible | deterministic search / recall with no LLM on the read path |
| storage you can inspect and migrate | SQLite for the default path, PostgreSQL for shared deployments, YAML for human-readable state |
| one memory product across stacks | Python, TypeScript, CLI, MCP, HTTP sidecar, Browser inspector, and framework adapters |
| memory you can debug and correct | list, get, delete, lineage, learn, add_resolved, and valid_until |
| more than one agent writing to memory | shared memory with trust, provenance, visibility, and fan-in recall |
conversation / tool output -> add or learn -> ai-knot -> SQLite | PostgreSQL | YAML
next question -> search / recall -> 3-5 relevant facts -> next prompt
The 2026 memory problem
First-generation memory layers (2023–2024) fixed transcript replay by throwing more LLM at it — a model to extract facts on write, a model to pick what to retrieve, sometimes a model to build a graph. That trades one problem for three: cost on every call, non-determinism you can't test, and benchmark numbers nobody can reproduce.
| ❌ First-gen (2023–2024) | ✅ ai-knot (2026) |
|---|---|
| LLM on extraction, retrieval, and ranking | no LLM on the read path or the write path |
| token + latency cost on every turn | recall is cheap and testable in CI |
| one shared bag of vectors, no governance | shared memory with trust, provenance, and visibility |
| a black box you overwrite blindly | lineage, supersession, and audit built in |
ai-knot is the 2026 take: memory as a deterministic, self-hosted, MCP-native layer you can inspect, test, and run air-gapped — the same add / search / list / delete loop across Python, TypeScript, CLI, MCP, and HTTP, with direct paths for Claude, OpenClaw, CrewAI, LangGraph, LlamaIndex, AutoGen, OpenAI Agents SDK, and PydanticAI.
Fastest proof (30 seconds)
Shortest proof the product works:
pip install ai-knot
ai-knot demo
From Node / TypeScript:
npm install ai-knot
npx ai-knot-demo
The raw Python API is just as small:
from ai_knot import KnowledgeBase
kb = KnowledgeBase(agent_id="assistant")
fact = kb.add("User deploys APIs with Docker and Kubernetes")
kb.add("User prefers Go and avoids Java")
kb.add("Team standup is at 10am")
print(kb.search("what stack does the user use?")) # alias: kb.recall(...)
# [1] User deploys APIs with Docker and Kubernetes
# [2] User prefers Go and avoids Java
print(kb.list())
print(kb.get(fact.id))
# kb.delete(fact.id) # alias: kb.forget(...)
That is the core promise: persist facts to your own storage, then pull back only the 3-5 facts the next turn needs.
Basic memory commands
The core product loop:
ai-knot add assistant "User deploys APIs with Docker and Kubernetes"
ai-knot search assistant "what does the user deploy with?" # alias: ai-knot recall
ai-knot list assistant # alias: ai-knot show
ai-knot delete assistant <fact_id> # alias: ai-knot forget
The same loop exists across every major surface:
| Surface | Add | Search | List | Delete |
|---|---|---|---|---|
| Core Python | kb.add(...) |
kb.search(...) / kb.recall(...) |
kb.list() / kb.list_facts() |
kb.delete(id) / kb.forget(id) |
| TypeScript / npm | await kb.add(...) |
await kb.search(...) / await kb.recall(...) |
await kb.list() / await kb.listFacts() |
await kb.delete(id) / await kb.forget(id) |
| CLI | ai-knot add ... |
ai-knot search ... / ai-knot recall ... |
ai-knot list ... / ai-knot show ... |
ai-knot delete ... / ai-knot forget ... |
| MCP | add |
search / recall |
list / list_facts |
delete / forget |
| HTTP sidecar | POST /v1/facts |
POST /v1/search |
GET /v1/facts |
DELETE /v1/facts/{fact_id} |
When you need a deeper correction or audit loop:
- use
getwhen you already have afact_id - use
lineagewhen the history of one fact matters - use
learnwhen you want extract-on-write from raw text - use
add_resolvedwhen you want explicitupdate/deletesemantics withvalid_until
For the full command map, including include_inactive, lineage, structured correction, and cross-surface equivalents, use docs/memory-commands.md.
Wiring Claude or OpenClaw: keep setup separate from the memory verbs.
ai-knot setup openclaw --agent-id assistant --storage sqlite --write-default-config
ai-knot setup claude --agent-id assistant --storage sqlite --write-default-config
ai-knot doctor --json
Once the MCP server is live, use the same add / search / list / delete loop inside the client.
Start here
Find your stack, install it, and run one command to see the full memory loop:
| If you're starting from… | Install | Run this first | What it proves |
|---|---|---|---|
| Core Python | pip install ai-knot |
ai-knot demo |
the end-to-end add / search / list / get / delete loop against temporary local storage |
| Node / TypeScript | npm install ai-knot |
npx ai-knot-demo |
the same built-in proof through the packaged Node bridge |
| Any function-calling Python agent | pip install ai-knot |
python examples/function_calling_surface_demo.py |
plain Python memory callables for runtimes that register ordinary tools |
| CrewAI | pip install "ai-knot[crewai]" |
python examples/crewai_surface_demo.py |
root memory plus scoped agent memory without a real model call |
| LangGraph tool-style memory | pip install "ai-knot[langgraph]" |
python examples/langgraph_surface_demo.py |
explicit add / search / list / delete tools on a LangGraph-shaped path |
| LlamaIndex | pip install "ai-knot[llamaindex]" "llama-index-llms-openai" |
python examples/llamaindex_surface_demo.py |
the memory=... seam on a zero-network path |
| PydanticAI | pip install "ai-knot[pydanticai]" |
python examples/pydanticai_surface_demo.py |
per-run instruction injection with deterministic memory |
| Claude / OpenClaw / any MCP client | pip install "ai-knot[mcp]" |
ai-knot setup openclaw --agent-id assistant --storage sqlite --write-default-config |
one-command config merge plus MCP sanity check |
| HTTP sidecar | pip install "ai-knot[server]" |
python examples/http_sidecar_surface_demo.py |
/v1/facts, /v1/search, GET /v1/facts, and delete over the HTTP JSON surface |
| Vercel AI SDK | npm install ai-knot ai @ai-sdk/openai |
cd npm && npm run example:vercel-ai-sdk |
memory injection into a mainstream TypeScript app path |
| No local install | none | follow docs/codespaces-quickstart.md | install-free first run in Codespaces |
Need the repo-native CLI transcript first? Run python examples/cli_memory_loop.py.
Need the visual debug surface first? Run python examples/browser_inspector_demo.py for the Browser inspector.
Need the real model-backed LlamaIndex path? Run OPENAI_API_KEY=... python examples/llamaindex_integration.py.
Need every runnable path in one place? Use examples/README.md.
TypeScript note: the npm package uses the Python engine underneath, so keep Python 3.11+ on PATH and use npx ai-knot-doctor --json if the bridge looks wrong.
To check the bridge or environment:
ai-knot doctor --json
npx ai-knot-doctor --json
What it looks like in your stack
| Stack | Integration seam |
|---|---|
| Core Python | KnowledgeBase(...) |
| Plain function-calling Python runtimes | create_basic_memory_functions(...) |
| LangChain / LangGraph tools | create_basic_memory_tools(...) |
| CrewAI | AiKnotCrewAIMemory |
| LlamaIndex | AiKnotLlamaIndexMemory |
| AutoGen | AiKnotAutoGenMemory |
| OpenAI Agents SDK | AiKnotAgentsMemory |
| PydanticAI | AiKnotPydanticAIMemory |
| TypeScript / Node | KnowledgeBase |
| TypeScript over HTTP | HttpKnowledgeBase |
| Claude / OpenClaw / any MCP host | ai-knot-mcp via setup or serve-mcp |
Any function-calling Python agent
from ai_knot.integrations import create_basic_memory_functions
functions = create_basic_memory_functions(kb, top_k=5, include_get=True)
CrewAI
from ai_knot.integrations.crewai import AiKnotCrewAIMemory
memory = AiKnotCrewAIMemory(kb, top_k=5)
crew = Crew(agents=[researcher, writer], tasks=[task], memory=memory)
LangGraph / LangChain
from langgraph.prebuilt import create_react_agent
from ai_knot.integrations.langchain import create_basic_memory_tools
tools = create_basic_memory_tools(kb, top_k=5)
agent = create_react_agent(model, tools=tools)
LlamaIndex
from ai_knot.integrations.llamaindex import AiKnotLlamaIndexMemory
memory = AiKnotLlamaIndexMemory.from_defaults(knowledge_base=kb, top_k=5)
TypeScript / Vercel AI SDK
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
import { AiKnotAISDKMemory, KnowledgeBase } from "ai-knot";
const kb = new KnowledgeBase({ agentId: "assistant", storage: "sqlite" });
const memory = new AiKnotAISDKMemory(kb, { topK: 5 });
const system = await memory.buildSystem("Write a deployment checklist.", {
baseSystem: "You are a concise staff engineer.",
});
const { text } = await generateText({
model: openai("gpt-5"),
system,
prompt: "Write a deployment checklist.",
});
TypeScript / HTTP sidecar
import { HttpKnowledgeBase } from "ai-knot";
const kb = new HttpKnowledgeBase({
baseUrl: "http://127.0.0.1:8000",
token: process.env.AI_KNOT_SERVER_TOKEN,
});
Claude / OpenClaw / any MCP client
ai-knot setup claude --agent-id assistant --storage sqlite --write-default-config
ai-knot setup openclaw --agent-id assistant --storage sqlite --write-default-config
ai-knot serve-mcp assistant --port 8765
# MCP endpoint: http://127.0.0.1:8765/mcp
For the full surface map, use docs/integrations.md. If you want the assistant itself to know these surfaces before editing your repo, use skills/README.md. For a shareable landing page, use docs/site/index.html.
Why teams pick ai-knot
- Deterministic recall. No LLM on the read path, so the hot path is cheaper, faster, and regression-testable.
- Storage you control. SQLite for the default path, PostgreSQL for shared deployments, YAML when you want human-readable state.
- Fact lifecycle, not blind overwrite.
learn,add_resolved,valid_until, andlineagemake memory correction explicit. - Framework breadth without lock-in. Python, TypeScript, MCP, HTTP, and adapters for the agent stacks people already use.
- Multi-agent governance. Shared memory with provenance, trust, visibility, and fan-in recall instead of "everyone writes to one bag of vectors."
- Benchmark credibility. Named-reader QA numbers plus deterministic retrieval metrics you can actually rerun.
Built for teams of agents
The single-agent path is the easy part. The harder problem is shared memory that does not turn into noise.
- fan-in recall across multiple agents
- evidence-before-belief gating
- per-agent visibility control
- deterministic conflict handling
- trust penalties that survive flooding or laundering attempts
This is one of ai-knot's sharpest edges. See docs/multi-agent-governance.md for how it maps to the 2026 governed-shared-memory problem, and watch it defend itself under attack in examples/poisoned_pool.py (python examples/poisoned_pool.py). Full API: docs/usage.md.
What you can build
| You are building… | ai-knot gives you… |
|---|---|
| A chatbot that remembers users | persistent per-user facts without replaying the full chat log |
| A coding agent | project, tooling, and preference memory that comes back in milliseconds |
| A team of agents | shared memory with trust and visibility rules, not just a shared database |
| A regulated or air-gapped system | self-hosted storage and no LLM on recall |
| A product that must be testable | deterministic retrieval you can lock into regression tests |
How it compares
ai-knot is the newcomer in a crowded 2026 memory landscape, not the incumbent. Several projects are far more adopted — Mem0 (~60k★), Graphiti (~28k★), Cognee (~27k★), Letta (~24k★), Memori (~15.5k★). ai-knot's wedge is narrow on purpose.
| If you want… | Best fit |
|---|---|
| memory that needs no LLM on read or write (air-gapped, reproducible) | ai-knot |
| the largest, most-adopted general memory layer | Mem0 |
| an LLM-built temporal knowledge graph | Zep / Graphiti |
| the LLM to manage its own memory inside the agent loop | Letta (ex-MemGPT) |
| an ontology + knowledge-graph memory pipeline | Cognee |
| the most native memory for a LangGraph-only stack | LangMem |
| SQL-native structured memory with no vector DB | Memori |
Several of these also keep the LLM off recall (Graphiti, LangMem, Memori). What's rarer: ai-knot needs no LLM on the write path either — direct fact insertion is the default and learn() extraction is optional — so the whole pipeline can run with zero model calls.
The honest wedge: self-hosted deterministic memory with no LLM required on read or write, one-line integration across your stack, and real multi-agent governance.
For the full, checked feature matrix versus each project, use docs/comparison.md.
Benchmarks you can rerun
Memory claims in this category swing hard depending on the reader model, judge model, prompts, and scoring rules. ai-knot publishes both named-reader QA numbers and deterministic retrieval metrics.
| Benchmark | Metric | ai-knot |
|---|---|---|
| Golden suite | ranking MRR, deterministic, no LLM | 0.83 vs 0.18 naive |
| LoCoMo | evidence_recall@5, deterministic, no LLM |
0.26 vs 0.15 naive |
| LoCoMo | QA accuracy, cat1-4, gpt-4.1 reader / gpt-4o judge |
78.0% |
| LongMemEval | QA accuracy, Oracle, gpt-4.1 / gpt-4o |
59.6% |
The first two rows are the anchor: deterministic, no LLM, fixed seeds — re-run and you get the same numbers. The QA rows are LLM-judged (reader + judge named), so they move with the models; the deterministic rows don't.
LoCoMo by category — nothing cherry-picked. Reader gpt-4.1, judge gpt-4o; categories 1–4 scored (category 5 is adversarial and excluded per the dataset authors — the exact step the field's headline benchmark dispute got wrong):
| cat1 single-hop | cat2 multi-hop | cat3 temporal | cat4 open-ended | overall |
|---|---|---|---|---|
| 60.6% | 67.6% | 63.5% | 89.4% | 78.0% |
Strong on open-ended synthesis, honestly mid on single-hop and temporal — and 74–84% on every one of the 10 conversations, not one lucky run.
AI_KNOT_EMBED_URL="" python -m tests.eval.benchmark.runner \
--mock-judge --skip-multi-agent --backends baseline,ai_knot_no_llm
Full methodology, caveats, and per-conversation tables: docs/benchmarks.md.
Performance
In-process BM25 recall, measured with pytest-benchmark:
| Facts in memory | recall p50 | p95 |
|---|---|---|
| 100 | ~1 ms | ~3 ms |
| 1,000 | ~8 ms | ~25 ms |
| 10,000 | ~80 ms | ~200 ms |
MCP tool round-trip over stdio is roughly add ~15 ms / recall ~20 ms p50. For the fuller picture — methodology, per-conversation tables, and the deterministic suite you can re-run — use docs/benchmarks.md. Continuous pytest-benchmark history is published to GitHub Pages once Pages is enabled (see docs/RELEASE.md).
Documentation
- Start with docs/usage.md, docs/memory-commands.md, and docs/integrations.md.
- For runnable proofs, use examples/README.md.
- For positioning and buyer-facing material, use docs/positioning.md, docs/comparison.md, and docs/faq.md.
- For benchmark methodology, use docs/benchmarks.md.
- For long-form material, use docs/whitepaper.md, docs/developer-article.md, and docs/site/index.html.
- For productized assistant instructions, use skills/README.md.
- For deployment and repo internals, use docs/deployment.md, docs/production-readiness.md, ARCHITECTURE.md, and docs/README.md.
Contributing
PRs are welcome, especially around storage backends, framework adapters, benchmark coverage, and docs. Start with CONTRIBUTING.md and DEVELOPMENT.md.
License
MIT. If a stack you use is missing, open an issue with the integration surface you want next.
Project details
Release history Release notifications | RSS feed
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 ai_knot-0.12.0.tar.gz.
File metadata
- Download URL: ai_knot-0.12.0.tar.gz
- Upload date:
- Size: 1.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c83d3ad0e2795f7151e2534a461dab9cbf1059574d063d90d68478640f91df4
|
|
| MD5 |
d958992c267e8d0e748d05dd328ffce9
|
|
| BLAKE2b-256 |
e33e613f54f2518850cf08761e1034fc7fe8afc207504276dab0f85087c45110
|
Provenance
The following attestation bundles were made for ai_knot-0.12.0.tar.gz:
Publisher:
publish.yml on alsoleg89/ai-knot
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ai_knot-0.12.0.tar.gz -
Subject digest:
0c83d3ad0e2795f7151e2534a461dab9cbf1059574d063d90d68478640f91df4 - Sigstore transparency entry: 2106628804
- Sigstore integration time:
-
Permalink:
alsoleg89/ai-knot@553702f864447635b06145e4461261319c27e02a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/alsoleg89
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@553702f864447635b06145e4461261319c27e02a -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file ai_knot-0.12.0-py3-none-any.whl.
File metadata
- Download URL: ai_knot-0.12.0-py3-none-any.whl
- Upload date:
- Size: 228.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e3ca643af34b85a998129b7048908eca69c40391d9ef4bea46c7c9b47eee778
|
|
| MD5 |
347cd4139bdd23484c48089ee0c0ae84
|
|
| BLAKE2b-256 |
d0d5d58ed7ea106b112d6621b4627f4e515a81eb3c1505123e60c1b3d7321e96
|
Provenance
The following attestation bundles were made for ai_knot-0.12.0-py3-none-any.whl:
Publisher:
publish.yml on alsoleg89/ai-knot
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ai_knot-0.12.0-py3-none-any.whl -
Subject digest:
4e3ca643af34b85a998129b7048908eca69c40391d9ef4bea46c7c9b47eee778 - Sigstore transparency entry: 2106628984
- Sigstore integration time:
-
Permalink:
alsoleg89/ai-knot@553702f864447635b06145e4461261319c27e02a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/alsoleg89
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@553702f864447635b06145e4461261319c27e02a -
Trigger Event:
workflow_dispatch
-
Statement type: