Temporal knowledge graph for AI agents via MCP
Project description
Lorekeep
A temporal knowledge graph for AI agents, served read-only over MCP.
Lorekeep compiles a team's raw documentation into a versioned, time-aware
knowledge graph (facts.jsonl) and exposes it to coding agents (Claude Code,
Cursor, Codex) through the Model Context Protocol — with per-namespace
permission and zero servers to run.
It applies Andrej Karpathy's "LLM Knowledge Base" idea: raw docs are the source code, the compiled graph is the executable. Knowledge is processed once at compile time, not re-RAG'd on every query.
Why
Existing tools each miss part of what a team needs:
| file-based | temporal KG | compile step | team permission | MCP | |
|---|---|---|---|---|---|
| Obsidian + MCP | ✅ | ❌ | ❌ | ❌ | ✅ |
| mcp-knowledge-graph | ✅ | ❌ | ❌ | ❌ (local) | ✅ |
| mem0 / cognee | ❌ (DB) | partial | ❌ | partial (DB) | ✅ |
Lorekeep targets the gap: strictly file-based + temporal graph + compile-once + namespace-scoped permission + MCP — for team-level (not just single-user) knowledge.
Features
- Compile-only — a curator (human + LLM) builds the graph; agents only read. No write path, no concurrency hell, deterministic output.
- File-sovereign —
facts.jsonl(one fact per line, sorted) is the single source of truth and the sync unit (git or S3). No binary store committed. - Temporal — every fact carries
valid_from/valid_to(half-open[from, to)); query "what was true at T", history, diffs. - Namespace permission — facts are tagged
nsfrom the directory tree (raw/<ns>/); agents scoped to namespaces; cross-namespace edges hidden unless both endpoints are visible. Deny-by-default. - MCP, stdio-first —
lorekeep serveexposes 8 read-only tools;lorekeep mcp addwires Claude Code / Cursor / Codex. No server process to babysit. - Lazy-reload —
lorekeep compileupdates the graph; the MCP server auto-refreshes on the next query. Connect once, use forever. - Provider-pluggable extraction — litellm (OpenAI / Anthropic / DashScope/Qwen / Ollama). Strict-privacy → Ollama, fully local.
- Tier-1 eval — extraction P/R/F1 vs a gold corpus, entity-resolution F1, graph-structure metrics, determinism property tests.
Install
# from PyPI:
uvx lorekeep init # try it without installing
# or from a clone:
git clone https://github.com/manhhailua/lorekeep && cd lorekeep
uv tool install . # installs the `lorekeep` command
Quickstart
# 1. bootstrap a data home (~/.config/lorekeep + ~/.local/share/lorekeep)
uvx lorekeep init
# 2. add docs under the data home's raw/<namespace>/
mkdir -p ~/.local/share/lorekeep/raw/backend
cp your-docs.md ~/.local/share/lorekeep/raw/backend/
# 3. set a provider (edit ~/.config/lorekeep/config.yaml), then compile
uvx lorekeep compile # raw/*.md -> graph/facts.jsonl
# 4. wire a coding agent (writes a portable .mcp.json)
uvx lorekeep mcp add --agent claude --ns backend
# 5. verify
uvx lorekeep doctor
Restart Claude Code → the 8 Lorekeep tools are available, scoped to your namespace.
How it works
COMPILE (offline, curator) SYNC
raw/<ns>/*.md ──► ingest ──► extract(LLM) ──► resolve ──► writer ──► facts.jsonl
│
┌─────────────────────────────────┘
▼ (git pull / aws s3 sync)
SERVE + QUERY (runtime, per device)
facts.jsonl ──load──► GraphStore (networkx, temporal) ──► ScopedGraph (ns) ──► MCP ──► agent
▲ │
└── lazy-reload on mtime change ◄──┘
Pipeline (ingest → extract → resolve → writer): markdown is chunked with
provenance; an LLM extracts schema-constrained nodes/edges with temporal +
namespace tags; aliases collapse to canonical entities; a deterministic writer
emits sorted, byte-stable facts.jsonl + a manifest.json (provenance +
errors + quarantine). Re-compiling unchanged input is byte-identical (per-chunk
hash cache), so git diffs stay clean.
Serve: GraphStore loads facts.jsonl into a networkx graph with temporal
queries. ScopedGraph is the single permission chokepoint — every query is
filtered through strict visibility rules. The FastMCP server is a thin layer of
read-only tools over ScopedGraph. It lazy-reloads when facts.jsonl changes,
so compile is instantly visible without reconnecting.
Concepts
fact — one line of facts.jsonl, a node or edge:
{"kind":"node","id":"svc:payments","type":"service","ns":["backend"],"valid_from":"2024-01-15","valid_to":null,"props":{"lang":"go"},"src":["raw/backend/payments.md:12"]}
{"kind":"edge","id":"e_depends_on_0001","type":"depends_on","from":"svc:payments","to":"svc:auth","ns":["backend"],"valid_from":"2024-01-15","valid_to":"2025-03-01","props":{},"src":["...:20"]}
ns— namespace set;["public"]is globally visible.valid_to: null⇒ current. History = multiple edges, same endpoints, different windows.src— provenance to raw doc line (audit, incremental re-compile, agent citations).
Permission — effective_ns = allowed ∪ {public}. Node visible iff
ns ∩ effective_ns ≠ ∅. Edge visible iff both endpoints visible and
edge.ns ∩ effective_ns ≠ ∅. Deny-by-default; an edge never reveals a
neighbor the caller can't see.
Temporal queries — at_time(T) (snapshot of facts valid at T, half-open
[from,to)), history(id) (versions of an entity), changes(t1,t2) (edges
that began/ended in the window).
MCP tools (read-only, scoped)
search · get_node · neighbors · at_time · history · changes ·
list_namespaces · schema. Every result is filtered to the caller's
namespace.
Configuration
config.yaml (resolved by precedence: explicit LOREKEEP_* env > LOREKEEP_HOME >
dev marker > XDG):
provider:
model: openai/qwen-plus # litellm model string
api_base: https://dashscope-intl.aliyuncs.com/compatible-mode/v1
api_key_env: DASHSCOPE_API_KEY # env var name (preferred)
api_key: null # or inline (gitignored config only)
ns:
default: [public]
install_source: pypi # pypi = portable .mcp.json
API keys never live in committed files — use api_key_env (env) or inline
api_key in the gitignored config only. Examples (DashScope / OpenAI / Ollama)
in .lorekeep/config.yaml.example.
Data home & dev mode
Path resolution (high → low): explicit LOREKEEP_* env → LOREKEEP_HOME →
dev mode (.lorekeep/ or raw/ in CWD; auto-detected in a source checkout)
→ XDG (~/.config/lorekeep, ~/.local/share/lorekeep).
Full details, per-path overrides, and lorekeep init: docs/guides/data-home.md.
For usage, see the docs/ index.
Evaluation
Tier-1 (CI): extraction P/R/F1 vs a gold corpus, entity-resolution pairwise F1,
graph-structure metrics, determinism. Run: uvx lorekeep eval. The north star is
systematic thinking with complete information — memory-recall benchmarks
(LoCoMo, LongMemEval) are parity checks, not the optimization target. See
docs/architecture/evaluation.md.
Project layout
src/lorekeep/
models.py shared contract (Node/Edge/Schema/Manifest)
facts_io.py facts.jsonl loader (store + eval)
paths.py 4-tier path resolution (env/home/dev/XDG)
defaults.py default schema + config (for `init`)
config.py, schema_io.py
compile/{ingest,extract,resolve,writer}.py the compile pipeline
compile/providers.py LLMProvider (Fake/LiteLLM)
store/{graph,fts}.py GraphStore + optional FTS cache
perm/ns.py ScopedGraph permission chokepoint
mcp_server.py FastMCP + 8 read tools (lazy-reload)
integrations/{claude_code,cursor,codex,common}.py
pipeline.py, cli.py
eval/{gold,construction,retrieval}.py
tests/ ~106 tests
docs/ README.md index, architecture/, guides/
Status
v1 — compile pipeline + serve (store/permission/MCP/integrations) + data-home
- dev mode + lazy-reload, all merged to
main, 114 tests green. Published to PyPI aslorekeep.
Roadmap (phase 2+): streamable-HTTP team server, OIDC/SSO,
embeddings/hybrid search, wiki.md views, full Tier-2 benchmark datasets
(HotpotQA/CronQuestions) and the bespoke Tier-3 Lorekeep-Reason eval.
Documentation
The docs/ index is the entry point.
Guides
Architecture
- Overview · Data model · Permission · Temporal · Compile pipeline · Serve & MCP · Testing & evaluation
License
Lorekeep is released under the MIT License — see LICENSE.
Copyright © 2026 Manh Pham. You're free to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the software, provided the copyright and permission notice are included in all copies. The software is provided "as is", without warranty of any kind.
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 lorekeep-0.1.3.tar.gz.
File metadata
- Download URL: lorekeep-0.1.3.tar.gz
- Upload date:
- Size: 976.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
842bb9e743bf854cf723637ebe6d30b906b77bf8d38b921402ebdccb580b59bf
|
|
| MD5 |
0eb42cc48061fd371a2c73d67cdddd9c
|
|
| BLAKE2b-256 |
5241e93dd37fa059220d8f731e3119f0043103f82969d325c4b67e7fc04c2f2d
|
Provenance
The following attestation bundles were made for lorekeep-0.1.3.tar.gz:
Publisher:
release.yml on manhhailua/lorekeep
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lorekeep-0.1.3.tar.gz -
Subject digest:
842bb9e743bf854cf723637ebe6d30b906b77bf8d38b921402ebdccb580b59bf - Sigstore transparency entry: 1848899955
- Sigstore integration time:
-
Permalink:
manhhailua/lorekeep@06e58c5fd7cb768f869f64cffde83e342ab3d372 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/manhhailua
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@06e58c5fd7cb768f869f64cffde83e342ab3d372 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file lorekeep-0.1.3-py3-none-any.whl.
File metadata
- Download URL: lorekeep-0.1.3-py3-none-any.whl
- Upload date:
- Size: 39.5 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 |
e2095a182ceef0142748c78c8d67ebcbfe0072415f7b885a2f42bd1ff324933c
|
|
| MD5 |
ca5404c3e439e80101da3f6a14ca8995
|
|
| BLAKE2b-256 |
78c4b830eae7ad22b3270950e44a2d91e07e0e9f4b6b0a0045255a63568af94b
|
Provenance
The following attestation bundles were made for lorekeep-0.1.3-py3-none-any.whl:
Publisher:
release.yml on manhhailua/lorekeep
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lorekeep-0.1.3-py3-none-any.whl -
Subject digest:
e2095a182ceef0142748c78c8d67ebcbfe0072415f7b885a2f42bd1ff324933c - Sigstore transparency entry: 1848900063
- Sigstore integration time:
-
Permalink:
manhhailua/lorekeep@06e58c5fd7cb768f869f64cffde83e342ab3d372 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/manhhailua
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@06e58c5fd7cb768f869f64cffde83e342ab3d372 -
Trigger Event:
workflow_dispatch
-
Statement type: