lorekeep 0.6.0__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lorekeep-0.7.0/.github/workflows/auto-merge-release-please.yml +47 -0
- lorekeep-0.7.0/.release-please-manifest.json +3 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/AGENTS.md +3 -3
- {lorekeep-0.6.0 → lorekeep-0.7.0}/CHANGELOG.md +14 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/PKG-INFO +34 -30
- {lorekeep-0.6.0 → lorekeep-0.7.0}/README.md +33 -29
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/README.md +1 -1
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/data-model.md +1 -1
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/serve-mcp.md +1 -1
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/getting-started.md +2 -2
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/serve.md +46 -2
- {lorekeep-0.6.0 → lorekeep-0.7.0}/pyproject.toml +1 -1
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/__init__.py +1 -1
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/cli.py +3 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/mcp_server.py +38 -3
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/models.py +7 -1
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/perm/ns.py +65 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/pipeline.py +2 -1
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/store/graph.py +36 -0
- lorekeep-0.7.0/tests/test_scope_awareness.py +308 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/uv.lock +1 -1
- lorekeep-0.6.0/.github/workflows/auto-merge-release-please.yml +0 -23
- lorekeep-0.6.0/.release-please-manifest.json +0 -3
- {lorekeep-0.6.0 → lorekeep-0.7.0}/.commitlintrc.json +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/.github/workflows/ci.yml +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/.github/workflows/lint-commits.yml +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/.github/workflows/release-please.yml +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/.gitignore +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/.lorekeep/config.yaml.example +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/.lorekeep/schema.json +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/.pre-commit-config.yaml +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/CLAUDE.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/LICENSE +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/SECURITY.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/cover.jpeg +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/agent.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/evaluation.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/journal.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/overview.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/permission.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/pipeline.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/temporal.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/backup.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/compile.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/data-home.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/import.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/wiki.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/superpowers/plans/2026-06-26-lorekeep-dotdir-backup.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/superpowers/specs/2026-06-26-lorekeep-dotdir-layout-design.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/release-please-config.json +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/scripts/check-conventional-commit.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/agent.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/backup.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/compile/__init__.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/compile/extract.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/compile/ingest.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/compile/providers.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/compile/resolve.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/compile/writer.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/config.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/defaults.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/eval/__init__.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/eval/construction.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/eval/gold.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/eval/retrieval.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/facts_io.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/importer/__init__.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/importer/claude.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/importer/codex.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/importer/cursor.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/importer/opencode.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/__init__.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/claude_code.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/codex.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/common.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/cursor.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/detect.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/opencode.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/journal.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/paths.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/perm/__init__.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/schema_io.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/store/__init__.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/store/fts.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/wiki.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/conftest.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/claude-session/memory/MEMORY.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/claude-session/memory/lorekeep-design.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/claude-session/memory/lorekeep-project-state.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/claude-session/test.jsonl +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/gold/payments.facts.jsonl +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/raw/backend/payments.md +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/retrieval/questions.json +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/schema.json +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_agent_cli.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_agent_detect.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_backup.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_backup_cli.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_compile_cli.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_config.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_construction_eval.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_defaults.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_determinism.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_doctor_cli.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_eval_cli.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_extract.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_fts.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_graph_store.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_import_claude.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_import_codex.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_import_cursor.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_import_opencode.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_ingest.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_init_chain.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_init_cli.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_integrations.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_mcp_add_cli.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_mcp_reload.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_mcp_server.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_mcp_write_tools.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_merge_journals.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_models.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_paths.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_perm.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_pipeline.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_providers.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_resolve.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_retrieval_eval.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_schema_io.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_serve_cli.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_session_hook.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_smoke.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_watch_e2e.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_watch_sessions.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_wiki.py +0 -0
- {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_writer.py +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: auto-merge-release-please
|
|
2
|
+
|
|
3
|
+
# When release-please creates or updates a Release PR, this workflow:
|
|
4
|
+
# 1. Runs `uv lock` to sync the lockfile with the bumped version in pyproject.toml
|
|
5
|
+
# 2. Commits the updated uv.lock back to the PR branch (if changed)
|
|
6
|
+
# 3. Enables auto-merge so the PR merges once CI passes
|
|
7
|
+
#
|
|
8
|
+
# This ensures uv.lock is always correct in the release commit — no stale lockfile.
|
|
9
|
+
on:
|
|
10
|
+
pull_request:
|
|
11
|
+
types: [opened, synchronize]
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: write
|
|
15
|
+
pull-requests: write
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
prepare-and-auto-merge:
|
|
19
|
+
if: startsWith(github.head_ref, 'release-please--')
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v5
|
|
23
|
+
with:
|
|
24
|
+
ref: ${{ github.head_ref }}
|
|
25
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
26
|
+
|
|
27
|
+
- uses: astral-sh/setup-uv@v7
|
|
28
|
+
|
|
29
|
+
- name: Sync uv.lock
|
|
30
|
+
run: uv lock
|
|
31
|
+
continue-on-error: true
|
|
32
|
+
|
|
33
|
+
- name: Commit uv.lock if changed
|
|
34
|
+
continue-on-error: true
|
|
35
|
+
run: |
|
|
36
|
+
git config user.name "github-actions[bot]"
|
|
37
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
38
|
+
git add uv.lock
|
|
39
|
+
git diff --cached --quiet || git commit -m "chore: sync uv.lock"
|
|
40
|
+
git push || true
|
|
41
|
+
|
|
42
|
+
- name: Enable auto-merge for Release PR
|
|
43
|
+
run: |
|
|
44
|
+
sleep 3
|
|
45
|
+
gh pr merge --auto --squash "${{ github.event.pull_request.html_url }}"
|
|
46
|
+
env:
|
|
47
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
|
4
4
|
|
|
5
5
|
## What this is
|
|
6
6
|
|
|
7
|
-
Lorekeep compiles a team's raw markdown docs into a **temporal knowledge graph** (`facts.jsonl`) and exposes it to coding agents (Claude Code, Cursor, Codex, opencode) over MCP, with per-namespace permission. Agents read facts through
|
|
7
|
+
Lorekeep compiles a team's raw markdown docs into a **temporal knowledge graph** (`facts.jsonl`) and exposes it to coding agents (Claude Code, Cursor, Codex, opencode) over MCP, with per-namespace permission. Agents read facts through 9 read tools and propose new facts through 5 journal-based write tools (confidence-gated, merged on resolve). Knowledge is processed once at compile time, not re-RAG'd per query.
|
|
8
8
|
|
|
9
9
|
## Commands
|
|
10
10
|
|
|
@@ -29,7 +29,7 @@ uv run lorekeep <command> # run the CLI in dev mode
|
|
|
29
29
|
| `check` | Validate compiled graph loads, no dangling edges (exit 1 on failure) |
|
|
30
30
|
| `eval` | Tier-1 construction P/R/F1 vs gold corpus + structure metrics |
|
|
31
31
|
| `wiki` | Regenerate `wiki/` from `facts.jsonl` (Obsidian-compatible markdown) |
|
|
32
|
-
| `serve [--transport stdio\|http]` | Run the MCP server (
|
|
32
|
+
| `serve [--transport stdio\|http]` | Run the MCP server (9 read + 5 write tools) |
|
|
33
33
|
| `mcp add --agent claude\|cursor\|codex\|opencode --ns NS` | Write agent MCP config |
|
|
34
34
|
| `import --from claude\|cursor\|codex\|opencode` | Import agent sessions into `raw/` |
|
|
35
35
|
| `doctor` | Verify install: graph loads, schema valid, a tool responds |
|
|
@@ -58,7 +58,7 @@ Pydantic, all `frozen=True`, `extra="forbid"`. `Node` / `Edge` are the two `kind
|
|
|
58
58
|
- **`perm/ns.py` `ScopedGraph`** — the **single permission chokepoint**. Wraps a `GraphStore` and filters *every* query. Deny-by-default: `effective_ns = allowed ∪ {public}`; a node is visible iff `ns ∩ effective_ns ≠ ∅`; an edge iff **both** endpoints visible **and** `edge.ns ∩ effective_ns ≠ ∅` (an edge never leaks a neighbor the caller can't see). **Any new query path must go through `ScopedGraph`, not `GraphStore` directly.**
|
|
59
59
|
|
|
60
60
|
### Serve (`mcp_server.py`)
|
|
61
|
-
`FastMCP` with
|
|
61
|
+
`FastMCP` with 9 read tools (`search`, `get_node`, `neighbors`, `at_time`, `history`, `changes`, `list_namespaces`, `schema`, `meta`) and 5 write tools (`propose_fact`, `link_facts`, `flag_contradiction`, `update_fact`, `suggest_improvement`). Module-global `ScopedGraph` is set by `configure()`; `_require()` lazy-reloads when `facts.jsonl` mtime changes (so `compile` is visible without reconnecting). `_manifest` global loads `manifest.json` alongside facts (for `meta` tool's `compiled_at` + `merged_count`). Tools are plain functions registered with `@mcp.tool()` but stay directly callable — **tests invoke them directly, no MCP transport**. The writer uses atomic `os.replace` so lazy-reload never reads a half-written file.
|
|
62
62
|
|
|
63
63
|
### Wiki (`wiki.py`)
|
|
64
64
|
Pure JSONL → markdown transform (no LLM). `generate_wiki(graph_dir, wiki_dir)` reads `facts.jsonl` via `GraphStore` → entity pages (`entities/<type>/<slug>.md` with YAML frontmatter, wikilinks, props table), `index.md` (catalog), `overview.md` (stats dashboard), `log.md` (append-only, preserved across regen). Builds into `.wiki-build.tmp` then `os.rename` swaps into place (atomic). `_slug()` replaces `:`/`/` with `-`; collisions raise `ValueError`. YAML scalars quoted via `json.dumps` so IDs like `svc:payments-api` parse correctly. Props table escapes `\|`, collapses newlines, serializes non-strings. Regenerates on every `facts.jsonl` mutation: `compile` (single regen — `_do_auto_resolve` returns bool, compile skips if resolve already regend), `resolve` (gated on merge/flag), daemon auto-resolve (on actual merge). Best-effort — never blocks compile or resolve.
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.0](https://github.com/manhhailua/lorekeep/compare/v0.6.1...v0.7.0) (2026-06-30)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add scope-awareness meta tool — 9th MCP read tool ([#72](https://github.com/manhhailua/lorekeep/issues/72)) ([d7a6c95](https://github.com/manhhailua/lorekeep/commit/d7a6c950ea009bea8c22c81850336b7a3ae0eb12))
|
|
9
|
+
|
|
10
|
+
## [0.6.1](https://github.com/manhhailua/lorekeep/compare/v0.6.0...v0.6.1) (2026-06-30)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Documentation
|
|
14
|
+
|
|
15
|
+
* sync README with shipped features ([#70](https://github.com/manhhailua/lorekeep/issues/70)) ([ea81476](https://github.com/manhhailua/lorekeep/commit/ea81476f4ad49938a5bf1d616e6658ab8b204b36))
|
|
16
|
+
|
|
3
17
|
## [0.6.0](https://github.com/manhhailua/lorekeep/compare/v0.5.0...v0.6.0) (2026-06-29)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lorekeep
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Temporal knowledge graph for AI agents via MCP
|
|
5
5
|
Project-URL: Homepage, https://github.com/manhhailua/lorekeep
|
|
6
6
|
Project-URL: Repository, https://github.com/manhhailua/lorekeep
|
|
@@ -30,7 +30,7 @@ Description-Content-Type: text/markdown
|
|
|
30
30
|
|
|
31
31
|
Lorekeep compiles a team's raw documentation into a versioned, time-aware
|
|
32
32
|
knowledge graph (`facts.jsonl`) and exposes it to coding agents (Claude Code,
|
|
33
|
-
Cursor, Codex) through the Model Context Protocol — with per-namespace
|
|
33
|
+
Cursor, Codex, opencode) through the Model Context Protocol — with per-namespace
|
|
34
34
|
permission and zero servers to run.
|
|
35
35
|
|
|
36
36
|
It applies Andrej Karpathy's "LLM Knowledge Base" idea: raw docs are the
|
|
@@ -69,13 +69,16 @@ knowledge.
|
|
|
69
69
|
- **Namespace permission** — facts are tagged `ns` from the directory tree
|
|
70
70
|
(`raw/<ns>/`); agents scoped to namespaces; cross-namespace edges
|
|
71
71
|
hidden unless both endpoints are visible. Deny-by-default.
|
|
72
|
-
- **MCP, stdio-first** — `lorekeep serve` exposes
|
|
72
|
+
- **MCP, stdio-first** — `lorekeep serve` exposes 9 read + 5 write tools;
|
|
73
73
|
`lorekeep mcp add` wires Claude Code / Cursor / Codex / opencode.
|
|
74
74
|
- **Autonomous agent daemon** — `lorekeep agent watch` keeps the graph current:
|
|
75
75
|
auto-compile on raw/ change, auto-resolve pending journals, delta import of
|
|
76
76
|
agent session memory. Runs in the background; MCP server lazy-reloads.
|
|
77
|
-
- **
|
|
78
|
-
|
|
77
|
+
- **Session-end hooks** — `lorekeep hook` auto-imports agent memory when a
|
|
78
|
+
session ends (Claude / Cursor / Codex / opencode). Wired by `mcp add`.
|
|
79
|
+
- **Obsidian wiki** — auto-generated after every compile/resolve: human-browsable
|
|
80
|
+
markdown pages with `[[wikilinks]]`, YAML frontmatter, graph view.
|
|
81
|
+
- **Lazy-reload** — graph updates visible on next query. Connect once, use forever.
|
|
79
82
|
- **Provider-pluggable extraction** — litellm (OpenAI / Anthropic /
|
|
80
83
|
DashScope/Qwen / Ollama). Strict-privacy → Ollama, fully local.
|
|
81
84
|
- **Tier-1 eval** — extraction P/R/F1 vs a gold corpus, entity-resolution F1,
|
|
@@ -103,7 +106,7 @@ mkdir -p ~/.local/share/lorekeep/raw/backend
|
|
|
103
106
|
cp your-docs.md ~/.local/share/lorekeep/raw/backend/
|
|
104
107
|
|
|
105
108
|
# 3. set a provider (edit ~/.config/lorekeep/config.yaml), then compile
|
|
106
|
-
uvx lorekeep compile # raw/*.md
|
|
109
|
+
uvx lorekeep compile # raw/*.md → graph/facts.jsonl + wiki/
|
|
107
110
|
|
|
108
111
|
# 4. wire a coding agent (writes a portable .mcp.json)
|
|
109
112
|
uvx lorekeep mcp add --agent claude --ns backend
|
|
@@ -112,7 +115,7 @@ uvx lorekeep mcp add --agent claude --ns backend
|
|
|
112
115
|
uvx lorekeep doctor
|
|
113
116
|
```
|
|
114
117
|
|
|
115
|
-
Restart Claude Code →
|
|
118
|
+
Restart Claude Code → 14 Lorekeep tools are available (9 read + 5 write), scoped to your namespace. Open `~/.local/share/lorekeep/wiki/` in Obsidian to browse the graph as a human.
|
|
116
119
|
|
|
117
120
|
## Lifecycle
|
|
118
121
|
|
|
@@ -124,23 +127,23 @@ The full journey from install to continuous use — see the
|
|
|
124
127
|
════ ═══════ ══════ ════════════ ════
|
|
125
128
|
┌─────┐ ┌──────────┐ ┌─────────┐ ┌───────────────┐ ┌────────┐
|
|
126
129
|
│init │──►│raw/*.md │──► │mcp add │──► │ agent watch │──► │backup │
|
|
127
|
-
│ │ │compile │ compile│serve │ serve │ raw/
|
|
128
|
-
│ │ │
|
|
129
|
-
└─────┘ └──────────┘
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
│ │ │compile │ compile│serve │ serve │ raw/ → compile │
|
|
131
|
+
│ │ │ │────────│+hook │ │ pending/ → resolve │
|
|
132
|
+
└─────┘ └──────────┘ wiki │ │ │ memory/ → import └────────┘
|
|
133
|
+
└─────────┘ └───────┬───────┘ │
|
|
134
|
+
▲ │ lazy-reload │ git sync
|
|
135
|
+
│◄────────────────────┘ │
|
|
136
|
+
│◄──────────────────────────────────────┘
|
|
134
137
|
```
|
|
135
138
|
|
|
136
139
|
| Step | Command | What it does |
|
|
137
140
|
|---|---|---|
|
|
138
141
|
| 1. Bootstrap | `lorekeep init` | Create data home (config + schema + dirs) |
|
|
139
142
|
| 2. Curate | `raw/<ns>/*.md` | Drop markdown docs under namespace dirs |
|
|
140
|
-
| 3. Compile | `lorekeep compile` | LLM-extract
|
|
141
|
-
| 4. Wire agent | `lorekeep mcp add --agent claude --ns <ns>` | Write `.mcp.json
|
|
143
|
+
| 3. Compile | `lorekeep compile` | LLM-extract → `facts.jsonl` + `wiki/` (cached, deterministic) |
|
|
144
|
+
| 4. Wire agent | `lorekeep mcp add --agent claude --ns <ns>` | Write `.mcp.json` + session-end hook, scoped to namespace |
|
|
142
145
|
| 5. Verify | `lorekeep doctor` | Graph loads, schema valid, tool responds |
|
|
143
|
-
| 6. Serve | `lorekeep serve` | MCP server (
|
|
146
|
+
| 6. Serve | `lorekeep serve` | MCP server (9 read + 5 write tools, lazy-reload) |
|
|
144
147
|
| 7. Keep current | `lorekeep agent watch &` | Daemon: auto-compile, auto-resolve, delta-import sessions |
|
|
145
148
|
| 8. Back up | `lorekeep backup` | Push data home to private git repo (raw/ + schema.json) |
|
|
146
149
|
|
|
@@ -156,13 +159,13 @@ raw/<ns>/*.md ──► ingest ──► extract(LLM) ──┐
|
|
|
156
159
|
│
|
|
157
160
|
agent propose ──► MCP write tools ──► ──────┤
|
|
158
161
|
(ZERO LLM cost, journal append) │
|
|
159
|
-
├──► resolve ──► writer ──► facts.jsonl
|
|
160
|
-
import ──► raw/ ──► compile ────────────────┘ (pure logic,
|
|
161
|
-
ZERO LLM)
|
|
162
|
+
├──► resolve ──► writer ──► facts.jsonl ──► wiki/*.md
|
|
163
|
+
import ──► raw/ ──► compile ────────────────┘ (pure logic, (sorted) (Obsidian)
|
|
164
|
+
ZERO LLM)
|
|
162
165
|
┌───────────────┘
|
|
163
166
|
▼ (git / S3 sync)
|
|
164
167
|
SERVE + QUERY (runtime, per device)
|
|
165
|
-
facts.jsonl ──load──► GraphStore ──► ScopedGraph(ns) ──► MCP ──► agent
|
|
168
|
+
facts.jsonl ──load──► GraphStore ──► ScopedGraph(ns) ──► MCP (9 read + 5 write) ──► agent
|
|
166
169
|
▲ ▲ │
|
|
167
170
|
│ │ ◄── read queries
|
|
168
171
|
│ └────────── write proposals (journal)
|
|
@@ -172,14 +175,14 @@ facts.jsonl ──load──► GraphStore ──► ScopedGraph(ns) ──► M
|
|
|
172
175
|
lorekeep agent watch:
|
|
173
176
|
├── watch raw/ → auto-compile
|
|
174
177
|
├── watch pending/ → auto-resolve
|
|
175
|
-
└── watch
|
|
178
|
+
└── watch agent memory/ → delta import → raw/
|
|
176
179
|
```
|
|
177
180
|
|
|
178
181
|
**Three write paths → one resolve**: markdown is compiled by an LLM (chunked + cached); agents propose facts at runtime through MCP write tools at **zero marginal LLM cost** (the agent already ran the LLM for the conversation); agent sessions are imported into raw/. All converge at `resolve` — pure Python logic that merges, deduplicates, validates, and writes byte-stable `facts.jsonl`.
|
|
179
182
|
|
|
180
183
|
**Serve**: `GraphStore` loads `facts.jsonl` into a networkx graph with temporal
|
|
181
184
|
queries. `ScopedGraph` is the single permission chokepoint — every query is
|
|
182
|
-
filtered through strict visibility rules. The FastMCP server exposes
|
|
185
|
+
filtered through strict visibility rules. The FastMCP server exposes 9 read
|
|
183
186
|
+ 5 write tools over `ScopedGraph`. It lazy-reloads when
|
|
184
187
|
`facts.jsonl` changes, so `compile` is instantly visible without reconnecting.
|
|
185
188
|
|
|
@@ -205,11 +208,11 @@ that began/ended in the window).
|
|
|
205
208
|
|
|
206
209
|
**Agent-driven knowledge** — agents propose facts at runtime through MCP write tools (zero LLM cost). Facts land in `pending/<ns>/journal.jsonl` with agent id, confidence score, and timestamp. Resolve merges them into the graph: high-confidence (≥0.8) auto-merge, medium (0.5-0.8) merge + flag, low (<0.5) quarantine.
|
|
207
210
|
|
|
208
|
-
**Autonomous agent daemon** — `lorekeep agent watch` keeps the graph current: watches `raw/` for changes → auto-compile; monitors `pending/` → auto-resolve; delta-imports
|
|
211
|
+
**Autonomous agent daemon** — `lorekeep agent watch` keeps the graph current: watches `raw/` for changes → auto-compile; monitors `pending/` → auto-resolve; delta-imports agent session memory (Claude / Cursor / Codex / opencode) into `raw/`. Session-end hooks auto-trigger `lorekeep hook` when the agent exits. Scheduled lint and weekly suggestions are planned. See [docs/architecture/agent.md](docs/architecture/agent.md).
|
|
209
212
|
|
|
210
|
-
## MCP tools (
|
|
213
|
+
## MCP tools (9 read + 5 write, scoped)
|
|
211
214
|
|
|
212
|
-
**Read:** `search` · `get_node` · `neighbors` · `at_time` · `history` · `changes` · `list_namespaces` · `schema`.
|
|
215
|
+
**Read:** `search` · `get_node` · `neighbors` · `at_time` · `history` · `changes` · `list_namespaces` · `schema` · `meta`.
|
|
213
216
|
|
|
214
217
|
**Write** (journal-based, zero LLM cost): `propose_fact` · `link_facts` · `flag_contradiction` · `update_fact` · `suggest_improvement`.
|
|
215
218
|
|
|
@@ -263,23 +266,24 @@ src/lorekeep/
|
|
|
263
266
|
defaults.py default schema + config (for `init`)
|
|
264
267
|
config.py, schema_io.py
|
|
265
268
|
compile/{ingest,extract,resolve,writer}.py the compile pipeline
|
|
266
|
-
compile/providers.py
|
|
269
|
+
compile/providers.py LiteLLMProvider (OpenAI/Anthropic/Ollama)
|
|
267
270
|
journal.py append-only journal writer + loader
|
|
268
271
|
agent.py autonomous agent: ingest, lint, suggest, status, watch
|
|
269
272
|
store/{graph,fts}.py GraphStore + optional FTS cache
|
|
270
273
|
perm/ns.py ScopedGraph permission chokepoint
|
|
271
|
-
mcp_server.py FastMCP +
|
|
274
|
+
mcp_server.py FastMCP + 9 read + 5 write tools
|
|
272
275
|
wiki.py Obsidian-compatible wiki generator
|
|
276
|
+
importer/{claude,cursor,codex,opencode}.py agent session → raw/ importers
|
|
273
277
|
integrations/{claude_code,cursor,codex,opencode,common}.py
|
|
274
278
|
pipeline.py, cli.py
|
|
275
279
|
eval/{gold,construction,retrieval}.py
|
|
276
|
-
tests/ ~
|
|
280
|
+
tests/ ~310 tests
|
|
277
281
|
docs/ README.md index, architecture/, guides/
|
|
278
282
|
```
|
|
279
283
|
|
|
280
284
|
## Status
|
|
281
285
|
|
|
282
|
-
**v1 (implemented)** — compile pipeline + serve (store/permission/MCP read+write/4-agent integrations) + import (Claude/Cursor/Codex/opencode) + session-end hooks + agent daemon (watch/ingest/lint/suggest/status) + journal + resolve + data-home + dev mode + lazy-reload + backup + eval + **wiki** (Obsidian-compatible markdown output). Published to PyPI as `lorekeep`.
|
|
286
|
+
**v1 (implemented)** — compile pipeline + serve (store/permission/MCP 9 read+5 write/4-agent integrations) + import (Claude/Cursor/Codex/opencode) + session-end hooks + agent daemon (watch/ingest/lint/suggest/status) + journal + resolve + data-home + dev mode + lazy-reload + backup + eval + scope awareness (`meta` tool) + **wiki** (Obsidian-compatible markdown output). Published to PyPI as `lorekeep`.
|
|
283
287
|
|
|
284
288
|
**Phase 2 (planned)** — streamable-HTTP team server, OIDC/SSO, embeddings/hybrid search, scheduled nightly lint/suggest in daemon, schema evolve, full Tier-2 benchmark datasets (HotpotQA/CronQuestions) and the bespoke Tier-3 Lorekeep-Reason eval.
|
|
285
289
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
Lorekeep compiles a team's raw documentation into a versioned, time-aware
|
|
10
10
|
knowledge graph (`facts.jsonl`) and exposes it to coding agents (Claude Code,
|
|
11
|
-
Cursor, Codex) through the Model Context Protocol — with per-namespace
|
|
11
|
+
Cursor, Codex, opencode) through the Model Context Protocol — with per-namespace
|
|
12
12
|
permission and zero servers to run.
|
|
13
13
|
|
|
14
14
|
It applies Andrej Karpathy's "LLM Knowledge Base" idea: raw docs are the
|
|
@@ -47,13 +47,16 @@ knowledge.
|
|
|
47
47
|
- **Namespace permission** — facts are tagged `ns` from the directory tree
|
|
48
48
|
(`raw/<ns>/`); agents scoped to namespaces; cross-namespace edges
|
|
49
49
|
hidden unless both endpoints are visible. Deny-by-default.
|
|
50
|
-
- **MCP, stdio-first** — `lorekeep serve` exposes
|
|
50
|
+
- **MCP, stdio-first** — `lorekeep serve` exposes 9 read + 5 write tools;
|
|
51
51
|
`lorekeep mcp add` wires Claude Code / Cursor / Codex / opencode.
|
|
52
52
|
- **Autonomous agent daemon** — `lorekeep agent watch` keeps the graph current:
|
|
53
53
|
auto-compile on raw/ change, auto-resolve pending journals, delta import of
|
|
54
54
|
agent session memory. Runs in the background; MCP server lazy-reloads.
|
|
55
|
-
- **
|
|
56
|
-
|
|
55
|
+
- **Session-end hooks** — `lorekeep hook` auto-imports agent memory when a
|
|
56
|
+
session ends (Claude / Cursor / Codex / opencode). Wired by `mcp add`.
|
|
57
|
+
- **Obsidian wiki** — auto-generated after every compile/resolve: human-browsable
|
|
58
|
+
markdown pages with `[[wikilinks]]`, YAML frontmatter, graph view.
|
|
59
|
+
- **Lazy-reload** — graph updates visible on next query. Connect once, use forever.
|
|
57
60
|
- **Provider-pluggable extraction** — litellm (OpenAI / Anthropic /
|
|
58
61
|
DashScope/Qwen / Ollama). Strict-privacy → Ollama, fully local.
|
|
59
62
|
- **Tier-1 eval** — extraction P/R/F1 vs a gold corpus, entity-resolution F1,
|
|
@@ -81,7 +84,7 @@ mkdir -p ~/.local/share/lorekeep/raw/backend
|
|
|
81
84
|
cp your-docs.md ~/.local/share/lorekeep/raw/backend/
|
|
82
85
|
|
|
83
86
|
# 3. set a provider (edit ~/.config/lorekeep/config.yaml), then compile
|
|
84
|
-
uvx lorekeep compile # raw/*.md
|
|
87
|
+
uvx lorekeep compile # raw/*.md → graph/facts.jsonl + wiki/
|
|
85
88
|
|
|
86
89
|
# 4. wire a coding agent (writes a portable .mcp.json)
|
|
87
90
|
uvx lorekeep mcp add --agent claude --ns backend
|
|
@@ -90,7 +93,7 @@ uvx lorekeep mcp add --agent claude --ns backend
|
|
|
90
93
|
uvx lorekeep doctor
|
|
91
94
|
```
|
|
92
95
|
|
|
93
|
-
Restart Claude Code →
|
|
96
|
+
Restart Claude Code → 14 Lorekeep tools are available (9 read + 5 write), scoped to your namespace. Open `~/.local/share/lorekeep/wiki/` in Obsidian to browse the graph as a human.
|
|
94
97
|
|
|
95
98
|
## Lifecycle
|
|
96
99
|
|
|
@@ -102,23 +105,23 @@ The full journey from install to continuous use — see the
|
|
|
102
105
|
════ ═══════ ══════ ════════════ ════
|
|
103
106
|
┌─────┐ ┌──────────┐ ┌─────────┐ ┌───────────────┐ ┌────────┐
|
|
104
107
|
│init │──►│raw/*.md │──► │mcp add │──► │ agent watch │──► │backup │
|
|
105
|
-
│ │ │compile │ compile│serve │ serve │ raw/
|
|
106
|
-
│ │ │
|
|
107
|
-
└─────┘ └──────────┘
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
│ │ │compile │ compile│serve │ serve │ raw/ → compile │
|
|
109
|
+
│ │ │ │────────│+hook │ │ pending/ → resolve │
|
|
110
|
+
└─────┘ └──────────┘ wiki │ │ │ memory/ → import └────────┘
|
|
111
|
+
└─────────┘ └───────┬───────┘ │
|
|
112
|
+
▲ │ lazy-reload │ git sync
|
|
113
|
+
│◄────────────────────┘ │
|
|
114
|
+
│◄──────────────────────────────────────┘
|
|
112
115
|
```
|
|
113
116
|
|
|
114
117
|
| Step | Command | What it does |
|
|
115
118
|
|---|---|---|
|
|
116
119
|
| 1. Bootstrap | `lorekeep init` | Create data home (config + schema + dirs) |
|
|
117
120
|
| 2. Curate | `raw/<ns>/*.md` | Drop markdown docs under namespace dirs |
|
|
118
|
-
| 3. Compile | `lorekeep compile` | LLM-extract
|
|
119
|
-
| 4. Wire agent | `lorekeep mcp add --agent claude --ns <ns>` | Write `.mcp.json
|
|
121
|
+
| 3. Compile | `lorekeep compile` | LLM-extract → `facts.jsonl` + `wiki/` (cached, deterministic) |
|
|
122
|
+
| 4. Wire agent | `lorekeep mcp add --agent claude --ns <ns>` | Write `.mcp.json` + session-end hook, scoped to namespace |
|
|
120
123
|
| 5. Verify | `lorekeep doctor` | Graph loads, schema valid, tool responds |
|
|
121
|
-
| 6. Serve | `lorekeep serve` | MCP server (
|
|
124
|
+
| 6. Serve | `lorekeep serve` | MCP server (9 read + 5 write tools, lazy-reload) |
|
|
122
125
|
| 7. Keep current | `lorekeep agent watch &` | Daemon: auto-compile, auto-resolve, delta-import sessions |
|
|
123
126
|
| 8. Back up | `lorekeep backup` | Push data home to private git repo (raw/ + schema.json) |
|
|
124
127
|
|
|
@@ -134,13 +137,13 @@ raw/<ns>/*.md ──► ingest ──► extract(LLM) ──┐
|
|
|
134
137
|
│
|
|
135
138
|
agent propose ──► MCP write tools ──► ──────┤
|
|
136
139
|
(ZERO LLM cost, journal append) │
|
|
137
|
-
├──► resolve ──► writer ──► facts.jsonl
|
|
138
|
-
import ──► raw/ ──► compile ────────────────┘ (pure logic,
|
|
139
|
-
ZERO LLM)
|
|
140
|
+
├──► resolve ──► writer ──► facts.jsonl ──► wiki/*.md
|
|
141
|
+
import ──► raw/ ──► compile ────────────────┘ (pure logic, (sorted) (Obsidian)
|
|
142
|
+
ZERO LLM)
|
|
140
143
|
┌───────────────┘
|
|
141
144
|
▼ (git / S3 sync)
|
|
142
145
|
SERVE + QUERY (runtime, per device)
|
|
143
|
-
facts.jsonl ──load──► GraphStore ──► ScopedGraph(ns) ──► MCP ──► agent
|
|
146
|
+
facts.jsonl ──load──► GraphStore ──► ScopedGraph(ns) ──► MCP (9 read + 5 write) ──► agent
|
|
144
147
|
▲ ▲ │
|
|
145
148
|
│ │ ◄── read queries
|
|
146
149
|
│ └────────── write proposals (journal)
|
|
@@ -150,14 +153,14 @@ facts.jsonl ──load──► GraphStore ──► ScopedGraph(ns) ──► M
|
|
|
150
153
|
lorekeep agent watch:
|
|
151
154
|
├── watch raw/ → auto-compile
|
|
152
155
|
├── watch pending/ → auto-resolve
|
|
153
|
-
└── watch
|
|
156
|
+
└── watch agent memory/ → delta import → raw/
|
|
154
157
|
```
|
|
155
158
|
|
|
156
159
|
**Three write paths → one resolve**: markdown is compiled by an LLM (chunked + cached); agents propose facts at runtime through MCP write tools at **zero marginal LLM cost** (the agent already ran the LLM for the conversation); agent sessions are imported into raw/. All converge at `resolve` — pure Python logic that merges, deduplicates, validates, and writes byte-stable `facts.jsonl`.
|
|
157
160
|
|
|
158
161
|
**Serve**: `GraphStore` loads `facts.jsonl` into a networkx graph with temporal
|
|
159
162
|
queries. `ScopedGraph` is the single permission chokepoint — every query is
|
|
160
|
-
filtered through strict visibility rules. The FastMCP server exposes
|
|
163
|
+
filtered through strict visibility rules. The FastMCP server exposes 9 read
|
|
161
164
|
+ 5 write tools over `ScopedGraph`. It lazy-reloads when
|
|
162
165
|
`facts.jsonl` changes, so `compile` is instantly visible without reconnecting.
|
|
163
166
|
|
|
@@ -183,11 +186,11 @@ that began/ended in the window).
|
|
|
183
186
|
|
|
184
187
|
**Agent-driven knowledge** — agents propose facts at runtime through MCP write tools (zero LLM cost). Facts land in `pending/<ns>/journal.jsonl` with agent id, confidence score, and timestamp. Resolve merges them into the graph: high-confidence (≥0.8) auto-merge, medium (0.5-0.8) merge + flag, low (<0.5) quarantine.
|
|
185
188
|
|
|
186
|
-
**Autonomous agent daemon** — `lorekeep agent watch` keeps the graph current: watches `raw/` for changes → auto-compile; monitors `pending/` → auto-resolve; delta-imports
|
|
189
|
+
**Autonomous agent daemon** — `lorekeep agent watch` keeps the graph current: watches `raw/` for changes → auto-compile; monitors `pending/` → auto-resolve; delta-imports agent session memory (Claude / Cursor / Codex / opencode) into `raw/`. Session-end hooks auto-trigger `lorekeep hook` when the agent exits. Scheduled lint and weekly suggestions are planned. See [docs/architecture/agent.md](docs/architecture/agent.md).
|
|
187
190
|
|
|
188
|
-
## MCP tools (
|
|
191
|
+
## MCP tools (9 read + 5 write, scoped)
|
|
189
192
|
|
|
190
|
-
**Read:** `search` · `get_node` · `neighbors` · `at_time` · `history` · `changes` · `list_namespaces` · `schema`.
|
|
193
|
+
**Read:** `search` · `get_node` · `neighbors` · `at_time` · `history` · `changes` · `list_namespaces` · `schema` · `meta`.
|
|
191
194
|
|
|
192
195
|
**Write** (journal-based, zero LLM cost): `propose_fact` · `link_facts` · `flag_contradiction` · `update_fact` · `suggest_improvement`.
|
|
193
196
|
|
|
@@ -241,23 +244,24 @@ src/lorekeep/
|
|
|
241
244
|
defaults.py default schema + config (for `init`)
|
|
242
245
|
config.py, schema_io.py
|
|
243
246
|
compile/{ingest,extract,resolve,writer}.py the compile pipeline
|
|
244
|
-
compile/providers.py
|
|
247
|
+
compile/providers.py LiteLLMProvider (OpenAI/Anthropic/Ollama)
|
|
245
248
|
journal.py append-only journal writer + loader
|
|
246
249
|
agent.py autonomous agent: ingest, lint, suggest, status, watch
|
|
247
250
|
store/{graph,fts}.py GraphStore + optional FTS cache
|
|
248
251
|
perm/ns.py ScopedGraph permission chokepoint
|
|
249
|
-
mcp_server.py FastMCP +
|
|
252
|
+
mcp_server.py FastMCP + 9 read + 5 write tools
|
|
250
253
|
wiki.py Obsidian-compatible wiki generator
|
|
254
|
+
importer/{claude,cursor,codex,opencode}.py agent session → raw/ importers
|
|
251
255
|
integrations/{claude_code,cursor,codex,opencode,common}.py
|
|
252
256
|
pipeline.py, cli.py
|
|
253
257
|
eval/{gold,construction,retrieval}.py
|
|
254
|
-
tests/ ~
|
|
258
|
+
tests/ ~310 tests
|
|
255
259
|
docs/ README.md index, architecture/, guides/
|
|
256
260
|
```
|
|
257
261
|
|
|
258
262
|
## Status
|
|
259
263
|
|
|
260
|
-
**v1 (implemented)** — compile pipeline + serve (store/permission/MCP read+write/4-agent integrations) + import (Claude/Cursor/Codex/opencode) + session-end hooks + agent daemon (watch/ingest/lint/suggest/status) + journal + resolve + data-home + dev mode + lazy-reload + backup + eval + **wiki** (Obsidian-compatible markdown output). Published to PyPI as `lorekeep`.
|
|
264
|
+
**v1 (implemented)** — compile pipeline + serve (store/permission/MCP 9 read+5 write/4-agent integrations) + import (Claude/Cursor/Codex/opencode) + session-end hooks + agent daemon (watch/ingest/lint/suggest/status) + journal + resolve + data-home + dev mode + lazy-reload + backup + eval + scope awareness (`meta` tool) + **wiki** (Obsidian-compatible markdown output). Published to PyPI as `lorekeep`.
|
|
261
265
|
|
|
262
266
|
**Phase 2 (planned)** — streamable-HTTP team server, OIDC/SSO, embeddings/hybrid search, scheduled nightly lint/suggest in daemon, schema evolve, full Tier-2 benchmark datasets (HotpotQA/CronQuestions) and the bespoke Tier-3 Lorekeep-Reason eval.
|
|
263
267
|
|
|
@@ -16,7 +16,7 @@ Concepts and design — how the system fits together.
|
|
|
16
16
|
- [Agent](architecture/agent.md) — autonomous agent: daemon, trigger model, lint, resolve, suggest, cost profile.
|
|
17
17
|
- [Permission model](architecture/permission.md) — namespace visibility rules, deny-by-default, the single `ScopedGraph` chokepoint.
|
|
18
18
|
- [Temporal model](architecture/temporal.md) — `valid_from`/`valid_to`, `at_time` / `history` / `changes`.
|
|
19
|
-
- [Serve & MCP](architecture/serve-mcp.md) —
|
|
19
|
+
- [Serve & MCP](architecture/serve-mcp.md) — 9 read + 5 write MCP tools, lazy-reload, journal-based writes, agent integration, sync.
|
|
20
20
|
- [Testing & evaluation](architecture/evaluation.md) — the three-tier eval strategy and scope.
|
|
21
21
|
|
|
22
22
|
## Guides
|
|
@@ -102,7 +102,7 @@ Each component has one responsibility, a clear input/output interface, and is te
|
|
|
102
102
|
| `perm/ns` | `allowed_ns` (set) | filter / guard | **Single permission chokepoint.** Every store query passes through here. |
|
|
103
103
|
| `store/fts` (optional) | `facts.jsonl` | FTS cache | FTS5 over node text/props for text search. Local, gitignored, rebuilt from `facts.jsonl`. Falls back to in-memory scan if absent. |
|
|
104
104
|
| `integrations/*` | agent type, scope, ns | config file + snippet | Write Claude Code / Cursor / Codex MCP config; emit agent-memory text. |
|
|
105
|
-
| `mcp_server` | store + perm |
|
|
105
|
+
| `mcp_server` | store + perm | 9 read + 5 write MCP tools | FastMCP server, stdio (default). Loads store once; enforces permission per request. Write tools append to journals. |
|
|
106
106
|
|
|
107
107
|
### Dependency order
|
|
108
108
|
|
|
@@ -12,7 +12,7 @@ The serve chain loads `facts.jsonl` once and exposes it to coding agents over MC
|
|
|
12
12
|
- **Lazy-reload:** every query stats `facts.jsonl`'s mtime; if it changed (after compile or resolve) the graph is rebuilt automatically. Connect the server once — graph updates are visible without reconnecting. Reconnect is only needed for code or scope (`.mcp.json` `LOREKEEP_NS`) changes.
|
|
13
13
|
- **Journals:** write tools append to `pending/<ns>/journal.jsonl`; facts enter the graph on the next resolve pass, not immediately. This avoids write conflicts and keeps the read path fast.
|
|
14
14
|
|
|
15
|
-
## Read tools (
|
|
15
|
+
## Read tools (9 tools, scoped)
|
|
16
16
|
|
|
17
17
|
| Tool | Purpose |
|
|
18
18
|
|---|---|
|
|
@@ -133,8 +133,8 @@ uvx lorekeep mcp add --agent opencode --ns backend
|
|
|
133
133
|
|
|
134
134
|
Supported agents: `claude`, `cursor`, `codex`, `opencode`.
|
|
135
135
|
|
|
136
|
-
Restart the agent → the
|
|
137
|
-
`neighbors`, `at_time`, `history`, `changes`, `list_namespaces`, `schema`;
|
|
136
|
+
Restart the agent → the 14 Lorekeep tools (9 read: `search`, `get_node`,
|
|
137
|
+
`neighbors`, `at_time`, `history`, `changes`, `list_namespaces`, `schema`, `meta`;
|
|
138
138
|
5 write: `propose_fact`, `link_facts`, `flag_contradiction`, `update_fact`,
|
|
139
139
|
`suggest_improvement`) are
|
|
140
140
|
available, scoped to `backend` (+ `public`). See
|
|
@@ -42,12 +42,56 @@ LOREKEEP_HOME=~/kb-work uvx lorekeep init
|
|
|
42
42
|
LOREKEEP_HOME=~/kb-work uvx lorekeep compile
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
## Read tools (
|
|
45
|
+
## Read tools (9 tools, scoped)
|
|
46
46
|
|
|
47
47
|
`search`, `get_node`, `neighbors`, `at_time`, `history`, `changes`,
|
|
48
|
-
`list_namespaces`, `schema`. Results are filtered to `LOREKEEP_NS`; cross-namespace
|
|
48
|
+
`list_namespaces`, `schema`, `meta`. Results are filtered to `LOREKEEP_NS`; cross-namespace
|
|
49
49
|
edges are hidden unless both endpoints are visible.
|
|
50
50
|
|
|
51
|
+
### `meta(topic="")` — scope awareness
|
|
52
|
+
|
|
53
|
+
Agents call `meta()` to decide whether to query the graph or work from memory:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"nodes": 42,
|
|
58
|
+
"edges": 18,
|
|
59
|
+
"node_types": {"service": 30, "decision": 12},
|
|
60
|
+
"edge_types": {"depends_on": 15, "decided_by": 3},
|
|
61
|
+
"namespaces": ["backend", "frontend", "public"],
|
|
62
|
+
"provenance": {"curator": 38, "agent": 4},
|
|
63
|
+
"freshness": {
|
|
64
|
+
"oldest": "2024-01-15",
|
|
65
|
+
"newest": "2026-06-20",
|
|
66
|
+
"expired": 2
|
|
67
|
+
},
|
|
68
|
+
"compile": {
|
|
69
|
+
"run_id": "abc123",
|
|
70
|
+
"compiled_at": "2026-06-30T01:27:59Z",
|
|
71
|
+
"merged_count": 4,
|
|
72
|
+
"quarantined_count": 1
|
|
73
|
+
},
|
|
74
|
+
"pending": 7
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Pass `topic` to check coverage for a specific subject:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"coverage": {
|
|
83
|
+
"topic": "payments",
|
|
84
|
+
"matching_nodes": 3,
|
|
85
|
+
"matching_types": {"service": 2, "decision": 1},
|
|
86
|
+
"node_ids": ["svc:payments-api", "dec:adr-007", "svc:payments-worker"]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Provenance signal:** `provenance.curator` counts nodes with `src` (compiled from raw docs, higher trust). `provenance.agent` counts nodes without `src` (agent-proposed via journal, lower trust). If most facts are agent-proposed, the agent should verify before relying on them.
|
|
92
|
+
|
|
93
|
+
**Freshness signal:** `freshness.expired` counts nodes whose `valid_to` has passed. `compile.compiled_at` shows when the graph was last rebuilt. `pending` shows unresolved agent proposals.
|
|
94
|
+
|
|
51
95
|
## Write tools (5 tools, journal-based)
|
|
52
96
|
|
|
53
97
|
Agents contribute knowledge during conversation at **zero LLM cost**. Facts
|
|
@@ -10,6 +10,7 @@ import typer
|
|
|
10
10
|
from lorekeep import __version__
|
|
11
11
|
from lorekeep.compile.providers import LiteLLMProvider
|
|
12
12
|
from lorekeep.config import Config, load_config
|
|
13
|
+
from lorekeep.models import now_iso
|
|
13
14
|
from lorekeep.pipeline import compile_graph
|
|
14
15
|
from lorekeep.paths import resolve_paths
|
|
15
16
|
from lorekeep.defaults import DEFAULT_CONFIG_YAML, DEFAULT_SCHEMA, PROVIDER_PRESETS
|
|
@@ -214,6 +215,7 @@ def resolve(
|
|
|
214
215
|
edge_count=len(resolved.edges),
|
|
215
216
|
run_id="resolve",
|
|
216
217
|
facts_hash="",
|
|
218
|
+
compiled_at=now_iso(),
|
|
217
219
|
merged_count=merged.merge_count,
|
|
218
220
|
quarantined_count=merged.quarantine_count,
|
|
219
221
|
flagged_count=merged.flagged_count,
|
|
@@ -1236,6 +1238,7 @@ def _do_auto_resolve(out_dir: Path, pending_dir: Path, wiki_dir: Path | None = N
|
|
|
1236
1238
|
node_count=len(resolved.nodes),
|
|
1237
1239
|
edge_count=len(resolved.edges),
|
|
1238
1240
|
run_id="auto-resolve", facts_hash="",
|
|
1241
|
+
compiled_at=now_iso(),
|
|
1239
1242
|
merged_count=merged.merge_count,
|
|
1240
1243
|
quarantined_count=merged.quarantine_count,
|
|
1241
1244
|
flagged_count=merged.flagged_count,
|