epimemer 0.1.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 (101) hide show
  1. epimemer-0.1.0/LICENSE +22 -0
  2. epimemer-0.1.0/PKG-INFO +290 -0
  3. epimemer-0.1.0/README.md +250 -0
  4. epimemer-0.1.0/epimemer/__init__.py +0 -0
  5. epimemer-0.1.0/epimemer/cli.py +509 -0
  6. epimemer-0.1.0/epimemer/core/__init__.py +0 -0
  7. epimemer-0.1.0/epimemer/core/advisories.py +204 -0
  8. epimemer-0.1.0/epimemer/core/temporal.py +555 -0
  9. epimemer-0.1.0/epimemer/core/types.py +1804 -0
  10. epimemer-0.1.0/epimemer/embeddings/__init__.py +0 -0
  11. epimemer-0.1.0/epimemer/embeddings/mock.py +54 -0
  12. epimemer-0.1.0/epimemer/embeddings/protocol.py +25 -0
  13. epimemer-0.1.0/epimemer/embeddings/sentence_transformers.py +28 -0
  14. epimemer-0.1.0/epimemer/logging/__init__.py +0 -0
  15. epimemer-0.1.0/epimemer/logging/structured.py +84 -0
  16. epimemer-0.1.0/epimemer/mcp/__init__.py +0 -0
  17. epimemer-0.1.0/epimemer/mcp/config.py +206 -0
  18. epimemer-0.1.0/epimemer/mcp/retrieval_records.py +149 -0
  19. epimemer-0.1.0/epimemer/mcp/server.py +3602 -0
  20. epimemer-0.1.0/epimemer/mcp/tools.py +6410 -0
  21. epimemer-0.1.0/epimemer/mcp/types.py +45 -0
  22. epimemer-0.1.0/epimemer/orchestration/__init__.py +0 -0
  23. epimemer-0.1.0/epimemer/pipelines/__init__.py +0 -0
  24. epimemer-0.1.0/epimemer/pipelines/frames.py +360 -0
  25. epimemer-0.1.0/epimemer/pipelines/graph_construction/__init__.py +0 -0
  26. epimemer-0.1.0/epimemer/pipelines/graph_construction/edge_creation.py +150 -0
  27. epimemer-0.1.0/epimemer/pipelines/graph_construction/versioning.py +677 -0
  28. epimemer-0.1.0/epimemer/pipelines/orchestration/__init__.py +0 -0
  29. epimemer-0.1.0/epimemer/pipelines/orchestration/orchestration_net.py +372 -0
  30. epimemer-0.1.0/epimemer/pipelines/query/__init__.py +0 -0
  31. epimemer-0.1.0/epimemer/pipelines/query/corroboration.py +506 -0
  32. epimemer-0.1.0/epimemer/pipelines/query/fusion.py +85 -0
  33. epimemer-0.1.0/epimemer/pipelines/query/graph_expansion.py +89 -0
  34. epimemer-0.1.0/epimemer/pipelines/query/hybrid_retrieval.py +577 -0
  35. epimemer-0.1.0/epimemer/pipelines/query/lexical_search.py +245 -0
  36. epimemer-0.1.0/epimemer/pipelines/query/lineage.py +133 -0
  37. epimemer-0.1.0/epimemer/pipelines/query/types.py +128 -0
  38. epimemer-0.1.0/epimemer/pipelines/query/validity.py +90 -0
  39. epimemer-0.1.0/epimemer/pipelines/query/vector_search.py +51 -0
  40. epimemer-0.1.0/epimemer/pipelines/reflection/__init__.py +0 -0
  41. epimemer-0.1.0/epimemer/pipelines/reflection/archival.py +367 -0
  42. epimemer-0.1.0/epimemer/pipelines/reflection/batch_validation.py +183 -0
  43. epimemer-0.1.0/epimemer/pipelines/reflection/boundaries.py +498 -0
  44. epimemer-0.1.0/epimemer/pipelines/reflection/contradiction_detection.py +116 -0
  45. epimemer-0.1.0/epimemer/pipelines/reflection/fact_dedup.py +221 -0
  46. epimemer-0.1.0/epimemer/pipelines/reflection/inference_dedup.py +410 -0
  47. epimemer-0.1.0/epimemer/pipelines/reflection/pair_scoring.py +106 -0
  48. epimemer-0.1.0/epimemer/pipelines/reflection/relation_consolidation.py +168 -0
  49. epimemer-0.1.0/epimemer/pipelines/reflection/relation_verdicts.py +274 -0
  50. epimemer-0.1.0/epimemer/pipelines/reflection/retention.py +167 -0
  51. epimemer-0.1.0/epimemer/pipelines/reflection/review.py +451 -0
  52. epimemer-0.1.0/epimemer/pipelines/reflection/similarity_decisions.py +336 -0
  53. epimemer-0.1.0/epimemer/pipelines/reflection/soundness.py +202 -0
  54. epimemer-0.1.0/epimemer/pipelines/reflection/topic_consolidation.py +207 -0
  55. epimemer-0.1.0/epimemer/pipelines/reflection/topic_enrichment.py +72 -0
  56. epimemer-0.1.0/epimemer/pipelines/reflection/topic_hierarchy.py +133 -0
  57. epimemer-0.1.0/epimemer/pipelines/reflection/topic_splitting.py +135 -0
  58. epimemer-0.1.0/epimemer/pipelines/review/__init__.py +14 -0
  59. epimemer-0.1.0/epimemer/pipelines/review/apply.py +403 -0
  60. epimemer-0.1.0/epimemer/pipelines/review/difficulty.py +190 -0
  61. epimemer-0.1.0/epimemer/pipelines/review/modes.py +110 -0
  62. epimemer-0.1.0/epimemer/pipelines/segmentation/__init__.py +0 -0
  63. epimemer-0.1.0/epimemer/pipelines/segmentation/paragraph_split.py +97 -0
  64. epimemer-0.1.0/epimemer/pipelines/segmentation/semantic_similarity.py +263 -0
  65. epimemer-0.1.0/epimemer/pipelines/timeline/__init__.py +0 -0
  66. epimemer-0.1.0/epimemer/pipelines/timeline/functions.py +215 -0
  67. epimemer-0.1.0/epimemer/pipelines/timeline/temporal.py +323 -0
  68. epimemer-0.1.0/epimemer/storage/__init__.py +0 -0
  69. epimemer-0.1.0/epimemer/storage/active_graph.py +133 -0
  70. epimemer-0.1.0/epimemer/storage/bm25.py +230 -0
  71. epimemer-0.1.0/epimemer/storage/memory.py +1268 -0
  72. epimemer-0.1.0/epimemer/storage/protocol.py +1401 -0
  73. epimemer-0.1.0/epimemer/storage/surrealdb_adapter.py +2339 -0
  74. epimemer-0.1.0/epimemer/visualization/__init__.py +1 -0
  75. epimemer-0.1.0/epimemer/visualization/event_bus.py +193 -0
  76. epimemer-0.1.0/epimemer/visualization/events.py +555 -0
  77. epimemer-0.1.0/epimemer/visualization/graph_actions.py +129 -0
  78. epimemer-0.1.0/epimemer/visualization/hub.py +656 -0
  79. epimemer-0.1.0/epimemer/visualization/hub_client.py +195 -0
  80. epimemer-0.1.0/epimemer/visualization/instrumented_executor.py +226 -0
  81. epimemer-0.1.0/epimemer/visualization/instrumented_storage.py +847 -0
  82. epimemer-0.1.0/epimemer/visualization/phase_events.py +158 -0
  83. epimemer-0.1.0/epimemer/visualization/protocol.py +84 -0
  84. epimemer-0.1.0/epimemer/visualization/ring.py +51 -0
  85. epimemer-0.1.0/epimemer/visualization/snapshot.py +76 -0
  86. epimemer-0.1.0/epimemer/visualization/static/assets/index-BMXZD4a-.css +1 -0
  87. epimemer-0.1.0/epimemer/visualization/static/assets/index-DJhoXGzC.js +354 -0
  88. epimemer-0.1.0/epimemer/visualization/static/index.html +224 -0
  89. epimemer-0.1.0/epimemer.egg-info/PKG-INFO +290 -0
  90. epimemer-0.1.0/epimemer.egg-info/SOURCES.txt +99 -0
  91. epimemer-0.1.0/epimemer.egg-info/dependency_links.txt +1 -0
  92. epimemer-0.1.0/epimemer.egg-info/entry_points.txt +3 -0
  93. epimemer-0.1.0/epimemer.egg-info/requires.txt +21 -0
  94. epimemer-0.1.0/epimemer.egg-info/top_level.txt +2 -0
  95. epimemer-0.1.0/pyproject.toml +109 -0
  96. epimemer-0.1.0/setup.cfg +4 -0
  97. epimemer-0.1.0/tests/test_bench_smoke.py +287 -0
  98. epimemer-0.1.0/tests/test_cli.py +354 -0
  99. epimemer-0.1.0/tests/test_corpus_measure_smoke.py +228 -0
  100. epimemer-0.1.0/tests/test_docs.py +132 -0
  101. epimemer-0.1.0/tests/test_notebooks.py +273 -0
