mnemara 0.3.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.
- mnemara-0.3.0/LICENSE +21 -0
- mnemara-0.3.0/PKG-INFO +443 -0
- mnemara-0.3.0/README.md +406 -0
- mnemara-0.3.0/pyproject.toml +66 -0
- mnemara-0.3.0/setup.cfg +4 -0
- mnemara-0.3.0/src/mnemara/__init__.py +3 -0
- mnemara-0.3.0/src/mnemara/agent.py +1789 -0
- mnemara-0.3.0/src/mnemara/cli.py +221 -0
- mnemara-0.3.0/src/mnemara/config.py +292 -0
- mnemara-0.3.0/src/mnemara/graph.py +444 -0
- mnemara-0.3.0/src/mnemara/logging_util.py +32 -0
- mnemara-0.3.0/src/mnemara/mcp.py +30 -0
- mnemara-0.3.0/src/mnemara/paths.py +82 -0
- mnemara-0.3.0/src/mnemara/permissions.py +85 -0
- mnemara-0.3.0/src/mnemara/rag.py +165 -0
- mnemara-0.3.0/src/mnemara/repl.py +229 -0
- mnemara-0.3.0/src/mnemara/replay.py +611 -0
- mnemara-0.3.0/src/mnemara/role.py +20 -0
- mnemara-0.3.0/src/mnemara/store.py +1253 -0
- mnemara-0.3.0/src/mnemara/tools.py +382 -0
- mnemara-0.3.0/src/mnemara/tui.py +802 -0
- mnemara-0.3.0/src/mnemara/wiki.py +86 -0
- mnemara-0.3.0/src/mnemara.egg-info/PKG-INFO +443 -0
- mnemara-0.3.0/src/mnemara.egg-info/SOURCES.txt +29 -0
- mnemara-0.3.0/src/mnemara.egg-info/dependency_links.txt +1 -0
- mnemara-0.3.0/src/mnemara.egg-info/entry_points.txt +2 -0
- mnemara-0.3.0/src/mnemara.egg-info/requires.txt +13 -0
- mnemara-0.3.0/src/mnemara.egg-info/top_level.txt +1 -0
- mnemara-0.3.0/tests/test_graph_and_replay.py +351 -0
- mnemara-0.3.0/tests/test_multi_backend.py +221 -0
- mnemara-0.3.0/tests/test_smoke.py +4590 -0
mnemara-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michael Anderson
|
|
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.
|
mnemara-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mnemara
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Controlled rolling-context conversation runtime for Claude — transparent turns store, role doc system prompt, and the Claude Agent SDK underneath.
|
|
5
|
+
Author: Michael Anderson
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/mekickdemons-creator/mnemara
|
|
8
|
+
Project-URL: Repository, https://github.com/mekickdemons-creator/mnemara
|
|
9
|
+
Project-URL: Issues, https://github.com/mekickdemons-creator/mnemara/issues
|
|
10
|
+
Keywords: claude,anthropic,claude-agent-sdk,llm,agent,mcp,rolling-context,repl,tui,context-window
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: click>=8.1
|
|
25
|
+
Requires-Dist: prompt-toolkit>=3.0
|
|
26
|
+
Requires-Dist: rich>=13.0
|
|
27
|
+
Requires-Dist: textual>=0.86
|
|
28
|
+
Requires-Dist: lancedb>=0.30
|
|
29
|
+
Requires-Dist: httpx>=0.27
|
|
30
|
+
Requires-Dist: pyarrow>=15
|
|
31
|
+
Requires-Dist: kuzu>=0.10
|
|
32
|
+
Requires-Dist: pyperclip>=1.8
|
|
33
|
+
Requires-Dist: claude-agent-sdk>=0.1
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# Mnemara
|
|
39
|
+
|
|
40
|
+
A controlled rolling-context conversation runtime for Claude. Built on the
|
|
41
|
+
**[Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk-python)**:
|
|
42
|
+
Mnemara wraps the SDK with a transparent, file-based context layer so you can
|
|
43
|
+
see and shape exactly what the model sees on every turn.
|
|
44
|
+
|
|
45
|
+
What you get:
|
|
46
|
+
|
|
47
|
+
- A **role doc** re-read on every API call and pinned as the system prompt.
|
|
48
|
+
- A configurable **rolling window** of recent turns (FIFO, by row count or
|
|
49
|
+
token budget).
|
|
50
|
+
- Native tool use — Bash, Read, Edit, Write — plus an in-process `WriteMemory`
|
|
51
|
+
tool registered as an SDK MCP server.
|
|
52
|
+
- Optional **MCP wire-through**: declare stdio MCP servers in config and the
|
|
53
|
+
Claude Agent SDK exposes them to the model.
|
|
54
|
+
- A **Textual TUI** (`mnemara run`) and a bare prompt-toolkit REPL fallback.
|
|
55
|
+
- Per-instance, file-only state under `~/.mnemara/<instance>/` — no daemon,
|
|
56
|
+
no service, no hidden state.
|
|
57
|
+
- Optional memory/wiki + LanceDB RAG + Kuzu property graph backends, and a
|
|
58
|
+
`mnemara replay` consolidation primitive that drafts wiki pages and
|
|
59
|
+
role-amendment proposals from clustered memory atoms.
|
|
60
|
+
|
|
61
|
+
If you want a chat loop where you control the system prompt, control the
|
|
62
|
+
window, and can read every byte of state on disk, that's what this is.
|
|
63
|
+
|
|
64
|
+
## Install
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/mekickdemons-creator/mnemara.git
|
|
68
|
+
cd mnemara
|
|
69
|
+
python -m venv .venv
|
|
70
|
+
source .venv/bin/activate
|
|
71
|
+
pip install -e .
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Auth
|
|
75
|
+
|
|
76
|
+
Mnemara runs on the Claude Agent SDK, which talks to the Anthropic API. The
|
|
77
|
+
easiest way is to set your API key:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Get a key at <https://console.anthropic.com/>. The SDK also supports the local
|
|
84
|
+
`claude` CLI's subscription auth as a fallback if you have Claude Code
|
|
85
|
+
installed and logged in — but the documented path is the API key.
|
|
86
|
+
|
|
87
|
+
## Quick start
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
mnemara init --instance scratch
|
|
91
|
+
# (prompts for role doc path; you can leave it blank and set it later)
|
|
92
|
+
mnemara role --instance scratch --set examples/roles/sentinel.md
|
|
93
|
+
mnemara run --instance scratch
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The `--set` argument points at a **role doc** — a Markdown file that becomes
|
|
97
|
+
the agent's system prompt. The repo ships with `examples/roles/sentinel.md`
|
|
98
|
+
as a starting point; see [Role docs](#role-docs) below for what to put in
|
|
99
|
+
your own.
|
|
100
|
+
|
|
101
|
+
By default `mnemara run` opens the **Textual chat panel** (TUI). Pass
|
|
102
|
+
`--no-tui` (or set `MNEMARA_NO_TUI=1`) for the bare prompt-toolkit REPL —
|
|
103
|
+
useful for scripting or non-TTY contexts.
|
|
104
|
+
|
|
105
|
+
### Chat panel layout
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
+------------------------------------------------------------+
|
|
109
|
+
| mnemara: scratch model=claude-opus-4-7 role=... | header
|
|
110
|
+
+------------------------------------------------------------+
|
|
111
|
+
| |
|
|
112
|
+
| you: how do I check the lease timeout? |
|
|
113
|
+
| assistant: open server.py and grep for ... |
|
|
114
|
+
| > tool: Read(file_path=server.py) |
|
|
115
|
+
| result: ... |
|
|
116
|
+
| | chat log
|
|
117
|
+
+------------------------------------------------------------+
|
|
118
|
+
| turns: 12/100 | tokens: 14K/200K | model: claude-opus-4-7 | status
|
|
119
|
+
+------------------------------------------------------------+
|
|
120
|
+
| > _ | input
|
|
121
|
+
+------------------------------------------------------------+
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Keybindings:
|
|
125
|
+
|
|
126
|
+
| Key | Action |
|
|
127
|
+
|---|---|
|
|
128
|
+
| Enter | Send the message |
|
|
129
|
+
| Ctrl+L | Clear the on-screen chat log (does NOT touch turns.sqlite) |
|
|
130
|
+
| Ctrl+C | Quit |
|
|
131
|
+
| `/help` | Slash-command list (same as the REPL) |
|
|
132
|
+
|
|
133
|
+
The TUI accepts `/models`, `/swap`, `/tokens`, `/quit`, and `/exit`.
|
|
134
|
+
`/models` lists the available Claude model shortcuts; `/swap 1` or
|
|
135
|
+
`/swap claude-sonnet-4-6` switches the active model.
|
|
136
|
+
|
|
137
|
+
## Role docs
|
|
138
|
+
|
|
139
|
+
The role doc is a plain Markdown file that becomes the agent's **system
|
|
140
|
+
prompt**. Mnemara re-reads it on every API call and pins it at slot 0 of
|
|
141
|
+
the messages — meaning it applies to every turn, not just the opening one,
|
|
142
|
+
and you can edit the file mid-session and the next turn picks up the
|
|
143
|
+
changes.
|
|
144
|
+
|
|
145
|
+
This is the strongest steering signal you have over the agent. Use it.
|
|
146
|
+
|
|
147
|
+
### What to put in a role doc
|
|
148
|
+
|
|
149
|
+
A good role doc is a short prose document (a few hundred to a few thousand
|
|
150
|
+
words) that answers, in order:
|
|
151
|
+
|
|
152
|
+
1. **Who the agent is** — its identity and standing instructions in this
|
|
153
|
+
instance. ("You are a code reviewer for the Acme repo." "You are a
|
|
154
|
+
research assistant working on tax law.")
|
|
155
|
+
2. **What it should and shouldn't do** — scope, hard constraints,
|
|
156
|
+
anti-patterns to avoid.
|
|
157
|
+
3. **How it should behave when something goes wrong** — when to halt,
|
|
158
|
+
when to ask for help, when to escalate.
|
|
159
|
+
|
|
160
|
+
You can include style notes ("be terse, no apologies"), tooling
|
|
161
|
+
conventions ("always run the tests after writing code"), or domain
|
|
162
|
+
glossaries. There is no required schema. The only mechanical requirement
|
|
163
|
+
is that the file exists and is readable.
|
|
164
|
+
|
|
165
|
+
### Solving the looping / drift problem
|
|
166
|
+
|
|
167
|
+
The most common reason an interactive agent session burns through
|
|
168
|
+
tokens with nothing to show for it is that the agent **gets stuck**:
|
|
169
|
+
|
|
170
|
+
- It calls the same tool over and over waiting for output to change.
|
|
171
|
+
- It drifts from the user's actual request into adjacent rabbit holes.
|
|
172
|
+
- It reverses a correct conclusion the moment the user pushes back.
|
|
173
|
+
|
|
174
|
+
These are role-doc-shaped problems. The role doc is where you encode the
|
|
175
|
+
**rules that keep the agent from spiraling**. If those rules aren't in the
|
|
176
|
+
system prompt, they aren't applied consistently — they reappear only when
|
|
177
|
+
the user remembers to remind the agent.
|
|
178
|
+
|
|
179
|
+
### Example: Sentinel
|
|
180
|
+
|
|
181
|
+
[`examples/roles/sentinel.md`](examples/roles/sentinel.md) is a
|
|
182
|
+
self-monitoring role doc. Drop it in as your instance's role and the
|
|
183
|
+
agent will watch its own execution for the failure modes above
|
|
184
|
+
(timeout / no progress, polling, semantic drift, sycophantic reversal)
|
|
185
|
+
and **halt to ask the user** rather than spending another N turns on a
|
|
186
|
+
runaway loop.
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
mnemara role --instance my-agent --set examples/roles/sentinel.md
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Use it as-is for monitoring-flavored work, or treat it as a template:
|
|
193
|
+
copy the file, edit the trigger conditions to match the failure modes
|
|
194
|
+
you care about, and point your instance at the copy.
|
|
195
|
+
|
|
196
|
+
You can also layer Sentinel-style self-monitoring rules on top of a
|
|
197
|
+
task-specific role doc — there's nothing special about Sentinel; it's
|
|
198
|
+
just text in a Markdown file that the agent reads on every turn.
|
|
199
|
+
|
|
200
|
+
## State layout
|
|
201
|
+
|
|
202
|
+
Everything for an instance lives under `~/.mnemara/<instance>/`:
|
|
203
|
+
|
|
204
|
+
| Path | Purpose |
|
|
205
|
+
|---|---|
|
|
206
|
+
| `config.json` | The config (model, role-doc path, window size, tool policies, MCP servers). |
|
|
207
|
+
| `turns.sqlite` | The rolling-window store. One row per turn. |
|
|
208
|
+
| `permissions.json` | Persisted "always allow" patterns per tool. |
|
|
209
|
+
| `memory/YYYY-MM-DD.md` | Notes the agent or user have written via `WriteMemory` / `/note`. |
|
|
210
|
+
| `wiki/<slug>.md` | Topic-keyed wiki pages (slash-allowed slugs). |
|
|
211
|
+
| `index/` | LanceDB RAG index (embeddings of memory + wiki + manual entries). |
|
|
212
|
+
| `graph/` | Kuzu property graph (entities, wiki pages, topic tags, edges). |
|
|
213
|
+
| `wiki_proposals/<slug>.md` | Replay-drafted wiki promotions awaiting agent review. |
|
|
214
|
+
| `sleep/YYYY-MM-DD.md` | Sleep digests written by the replay primitive. |
|
|
215
|
+
| `memory/archive/` | Near-duplicate memory atoms archived (never deleted) by replay. |
|
|
216
|
+
| `role_proposals/` | Role-amendment proposals — written by `propose_role_amendment` or replay. |
|
|
217
|
+
| `debug.log` | Append-only JSONL log: errors, tool calls, eviction events. |
|
|
218
|
+
| `.prompt_history` | REPL input history. |
|
|
219
|
+
|
|
220
|
+
## Config fields
|
|
221
|
+
|
|
222
|
+
`~/.mnemara/<instance>/config.json`:
|
|
223
|
+
|
|
224
|
+
| Field | Meaning |
|
|
225
|
+
|---|---|
|
|
226
|
+
| `role_doc_path` | Absolute path to the role doc. Re-read on every API call. Pinned as the system prompt. |
|
|
227
|
+
| `model` | Claude model id (e.g. `claude-opus-4-7`, `claude-sonnet-4-6`, `claude-haiku-4-5`). |
|
|
228
|
+
| `max_window_turns` | Rolling-window size (FIFO). Default 20. Counts both user and assistant turns. |
|
|
229
|
+
| `max_window_tokens` | Token-budget cap. The window is FIFO-trimmed once total tokens exceed this. |
|
|
230
|
+
| `allowed_tools` | List of `{tool, mode, allowed_patterns}` policies. `mode` ∈ `allow`/`ask`/`deny`. |
|
|
231
|
+
| `mcp_servers` | List of stdio MCP servers wired through to the model. |
|
|
232
|
+
| `stream` | If true, render the model's text deltas as they arrive. |
|
|
233
|
+
| `bash_timeout_seconds` | Bash command timeout. Default 60. |
|
|
234
|
+
| `file_tool_home_only` | If true, Read/Write/Edit refuse paths outside `$HOME`. Default true. |
|
|
235
|
+
|
|
236
|
+
## CLI commands
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
mnemara init --instance <name> # create ~/.mnemara/<name>/, refuses to overwrite
|
|
240
|
+
mnemara run --instance <name> # open the chat panel (TUI; --no-tui for bare REPL)
|
|
241
|
+
mnemara list # list instances
|
|
242
|
+
mnemara show --instance <name> [-n N] # print the rolling window (read-only)
|
|
243
|
+
mnemara clear --instance <name> # wipe the rolling window
|
|
244
|
+
mnemara delete --instance <name> --force # nuke ~/.mnemara/<name>/
|
|
245
|
+
mnemara role --instance <name> --set PATH # set role_doc_path
|
|
246
|
+
mnemara note --instance <name> TEXT... # append a memory note from the shell
|
|
247
|
+
mnemara replay --instance <name> [--days N] [--threshold N] [--apply] # consolidation pass
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Slash commands (REPL and TUI)
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
/role <path> swap role doc (also persists to config)
|
|
254
|
+
/show print the rolling window
|
|
255
|
+
/clear wipe the window (with confirm)
|
|
256
|
+
/models list available Claude model shortcuts
|
|
257
|
+
/swap <model|n> switch model for this and future sessions
|
|
258
|
+
/note <text> append to today's memory file
|
|
259
|
+
/proposals list pending role-amendment proposals
|
|
260
|
+
/quit, /exit save state and exit
|
|
261
|
+
/help show this list
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Permissions model
|
|
265
|
+
|
|
266
|
+
Each tool has a `mode`:
|
|
267
|
+
|
|
268
|
+
- `allow` — never prompts.
|
|
269
|
+
- `ask` — prompts on first use; user picks `yes`, `no`, `always`, or `session`.
|
|
270
|
+
- `deny` — always blocked.
|
|
271
|
+
|
|
272
|
+
Defaults: Bash=ask, Read=allow, Write=ask, Edit=ask, WriteMemory=allow.
|
|
273
|
+
|
|
274
|
+
When prompted at the REPL:
|
|
275
|
+
- `y` allow this one invocation
|
|
276
|
+
- `n` deny this one invocation
|
|
277
|
+
- `a` always allow this exact target (writes a regex to `permissions.json`)
|
|
278
|
+
- `s` allow this tool for the rest of the session (not persisted)
|
|
279
|
+
|
|
280
|
+
You can pre-seed `allowed_patterns` in `config.json`:
|
|
281
|
+
|
|
282
|
+
```json
|
|
283
|
+
{"tool": "Bash", "mode": "ask", "allowed_patterns": ["^git status$", "^ls( |$)"]}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Memory files
|
|
287
|
+
|
|
288
|
+
Anything that needs to survive rolling-window eviction goes here.
|
|
289
|
+
|
|
290
|
+
- The agent calls the `WriteMemory` tool with `text` and an optional `category`.
|
|
291
|
+
- You call `/note <text>` in the REPL or `mnemara note --instance <name> <text>` from the shell.
|
|
292
|
+
|
|
293
|
+
Format: append-only Markdown, one block per note:
|
|
294
|
+
|
|
295
|
+
```
|
|
296
|
+
## [2026-04-27T18:32:01+00:00] insight
|
|
297
|
+
|
|
298
|
+
Worth remembering across sessions.
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## MCP wire-through
|
|
302
|
+
|
|
303
|
+
Add an entry to `mcp_servers` in `config.json`:
|
|
304
|
+
|
|
305
|
+
```json
|
|
306
|
+
"mcp_servers": [
|
|
307
|
+
{
|
|
308
|
+
"name": "myserver",
|
|
309
|
+
"command": "/usr/local/bin/my-mcp-server",
|
|
310
|
+
"args": [],
|
|
311
|
+
"env": {}
|
|
312
|
+
}
|
|
313
|
+
]
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Mnemara records these servers in its runtime metadata and allow-lists their
|
|
317
|
+
`mcp__<name>__*` tool namespace. The Claude Agent SDK handles the actual
|
|
318
|
+
stdio transport.
|
|
319
|
+
|
|
320
|
+
## Graph backend (Kuzu) + sleep/replay primitive
|
|
321
|
+
|
|
322
|
+
Two co-evolving features. The graph captures relational structure between
|
|
323
|
+
memories and entities; replay exploits that structure on each consolidation
|
|
324
|
+
pass.
|
|
325
|
+
|
|
326
|
+
**Graph backend** — `graph/` directory holding a [Kuzu](https://kuzudb.com/)
|
|
327
|
+
property graph. Two tables: `Node(id, label, properties JSON, created_at)`
|
|
328
|
+
and `Edge(FROM Node TO Node, id, relationship, properties JSON, created_at)`.
|
|
329
|
+
Six tools registered:
|
|
330
|
+
|
|
331
|
+
```
|
|
332
|
+
graph_add_node(label, properties_json) -> id
|
|
333
|
+
graph_add_edge(from_id, to_id, relationship, properties_json) -> id
|
|
334
|
+
graph_query(cypher) -> rows
|
|
335
|
+
graph_neighbors(node_id, depth=1) -> adjacent nodes
|
|
336
|
+
graph_match(pattern_json) -> nodes matching {label, properties_subset}
|
|
337
|
+
graph_shortest_path(from_id, to_id) -> list of node ids
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Auto-edge hooks fire on every `write_memory` (with structured `applies_to`)
|
|
341
|
+
and `wiki_write` (frontmatter `tags:`). All wrapped in try/except — graph
|
|
342
|
+
failure never fails the primary write.
|
|
343
|
+
|
|
344
|
+
Lazy: Kuzu is not opened until the first graph tool call. If Kuzu is absent
|
|
345
|
+
or the DB is corrupt, every tool returns
|
|
346
|
+
`{"ok": false, "error": "Graph backend unavailable: …"}` and the rest of the
|
|
347
|
+
system keeps working. Off-switch: `graph_enabled: false` in config.
|
|
348
|
+
|
|
349
|
+
**Sleep / replay primitive** — `mnemara replay --instance <name>`. Seven
|
|
350
|
+
phases:
|
|
351
|
+
|
|
352
|
+
1. Load atoms from `memory/*.md` over the last `--days` (default 7).
|
|
353
|
+
2. Cluster atoms via RAG similarity. Atoms within distance 0.35 cluster;
|
|
354
|
+
`--threshold` (default 3) sets the minimum count to count as a pattern.
|
|
355
|
+
3. Augment patterns with graph structure — frequently-co-occurring entities
|
|
356
|
+
from `applies_to` edges; causal phrasing in member text.
|
|
357
|
+
4. For patterns not already covered by an existing wiki page, draft a
|
|
358
|
+
proposal at `wiki_proposals/<slug>.md`.
|
|
359
|
+
5. Archive near-duplicate atoms (distance < 0.10) into `memory/archive/`.
|
|
360
|
+
**Never deletes.**
|
|
361
|
+
6. When `self_observation` atoms cluster, draft a role-amendment proposal
|
|
362
|
+
at `role_proposals/<ts>_replay-<slug>.md`.
|
|
363
|
+
7. Write a sleep digest at `sleep/YYYY-MM-DD.md` with counts and pointers.
|
|
364
|
+
|
|
365
|
+
Default behavior is dry-run. Pass `--apply` to actually write proposals,
|
|
366
|
+
archive duplicates, and emit the digest.
|
|
367
|
+
|
|
368
|
+
## Multi-backend memory (wiki + RAG)
|
|
369
|
+
|
|
370
|
+
Three memory surfaces write together. The agent picks which surface to read
|
|
371
|
+
from given the kind of recall it needs.
|
|
372
|
+
|
|
373
|
+
**Memory file** — `memory/YYYY-MM-DD.md`. Append-only, chronological.
|
|
374
|
+
|
|
375
|
+
**Wiki** — `wiki/<slug>.md`. Slash-allowed slugs (e.g. `replay_policy`,
|
|
376
|
+
`patterns/loader_traps`). Plain markdown, optional frontmatter, no schema.
|
|
377
|
+
|
|
378
|
+
```
|
|
379
|
+
wiki_read(path)
|
|
380
|
+
wiki_write(path, content, mode='replace') # 'replace'|'append'
|
|
381
|
+
wiki_list(prefix='')
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**RAG** — `index/` (LanceDB), embeddings via Ollama `nomic-embed-text` (768-dim).
|
|
385
|
+
|
|
386
|
+
```
|
|
387
|
+
rag_index(text, kind='manual', source_path='', category='')
|
|
388
|
+
rag_query(question, k=5, kind=None)
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**Write-to-all consolidation:** every `write_memory` call also `rag_index`es
|
|
392
|
+
the content. Every `wiki_write` also indexes itself. If `category` starts
|
|
393
|
+
with `wiki/`, `write_memory` ALSO writes the body to `wiki/<rest>.md`.
|
|
394
|
+
|
|
395
|
+
**Setup for RAG:**
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
ollama pull nomic-embed-text # one-time; ~270MB
|
|
399
|
+
# Ollama must be running on http://localhost:11434
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
If Ollama is unreachable or LanceDB import fails, RAG tools return
|
|
403
|
+
`"RAG backend unavailable: <reason>"` and memory + wiki keep working.
|
|
404
|
+
|
|
405
|
+
## Architecture note
|
|
406
|
+
|
|
407
|
+
Mnemara is a thin runtime around the Claude Agent SDK. The SDK runs the
|
|
408
|
+
model and its native tools (Bash/Read/Edit/Write); Mnemara owns:
|
|
409
|
+
|
|
410
|
+
- The persistent turn store (`turns.sqlite`).
|
|
411
|
+
- The role doc, re-read every call as `system_prompt`.
|
|
412
|
+
- The rolling-window transcript serialized into each turn's prompt
|
|
413
|
+
(the SDK is stateless per `query()`).
|
|
414
|
+
- The permission policy (mediated via the SDK's `can_use_tool` callback).
|
|
415
|
+
- The memory/wiki/RAG/graph backends and the `replay` consolidation pass.
|
|
416
|
+
|
|
417
|
+
## Troubleshooting
|
|
418
|
+
|
|
419
|
+
- **Auth errors** — confirm `ANTHROPIC_API_KEY` is set, or that `claude`
|
|
420
|
+
CLI is installed and `claude login` has been run as a fallback.
|
|
421
|
+
- **Role doc not loading** — Mnemara warns to stderr and uses an empty system
|
|
422
|
+
prompt; the REPL stays alive. Check `debug.log` for the path that failed.
|
|
423
|
+
- **MCP server crashes** — check `debug.log` and the server's own stderr.
|
|
424
|
+
As a fallback, remove the entry from `mcp_servers`.
|
|
425
|
+
- **Window eviction surprises** — `mnemara show --instance <name>` prints the
|
|
426
|
+
current window. The rolling window keeps the last `max_window_turns` rows;
|
|
427
|
+
long tool-use turns count as one row but can carry many content blocks.
|
|
428
|
+
- **Token errors** — if a long role doc + window overruns the model context,
|
|
429
|
+
drop `max_window_turns` or split the role doc.
|
|
430
|
+
|
|
431
|
+
## Running the tests
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
pip install -e ".[dev]"
|
|
435
|
+
pytest -q tests/
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Tests do not call the network — they cover the store, config, permissions,
|
|
439
|
+
and the file tools.
|
|
440
|
+
|
|
441
|
+
## License
|
|
442
|
+
|
|
443
|
+
MIT. See [LICENSE](LICENSE).
|