memkernel 0.2.0__tar.gz → 0.4.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.
- {memkernel-0.2.0 → memkernel-0.4.0}/PKG-INFO +116 -19
- {memkernel-0.2.0 → memkernel-0.4.0}/README.md +113 -18
- {memkernel-0.2.0 → memkernel-0.4.0}/pyproject.toml +3 -1
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/__init__.py +1 -1
- memkernel-0.4.0/src/memkernel/adapters/__init__.py +3 -0
- memkernel-0.4.0/src/memkernel/adapters/rlmstudio.py +123 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/api/routes/admin.py +16 -1
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/config.py +14 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/core/models.py +110 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/core/ports.py +45 -5
- memkernel-0.4.0/src/memkernel/core/services.py +1227 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/factory.py +37 -1
- memkernel-0.4.0/src/memkernel/lifecycle.py +221 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/mcp/server.py +41 -8
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/mcp/tools/memory.py +31 -7
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/retrieval/chunking.py +20 -0
- memkernel-0.4.0/src/memkernel/retrieval/reasoner.py +83 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/retrieval/search.py +31 -2
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/storage/chroma.py +53 -19
- memkernel-0.4.0/src/memkernel/storage/documents.py +185 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/wiki/sync.py +4 -4
- memkernel-0.2.0/src/memkernel/core/services.py +0 -485
- {memkernel-0.2.0 → memkernel-0.4.0}/LICENSE +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/NOTICE +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/api/__init__.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/api/app.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/api/routes/__init__.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/core/__init__.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/mcp/__init__.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/mcp/tools/__init__.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/mcp/tools/wiki.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/memory/__init__.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/memory/dedup.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/memory/lifecycle.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/memory/types.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/py.typed +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/retrieval/__init__.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/retrieval/embeddings.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/retrieval/sparse.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/storage/__init__.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/wiki/__init__.py +0 -0
- {memkernel-0.2.0 → memkernel-0.4.0}/src/memkernel/wiki/pages.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memkernel
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Code-aware memory server for AI coding copilots
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -22,16 +22,23 @@ Requires-Dist: rank-bm25 (>=0.2)
|
|
|
22
22
|
Requires-Dist: sentence-transformers (>=4.0,<6)
|
|
23
23
|
Requires-Dist: tree-sitter (>=0.22,<1)
|
|
24
24
|
Requires-Dist: tree-sitter-python (>=0.23)
|
|
25
|
+
Project-URL: Documentation, https://memkernel.dev
|
|
26
|
+
Project-URL: Homepage, https://memkernel.dev
|
|
25
27
|
Project-URL: Repository, https://github.com/gosha70/memkernel
|
|
26
28
|
Description-Content-Type: text/markdown
|
|
27
29
|
|
|
28
|
-
|
|
30
|
+
<h1>
|
|
31
|
+
<img src="https://raw.githubusercontent.com/gosha70/memkernel/main/docs/assets/memkernel-logo.png" alt="MemKernel logo: a glowing memory core on three stacked tiers" width="110" align="absmiddle">
|
|
32
|
+
MemKernel
|
|
33
|
+
</h1>
|
|
29
34
|
|
|
30
35
|
[](https://github.com/gosha70/memkernel/actions/workflows/ci.yml)
|
|
31
36
|
[](https://pypi.org/project/memkernel/)
|
|
32
37
|
[](pyproject.toml)
|
|
33
38
|
[](LICENSE)
|
|
34
39
|
|
|
40
|
+
**Site:** [memkernel.dev](https://memkernel.dev) · **Package:** [pypi.org/project/memkernel](https://pypi.org/project/memkernel/)
|
|
41
|
+
|
|
35
42
|
Code-aware memory server for AI coding copilots.
|
|
36
43
|
|
|
37
44
|
MemKernel gives Claude Code (and any MCP-compatible copilot) persistent memory across sessions. When Claude compacts context or a session ends, project decisions, conventions, and code understanding are normally lost. MemKernel stores them in a local vector database and retrieves them on demand.
|
|
@@ -44,23 +51,33 @@ MemKernel gives Claude Code (and any MCP-compatible copilot) persistent memory a
|
|
|
44
51
|
|
|
45
52
|
## Requirements
|
|
46
53
|
|
|
47
|
-
- Python 3.11 – 3.13
|
|
54
|
+
- Python 3.11 – 3.13 (the package declares `Requires-Python >=3.11,<3.14`; pip reports "from versions: none" when the installing interpreter is outside that range)
|
|
48
55
|
- [Poetry](https://python-poetry.org) (for development installs)
|
|
49
56
|
|
|
50
57
|
---
|
|
51
58
|
|
|
52
59
|
## Install
|
|
53
60
|
|
|
61
|
+
MemKernel is a Python package on PyPI. Its `memkernel` command is the MCP server. There is no npm package: an `npx` install someone suggests is a hallucination.
|
|
62
|
+
|
|
63
|
+
**Recommended: an isolated install with [pipx](https://pipx.pypa.io)**, which puts the `memkernel` command on your PATH without touching any other Python environment:
|
|
64
|
+
|
|
54
65
|
```bash
|
|
55
|
-
|
|
66
|
+
pipx install memkernel
|
|
67
|
+
# if pipx's default interpreter is outside 3.11–3.13:
|
|
68
|
+
pipx install --python python3.11 memkernel
|
|
56
69
|
```
|
|
57
70
|
|
|
58
|
-
|
|
71
|
+
**As a library inside a project**, install it into that project's virtual environment:
|
|
59
72
|
|
|
60
73
|
```bash
|
|
61
|
-
poetry add memkernel
|
|
74
|
+
pip install memkernel # or: poetry add memkernel
|
|
62
75
|
```
|
|
63
76
|
|
|
77
|
+
Avoid a plain `pip install memkernel` into a shared or system interpreter (Homebrew's `python3`, for example). MemKernel pins `chromadb` 1.x and recent `cffi`, so pip will replace older copies and can break unrelated tools that need them.
|
|
78
|
+
|
|
79
|
+
Verify the install with `pipx list` or `which memkernel`. Running `memkernel` with no arguments starts the MCP server on stdio and waits for a client; `memkernel --version` and `memkernel --help` print and exit.
|
|
80
|
+
|
|
64
81
|
---
|
|
65
82
|
|
|
66
83
|
## Add to Claude Code
|
|
@@ -73,17 +90,29 @@ Add MemKernel to `.claude/settings.json` in your project:
|
|
|
73
90
|
{
|
|
74
91
|
"mcpServers": {
|
|
75
92
|
"memkernel": {
|
|
76
|
-
"command": "memkernel",
|
|
93
|
+
"command": "/Users/you/.local/bin/memkernel",
|
|
77
94
|
"args": [],
|
|
78
95
|
"env": {
|
|
79
|
-
"MEMKERNEL_PROJECT_ID": "my-project"
|
|
96
|
+
"MEMKERNEL_PROJECT_ID": "my-project",
|
|
97
|
+
"MEMKERNEL_CHROMA_PERSIST_PATH": "/Users/you/.memkernel/my-project"
|
|
80
98
|
}
|
|
81
99
|
}
|
|
82
100
|
}
|
|
83
101
|
}
|
|
84
102
|
```
|
|
85
103
|
|
|
86
|
-
Replace `my-project` with a short identifier for the project — memories are isolated per project.
|
|
104
|
+
Replace `my-project` with a short identifier for the project — memories are isolated per project. Use the absolute path of the command (`which memkernel` prints it) because Claude Code does not necessarily see the PATH changes your shell profile makes, and an absolute `MEMKERNEL_CHROMA_PERSIST_PATH` keeps the store outside the repository. On first server initialization, MemKernel downloads the embedding model (about 90 MB) if it is not already cached: `build_service()` loads the sentence-transformers model when the MCP server starts, before any tool call, so the first connection can take a minute. Later starts and every tool call are fast.
|
|
105
|
+
|
|
106
|
+
<details>
|
|
107
|
+
<summary>Troubleshooting the install</summary>
|
|
108
|
+
|
|
109
|
+
- **`pipx install memkernel` says "No matching distribution found"** — pipx used an interpreter outside 3.11–3.13. Pass one explicitly: `pipx install --python /opt/homebrew/opt/python@3.11/bin/python3.11 memkernel`.
|
|
110
|
+
- **`bash: /some/old/path/memkernel: No such file or directory`** right after reinstalling — the shell cached the old location. Run `hash -r` (bash) or `rehash` (zsh), then `which memkernel`.
|
|
111
|
+
- **`memkernel --help` seems to hang** on versions before 0.4.0 — the command had no flags and started the server; press Ctrl-C. From 0.4.0 on, `--help` and `--version` print and exit.
|
|
112
|
+
- **The first MCP connection is slow or times out** — the server is downloading the embedding model at startup (see above). Wait for it once, or pre-warm it with `python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('all-MiniLM-L6-v2')"` in the same environment.
|
|
113
|
+
- **A global pip install broke another tool** (for example `langchain-chroma` wanting `chromadb < 0.6`) — uninstall memkernel from that interpreter, reinstall the versions the other tool needs, and install memkernel with pipx instead.
|
|
114
|
+
|
|
115
|
+
</details>
|
|
87
116
|
|
|
88
117
|
### 2. Add memory instructions to CLAUDE.md
|
|
89
118
|
|
|
@@ -99,7 +128,21 @@ Copy the hook scripts from [`templates/hooks/`](templates/hooks/) to `.claude/ho
|
|
|
99
128
|
| `pre-compact.py` | `PreCompact` | Retains a checkpoint episode, runs a consolidation pass |
|
|
100
129
|
| `post-compact.py` | `PostCompact` | Re-injects the checkpoint, long-term context and promotion candidates |
|
|
101
130
|
|
|
102
|
-
See the Prerequisites section inside each script for the Python environment requirement.
|
|
131
|
+
See the Prerequisites section inside each script for the Python environment requirement. Each script is a thin wrapper over [`MemoryLifecycle`](#embedding-memkernel-in-your-own-harness), so an in-process harness gets the same behaviour without the scripts.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Add to Kiro
|
|
136
|
+
|
|
137
|
+
Kiro (and the Kiro CLI, formerly Amazon Q Developer CLI) connects to MemKernel as a stdio MCP server. [`templates/kiro/`](templates/kiro/) holds the three files to copy into a workspace:
|
|
138
|
+
|
|
139
|
+
| Template | Destination | Role |
|
|
140
|
+
|----------|-------------|------|
|
|
141
|
+
| `settings/mcp.json` | `.kiro/settings/mcp.json` | Server entry with `env` and `autoApprove` |
|
|
142
|
+
| `steering/memory.md` | `.kiro/steering/memory.md` | Memory instructions, always included |
|
|
143
|
+
| `hooks/memkernel.json` | `.kiro/hooks/memkernel.json` | `SessionStart` recall, `Stop` retain, manual checkpoint |
|
|
144
|
+
|
|
145
|
+
[`templates/kiro/README.md`](templates/kiro/README.md) has the setup steps, the Kiro CLI custom-agent variant and the caveats (absolute persist path, hook format by Kiro version).
|
|
103
146
|
|
|
104
147
|
---
|
|
105
148
|
|
|
@@ -108,12 +151,12 @@ See the Prerequisites section inside each script for the Python environment requ
|
|
|
108
151
|
| Tool | What it does |
|
|
109
152
|
|------|-------------|
|
|
110
153
|
| `retain(content, type, session_id?, checkpoint?, source?, importance?, tags?, supersedes?)` | Store a memory. Returns `ref_id`. Idempotent — identical content + type returns the same `ref_id`. `supersedes` hides the memory it replaces. |
|
|
111
|
-
| `recall(query, type?, tier?, session_id?, checkpoint_only?, top_k?)` | Search by natural language or identifier. Returns lightweight `ArtifactRef` list ranked by relevance + recency + importance. Records an access (reinforces retention). |
|
|
154
|
+
| `recall(query, type?, tier?, session_id?, checkpoint_only?, top_k?, include_needs_review?)` | Search by natural language or identifier. Returns lightweight `ArtifactRef` list ranked by relevance + recency + importance. Records an access (reinforces retention). Code memories flagged `needs_review` are hidden unless `include_needs_review=true`. |
|
|
112
155
|
| `get(ref_id)` | Fetch full content of a specific memory. Records an access. |
|
|
113
156
|
| `forget(ref_id)` | Delete a memory from all indexes. |
|
|
114
157
|
| `promote(ref_id, type, content?, importance?, tags?)` | Turn a short-term/working memory into a long-term one (you supply the distilled text). Keeps provenance via `promoted_from`. |
|
|
115
|
-
| `consolidate(session_id?, limit?)` | Purge expired short-term memories and list the ones most worth promoting (ranked by importance × how often they were recalled). |
|
|
116
|
-
| `
|
|
158
|
+
| `consolidate(session_id?, limit?, synthesize?, revalidate?)` | Purge expired short-term memories and list the ones most worth promoting (ranked by importance × how often they were recalled). `synthesize=true` also asks an external reasoner to draft long-term statements (`suggested`); `revalidate=true` first checks every code memory against its source file (`revalidated`). The report always carries a `health` summary. |
|
|
159
|
+
| `ask(ref_id, question, mode?)` | Answer a question about one memory without loading it — for a `document` the full body is consulted. `mode`: `direct` \| `rag` \| `rlm` \| `auto`, passed to the reasoner unchanged; the built-in reasoner answers in `rag` mode with the best-matching chunks. Returns `answer`, `mode`, `citations`, `usage`. |
|
|
117
160
|
| `wiki_export(wiki_dir?)` | Compile long-term memories without a wiki page into draft markdown pages (`index.md`, `log.md` updated). |
|
|
118
161
|
| `wiki_import(wiki_dir?)` | Index curated wiki pages as long-term memories (idempotent; changed pages supersede). |
|
|
119
162
|
|
|
@@ -125,7 +168,8 @@ See the Prerequisites section inside each script for the Python environment requ
|
|
|
125
168
|
| `convention` | long-term | Naming rules, code style, project patterns | 0.9 | Never |
|
|
126
169
|
| `fact` | long-term | Durable project facts: build commands, environments, contracts | 0.7 | Never |
|
|
127
170
|
| `procedure` | long-term | How-to that worked: workflows, recipes, verified skills | 0.8 | Never |
|
|
128
|
-
| `code` | long-term | Function/class snapshots, API contracts | 0.6 | Never |
|
|
171
|
+
| `code` | long-term | Function/class snapshots, API contracts; identified by `(source, content)`, a changed file supersedes the old snapshot, a drifted source flags `needs_review` | 0.6 | Never (superseded on re-retain) |
|
|
172
|
+
| `document` | long-term | Large artefacts (specs, transcripts, files): the body is stored and chunk-indexed, `get` returns a summary, `ask` answers from the indexed chunks (local reasoner) or the body (RLM Studio) | 0.6 | Never |
|
|
129
173
|
| `episode` | short-term | Session events, compaction checkpoints | 0.4 | 30 days, extended by every recall |
|
|
130
174
|
| `observation` | short-term | Findings, tool outputs, things noticed | 0.3 | 7 days, extended by every recall |
|
|
131
175
|
| `task` | working | The current goal, plan state, open questions | 0.5 | 24 hours |
|
|
@@ -138,7 +182,9 @@ Retention: `ttl = base_ttl × (1 + access_boost × access_count)`, measured from
|
|
|
138
182
|
2. **While working** — `retain(type="task")` when the plan changes; `retain(type="observation")` for findings; durable knowledge as `decision` / `convention` / `fact` / `procedure`.
|
|
139
183
|
3. **Before compaction** — `retain(type="episode", checkpoint=true)` (the `pre-compact.py` hook) and `consolidate()`.
|
|
140
184
|
4. **After compaction / end of phase** — `promote(ref_id, type, content)` for the candidates worth keeping.
|
|
141
|
-
5. **
|
|
185
|
+
5. **Large artefacts** — `retain(type="document", content=<body>, source=<name>)` then `ask(ref_id, question)`; never `get` a document to read it.
|
|
186
|
+
7. **Code snapshots** — `retain(type="code", content=<file>, source=<path>)`; retain the file again after editing it (the new snapshot supersedes the old one). The session-start hook revalidates snapshots against their files and lists the ones that need re-retaining.
|
|
187
|
+
6. **Curate** — `wiki_export` → review the drafts → `wiki_import`.
|
|
142
188
|
|
|
143
189
|
### Quick examples
|
|
144
190
|
|
|
@@ -164,6 +210,10 @@ retain(content="Use arq, not Celery", type="decision", supersedes="<old decision
|
|
|
164
210
|
get(ref_id="<ref_id from recall>")
|
|
165
211
|
|
|
166
212
|
forget(ref_id="<ref_id>")
|
|
213
|
+
|
|
214
|
+
retain(content=<the whole spec>, type="document", source="specs/auth/spec.md")
|
|
215
|
+
|
|
216
|
+
ask(ref_id="<document ref_id>", question="Which endpoints need rate limiting?", mode="auto")
|
|
167
217
|
```
|
|
168
218
|
|
|
169
219
|
---
|
|
@@ -185,6 +235,14 @@ All settings are read from environment variables with the `MEMKERNEL_` prefix, o
|
|
|
185
235
|
| `MEMKERNEL_PREVIEW_LENGTH` | `200` | Max characters in the `preview` field of `ArtifactRef` |
|
|
186
236
|
| `MEMKERNEL_CHUNK_SIZE` | `1500` | Max characters per AST chunk (code memories) |
|
|
187
237
|
| `MEMKERNEL_CHUNK_OVERLAP` | `200` | Character overlap between token-based fallback chunks |
|
|
238
|
+
| `MEMKERNEL_DOCUMENT_STORE` | `local` | Where `document` bodies live (`local` = the project's own ChromaDB collection) |
|
|
239
|
+
| `MEMKERNEL_DOCUMENT_SUMMARY_CHARS` | `1000` | Characters of the body kept in a `document` memory's summary record |
|
|
240
|
+
| `MEMKERNEL_REASONER` | `local` | `ReasonerPort` behind `ask`: `local` (hybrid search over chunks, no LLM) or `rlmstudio` (falls back to `local` when `rlmstudio` is not importable) |
|
|
241
|
+
| `MEMKERNEL_ASK_TOP_K` | `5` | Chunks the local reasoner returns per `ask` |
|
|
242
|
+
| `MEMKERNEL_PROJECT_ROOT` | `.` | Directory that relative `source` paths of `code` memories resolve under; nothing outside it is ever read. Set it whenever the server or a hook is not started from the project directory |
|
|
243
|
+
| `MEMKERNEL_HEALTH_DUPLICATE_THRESHOLD` | `0.95` | Cosine similarity in [0, 1] from which two long-term memories count as near-duplicates in the health pass |
|
|
244
|
+
| `MEMKERNEL_HEALTH_DUPLICATE_LIMIT` | `500` | Most recent long-term memories the near-duplicate check covers |
|
|
245
|
+
| `MEMKERNEL_HEALTH_REPORT_LIMIT` | `20` | Items listed per category in a health report |
|
|
188
246
|
| `MEMKERNEL_EPISODE_TTL_DAYS` | `30` | Base TTL for `episode` memories (short-term) |
|
|
189
247
|
| `MEMKERNEL_OBSERVATION_TTL_DAYS` | `7` | Base TTL for `observation` memories (short-term) |
|
|
190
248
|
| `MEMKERNEL_TASK_TTL_HOURS` | `24` | Base TTL for `task` memories (working) |
|
|
@@ -237,6 +295,35 @@ report = svc.consolidate() # {"purged": n, "candidates": [...]}
|
|
|
237
295
|
|
|
238
296
|
`build_service()` is the supported entry point; the MCP server, the admin API and the hook templates all use it. Integration notes for `code-copilot-team` and `haa` are in [`docs/integration/harness-integration.md`](docs/integration/harness-integration.md).
|
|
239
297
|
|
|
298
|
+
### The session protocol as a component
|
|
299
|
+
|
|
300
|
+
`MemoryLifecycle` packages what the hook scripts do, so a harness calls four methods instead of re-implementing the protocol. Every method returns markdown ready for injection and does nothing but talk to the service:
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
from memkernel.factory import build_service
|
|
304
|
+
from memkernel.lifecycle import MemoryLifecycle
|
|
305
|
+
|
|
306
|
+
memory = MemoryLifecycle(build_service())
|
|
307
|
+
system_context = memory.on_session_start() # checkpoint, long-term context, promotion candidates, wiki pointer
|
|
308
|
+
...
|
|
309
|
+
memory.on_pre_compact(summary) # checkpoint episode + consolidation, before the context is compacted
|
|
310
|
+
recovered = memory.on_post_compact() # what to re-inject after compaction
|
|
311
|
+
memory.on_session_end(summary) # final checkpoint + consolidation
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Documents and `ask`
|
|
315
|
+
|
|
316
|
+
`retain(type="document")` keeps large artefacts out of the context window: the body goes to the document store (built-in: the project's own ChromaDB collection), its chunks are indexed for hybrid search, and the memkernel record is a summary. `ask(ref_id, question, mode)` answers through a `ReasonerPort`:
|
|
317
|
+
|
|
318
|
+
- `MEMKERNEL_REASONER=local` (default) — no LLM: the question is matched against the document's chunks with dense + BM25 + RRF and the best chunks come back as the answer, `mode="rag"`.
|
|
319
|
+
- `MEMKERNEL_REASONER=rlmstudio` — delegates to [rlm-studio](https://github.com/gosha70/rlm-studio)'s `interact(content, question, mode=mode)`, so `direct`, `rag`, `rlm` and `auto` select how the document is read (ADR-009). `rlm-studio` is not a memkernel dependency and is not on PyPI yet; install it from git into the same environment:
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
pip install "rlm-studio @ git+https://github.com/gosha70/rlm-studio"
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
When it is not importable, `build_service()` logs a warning and uses the local reasoner. With an external reasoner, `consolidate(synthesize=True)` also drafts long-term statements from the session's short-term memories.
|
|
326
|
+
|
|
240
327
|
## LLM wiki bridge
|
|
241
328
|
|
|
242
329
|
Long-term memory has a human-readable twin: a markdown wiki in the [LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) pattern (`index.md`, `log.md`, typed pages with cited sources — the same schema as `code-copilot-team/knowledge/wiki`).
|
|
@@ -246,6 +333,12 @@ Long-term memory has a human-readable twin: a markdown wiki in the [LLM Wiki](ht
|
|
|
246
333
|
|
|
247
334
|
Set `MEMKERNEL_WIKI_DIR` (for example `knowledge/wiki`) or pass `wiki_dir` to the tools. Rationale and the proposed standalone `ai-wiki` repo: [`docs/adr/ADR-008-llm-wiki-as-semantic-layer.md`](docs/adr/ADR-008-llm-wiki-as-semantic-layer.md).
|
|
248
335
|
|
|
336
|
+
### Revalidation and store health
|
|
337
|
+
|
|
338
|
+
A `code` memory is a snapshot of a file. `MemoryService.revalidate()` hashes each live snapshot's whole source file and compares it with the stored content hash: a changed file flags the memory `needs_review` (`changed`), a vanished file flags it `missing`, a matching file clears the flag. Flagged memories leave default `recall` until the file is retained again (which supersedes the stale snapshot) or they are asked for with `include_needs_review=true`. Revalidation runs from `consolidate(revalidate=true)`, at every session start through `MemoryLifecycle.on_session_start()` (a `### Needs review` section lists what to re-retain), and from `POST /revalidate`. Sources resolve under `MEMKERNEL_PROJECT_ROOT` (default: the current directory); set it whenever the server or a hook is not started from the project directory. Nothing outside that root is ever read. 0.4 hashes whole files; per-chunk invalidation is a follow-up.
|
|
339
|
+
|
|
340
|
+
`MemoryService.health()` audits the store without changing it: orphaned chunk and document records, dangling `supersedes` / `superseded_by` / `promoted_from` / `parent_ref` links, supersessions from 0.2/0.3 that lack the durable marker, `code` memories whose source file is gone, memories flagged for review, expired short-term memories not yet purged and, in full mode only, near-duplicate pairs among the most recent long-term memories (cosine ≥ `MEMKERNEL_HEALTH_DUPLICATE_THRESHOLD`). The quick report (counts only, no embeddings, no content loads) is part of every `consolidate()` report and of the `memory://status` resource; the full report is `GET /health/store`. The pass never fixes anything: a fix mode is a later feature.
|
|
341
|
+
|
|
249
342
|
## Admin API
|
|
250
343
|
|
|
251
344
|
A FastAPI admin server provides health and stats endpoints (independent of MCP):
|
|
@@ -259,6 +352,8 @@ uvicorn memkernel.api.app:app --host 127.0.0.1 --port 8766
|
|
|
259
352
|
| `GET /health` | Server health and memory count |
|
|
260
353
|
| `GET /stats` | Total memory count, per-type and per-tier breakdown, growth rate, last recall latency |
|
|
261
354
|
| `GET /collections` | List ChromaDB collections |
|
|
355
|
+
| `GET /health/store` | Full store health report (orphans, dangling links, stale sources, near-duplicates, …) |
|
|
356
|
+
| `POST /revalidate` | Check every code memory against its source file; flag changed or missing ones |
|
|
262
357
|
|
|
263
358
|
---
|
|
264
359
|
|
|
@@ -281,7 +376,7 @@ Releases are published to PyPI by [`.github/workflows/release.yml`](.github/work
|
|
|
281
376
|
|
|
282
377
|
1. Set `version` in `pyproject.toml` and move the `[Unreleased]` entries in [`CHANGELOG.md`](CHANGELOG.md) under the new version.
|
|
283
378
|
2. Merge to `main` with CI green.
|
|
284
|
-
3. Tag and push: `git tag -a v0.
|
|
379
|
+
3. Tag and push: `git tag -a v0.4.0 -m "memkernel 0.4.0" && git push origin v0.4.0`.
|
|
285
380
|
|
|
286
381
|
The workflow refuses a tag that does not match the `pyproject.toml` version, builds the sdist and wheel, smoke-installs the wheel, and uploads through the `pypi` environment.
|
|
287
382
|
|
|
@@ -293,12 +388,14 @@ The workflow refuses a tag that does not match the `pyproject.toml` version, bui
|
|
|
293
388
|
src/memkernel/
|
|
294
389
|
├── mcp/ # MCP server + tool definitions (memory tools, wiki tools)
|
|
295
390
|
├── core/ # Domain models (tiers, types), MemoryService, ports (interfaces)
|
|
296
|
-
├──
|
|
297
|
-
├──
|
|
391
|
+
├── adapters/ # Optional external systems (RLM Studio reasoner), imported lazily
|
|
392
|
+
├── storage/ # ChromaDB adapter, local document store
|
|
393
|
+
├── retrieval/ # AST/token chunking, embeddings, hybrid search (dense + BM25 + RRF + rescoring), local reasoner
|
|
298
394
|
├── memory/ # Lifecycle: TTL/decay policies, retention, deduplication
|
|
299
395
|
├── wiki/ # LLM-wiki bridge: page model, export, import
|
|
300
396
|
├── api/ # FastAPI admin endpoints
|
|
301
397
|
├── factory.py # build_service() — the supported embedding entry point
|
|
398
|
+
├── lifecycle.py # MemoryLifecycle — the session protocol as a component
|
|
302
399
|
└── config.py # Pydantic settings
|
|
303
400
|
```
|
|
304
401
|
|
|
@@ -315,7 +412,7 @@ MemKernel is the memory component of a small family of projects by the same auth
|
|
|
315
412
|
| Project | Role | Relationship |
|
|
316
413
|
|---|---|---|
|
|
317
414
|
| [ai-wiki](https://github.com/gosha70/ai-wiki) | LLM-maintained markdown wiki (ingest / promote / query / lint) | the human-readable form of long-term memory; `wiki_export` / `wiki_import` speak its page schema (ADR-008) |
|
|
318
|
-
| [rlm-studio](https://github.com/gosha70/rlm-studio) | Recursive Language Models workbench: Direct / RAG / RLM / auto over large documents | the document layer
|
|
415
|
+
| [rlm-studio](https://github.com/gosha70/rlm-studio) | Recursive Language Models workbench: Direct / RAG / RLM / auto over large documents | the document layer behind `document` memories and the `ask()` tool (`MEMKERNEL_REASONER=rlmstudio`, ADR-009) |
|
|
319
416
|
| [code-copilot-team](https://github.com/gosha70/code-copilot-team) | Enforceable harness configuration for Claude Code, Pi and other copilots | consumes MemKernel through MCP and hooks |
|
|
320
417
|
| [haa](https://github.com/gosha70/haa) | Home-built AI coding harness, future component assembler | consumes MemKernel in-process through `build_service()` |
|
|
321
418
|
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
<h1>
|
|
2
|
+
<img src="https://raw.githubusercontent.com/gosha70/memkernel/main/docs/assets/memkernel-logo.png" alt="MemKernel logo: a glowing memory core on three stacked tiers" width="110" align="absmiddle">
|
|
3
|
+
MemKernel
|
|
4
|
+
</h1>
|
|
2
5
|
|
|
3
6
|
[](https://github.com/gosha70/memkernel/actions/workflows/ci.yml)
|
|
4
7
|
[](https://pypi.org/project/memkernel/)
|
|
5
8
|
[](pyproject.toml)
|
|
6
9
|
[](LICENSE)
|
|
7
10
|
|
|
11
|
+
**Site:** [memkernel.dev](https://memkernel.dev) · **Package:** [pypi.org/project/memkernel](https://pypi.org/project/memkernel/)
|
|
12
|
+
|
|
8
13
|
Code-aware memory server for AI coding copilots.
|
|
9
14
|
|
|
10
15
|
MemKernel gives Claude Code (and any MCP-compatible copilot) persistent memory across sessions. When Claude compacts context or a session ends, project decisions, conventions, and code understanding are normally lost. MemKernel stores them in a local vector database and retrieves them on demand.
|
|
@@ -17,23 +22,33 @@ MemKernel gives Claude Code (and any MCP-compatible copilot) persistent memory a
|
|
|
17
22
|
|
|
18
23
|
## Requirements
|
|
19
24
|
|
|
20
|
-
- Python 3.11 – 3.13
|
|
25
|
+
- Python 3.11 – 3.13 (the package declares `Requires-Python >=3.11,<3.14`; pip reports "from versions: none" when the installing interpreter is outside that range)
|
|
21
26
|
- [Poetry](https://python-poetry.org) (for development installs)
|
|
22
27
|
|
|
23
28
|
---
|
|
24
29
|
|
|
25
30
|
## Install
|
|
26
31
|
|
|
32
|
+
MemKernel is a Python package on PyPI. Its `memkernel` command is the MCP server. There is no npm package: an `npx` install someone suggests is a hallucination.
|
|
33
|
+
|
|
34
|
+
**Recommended: an isolated install with [pipx](https://pipx.pypa.io)**, which puts the `memkernel` command on your PATH without touching any other Python environment:
|
|
35
|
+
|
|
27
36
|
```bash
|
|
28
|
-
|
|
37
|
+
pipx install memkernel
|
|
38
|
+
# if pipx's default interpreter is outside 3.11–3.13:
|
|
39
|
+
pipx install --python python3.11 memkernel
|
|
29
40
|
```
|
|
30
41
|
|
|
31
|
-
|
|
42
|
+
**As a library inside a project**, install it into that project's virtual environment:
|
|
32
43
|
|
|
33
44
|
```bash
|
|
34
|
-
poetry add memkernel
|
|
45
|
+
pip install memkernel # or: poetry add memkernel
|
|
35
46
|
```
|
|
36
47
|
|
|
48
|
+
Avoid a plain `pip install memkernel` into a shared or system interpreter (Homebrew's `python3`, for example). MemKernel pins `chromadb` 1.x and recent `cffi`, so pip will replace older copies and can break unrelated tools that need them.
|
|
49
|
+
|
|
50
|
+
Verify the install with `pipx list` or `which memkernel`. Running `memkernel` with no arguments starts the MCP server on stdio and waits for a client; `memkernel --version` and `memkernel --help` print and exit.
|
|
51
|
+
|
|
37
52
|
---
|
|
38
53
|
|
|
39
54
|
## Add to Claude Code
|
|
@@ -46,17 +61,29 @@ Add MemKernel to `.claude/settings.json` in your project:
|
|
|
46
61
|
{
|
|
47
62
|
"mcpServers": {
|
|
48
63
|
"memkernel": {
|
|
49
|
-
"command": "memkernel",
|
|
64
|
+
"command": "/Users/you/.local/bin/memkernel",
|
|
50
65
|
"args": [],
|
|
51
66
|
"env": {
|
|
52
|
-
"MEMKERNEL_PROJECT_ID": "my-project"
|
|
67
|
+
"MEMKERNEL_PROJECT_ID": "my-project",
|
|
68
|
+
"MEMKERNEL_CHROMA_PERSIST_PATH": "/Users/you/.memkernel/my-project"
|
|
53
69
|
}
|
|
54
70
|
}
|
|
55
71
|
}
|
|
56
72
|
}
|
|
57
73
|
```
|
|
58
74
|
|
|
59
|
-
Replace `my-project` with a short identifier for the project — memories are isolated per project.
|
|
75
|
+
Replace `my-project` with a short identifier for the project — memories are isolated per project. Use the absolute path of the command (`which memkernel` prints it) because Claude Code does not necessarily see the PATH changes your shell profile makes, and an absolute `MEMKERNEL_CHROMA_PERSIST_PATH` keeps the store outside the repository. On first server initialization, MemKernel downloads the embedding model (about 90 MB) if it is not already cached: `build_service()` loads the sentence-transformers model when the MCP server starts, before any tool call, so the first connection can take a minute. Later starts and every tool call are fast.
|
|
76
|
+
|
|
77
|
+
<details>
|
|
78
|
+
<summary>Troubleshooting the install</summary>
|
|
79
|
+
|
|
80
|
+
- **`pipx install memkernel` says "No matching distribution found"** — pipx used an interpreter outside 3.11–3.13. Pass one explicitly: `pipx install --python /opt/homebrew/opt/python@3.11/bin/python3.11 memkernel`.
|
|
81
|
+
- **`bash: /some/old/path/memkernel: No such file or directory`** right after reinstalling — the shell cached the old location. Run `hash -r` (bash) or `rehash` (zsh), then `which memkernel`.
|
|
82
|
+
- **`memkernel --help` seems to hang** on versions before 0.4.0 — the command had no flags and started the server; press Ctrl-C. From 0.4.0 on, `--help` and `--version` print and exit.
|
|
83
|
+
- **The first MCP connection is slow or times out** — the server is downloading the embedding model at startup (see above). Wait for it once, or pre-warm it with `python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('all-MiniLM-L6-v2')"` in the same environment.
|
|
84
|
+
- **A global pip install broke another tool** (for example `langchain-chroma` wanting `chromadb < 0.6`) — uninstall memkernel from that interpreter, reinstall the versions the other tool needs, and install memkernel with pipx instead.
|
|
85
|
+
|
|
86
|
+
</details>
|
|
60
87
|
|
|
61
88
|
### 2. Add memory instructions to CLAUDE.md
|
|
62
89
|
|
|
@@ -72,7 +99,21 @@ Copy the hook scripts from [`templates/hooks/`](templates/hooks/) to `.claude/ho
|
|
|
72
99
|
| `pre-compact.py` | `PreCompact` | Retains a checkpoint episode, runs a consolidation pass |
|
|
73
100
|
| `post-compact.py` | `PostCompact` | Re-injects the checkpoint, long-term context and promotion candidates |
|
|
74
101
|
|
|
75
|
-
See the Prerequisites section inside each script for the Python environment requirement.
|
|
102
|
+
See the Prerequisites section inside each script for the Python environment requirement. Each script is a thin wrapper over [`MemoryLifecycle`](#embedding-memkernel-in-your-own-harness), so an in-process harness gets the same behaviour without the scripts.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Add to Kiro
|
|
107
|
+
|
|
108
|
+
Kiro (and the Kiro CLI, formerly Amazon Q Developer CLI) connects to MemKernel as a stdio MCP server. [`templates/kiro/`](templates/kiro/) holds the three files to copy into a workspace:
|
|
109
|
+
|
|
110
|
+
| Template | Destination | Role |
|
|
111
|
+
|----------|-------------|------|
|
|
112
|
+
| `settings/mcp.json` | `.kiro/settings/mcp.json` | Server entry with `env` and `autoApprove` |
|
|
113
|
+
| `steering/memory.md` | `.kiro/steering/memory.md` | Memory instructions, always included |
|
|
114
|
+
| `hooks/memkernel.json` | `.kiro/hooks/memkernel.json` | `SessionStart` recall, `Stop` retain, manual checkpoint |
|
|
115
|
+
|
|
116
|
+
[`templates/kiro/README.md`](templates/kiro/README.md) has the setup steps, the Kiro CLI custom-agent variant and the caveats (absolute persist path, hook format by Kiro version).
|
|
76
117
|
|
|
77
118
|
---
|
|
78
119
|
|
|
@@ -81,12 +122,12 @@ See the Prerequisites section inside each script for the Python environment requ
|
|
|
81
122
|
| Tool | What it does |
|
|
82
123
|
|------|-------------|
|
|
83
124
|
| `retain(content, type, session_id?, checkpoint?, source?, importance?, tags?, supersedes?)` | Store a memory. Returns `ref_id`. Idempotent — identical content + type returns the same `ref_id`. `supersedes` hides the memory it replaces. |
|
|
84
|
-
| `recall(query, type?, tier?, session_id?, checkpoint_only?, top_k?)` | Search by natural language or identifier. Returns lightweight `ArtifactRef` list ranked by relevance + recency + importance. Records an access (reinforces retention). |
|
|
125
|
+
| `recall(query, type?, tier?, session_id?, checkpoint_only?, top_k?, include_needs_review?)` | Search by natural language or identifier. Returns lightweight `ArtifactRef` list ranked by relevance + recency + importance. Records an access (reinforces retention). Code memories flagged `needs_review` are hidden unless `include_needs_review=true`. |
|
|
85
126
|
| `get(ref_id)` | Fetch full content of a specific memory. Records an access. |
|
|
86
127
|
| `forget(ref_id)` | Delete a memory from all indexes. |
|
|
87
128
|
| `promote(ref_id, type, content?, importance?, tags?)` | Turn a short-term/working memory into a long-term one (you supply the distilled text). Keeps provenance via `promoted_from`. |
|
|
88
|
-
| `consolidate(session_id?, limit?)` | Purge expired short-term memories and list the ones most worth promoting (ranked by importance × how often they were recalled). |
|
|
89
|
-
| `
|
|
129
|
+
| `consolidate(session_id?, limit?, synthesize?, revalidate?)` | Purge expired short-term memories and list the ones most worth promoting (ranked by importance × how often they were recalled). `synthesize=true` also asks an external reasoner to draft long-term statements (`suggested`); `revalidate=true` first checks every code memory against its source file (`revalidated`). The report always carries a `health` summary. |
|
|
130
|
+
| `ask(ref_id, question, mode?)` | Answer a question about one memory without loading it — for a `document` the full body is consulted. `mode`: `direct` \| `rag` \| `rlm` \| `auto`, passed to the reasoner unchanged; the built-in reasoner answers in `rag` mode with the best-matching chunks. Returns `answer`, `mode`, `citations`, `usage`. |
|
|
90
131
|
| `wiki_export(wiki_dir?)` | Compile long-term memories without a wiki page into draft markdown pages (`index.md`, `log.md` updated). |
|
|
91
132
|
| `wiki_import(wiki_dir?)` | Index curated wiki pages as long-term memories (idempotent; changed pages supersede). |
|
|
92
133
|
|
|
@@ -98,7 +139,8 @@ See the Prerequisites section inside each script for the Python environment requ
|
|
|
98
139
|
| `convention` | long-term | Naming rules, code style, project patterns | 0.9 | Never |
|
|
99
140
|
| `fact` | long-term | Durable project facts: build commands, environments, contracts | 0.7 | Never |
|
|
100
141
|
| `procedure` | long-term | How-to that worked: workflows, recipes, verified skills | 0.8 | Never |
|
|
101
|
-
| `code` | long-term | Function/class snapshots, API contracts | 0.6 | Never |
|
|
142
|
+
| `code` | long-term | Function/class snapshots, API contracts; identified by `(source, content)`, a changed file supersedes the old snapshot, a drifted source flags `needs_review` | 0.6 | Never (superseded on re-retain) |
|
|
143
|
+
| `document` | long-term | Large artefacts (specs, transcripts, files): the body is stored and chunk-indexed, `get` returns a summary, `ask` answers from the indexed chunks (local reasoner) or the body (RLM Studio) | 0.6 | Never |
|
|
102
144
|
| `episode` | short-term | Session events, compaction checkpoints | 0.4 | 30 days, extended by every recall |
|
|
103
145
|
| `observation` | short-term | Findings, tool outputs, things noticed | 0.3 | 7 days, extended by every recall |
|
|
104
146
|
| `task` | working | The current goal, plan state, open questions | 0.5 | 24 hours |
|
|
@@ -111,7 +153,9 @@ Retention: `ttl = base_ttl × (1 + access_boost × access_count)`, measured from
|
|
|
111
153
|
2. **While working** — `retain(type="task")` when the plan changes; `retain(type="observation")` for findings; durable knowledge as `decision` / `convention` / `fact` / `procedure`.
|
|
112
154
|
3. **Before compaction** — `retain(type="episode", checkpoint=true)` (the `pre-compact.py` hook) and `consolidate()`.
|
|
113
155
|
4. **After compaction / end of phase** — `promote(ref_id, type, content)` for the candidates worth keeping.
|
|
114
|
-
5. **
|
|
156
|
+
5. **Large artefacts** — `retain(type="document", content=<body>, source=<name>)` then `ask(ref_id, question)`; never `get` a document to read it.
|
|
157
|
+
7. **Code snapshots** — `retain(type="code", content=<file>, source=<path>)`; retain the file again after editing it (the new snapshot supersedes the old one). The session-start hook revalidates snapshots against their files and lists the ones that need re-retaining.
|
|
158
|
+
6. **Curate** — `wiki_export` → review the drafts → `wiki_import`.
|
|
115
159
|
|
|
116
160
|
### Quick examples
|
|
117
161
|
|
|
@@ -137,6 +181,10 @@ retain(content="Use arq, not Celery", type="decision", supersedes="<old decision
|
|
|
137
181
|
get(ref_id="<ref_id from recall>")
|
|
138
182
|
|
|
139
183
|
forget(ref_id="<ref_id>")
|
|
184
|
+
|
|
185
|
+
retain(content=<the whole spec>, type="document", source="specs/auth/spec.md")
|
|
186
|
+
|
|
187
|
+
ask(ref_id="<document ref_id>", question="Which endpoints need rate limiting?", mode="auto")
|
|
140
188
|
```
|
|
141
189
|
|
|
142
190
|
---
|
|
@@ -158,6 +206,14 @@ All settings are read from environment variables with the `MEMKERNEL_` prefix, o
|
|
|
158
206
|
| `MEMKERNEL_PREVIEW_LENGTH` | `200` | Max characters in the `preview` field of `ArtifactRef` |
|
|
159
207
|
| `MEMKERNEL_CHUNK_SIZE` | `1500` | Max characters per AST chunk (code memories) |
|
|
160
208
|
| `MEMKERNEL_CHUNK_OVERLAP` | `200` | Character overlap between token-based fallback chunks |
|
|
209
|
+
| `MEMKERNEL_DOCUMENT_STORE` | `local` | Where `document` bodies live (`local` = the project's own ChromaDB collection) |
|
|
210
|
+
| `MEMKERNEL_DOCUMENT_SUMMARY_CHARS` | `1000` | Characters of the body kept in a `document` memory's summary record |
|
|
211
|
+
| `MEMKERNEL_REASONER` | `local` | `ReasonerPort` behind `ask`: `local` (hybrid search over chunks, no LLM) or `rlmstudio` (falls back to `local` when `rlmstudio` is not importable) |
|
|
212
|
+
| `MEMKERNEL_ASK_TOP_K` | `5` | Chunks the local reasoner returns per `ask` |
|
|
213
|
+
| `MEMKERNEL_PROJECT_ROOT` | `.` | Directory that relative `source` paths of `code` memories resolve under; nothing outside it is ever read. Set it whenever the server or a hook is not started from the project directory |
|
|
214
|
+
| `MEMKERNEL_HEALTH_DUPLICATE_THRESHOLD` | `0.95` | Cosine similarity in [0, 1] from which two long-term memories count as near-duplicates in the health pass |
|
|
215
|
+
| `MEMKERNEL_HEALTH_DUPLICATE_LIMIT` | `500` | Most recent long-term memories the near-duplicate check covers |
|
|
216
|
+
| `MEMKERNEL_HEALTH_REPORT_LIMIT` | `20` | Items listed per category in a health report |
|
|
161
217
|
| `MEMKERNEL_EPISODE_TTL_DAYS` | `30` | Base TTL for `episode` memories (short-term) |
|
|
162
218
|
| `MEMKERNEL_OBSERVATION_TTL_DAYS` | `7` | Base TTL for `observation` memories (short-term) |
|
|
163
219
|
| `MEMKERNEL_TASK_TTL_HOURS` | `24` | Base TTL for `task` memories (working) |
|
|
@@ -210,6 +266,35 @@ report = svc.consolidate() # {"purged": n, "candidates": [...]}
|
|
|
210
266
|
|
|
211
267
|
`build_service()` is the supported entry point; the MCP server, the admin API and the hook templates all use it. Integration notes for `code-copilot-team` and `haa` are in [`docs/integration/harness-integration.md`](docs/integration/harness-integration.md).
|
|
212
268
|
|
|
269
|
+
### The session protocol as a component
|
|
270
|
+
|
|
271
|
+
`MemoryLifecycle` packages what the hook scripts do, so a harness calls four methods instead of re-implementing the protocol. Every method returns markdown ready for injection and does nothing but talk to the service:
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
from memkernel.factory import build_service
|
|
275
|
+
from memkernel.lifecycle import MemoryLifecycle
|
|
276
|
+
|
|
277
|
+
memory = MemoryLifecycle(build_service())
|
|
278
|
+
system_context = memory.on_session_start() # checkpoint, long-term context, promotion candidates, wiki pointer
|
|
279
|
+
...
|
|
280
|
+
memory.on_pre_compact(summary) # checkpoint episode + consolidation, before the context is compacted
|
|
281
|
+
recovered = memory.on_post_compact() # what to re-inject after compaction
|
|
282
|
+
memory.on_session_end(summary) # final checkpoint + consolidation
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Documents and `ask`
|
|
286
|
+
|
|
287
|
+
`retain(type="document")` keeps large artefacts out of the context window: the body goes to the document store (built-in: the project's own ChromaDB collection), its chunks are indexed for hybrid search, and the memkernel record is a summary. `ask(ref_id, question, mode)` answers through a `ReasonerPort`:
|
|
288
|
+
|
|
289
|
+
- `MEMKERNEL_REASONER=local` (default) — no LLM: the question is matched against the document's chunks with dense + BM25 + RRF and the best chunks come back as the answer, `mode="rag"`.
|
|
290
|
+
- `MEMKERNEL_REASONER=rlmstudio` — delegates to [rlm-studio](https://github.com/gosha70/rlm-studio)'s `interact(content, question, mode=mode)`, so `direct`, `rag`, `rlm` and `auto` select how the document is read (ADR-009). `rlm-studio` is not a memkernel dependency and is not on PyPI yet; install it from git into the same environment:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
pip install "rlm-studio @ git+https://github.com/gosha70/rlm-studio"
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
When it is not importable, `build_service()` logs a warning and uses the local reasoner. With an external reasoner, `consolidate(synthesize=True)` also drafts long-term statements from the session's short-term memories.
|
|
297
|
+
|
|
213
298
|
## LLM wiki bridge
|
|
214
299
|
|
|
215
300
|
Long-term memory has a human-readable twin: a markdown wiki in the [LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) pattern (`index.md`, `log.md`, typed pages with cited sources — the same schema as `code-copilot-team/knowledge/wiki`).
|
|
@@ -219,6 +304,12 @@ Long-term memory has a human-readable twin: a markdown wiki in the [LLM Wiki](ht
|
|
|
219
304
|
|
|
220
305
|
Set `MEMKERNEL_WIKI_DIR` (for example `knowledge/wiki`) or pass `wiki_dir` to the tools. Rationale and the proposed standalone `ai-wiki` repo: [`docs/adr/ADR-008-llm-wiki-as-semantic-layer.md`](docs/adr/ADR-008-llm-wiki-as-semantic-layer.md).
|
|
221
306
|
|
|
307
|
+
### Revalidation and store health
|
|
308
|
+
|
|
309
|
+
A `code` memory is a snapshot of a file. `MemoryService.revalidate()` hashes each live snapshot's whole source file and compares it with the stored content hash: a changed file flags the memory `needs_review` (`changed`), a vanished file flags it `missing`, a matching file clears the flag. Flagged memories leave default `recall` until the file is retained again (which supersedes the stale snapshot) or they are asked for with `include_needs_review=true`. Revalidation runs from `consolidate(revalidate=true)`, at every session start through `MemoryLifecycle.on_session_start()` (a `### Needs review` section lists what to re-retain), and from `POST /revalidate`. Sources resolve under `MEMKERNEL_PROJECT_ROOT` (default: the current directory); set it whenever the server or a hook is not started from the project directory. Nothing outside that root is ever read. 0.4 hashes whole files; per-chunk invalidation is a follow-up.
|
|
310
|
+
|
|
311
|
+
`MemoryService.health()` audits the store without changing it: orphaned chunk and document records, dangling `supersedes` / `superseded_by` / `promoted_from` / `parent_ref` links, supersessions from 0.2/0.3 that lack the durable marker, `code` memories whose source file is gone, memories flagged for review, expired short-term memories not yet purged and, in full mode only, near-duplicate pairs among the most recent long-term memories (cosine ≥ `MEMKERNEL_HEALTH_DUPLICATE_THRESHOLD`). The quick report (counts only, no embeddings, no content loads) is part of every `consolidate()` report and of the `memory://status` resource; the full report is `GET /health/store`. The pass never fixes anything: a fix mode is a later feature.
|
|
312
|
+
|
|
222
313
|
## Admin API
|
|
223
314
|
|
|
224
315
|
A FastAPI admin server provides health and stats endpoints (independent of MCP):
|
|
@@ -232,6 +323,8 @@ uvicorn memkernel.api.app:app --host 127.0.0.1 --port 8766
|
|
|
232
323
|
| `GET /health` | Server health and memory count |
|
|
233
324
|
| `GET /stats` | Total memory count, per-type and per-tier breakdown, growth rate, last recall latency |
|
|
234
325
|
| `GET /collections` | List ChromaDB collections |
|
|
326
|
+
| `GET /health/store` | Full store health report (orphans, dangling links, stale sources, near-duplicates, …) |
|
|
327
|
+
| `POST /revalidate` | Check every code memory against its source file; flag changed or missing ones |
|
|
235
328
|
|
|
236
329
|
---
|
|
237
330
|
|
|
@@ -254,7 +347,7 @@ Releases are published to PyPI by [`.github/workflows/release.yml`](.github/work
|
|
|
254
347
|
|
|
255
348
|
1. Set `version` in `pyproject.toml` and move the `[Unreleased]` entries in [`CHANGELOG.md`](CHANGELOG.md) under the new version.
|
|
256
349
|
2. Merge to `main` with CI green.
|
|
257
|
-
3. Tag and push: `git tag -a v0.
|
|
350
|
+
3. Tag and push: `git tag -a v0.4.0 -m "memkernel 0.4.0" && git push origin v0.4.0`.
|
|
258
351
|
|
|
259
352
|
The workflow refuses a tag that does not match the `pyproject.toml` version, builds the sdist and wheel, smoke-installs the wheel, and uploads through the `pypi` environment.
|
|
260
353
|
|
|
@@ -266,12 +359,14 @@ The workflow refuses a tag that does not match the `pyproject.toml` version, bui
|
|
|
266
359
|
src/memkernel/
|
|
267
360
|
├── mcp/ # MCP server + tool definitions (memory tools, wiki tools)
|
|
268
361
|
├── core/ # Domain models (tiers, types), MemoryService, ports (interfaces)
|
|
269
|
-
├──
|
|
270
|
-
├──
|
|
362
|
+
├── adapters/ # Optional external systems (RLM Studio reasoner), imported lazily
|
|
363
|
+
├── storage/ # ChromaDB adapter, local document store
|
|
364
|
+
├── retrieval/ # AST/token chunking, embeddings, hybrid search (dense + BM25 + RRF + rescoring), local reasoner
|
|
271
365
|
├── memory/ # Lifecycle: TTL/decay policies, retention, deduplication
|
|
272
366
|
├── wiki/ # LLM-wiki bridge: page model, export, import
|
|
273
367
|
├── api/ # FastAPI admin endpoints
|
|
274
368
|
├── factory.py # build_service() — the supported embedding entry point
|
|
369
|
+
├── lifecycle.py # MemoryLifecycle — the session protocol as a component
|
|
275
370
|
└── config.py # Pydantic settings
|
|
276
371
|
```
|
|
277
372
|
|
|
@@ -288,7 +383,7 @@ MemKernel is the memory component of a small family of projects by the same auth
|
|
|
288
383
|
| Project | Role | Relationship |
|
|
289
384
|
|---|---|---|
|
|
290
385
|
| [ai-wiki](https://github.com/gosha70/ai-wiki) | LLM-maintained markdown wiki (ingest / promote / query / lint) | the human-readable form of long-term memory; `wiki_export` / `wiki_import` speak its page schema (ADR-008) |
|
|
291
|
-
| [rlm-studio](https://github.com/gosha70/rlm-studio) | Recursive Language Models workbench: Direct / RAG / RLM / auto over large documents | the document layer
|
|
386
|
+
| [rlm-studio](https://github.com/gosha70/rlm-studio) | Recursive Language Models workbench: Direct / RAG / RLM / auto over large documents | the document layer behind `document` memories and the `ask()` tool (`MEMKERNEL_REASONER=rlmstudio`, ADR-009) |
|
|
292
387
|
| [code-copilot-team](https://github.com/gosha70/code-copilot-team) | Enforceable harness configuration for Claude Code, Pi and other copilots | consumes MemKernel through MCP and hooks |
|
|
293
388
|
| [haa](https://github.com/gosha70/haa) | Home-built AI coding harness, future component assembler | consumes MemKernel in-process through `build_service()` |
|
|
294
389
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "memkernel"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
description = "Code-aware memory server for AI coding copilots"
|
|
5
5
|
authors = ["EGOGE"]
|
|
6
6
|
license = "Apache-2.0"
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
repository = "https://github.com/gosha70/memkernel"
|
|
9
|
+
homepage = "https://memkernel.dev"
|
|
10
|
+
documentation = "https://memkernel.dev"
|
|
9
11
|
classifiers = [
|
|
10
12
|
"Programming Language :: Python :: 3",
|
|
11
13
|
"Programming Language :: Python :: 3.11",
|