epimemer-0.1.0/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Oleg Lenive
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,290 @@
1
+ Metadata-Version: 2.4
2
+ Name: epimemer
3
+ Version: 0.1.0
4
+ Summary: Epistemic memory for AI agents over MCP: a typed graph of claims with provenance, frames, validity in time, and a review loop
5
+ Author: Oleg Lenive
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/olenive/epimemer
8
+ Project-URL: Repository, https://github.com/olenive/epimemer
9
+ Project-URL: Issues, https://github.com/olenive/epimemer/issues
10
+ Project-URL: Changelog, https://github.com/olenive/epimemer/blob/main/CHANGELOG.md
11
+ Keywords: mcp,memory,knowledge-graph,agents,epistemic,claude
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
17
+ Classifier: Topic :: Database
18
+ Requires-Python: >=3.14
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: petritype>=0.1.1
22
+ Requires-Dist: numpy>=2.0
23
+ Requires-Dist: pydantic>=2.12.5
24
+ Requires-Dist: surrealdb>=1.0.8
25
+ Requires-Dist: fastmcp>=3.1.0
26
+ Requires-Dist: starlette>=0.46.0
27
+ Requires-Dist: uvicorn>=0.34.0
28
+ Requires-Dist: websockets>=13.0
29
+ Provides-Extra: sentence-transformers
30
+ Requires-Dist: sentence-transformers>=5.3.0; extra == "sentence-transformers"
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=9.0.2; extra == "dev"
33
+ Requires-Dist: pytest-asyncio>=1.3.0; extra == "dev"
34
+ Requires-Dist: ruff>=0.16; extra == "dev"
35
+ Provides-Extra: notebooks
36
+ Requires-Dist: marimo>=0.13.0; extra == "notebooks"
37
+ Requires-Dist: petritype[examples]; extra == "notebooks"
38
+ Requires-Dist: graphviz>=0.20; extra == "notebooks"
39
+ Dynamic: license-file
40
+
41
+ # Epimemer
42
+
43
+ ## Motivation
44
+ LLMs store general knowledge in their weights and specific or episodic
45
+ facts, inferences or background information in their context. However,
46
+ as specific details accumulate over time, they eventually exhaust the
47
+ available context window.
48
+ Epimemer is a tool for context engineering with the goal of providing
49
+ necessary information without flooding the context window with details
50
+ that are irrelevant to the task at hand.
51
+
52
+ ## Outline
53
+ An epistemic memory server for AI agents, speaking the
54
+ [Model Context Protocol](https://modelcontextprotocol.io). The agent hands
55
+ over what it has read, and Epimemer keeps it as a typed graph of **topics**,
56
+ **facts** and **inferences** that remembers where each claim came from, which world it is
57
+ about, when it held, what contradicts it, and who decided what. It then
58
+ nominates the graph's own weak points for the agent to review.
59
+
60
+ Epimemer performs no extraction of its own. Reading a document and deciding
61
+ what it claims is the calling agent's job; Epimemer's job is to hold those
62
+ claims honestly and to keep asking whether they still stand.
63
+
64
+ - **Provenance, not strings.** Every fact carries `sourced_from` edges to the
65
+ documents that assert it, and a merge keeps one per contributing source.
66
+ - **Frames.** A claim states which world it is about — the real one, a novel, a
67
+ named source, a perspective — so fiction never corroborates fact and two
68
+ perspectives can disagree without either being wrong.
69
+ - **Validity in time.** Each source records when it says a claim held, so a
70
+ fact read in 1997 and one read in 2024 can be the same condition with two
71
+ periods, or two events that must never merge.
72
+ - **A review loop.** `reflect` nominates near-duplicates, contradictions, stale
73
+ evidence and never-retrieved nodes; `apply_reflection` records the agent's
74
+ verdict on each, and a verdict once recorded is never asked again.
75
+ - **A decision journal.** Every judgment names the judge that made it. `review`
76
+ reads them back shakiest first, so a different agent — or a person — can
77
+ check what an earlier one decided.
78
+
79
+ Python 3.14+. MIT licensed.
80
+
81
+ ## Install
82
+
83
+ ```bash
84
+ uv tool install "epimemer[sentence-transformers]"
85
+ # or: pip install "epimemer[sentence-transformers]"
86
+ ```
87
+
88
+ | Extra | Adds | When you need it |
89
+ |-------|------|------------------|
90
+ | `sentence-transformers` | Local embeddings via [sentence-transformers](https://www.sbert.net) (pulls in PyTorch) | The default embedding provider. Without it, set `EPIMEMER_EMBEDDING_PROVIDER` to another provider, or the server refuses to start and says which extra to install |
91
+ | `notebooks` | [marimo](https://marimo.io) and the Petri-net plotting stack | Only for the walkthrough notebooks in the repository |
92
+
93
+ The embedding model (`all-MiniLM-L6-v2`, ~80 MB) downloads on first run.
94
+
95
+ ## Connect to Claude Code
96
+
97
+ ```bash
98
+ claude mcp add epimemer -- epimemer serve
99
+ ```
100
+
101
+ Then run `/mcp` inside Claude Code to confirm the server is listed. This uses
102
+ the defaults: local embeddings and **in-memory storage, lost when the server
103
+ exits** — see [Persistence](#persistence) for the setup that keeps a graph.
104
+
105
+ Any other MCP client works the same way: the server speaks stdio, and
106
+ `epimemer serve` is the command. The
107
+ [integration guide](https://github.com/olenive/epimemer/blob/main/INTEGRATION.md)
108
+ has the full configuration, the system-prompt guidance that tells an agent how
109
+ to use the tools well, and the canonical tool table.
110
+
111
+ ## Persistence
112
+
113
+ Persistent storage is a [SurrealDB](https://surrealdb.com) server. **The
114
+ storage path is the whole difference between persistent and not**: `surreal
115
+ start` takes an optional `[PATH]` whose default is `memory`, so a server
116
+ started without one keeps the entire graph in RAM and loses it on restart,
117
+ with no error and no warning. Every command here passes an explicit
118
+ `rocksdb:` path.
119
+
120
+ ```bash
121
+ # Docker — on disk, in a named volume that outlives the container.
122
+ # -u 0:0 because the image's non-root user cannot write the volume mount.
123
+ docker run -d --name surrealdb -p 8000:8000 \
124
+ --restart unless-stopped -u 0:0 \
125
+ -v surreal-data:/data \
126
+ surrealdb/surrealdb:latest \
127
+ start --user root --pass root rocksdb:/data/epimemer.db
128
+
129
+ # Or a native install — on disk, relative to the working directory
130
+ surreal start --user root --pass root rocksdb:epimemer.db
131
+ ```
132
+
133
+ Then register the server with the backend named:
134
+
135
+ ```bash
136
+ claude mcp add epimemer \
137
+ -e EPIMEMER_STORAGE_BACKEND=surrealdb \
138
+ -e EPIMEMER_SURREALDB_URL=ws://localhost:8000/rpc \
139
+ -e EPIMEMER_GRAPH=default \
140
+ -- epimemer serve
141
+ ```
142
+
143
+ `root`/`root` are SurrealDB's local-development credentials; set
144
+ `EPIMEMER_SURREALDB_USER` and `EPIMEMER_SURREALDB_PASS` for anything else. Set
145
+ `EPIMEMER_GRAPH` per server: the active graph is process state, so a client
146
+ reconnect lands back on whatever the server opened.
147
+
148
+ ## Configuration
149
+
150
+ All configuration is via `EPIMEMER_` environment variables:
151
+
152
+ | Variable | Default | Description |
153
+ |----------|---------|-------------|
154
+ | `EPIMEMER_STORAGE_BACKEND` | `memory` | `memory` or `surrealdb` |
155
+ | `EPIMEMER_SURREALDB_URL` | `ws://localhost:8000/rpc` | SurrealDB connection URL |
156
+ | `EPIMEMER_SURREALDB_USER` | `root` | SurrealDB username |
157
+ | `EPIMEMER_SURREALDB_PASS` | `root` | SurrealDB password |
158
+ | `EPIMEMER_SURREALDB_NAMESPACE` | `epimemer` | SurrealDB namespace |
159
+ | `EPIMEMER_SURREALDB_DATABASE` | `default` | SurrealDB database name — one database per graph. This is a *name*, not a storage mode: whether storage is in-memory is decided by `EPIMEMER_STORAGE_BACKEND` here and by the `[PATH]` argument on the server |
160
+ | `EPIMEMER_GRAPH` | (empty) | The graph this server opens, overriding the database name above. **Set it per server.** The active graph is process state, so `use_graph` lasts only as long as the process and a client reconnect lands back here — see the [integration guide](https://github.com/olenive/epimemer/blob/main/INTEGRATION.md#which-graph-a-server-opens) |
161
+ | `EPIMEMER_EMBEDDING_PROVIDER` | `sentence-transformers` | `sentence-transformers` or `mock` |
162
+ | `EPIMEMER_EMBEDDING_MODEL_ID` | `all-MiniLM-L6-v2` | Embedding model name |
163
+ | `EPIMEMER_EMBEDDING_DIMENSION` | `384` | Embedding vector dimension |
164
+ | `EPIMEMER_SEGMENTATION_STRATEGY` | `paragraph` | `paragraph` or `semantic` |
165
+ | `EPIMEMER_SIMILARITY_THRESHOLD` | `0.75` | Similarity threshold for search |
166
+ | `EPIMEMER_REFLECT_THRESHOLD` | `10` | Server-wide default: stores in a graph before suggesting reflection (counted per graph, in storage; reported with the count by `graph_stats`, and overridable per graph via `configure_reflection`) |
167
+ | `EPIMEMER_RECORD_RETRIEVAL` | `true` | Whether `search` stamps `retrieved_at` on what it returns. `false` disables it, at the cost of making `never_retrieved` blind; ranking is never affected either way |
168
+ | `EPIMEMER_IMPORTANCE_STEP` | `0.25` | How much of the gap to its bound one `judge_importance` call closes, up or down. Nothing automatic moves it |
169
+ | `EPIMEMER_TOOL_TIMEOUT_SECONDS` | `30.0` | Timeout per tool operation |
170
+ | `EPIMEMER_APPROVED_AGENTS` | (empty) | Comma-separated agent ids the user admits as judges in every graph this server opens. Read when the backend connects and when the server lands on a graph. The approval channel for clients with no approval prompt of their own, and the only one that reaches an embedded store — see [ATTRIBUTION.md](https://github.com/olenive/epimemer/blob/main/docs/ATTRIBUTION.md) |
171
+ | `EPIMEMER_REQUIRE_JUDGE` | `false` | Refuse any write that names no judge, on every graph this server opens. Off by default: a blank judge means *unknown*, and many graphs have no reason to care. Overridable per graph with `epimemer agents require`, and deliberately not settable by any MCP tool |
172
+ | `EPIMEMER_VIZ_ENABLED` | `true` | Publish visualization events to the hub |
173
+ | `EPIMEMER_VIZ_HOST` | `127.0.0.1` | Visualization hub host |
174
+ | `EPIMEMER_VIZ_PORT` | `8765` | Visualization hub port |
175
+ | `EPIMEMER_VIZ_AUTOSPAWN` | `true` | Spawn a hub automatically if none is running |
176
+ | `EPIMEMER_LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |
177
+ | `EPIMEMER_LOG_FILE` | (stderr) | Path to log file |
178
+
179
+ ## MCP Tools
180
+
181
+ Tools exposed via the Model Context Protocol (auto-prefixed as `mcp__epimemer__<name>` by Claude Code), grouped by purpose:
182
+
183
+ - **Core memory**: `segment`, `store_decomposition`, `search`, `link`, `update`, `supersede_by`, `judge_importance`
184
+ - **Discovery & stats**: `query_graph`, `topic_tree`, `find_nodes`, `list_sources`, `list_relations`, `describe_relation`, `graph_stats`
185
+ - **Conflict handling**: `check_conflicts`, `record_contradiction`, `record_variant`, `merge_facts`, `merge_inferences`, `reverse_merge`, `configure_merge`, `configure_warnings`
186
+ - **Reflection**: `reflect`, `configure_reflection`, `apply_reflection`
187
+ - **Temporal access**: `graph_as_of`, `query_changes`
188
+ - **Archival**: `archive`, `restore`
189
+ - **Timelines**: `create_timeline`, `set_reference_time`, `add_timepoint`, `query_timeline`, `create_timelink`
190
+ - **Metacontexts**: `create_metacontext`, `get_metacontexts`
191
+ - **Graph management**: `list_graphs`, `use_graph`, `delete_graph`
192
+ - **Agents**: `claim_agent` — say which judge you are; the user picks it, and
193
+ can rename it later without disturbing a single decision
194
+ - **Review**: `review` — the decisions this graph has recorded, shakiest first;
195
+ `apply_review` — record that you checked one, and whether you agree;
196
+ `rejudge` — revise a judgment made at ingest without touching the claim;
197
+ `reframe` — withdraw a metacontext from a node, or move it to another in
198
+ one call; `correct_interval` — replace what one source is recorded as
199
+ asserting about when a claim held
200
+ - **Visualization**: `viz_status`
201
+
202
+ The [integration guide](https://github.com/olenive/epimemer/blob/main/INTEGRATION.md#available-tools)
203
+ has the canonical table with one-line descriptions and the authoritative tool count.
204
+
205
+ ## Visualization
206
+
207
+ A browser dashboard showing the knowledge graph, pipeline execution and
208
+ timelines, live. It is a **standalone hub** that many MCP sessions publish to,
209
+ rather than a server embedded in each MCP process, so several agents can be
210
+ watched from one page.
211
+
212
+ - **The hub owns the port** (`EPIMEMER_VIZ_HOST:EPIMEMER_VIZ_PORT`, default
213
+ `127.0.0.1:8765`). Each MCP process dials out to it and registers as a
214
+ *session*; the browser picks a session from the header selector.
215
+ - **Auto-spawn**: the first MCP process with `EPIMEMER_VIZ_ENABLED=true` spawns
216
+ a detached hub if none is running (disable with `EPIMEMER_VIZ_AUTOSPAWN=false`).
217
+ - **CLI**: `epimemer-viz [--status|--stop]` for explicit control.
218
+ - **`viz_status` tool**: ask through the very session you are driving — it
219
+ returns the hub URL, whether the hub can see this session, and the
220
+ `session_id` to pick in the selector. The durable answer to "I opened the
221
+ visualizer but can't find my graph".
222
+ - **Activity log**: one entry per transaction — what the agent stored,
223
+ corrected, world-changed, merged, archived or restored — filterable by verb,
224
+ node id, text and time. Click an entry to highlight the nodes it acted on;
225
+ click a node to filter the log to it.
226
+ - **Retrieval focus**: pick a recent tool call and everything it did *not*
227
+ return desaturates. Dimmed nodes stay clickable — the interesting click is
228
+ on one that did not come back — and the drawer's **Response** tab shows
229
+ exactly what Epimemer returned.
230
+ - **Timeline**: one timeline at a time on a vertical axis, in *record time*
231
+ (when the graph learned each node) or *content time* (when the described
232
+ events happened). Large gaps collapse to a labelled break; vague timepoints
233
+ sit in an *undated* tray rather than being given an invented date.
234
+
235
+ > **`EPIMEMER_VIZ_HOST` is a privacy setting as well as a network one.** On the
236
+ > default loopback bind the hub keeps whole retrieval records, so they survive
237
+ > the MCP process exiting. Point it at a non-loopback address and sessions
238
+ > mirror **structural metadata only** — no query text, no response payloads —
239
+ > and the payloads stay in the MCP process, reachable only while it is running.
240
+
241
+ ## Administration
242
+
243
+ `epimemer agents list` shows a graph's approved judges, whether it requires
244
+ one, and what each has said about itself. `epimemer agents confirm <name>`
245
+ admits one, `epimemer agents rename <handle> <name>` renames one (add
246
+ `--same-judge` to consolidate two that are really one), and `epimemer agents
247
+ require on|off|default` decides whether writes to that graph must name one.
248
+ No MCP tool can perform these acts: they are deliberately reserved for a
249
+ person, because a tool the agent calls cannot prove that the user asked for
250
+ it.
251
+
252
+ `epimemer relations backfill` gives every relationship label already in use a
253
+ record, in one go. It is idempotent and never touches a label that has one.
254
+
255
+ All of these work only against a **served** SurrealDB. An embedded store
256
+ lives inside the server process, so a CLI writing to it would write to a
257
+ separate copy the running server never reads. For the two settings, use
258
+ `EPIMEMER_APPROVED_AGENTS` and `EPIMEMER_REQUIRE_JUDGE` instead; the command
259
+ refuses and names the right variable rather than appearing to succeed.
260
+
261
+ ## Architecture
262
+
263
+ - **Dual-space**: vector embeddings as primary representation, typed graph derived on top
264
+ - **Three node types**: Topics (themes), Facts (atomic statements), Inferences (provisional derivations)
265
+ - **Timelines**: ordered containers of timepoints for temporal relationships
266
+ - **Metacontexts**: epistemic frames that disambiguate fiction from fact, sources, perspectives
267
+ - **Petri nets**: all pipelines are executable, typed, visualizable Petri nets via [Petritype](https://github.com/olenive/petritype)
268
+ - **Immutable history**: a node's *content* is never mutated — updates create new versions with history edges (lifecycle metadata like `status` and value signals is mutated in place)
269
+ - **Sources, tags, relations**: provenance and aboutness are nodes & edges (`sourced_from`, `tagged_with`), not strings; relationships are open-vocabulary user-labelled edges
270
+
271
+ ## Documentation
272
+
273
+ - [SUMMARY.md](https://github.com/olenive/epimemer/blob/main/SUMMARY.md) — Architectural design: the concepts and their rationale
274
+ - [INTEGRATION.md](https://github.com/olenive/epimemer/blob/main/INTEGRATION.md) — Claude Code integration guide, system-prompt guidance and the canonical tool table
275
+ - [docs/RETRIEVAL.md](https://github.com/olenive/epimemer/blob/main/docs/RETRIEVAL.md) — How `search` is answered: the two arms, rank fusion, result provenance, lineage collapse
276
+ - [docs/VALIDITY.md](https://github.com/olenive/epimemer/blob/main/docs/VALIDITY.md) — When a claim was true: intervals per source, correction vs world-change, recurrence, the soundness check
277
+ - [docs/REFLECTION.md](https://github.com/olenive/epimemer/blob/main/docs/REFLECTION.md) — The review loop: verdicts, what `reflect` nominates, what `apply_reflection` writes
278
+ - [docs/ATTRIBUTION.md](https://github.com/olenive/epimemer/blob/main/docs/ATTRIBUTION.md) — Who judged this: the agent registry, why the user assigns the id, how approval reaches them, the append-only journal of every decision, and reading it back with `review` / `apply_review` / `rejudge`
279
+
280
+ ## Contributing
281
+
282
+ Development setup, the test suites, the frontend build and where the design
283
+ history lives are in
284
+ [CONTRIBUTING.md](https://github.com/olenive/epimemer/blob/main/CONTRIBUTING.md).
285
+ Bugs and proposals go to the
286
+ [issue tracker](https://github.com/olenive/epimemer/issues).
287
+
288
+ ## License
289
+
290
+ [MIT](https://github.com/olenive/epimemer/blob/main/LICENSE).
@@ -0,0 +1,250 @@
1
+ # Epimemer
2
+
3
+ ## Motivation
4
+ LLMs store general knowledge in their weights and specific or episodic
5
+ facts, inferences or background information in their context. However,
6
+ as specific details accumulate over time, they eventually exhaust the
7
+ available context window.
8
+ Epimemer is a tool for context engineering with the goal of providing
9
+ necessary information without flooding the context window with details
10
+ that are irrelevant to the task at hand.
11
+
12
+ ## Outline
13
+ An epistemic memory server for AI agents, speaking the
14
+ [Model Context Protocol](https://modelcontextprotocol.io). The agent hands
15
+ over what it has read, and Epimemer keeps it as a typed graph of **topics**,
16
+ **facts** and **inferences** that remembers where each claim came from, which world it is
17
+ about, when it held, what contradicts it, and who decided what. It then
18
+ nominates the graph's own weak points for the agent to review.
19
+
20
+ Epimemer performs no extraction of its own. Reading a document and deciding
21
+ what it claims is the calling agent's job; Epimemer's job is to hold those
22
+ claims honestly and to keep asking whether they still stand.
23
+
24
+ - **Provenance, not strings.** Every fact carries `sourced_from` edges to the
25
+ documents that assert it, and a merge keeps one per contributing source.
26
+ - **Frames.** A claim states which world it is about — the real one, a novel, a
27
+ named source, a perspective — so fiction never corroborates fact and two
28
+ perspectives can disagree without either being wrong.
29
+ - **Validity in time.** Each source records when it says a claim held, so a
30
+ fact read in 1997 and one read in 2024 can be the same condition with two
31
+ periods, or two events that must never merge.
32
+ - **A review loop.** `reflect` nominates near-duplicates, contradictions, stale
33
+ evidence and never-retrieved nodes; `apply_reflection` records the agent's
34
+ verdict on each, and a verdict once recorded is never asked again.
35
+ - **A decision journal.** Every judgment names the judge that made it. `review`
36
+ reads them back shakiest first, so a different agent — or a person — can
37
+ check what an earlier one decided.
38
+
39
+ Python 3.14+. MIT licensed.
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ uv tool install "epimemer[sentence-transformers]"
45
+ # or: pip install "epimemer[sentence-transformers]"
46
+ ```
47
+
48
+ | Extra | Adds | When you need it |
49
+ |-------|------|------------------|
50
+ | `sentence-transformers` | Local embeddings via [sentence-transformers](https://www.sbert.net) (pulls in PyTorch) | The default embedding provider. Without it, set `EPIMEMER_EMBEDDING_PROVIDER` to another provider, or the server refuses to start and says which extra to install |
51
+ | `notebooks` | [marimo](https://marimo.io) and the Petri-net plotting stack | Only for the walkthrough notebooks in the repository |
52
+
53
+ The embedding model (`all-MiniLM-L6-v2`, ~80 MB) downloads on first run.
54
+
55
+ ## Connect to Claude Code
56
+
57
+ ```bash
58
+ claude mcp add epimemer -- epimemer serve
59
+ ```
60
+
61
+ Then run `/mcp` inside Claude Code to confirm the server is listed. This uses
62
+ the defaults: local embeddings and **in-memory storage, lost when the server
63
+ exits** — see [Persistence](#persistence) for the setup that keeps a graph.
64
+
65
+ Any other MCP client works the same way: the server speaks stdio, and
66
+ `epimemer serve` is the command. The
67
+ [integration guide](https://github.com/olenive/epimemer/blob/main/INTEGRATION.md)
68
+ has the full configuration, the system-prompt guidance that tells an agent how
69
+ to use the tools well, and the canonical tool table.
70
+
71
+ ## Persistence
72
+
73
+ Persistent storage is a [SurrealDB](https://surrealdb.com) server. **The
74
+ storage path is the whole difference between persistent and not**: `surreal
75
+ start` takes an optional `[PATH]` whose default is `memory`, so a server
76
+ started without one keeps the entire graph in RAM and loses it on restart,
77
+ with no error and no warning. Every command here passes an explicit
78
+ `rocksdb:` path.
79
+
80
+ ```bash
81
+ # Docker — on disk, in a named volume that outlives the container.
82
+ # -u 0:0 because the image's non-root user cannot write the volume mount.
83
+ docker run -d --name surrealdb -p 8000:8000 \
84
+ --restart unless-stopped -u 0:0 \
85
+ -v surreal-data:/data \
86
+ surrealdb/surrealdb:latest \
87
+ start --user root --pass root rocksdb:/data/epimemer.db
88
+
89
+ # Or a native install — on disk, relative to the working directory
90
+ surreal start --user root --pass root rocksdb:epimemer.db
91
+ ```
92
+
93
+ Then register the server with the backend named:
94
+
95
+ ```bash
96
+ claude mcp add epimemer \
97
+ -e EPIMEMER_STORAGE_BACKEND=surrealdb \
98
+ -e EPIMEMER_SURREALDB_URL=ws://localhost:8000/rpc \
99
+ -e EPIMEMER_GRAPH=default \
100
+ -- epimemer serve
101
+ ```
102
+
103
+ `root`/`root` are SurrealDB's local-development credentials; set
104
+ `EPIMEMER_SURREALDB_USER` and `EPIMEMER_SURREALDB_PASS` for anything else. Set
105
+ `EPIMEMER_GRAPH` per server: the active graph is process state, so a client
106
+ reconnect lands back on whatever the server opened.
107
+
108
+ ## Configuration
109
+
110
+ All configuration is via `EPIMEMER_` environment variables:
111
+
112
+ | Variable | Default | Description |
113
+ |----------|---------|-------------|
114
+ | `EPIMEMER_STORAGE_BACKEND` | `memory` | `memory` or `surrealdb` |
115
+ | `EPIMEMER_SURREALDB_URL` | `ws://localhost:8000/rpc` | SurrealDB connection URL |
116
+ | `EPIMEMER_SURREALDB_USER` | `root` | SurrealDB username |
117
+ | `EPIMEMER_SURREALDB_PASS` | `root` | SurrealDB password |
118
+ | `EPIMEMER_SURREALDB_NAMESPACE` | `epimemer` | SurrealDB namespace |
119
+ | `EPIMEMER_SURREALDB_DATABASE` | `default` | SurrealDB database name — one database per graph. This is a *name*, not a storage mode: whether storage is in-memory is decided by `EPIMEMER_STORAGE_BACKEND` here and by the `[PATH]` argument on the server |
120
+ | `EPIMEMER_GRAPH` | (empty) | The graph this server opens, overriding the database name above. **Set it per server.** The active graph is process state, so `use_graph` lasts only as long as the process and a client reconnect lands back here — see the [integration guide](https://github.com/olenive/epimemer/blob/main/INTEGRATION.md#which-graph-a-server-opens) |
121
+ | `EPIMEMER_EMBEDDING_PROVIDER` | `sentence-transformers` | `sentence-transformers` or `mock` |
122
+ | `EPIMEMER_EMBEDDING_MODEL_ID` | `all-MiniLM-L6-v2` | Embedding model name |
123
+ | `EPIMEMER_EMBEDDING_DIMENSION` | `384` | Embedding vector dimension |
124
+ | `EPIMEMER_SEGMENTATION_STRATEGY` | `paragraph` | `paragraph` or `semantic` |
125
+ | `EPIMEMER_SIMILARITY_THRESHOLD` | `0.75` | Similarity threshold for search |
126
+ | `EPIMEMER_REFLECT_THRESHOLD` | `10` | Server-wide default: stores in a graph before suggesting reflection (counted per graph, in storage; reported with the count by `graph_stats`, and overridable per graph via `configure_reflection`) |
127
+ | `EPIMEMER_RECORD_RETRIEVAL` | `true` | Whether `search` stamps `retrieved_at` on what it returns. `false` disables it, at the cost of making `never_retrieved` blind; ranking is never affected either way |
128
+ | `EPIMEMER_IMPORTANCE_STEP` | `0.25` | How much of the gap to its bound one `judge_importance` call closes, up or down. Nothing automatic moves it |
129
+ | `EPIMEMER_TOOL_TIMEOUT_SECONDS` | `30.0` | Timeout per tool operation |
130
+ | `EPIMEMER_APPROVED_AGENTS` | (empty) | Comma-separated agent ids the user admits as judges in every graph this server opens. Read when the backend connects and when the server lands on a graph. The approval channel for clients with no approval prompt of their own, and the only one that reaches an embedded store — see [ATTRIBUTION.md](https://github.com/olenive/epimemer/blob/main/docs/ATTRIBUTION.md) |
131
+ | `EPIMEMER_REQUIRE_JUDGE` | `false` | Refuse any write that names no judge, on every graph this server opens. Off by default: a blank judge means *unknown*, and many graphs have no reason to care. Overridable per graph with `epimemer agents require`, and deliberately not settable by any MCP tool |
132
+ | `EPIMEMER_VIZ_ENABLED` | `true` | Publish visualization events to the hub |
133
+ | `EPIMEMER_VIZ_HOST` | `127.0.0.1` | Visualization hub host |
134
+ | `EPIMEMER_VIZ_PORT` | `8765` | Visualization hub port |
135
+ | `EPIMEMER_VIZ_AUTOSPAWN` | `true` | Spawn a hub automatically if none is running |
136
+ | `EPIMEMER_LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` |
137
+ | `EPIMEMER_LOG_FILE` | (stderr) | Path to log file |
138
+
139
+ ## MCP Tools
140
+
141
+ Tools exposed via the Model Context Protocol (auto-prefixed as `mcp__epimemer__<name>` by Claude Code), grouped by purpose:
142
+
143
+ - **Core memory**: `segment`, `store_decomposition`, `search`, `link`, `update`, `supersede_by`, `judge_importance`
144
+ - **Discovery & stats**: `query_graph`, `topic_tree`, `find_nodes`, `list_sources`, `list_relations`, `describe_relation`, `graph_stats`
145
+ - **Conflict handling**: `check_conflicts`, `record_contradiction`, `record_variant`, `merge_facts`, `merge_inferences`, `reverse_merge`, `configure_merge`, `configure_warnings`
146
+ - **Reflection**: `reflect`, `configure_reflection`, `apply_reflection`
147
+ - **Temporal access**: `graph_as_of`, `query_changes`
148
+ - **Archival**: `archive`, `restore`
149
+ - **Timelines**: `create_timeline`, `set_reference_time`, `add_timepoint`, `query_timeline`, `create_timelink`
150
+ - **Metacontexts**: `create_metacontext`, `get_metacontexts`
151
+ - **Graph management**: `list_graphs`, `use_graph`, `delete_graph`
152
+ - **Agents**: `claim_agent` — say which judge you are; the user picks it, and
153
+ can rename it later without disturbing a single decision
154
+ - **Review**: `review` — the decisions this graph has recorded, shakiest first;
155
+ `apply_review` — record that you checked one, and whether you agree;
156
+ `rejudge` — revise a judgment made at ingest without touching the claim;
157
+ `reframe` — withdraw a metacontext from a node, or move it to another in
158
+ one call; `correct_interval` — replace what one source is recorded as
159
+ asserting about when a claim held
160
+ - **Visualization**: `viz_status`
161
+
162
+ The [integration guide](https://github.com/olenive/epimemer/blob/main/INTEGRATION.md#available-tools)
163
+ has the canonical table with one-line descriptions and the authoritative tool count.
164
+
165
+ ## Visualization
166
+
167
+ A browser dashboard showing the knowledge graph, pipeline execution and
168
+ timelines, live. It is a **standalone hub** that many MCP sessions publish to,
169
+ rather than a server embedded in each MCP process, so several agents can be
170
+ watched from one page.
171
+
172
+ - **The hub owns the port** (`EPIMEMER_VIZ_HOST:EPIMEMER_VIZ_PORT`, default
173
+ `127.0.0.1:8765`). Each MCP process dials out to it and registers as a
174
+ *session*; the browser picks a session from the header selector.
175
+ - **Auto-spawn**: the first MCP process with `EPIMEMER_VIZ_ENABLED=true` spawns
176
+ a detached hub if none is running (disable with `EPIMEMER_VIZ_AUTOSPAWN=false`).
177
+ - **CLI**: `epimemer-viz [--status|--stop]` for explicit control.
178
+ - **`viz_status` tool**: ask through the very session you are driving — it
179
+ returns the hub URL, whether the hub can see this session, and the
180
+ `session_id` to pick in the selector. The durable answer to "I opened the
181
+ visualizer but can't find my graph".
182
+ - **Activity log**: one entry per transaction — what the agent stored,
183
+ corrected, world-changed, merged, archived or restored — filterable by verb,
184
+ node id, text and time. Click an entry to highlight the nodes it acted on;
185
+ click a node to filter the log to it.
186
+ - **Retrieval focus**: pick a recent tool call and everything it did *not*
187
+ return desaturates. Dimmed nodes stay clickable — the interesting click is
188
+ on one that did not come back — and the drawer's **Response** tab shows
189
+ exactly what Epimemer returned.
190
+ - **Timeline**: one timeline at a time on a vertical axis, in *record time*
191
+ (when the graph learned each node) or *content time* (when the described
192
+ events happened). Large gaps collapse to a labelled break; vague timepoints
193
+ sit in an *undated* tray rather than being given an invented date.
194
+
195
+ > **`EPIMEMER_VIZ_HOST` is a privacy setting as well as a network one.** On the
196
+ > default loopback bind the hub keeps whole retrieval records, so they survive
197
+ > the MCP process exiting. Point it at a non-loopback address and sessions
198
+ > mirror **structural metadata only** — no query text, no response payloads —
199
+ > and the payloads stay in the MCP process, reachable only while it is running.
200
+
201
+ ## Administration
202
+
203
+ `epimemer agents list` shows a graph's approved judges, whether it requires
204
+ one, and what each has said about itself. `epimemer agents confirm <name>`
205
+ admits one, `epimemer agents rename <handle> <name>` renames one (add
206
+ `--same-judge` to consolidate two that are really one), and `epimemer agents
207
+ require on|off|default` decides whether writes to that graph must name one.
208
+ No MCP tool can perform these acts: they are deliberately reserved for a
209
+ person, because a tool the agent calls cannot prove that the user asked for
210
+ it.
211
+
212
+ `epimemer relations backfill` gives every relationship label already in use a
213
+ record, in one go. It is idempotent and never touches a label that has one.
214
+
215
+ All of these work only against a **served** SurrealDB. An embedded store
216
+ lives inside the server process, so a CLI writing to it would write to a
217
+ separate copy the running server never reads. For the two settings, use
218
+ `EPIMEMER_APPROVED_AGENTS` and `EPIMEMER_REQUIRE_JUDGE` instead; the command
219
+ refuses and names the right variable rather than appearing to succeed.
220
+
221
+ ## Architecture
222
+
223
+ - **Dual-space**: vector embeddings as primary representation, typed graph derived on top
224
+ - **Three node types**: Topics (themes), Facts (atomic statements), Inferences (provisional derivations)
225
+ - **Timelines**: ordered containers of timepoints for temporal relationships
226
+ - **Metacontexts**: epistemic frames that disambiguate fiction from fact, sources, perspectives
227
+ - **Petri nets**: all pipelines are executable, typed, visualizable Petri nets via [Petritype](https://github.com/olenive/petritype)
228
+ - **Immutable history**: a node's *content* is never mutated — updates create new versions with history edges (lifecycle metadata like `status` and value signals is mutated in place)
229
+ - **Sources, tags, relations**: provenance and aboutness are nodes & edges (`sourced_from`, `tagged_with`), not strings; relationships are open-vocabulary user-labelled edges
230
+
231
+ ## Documentation
232
+
233
+ - [SUMMARY.md](https://github.com/olenive/epimemer/blob/main/SUMMARY.md) — Architectural design: the concepts and their rationale
234
+ - [INTEGRATION.md](https://github.com/olenive/epimemer/blob/main/INTEGRATION.md) — Claude Code integration guide, system-prompt guidance and the canonical tool table
235
+ - [docs/RETRIEVAL.md](https://github.com/olenive/epimemer/blob/main/docs/RETRIEVAL.md) — How `search` is answered: the two arms, rank fusion, result provenance, lineage collapse
236
+ - [docs/VALIDITY.md](https://github.com/olenive/epimemer/blob/main/docs/VALIDITY.md) — When a claim was true: intervals per source, correction vs world-change, recurrence, the soundness check
237
+ - [docs/REFLECTION.md](https://github.com/olenive/epimemer/blob/main/docs/REFLECTION.md) — The review loop: verdicts, what `reflect` nominates, what `apply_reflection` writes
238
+ - [docs/ATTRIBUTION.md](https://github.com/olenive/epimemer/blob/main/docs/ATTRIBUTION.md) — Who judged this: the agent registry, why the user assigns the id, how approval reaches them, the append-only journal of every decision, and reading it back with `review` / `apply_review` / `rejudge`
239
+
240
+ ## Contributing
241
+
242
+ Development setup, the test suites, the frontend build and where the design
243
+ history lives are in
244
+ [CONTRIBUTING.md](https://github.com/olenive/epimemer/blob/main/CONTRIBUTING.md).
245
+ Bugs and proposals go to the
246
+ [issue tracker](https://github.com/olenive/epimemer/issues).
247
+
248
+ ## License
249
+
250
+ [MIT](https://github.com/olenive/epimemer/blob/main/LICENSE).
File without changes