Lorekeep
A file-sovereign, temporal knowledge graph shared by you and your coding agents over MCP.
Lorekeep compiles Markdown from multiple namespaces into a deterministic
facts.jsonl graph, projects that graph into a human-readable Obsidian/Tolaria
wiki, and exposes a compact namespace-scoped MCP surface to Claude Code, Cursor,
Codex, and opencode. Agents can also propose facts during a session; proposals
land in append-only journals and become visible after a confidence-gated resolve.
The LLM work happens during compile or an explicitly requested deep import. Ordinary graph queries, journal writes, resolve, wiki generation, lint, and status checks do not call another LLM.
What is available today
| Area | Current behavior |
|---|---|
| Compile | raw/<ns>/*.md → schema-constrained extraction → resolve → sorted facts.jsonl + manifest + wiki |
| Query | Eight MCP tools plus passive schema, namespace, and status resources |
| Permission | Deny-by-default namespace filtering through one ScopedGraph chokepoint |
| Time | Half-open validity windows plus snapshot, history, and change queries |
| Agent input | Session import and hooks for Claude Code, Cursor, Codex, and opencode |
| Agent writes | Namespace-enforced, confidence-gated journals; no direct graph mutation |
| Automation | Watch raw docs, journals, memories/transcripts, agent wiring, backup sync, and restart after an external package upgrade |
| Human view | Deterministic, readable Markdown wiki for Obsidian and Tolaria |
| Operations | Runtime logs, redacted support bundles, install diagnostics, and optional automatic GitHub issues |
Lorekeep is suitable for one person using several coding agents and several devices, with an important current constraint: Git backup/sync is sequential. Simultaneous edits to the same raw document or journal can still require manual conflict resolution. A shared authenticated team server is roadmap work, not a shipped capability.
Get started
One-liner install (no uv needed — uses pipx or pip):
curl -fsSL https://raw.githubusercontent.com/manhhailua/lorekeep/main/scripts/install.sh | bash
lorekeep init
That's it. init sets up config, schema, provider, agent wiring, compiles any
existing markdown, and starts a background daemon that auto-compiles future
changes. Open the wiki in Obsidian/Tolaria and watch pages appear as the
compile finishes.
Or with uv:
uv tool install lorekeep
lorekeep init
Non-interactive (CI, scripts):
lorekeep init --yes
What init does
Configures provider + namespace → writes about.md + profile.md → detects
and wires coding agents (Claude Code, Cursor, Codex, opencode) → quick-imports
available memory files → compiles if a provider key exists → starts the daemon.
Idempotent — re-run anytime to pick up newly installed agents.
Add documents
# Drop Markdown under raw/<namespace>/
cp your-docs.md ~/.local/share/lorekeep/raw/backend/
# Compile runs in the background by default — wiki updates automatically
lorekeep compile
# Validate graph, schema, MCP, and provider
lorekeep doctor
The daemon watches raw/ and auto-compiles on file changes. No need to run
compile manually unless you want immediate results.
Make the daemon persistent (survives reboot)
lorekeep agent service install # systemd (Linux) / launchd (macOS)
Upgrade
lorekeep update # upgrade to latest from PyPI
lorekeep update --check # preview without upgrading
Wire an agent that wasn't auto-detected
lorekeep agent wire --agent codex --scope user --ns backend
Restart the agent after its MCP config changes. Open the wiki with
lorekeep wiki --open.
Runtime model
COMPILE / CURATE
raw/<ns>/*.md ──> chunk ──> extract(LLM, cached) ──> resolve ──┐
│
pending/<ns>/journal.jsonl ──> confidence gate + replay ────────┤
v
facts.jsonl + manifest.json
│
├──> wiki/*.md
└──> local FTS cache
SERVE / USE
facts.jsonl ──> GraphStore ──> ScopedGraph(allowed namespaces) ──> MCP
^ lazy reload on facts.jsonl mtime │
└──────────── resolve <──── namespace journal <──── agent write ─┘
Raw Markdown, schema.json, and accepted/pending journals are the durable
knowledge inputs. The graph, manifest, wiki, cache, and FTS index are derived and
can be rebuilt on each device.
Compile, resolve, and wiki
lorekeep compile is the normal all-in-one operation:
- chunk
raw/withpath:lineprovenance; - extract typed nodes, edges, aliases, summaries, and relation descriptions
(parallel via
ThreadPoolExecutor, cached per-chunk hash); - resolve aliases, validate facts, and quarantine invalid candidates;
- write sorted
facts.jsonlandmanifest.jsonatomically; - replay/merge journals when present; and
- generate the wiki once from the final graph.
Extraction runs in parallel across chunks (compile.max_workers, default 4).
Every compile.flush_interval completed chunks (default 10), an intermediate
facts.jsonl is written so the serve layer sees live graph updates during
compile; the final resolve + write overwrites with deterministic edge IDs.
Unchanged chunks use a hash cache, so they do not repeat extraction calls; sorted publication keeps the resulting graph byte-stable for unchanged inputs.
Use the narrower commands when only the derived view or journals changed:
lorekeep resolve # merge pending journal entries; zero LLM calls
lorekeep wiki --open # re-project the existing graph; zero LLM calls
Daemon and service
lorekeep agent watch polls at a configurable interval (60 seconds by default)
and currently performs event-driven maintenance:
- raw file count/mtime or schema change → compile;
- journal mtime change → resolve;
- Claude/Codex memory change → quick import;
- supported live transcripts → bounded Markdown dumps under
raw/; - detected agent change → idempotent MCP/hook wiring;
- successful compile → self-heal, wiki refresh, and backup sync when configured;
- external compile detected (manifest mtime change) → backup sync so graph changes from CLI/serve/another daemon are not lost;
- installed Lorekeep version change → restart the running watcher.
It does not currently run nightly lint, weekly suggestions, or an autonomous schema-evolution scheduler. Run those one-shot operations explicitly:
lorekeep agent lint
lorekeep agent lint --auto-fix
lorekeep agent suggest
lorekeep agent status
For login/restart persistence:
lorekeep agent service install
lorekeep agent service status
MCP contract
The runtime exposes exactly eight composable tools:
| Tool | Purpose |
|---|---|
search(query, limit=10) |
Find visible nodes by id, type, and properties |
get_node(id) |
Fetch one visible node with properties and provenance |
neighbors(id, edge_type="", depth=1) |
Traverse visible edges in both directions, up to five hops |
temporal_query(mode, params) |
at_time, history, or changes |
context(section="all", topic="") |
Ontology, visible namespaces, coverage, freshness, and pending count |
propose_change(operation, payload, confidence) |
Journal a create, link, or complete-props update |
merge_entities(from_id, to_id, reason="") |
Declare two nodes are the same entity; merges on resolve |
review_note(kind, description, fact_ids=None) |
Record a contradiction or improvement for curator review |
Clients that support MCP resources can also read:
lorekeep://schemalorekeep://namespaceslorekeep://status
Every graph-fact query and graph statistic goes through ScopedGraph. Effective
visibility is the configured scope plus public; an edge is returned only when
its own namespace and both endpoints are visible. Static schema and aggregate
compile/pending operational metadata are process-wide. Write namespaces come
from the verified server scope, not from caller payloads.
Making the MCP server available does not guarantee that every coding agent will
choose to call it. init and mcp add print an instruction snippet that tells
the agent to use this retrieval sequence:
context(section="status") → search(query) → get_node(id) → neighbors/temporal_query
Keep that snippet in the agent's project/user instructions when the client does
not persist it automatically. Agents should cite src, check graph freshness,
and treat “not found” as “absent or outside this namespace,” not proof that a
fact does not exist globally.
Configuration
All model names must use LiteLLM's {provider}/{model} form. Native providers
include OpenAI, Anthropic, DeepSeek, DashScope/Qwen, Gemini, OpenRouter, Mistral,
Groq, Together AI, and others exposed by LiteLLM. Ollama, vLLM, and LM Studio are
available for local/custom endpoints.
provider:
model: deepseek/deepseek-chat
api_key_env: DEEPSEEK_API_KEY
timeout_seconds: 120
max_retries: 2
compile:
language: en
ns:
default: [me]
personal: me
agents:
enabled: [claude, codex, cursor, opencode]
auto_wire: true
wire_scope: user
watch_transcripts: true
self_heal: true
Prefer provider.api_key_env. An inline provider.api_key is accepted only in
the local gitignored config.yaml. Native providers normally need no
api_base; set it for Ollama on a non-default host or another custom
OpenAI-compatible endpoint. See the validated
configuration example.
Change settings without editing YAML:
lorekeep config show
lorekeep config set provider.model openrouter/deepseek/deepseek-chat
lorekeep config set provider.api_key_env OPENROUTER_API_KEY
lorekeep config set compile.language vi
lorekeep config set ns.default me,backend
lorekeep config set agents.wire_scope user
Optional LiteLLM tracing is available through Langfuse or LangSmith by setting
observability.provider and the corresponding environment credentials.
compile.language is a lowercase ISO 639-1 code, defaults to en, and keeps
LLM-extracted names, summaries, and descriptions consistent even when source
files mix languages. Changing it invalidates the relevant extraction cache
entries on the next compile. Raw Markdown, proper nouns, stable IDs, and
technical identifiers are preserved.
Data home and paths
Path precedence, high to low:
- per-path
LOREKEEP_RAW,LOREKEEP_OUT,LOREKEEP_CACHE,LOREKEEP_SCHEMA,LOREKEEP_CONFIG,LOREKEEP_PENDING,LOREKEEP_WIKI, orLOREKEEP_LOGS; LOREKEEP_HOME;- development mode (
.lorekeep/in the current checkout orLOREKEEP_DEV=1); and - default dotdir
~/.lorekeep/.
All platforms (Linux, macOS, Windows) default to ~/.lorekeep/ for both
config and data. See the
data-home guide for other platforms and overrides.
Multi-device backup
Lorekeep backs up to a private Git remote — durable inputs (raw markdown, schema, journals) plus the latest graph/wiki snapshot:
# One-time setup (create a private repo first on GitHub)
lorekeep backup --init https://github.com/<you>/lorekeep-data.git
After that, the daemon auto-syncs after every compile, resolve, self-heal, and when it detects an external compile (another process changed the graph). Manual sync:
lorekeep backup
Restore on a new device:
# Install lorekeep, then clone the backup into the data home:
git clone https://github.com/<you>/lorekeep-data.git ~/.lorekeep
lorekeep init --yes # creates local config, rewires agents, preserves data
The restored graph and wiki are immediately usable — no recompile needed. Config/secrets, cache, FTS, logs, and Obsidian settings stay local and are never backed up.
Generated graph/wiki files are marked non-mergeable: Git may merge durable inputs but never silently combines two compiled snapshots. If both devices changed durable sources, reconcile and compile once.
Diagnostics and support
lorekeep doctor is the pass/fail installation check. Runtime logs live under
the resolved logs/ directory and avoid prompts, raw docs, fact properties,
journal payloads, and credentials.
lorekeep doctor
lorekeep agent service status
lorekeep support # print report + create redacted ZIP
lorekeep support --report-only
lorekeep support status # automatic issue-reporting state
lorekeep support off # disable automatic issue creation
The support bundle contains an allowlisted report, redacted log tail, and manifest counters—not raw knowledge or configuration. See runtime logging and bug reports.
Current limits
- Search is keyword/FTS plus graph traversal; hybrid/vector retrieval is planned.
- Git sync is sequential; conflicting simultaneous edits need manual resolution.
- Local stdio is the supported transport; authenticated shared-team HTTP hosting and OIDC/SSO are not shipped.
- Lint, suggest, and contribution analysis are one-shot commands, not scheduled jobs.
- There are no built-in software-source connectors for repositories, observability systems, CI, Confluence, PDFs, or URLs yet.
- Coding-agent tool use depends on the client's MCP support and instructions.
See the roadmap for unshipped directions. Architecture docs describe only current behavior unless a section is explicitly marked planned.
Development
git clone https://github.com/manhhailua/lorekeep.git
cd lorekeep
uv sync
uv run lorekeep init # uses .lorekeep/ in the repo (dev mode)
uv run pytest
uv run pytest tests/test_core_regression.py -q
uv run python scripts/generate_cli_reference.py --check
uv build
Tests use FakeProvider; no API key or network call is required. Determinism and
the compact seven-tool MCP surface are regression contracts.
Documentation
Start at the documentation index.
- Getting started
- Compiling and resolving
- Importing agent sessions
- Serving the graph over MCP
- Browsing the wiki
- Backing up and syncing
- Runtime logging and bug reports
- Architecture overview
- Generated CLI reference
License
Lorekeep is released under the MIT License.
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.35.0.tar.gz.
File metadata
- Download URL: lorekeep-0.35.0.tar.gz
- Upload date:
- Size: 1.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74d7fc3237021c006fcce11bad1164a0b4e79702b6ef287317e1868670b296d9
|
|
| MD5 |
9de94e63adcb8c09fcd49c50cc56ded6
|
|
| BLAKE2b-256 |
154389b9284279029aa76d17b2653138130e0ef85ea7d0467630d278a1c4b476
|
Provenance
The following attestation bundles were made for lorekeep-0.35.0.tar.gz:
Publisher:
release-please.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.35.0.tar.gz -
Subject digest:
74d7fc3237021c006fcce11bad1164a0b4e79702b6ef287317e1868670b296d9 - Sigstore transparency entry: 2430863246
- Sigstore integration time:
-
Permalink:
manhhailua/lorekeep@010e95d459843ada21a98779dce9d53b2487eb28 -
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-please.yml@010e95d459843ada21a98779dce9d53b2487eb28 -
Trigger Event:
push
-
Statement type:
File details
Details for the file lorekeep-0.35.0-py3-none-any.whl.
File metadata
- Download URL: lorekeep-0.35.0-py3-none-any.whl
- Upload date:
- Size: 163.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae42855801f411c9b05bfbdfde5b430dbd0e0339920ddd925b2a09b6920431cc
|
|
| MD5 |
431c3b19bf3360088092a53ae4dfb3cc
|
|
| BLAKE2b-256 |
dc083ed295dd787595f31d66c60e31b1c498bc67baf60d9ca3d1c4db920628a0
|
Provenance
The following attestation bundles were made for lorekeep-0.35.0-py3-none-any.whl:
Publisher:
release-please.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.35.0-py3-none-any.whl -
Subject digest:
ae42855801f411c9b05bfbdfde5b430dbd0e0339920ddd925b2a09b6920431cc - Sigstore transparency entry: 2430863399
- Sigstore integration time:
-
Permalink:
manhhailua/lorekeep@010e95d459843ada21a98779dce9d53b2487eb28 -
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-please.yml@010e95d459843ada21a98779dce9d53b2487eb28 -
Trigger Event:
push
-
Statement type: