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.
Files changed (136) hide show
  1. lorekeep-0.7.0/.github/workflows/auto-merge-release-please.yml +47 -0
  2. lorekeep-0.7.0/.release-please-manifest.json +3 -0
  3. {lorekeep-0.6.0 → lorekeep-0.7.0}/AGENTS.md +3 -3
  4. {lorekeep-0.6.0 → lorekeep-0.7.0}/CHANGELOG.md +14 -0
  5. {lorekeep-0.6.0 → lorekeep-0.7.0}/PKG-INFO +34 -30
  6. {lorekeep-0.6.0 → lorekeep-0.7.0}/README.md +33 -29
  7. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/README.md +1 -1
  8. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/data-model.md +1 -1
  9. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/serve-mcp.md +1 -1
  10. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/getting-started.md +2 -2
  11. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/serve.md +46 -2
  12. {lorekeep-0.6.0 → lorekeep-0.7.0}/pyproject.toml +1 -1
  13. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/__init__.py +1 -1
  14. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/cli.py +3 -0
  15. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/mcp_server.py +38 -3
  16. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/models.py +7 -1
  17. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/perm/ns.py +65 -0
  18. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/pipeline.py +2 -1
  19. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/store/graph.py +36 -0
  20. lorekeep-0.7.0/tests/test_scope_awareness.py +308 -0
  21. {lorekeep-0.6.0 → lorekeep-0.7.0}/uv.lock +1 -1
  22. lorekeep-0.6.0/.github/workflows/auto-merge-release-please.yml +0 -23
  23. lorekeep-0.6.0/.release-please-manifest.json +0 -3
  24. {lorekeep-0.6.0 → lorekeep-0.7.0}/.commitlintrc.json +0 -0
  25. {lorekeep-0.6.0 → lorekeep-0.7.0}/.github/workflows/ci.yml +0 -0
  26. {lorekeep-0.6.0 → lorekeep-0.7.0}/.github/workflows/lint-commits.yml +0 -0
  27. {lorekeep-0.6.0 → lorekeep-0.7.0}/.github/workflows/release-please.yml +0 -0
  28. {lorekeep-0.6.0 → lorekeep-0.7.0}/.gitignore +0 -0
  29. {lorekeep-0.6.0 → lorekeep-0.7.0}/.lorekeep/config.yaml.example +0 -0
  30. {lorekeep-0.6.0 → lorekeep-0.7.0}/.lorekeep/schema.json +0 -0
  31. {lorekeep-0.6.0 → lorekeep-0.7.0}/.pre-commit-config.yaml +0 -0
  32. {lorekeep-0.6.0 → lorekeep-0.7.0}/CLAUDE.md +0 -0
  33. {lorekeep-0.6.0 → lorekeep-0.7.0}/LICENSE +0 -0
  34. {lorekeep-0.6.0 → lorekeep-0.7.0}/SECURITY.md +0 -0
  35. {lorekeep-0.6.0 → lorekeep-0.7.0}/cover.jpeg +0 -0
  36. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/agent.md +0 -0
  37. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/evaluation.md +0 -0
  38. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/journal.md +0 -0
  39. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/overview.md +0 -0
  40. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/permission.md +0 -0
  41. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/pipeline.md +0 -0
  42. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/architecture/temporal.md +0 -0
  43. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/backup.md +0 -0
  44. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/compile.md +0 -0
  45. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/data-home.md +0 -0
  46. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/import.md +0 -0
  47. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/guides/wiki.md +0 -0
  48. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/superpowers/plans/2026-06-26-lorekeep-dotdir-backup.md +0 -0
  49. {lorekeep-0.6.0 → lorekeep-0.7.0}/docs/superpowers/specs/2026-06-26-lorekeep-dotdir-layout-design.md +0 -0
  50. {lorekeep-0.6.0 → lorekeep-0.7.0}/release-please-config.json +0 -0
  51. {lorekeep-0.6.0 → lorekeep-0.7.0}/scripts/check-conventional-commit.py +0 -0
  52. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/agent.py +0 -0
  53. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/backup.py +0 -0
  54. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/compile/__init__.py +0 -0
  55. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/compile/extract.py +0 -0
  56. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/compile/ingest.py +0 -0
  57. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/compile/providers.py +0 -0
  58. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/compile/resolve.py +0 -0
  59. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/compile/writer.py +0 -0
  60. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/config.py +0 -0
  61. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/defaults.py +0 -0
  62. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/eval/__init__.py +0 -0
  63. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/eval/construction.py +0 -0
  64. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/eval/gold.py +0 -0
  65. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/eval/retrieval.py +0 -0
  66. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/facts_io.py +0 -0
  67. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/importer/__init__.py +0 -0
  68. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/importer/claude.py +0 -0
  69. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/importer/codex.py +0 -0
  70. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/importer/cursor.py +0 -0
  71. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/importer/opencode.py +0 -0
  72. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/__init__.py +0 -0
  73. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/claude_code.py +0 -0
  74. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/codex.py +0 -0
  75. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/common.py +0 -0
  76. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/cursor.py +0 -0
  77. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/detect.py +0 -0
  78. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/integrations/opencode.py +0 -0
  79. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/journal.py +0 -0
  80. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/paths.py +0 -0
  81. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/perm/__init__.py +0 -0
  82. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/schema_io.py +0 -0
  83. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/store/__init__.py +0 -0
  84. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/store/fts.py +0 -0
  85. {lorekeep-0.6.0 → lorekeep-0.7.0}/src/lorekeep/wiki.py +0 -0
  86. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/conftest.py +0 -0
  87. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/claude-session/memory/MEMORY.md +0 -0
  88. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/claude-session/memory/lorekeep-design.md +0 -0
  89. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/claude-session/memory/lorekeep-project-state.md +0 -0
  90. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/claude-session/test.jsonl +0 -0
  91. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/gold/payments.facts.jsonl +0 -0
  92. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/raw/backend/payments.md +0 -0
  93. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/retrieval/questions.json +0 -0
  94. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/fixtures/schema.json +0 -0
  95. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_agent_cli.py +0 -0
  96. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_agent_detect.py +0 -0
  97. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_backup.py +0 -0
  98. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_backup_cli.py +0 -0
  99. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_compile_cli.py +0 -0
  100. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_config.py +0 -0
  101. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_construction_eval.py +0 -0
  102. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_defaults.py +0 -0
  103. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_determinism.py +0 -0
  104. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_doctor_cli.py +0 -0
  105. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_eval_cli.py +0 -0
  106. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_extract.py +0 -0
  107. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_fts.py +0 -0
  108. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_graph_store.py +0 -0
  109. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_import_claude.py +0 -0
  110. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_import_codex.py +0 -0
  111. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_import_cursor.py +0 -0
  112. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_import_opencode.py +0 -0
  113. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_ingest.py +0 -0
  114. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_init_chain.py +0 -0
  115. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_init_cli.py +0 -0
  116. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_integrations.py +0 -0
  117. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_mcp_add_cli.py +0 -0
  118. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_mcp_reload.py +0 -0
  119. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_mcp_server.py +0 -0
  120. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_mcp_write_tools.py +0 -0
  121. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_merge_journals.py +0 -0
  122. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_models.py +0 -0
  123. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_paths.py +0 -0
  124. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_perm.py +0 -0
  125. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_pipeline.py +0 -0
  126. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_providers.py +0 -0
  127. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_resolve.py +0 -0
  128. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_retrieval_eval.py +0 -0
  129. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_schema_io.py +0 -0
  130. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_serve_cli.py +0 -0
  131. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_session_hook.py +0 -0
  132. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_smoke.py +0 -0
  133. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_watch_e2e.py +0 -0
  134. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_watch_sessions.py +0 -0
  135. {lorekeep-0.6.0 → lorekeep-0.7.0}/tests/test_wiki.py +0 -0
  136. {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 }}
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.7.0"
3
+ }
@@ -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 8 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.
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 (8 read + 5 write tools) |
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 8 read tools (`search`, `get_node`, `neighbors`, `at_time`, `history`, `changes`, `list_namespaces`, `schema`) 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). 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.
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.6.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 8 read + 5 write tools;
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
- - **Lazy-reload** — graph updates (compile or resolve) are visible on the next
78
- query. Connect once, use forever.
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 -> graph/facts.jsonl
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 → 13 Lorekeep tools are available (8 read + 5 write), scoped to your namespace.
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/ → compile│ │ │
128
- │ │ │ │────────│ │ │ pending/ → resolve │
129
- └─────┘ └──────────┘ └─────────┘ │ memory/ → import │ └────────┘
130
- ▲ └───────┬───────┘ │
131
- │ │ lazy-reload │ git sync
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 facts → `facts.jsonl` (cached, deterministic) |
141
- | 4. Wire agent | `lorekeep mcp add --agent claude --ns <ns>` | Write `.mcp.json`, scoped to namespace |
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 (8 read + 5 write tools, lazy-reload) |
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 Claude memory/ → delta import → raw/
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 8 read
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 Claude session memory into `raw/`. Scheduled lint and weekly suggestions are planned. See [docs/architecture/agent.md](docs/architecture/agent.md).
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 (8 read + 5 write, scoped)
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 LLMProvider (Fake/LiteLLM)
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 + 8 read + 5 write tools
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/ ~140 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 8 read + 5 write tools;
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
- - **Lazy-reload** — graph updates (compile or resolve) are visible on the next
56
- query. Connect once, use forever.
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 -> graph/facts.jsonl
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 → 13 Lorekeep tools are available (8 read + 5 write), scoped to your namespace.
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/ → compile│ │ │
106
- │ │ │ │────────│ │ │ pending/ → resolve │
107
- └─────┘ └──────────┘ └─────────┘ │ memory/ → import │ └────────┘
108
- ▲ └───────┬───────┘ │
109
- │ │ lazy-reload │ git sync
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 facts → `facts.jsonl` (cached, deterministic) |
119
- | 4. Wire agent | `lorekeep mcp add --agent claude --ns <ns>` | Write `.mcp.json`, scoped to namespace |
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 (8 read + 5 write tools, lazy-reload) |
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 Claude memory/ → delta import → raw/
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 8 read
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 Claude session memory into `raw/`. Scheduled lint and weekly suggestions are planned. See [docs/architecture/agent.md](docs/architecture/agent.md).
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 (8 read + 5 write, scoped)
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 LLMProvider (Fake/LiteLLM)
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 + 8 read + 5 write tools
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/ ~140 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) — 8 read + 5 write MCP tools, lazy-reload, journal-based writes, agent integration, sync.
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 | 8 read + 5 write MCP tools | FastMCP server, stdio (default). Loads store once; enforces permission per request. Write tools append to journals. |
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 (8 tools, scoped)
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 13 Lorekeep tools (8 read: `search`, `get_node`,
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 (8 tools, scoped)
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lorekeep"
3
- version = "0.6.0"
3
+ version = "0.7.0"
4
4
  description = "Temporal knowledge graph for AI agents via MCP"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -1,3 +1,3 @@
1
1
  """Lorekeep — temporal knowledge graph for AI agents via MCP."""
2
2
 
3
- __version__ = "0.6.0"
3
+ __version__ = "0.7.0"
@@ -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,