mnemo-claude 0.12.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.
- mnemo_claude-0.12.0/LICENSE +21 -0
- mnemo_claude-0.12.0/PKG-INFO +542 -0
- mnemo_claude-0.12.0/README.md +528 -0
- mnemo_claude-0.12.0/pyproject.toml +46 -0
- mnemo_claude-0.12.0/setup.cfg +4 -0
- mnemo_claude-0.12.0/src/mnemo/__init__.py +1 -0
- mnemo_claude-0.12.0/src/mnemo/__main__.py +4 -0
- mnemo_claude-0.12.0/src/mnemo/cli/__init__.py +31 -0
- mnemo_claude-0.12.0/src/mnemo/cli/_helpers/__init__.py +80 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/__init__.py +25 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/briefing.py +35 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/dedup_rules.py +44 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/disable_rule.py +62 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/doctor.py +124 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/doctor_checks/__init__.py +30 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/doctor_checks/activation.py +211 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/doctor_checks/fidelity.py +38 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/doctor_checks/misc.py +92 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/doctor_checks/orphan_worktree_briefings.py +85 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/doctor_checks/reflex.py +189 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/doctor_checks/rules.py +179 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/extract.py +88 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/init.py +204 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/list_enforced.py +56 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/migrate_worktree_briefings.py +90 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/misc.py +87 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/recall.py +79 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/status.py +224 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/statusline.py +34 -0
- mnemo_claude-0.12.0/src/mnemo/cli/commands/telemetry.py +24 -0
- mnemo_claude-0.12.0/src/mnemo/cli/parser.py +102 -0
- mnemo_claude-0.12.0/src/mnemo/cli/runtime.py +47 -0
- mnemo_claude-0.12.0/src/mnemo/core/__init__.py +0 -0
- mnemo_claude-0.12.0/src/mnemo/core/agent.py +111 -0
- mnemo_claude-0.12.0/src/mnemo/core/briefing.py +234 -0
- mnemo_claude-0.12.0/src/mnemo/core/config.py +138 -0
- mnemo_claude-0.12.0/src/mnemo/core/dashboard.py +200 -0
- mnemo_claude-0.12.0/src/mnemo/core/dedup_rules.py +169 -0
- mnemo_claude-0.12.0/src/mnemo/core/errors.py +126 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/__init__.py +542 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/inbox/__init__.py +75 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/inbox/apply.py +160 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/inbox/branches/__init__.py +14 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/inbox/branches/auto_promoted.py +163 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/inbox/branches/inbox_flow.py +180 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/inbox/branches/upgrade.py +41 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/inbox/dedup.py +218 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/inbox/io.py +86 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/inbox/paths.py +66 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/inbox/rendering.py +157 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/inbox/state_io.py +94 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/inbox/types.py +46 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/promote.py +100 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/prompts/__init__.py +42 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/prompts/encoding.py +30 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/prompts/render.py +127 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/prompts/templates/__init__.py +7 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/prompts/templates/briefing.py +50 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/prompts/templates/few_shot_feedback.py +167 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/prompts/templates/few_shot_simple.py +44 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/prompts/templates/schema.py +48 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/prompts/templates/system_feedback.py +105 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/prompts/templates/system_simple.py +33 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/prompts/vault_tags.py +33 -0
- mnemo_claude-0.12.0/src/mnemo/core/extract/scanner.py +215 -0
- mnemo_claude-0.12.0/src/mnemo/core/filters.py +229 -0
- mnemo_claude-0.12.0/src/mnemo/core/llm.py +184 -0
- mnemo_claude-0.12.0/src/mnemo/core/locks.py +44 -0
- mnemo_claude-0.12.0/src/mnemo/core/log_utils.py +15 -0
- mnemo_claude-0.12.0/src/mnemo/core/log_writer.py +70 -0
- mnemo_claude-0.12.0/src/mnemo/core/mcp/__init__.py +6 -0
- mnemo_claude-0.12.0/src/mnemo/core/mcp/access_log.py +113 -0
- mnemo_claude-0.12.0/src/mnemo/core/mcp/access_log_summary.py +220 -0
- mnemo_claude-0.12.0/src/mnemo/core/mcp/recall.py +346 -0
- mnemo_claude-0.12.0/src/mnemo/core/mcp/server.py +231 -0
- mnemo_claude-0.12.0/src/mnemo/core/mcp/session_state.py +212 -0
- mnemo_claude-0.12.0/src/mnemo/core/mcp/tools.py +291 -0
- mnemo_claude-0.12.0/src/mnemo/core/mirror.py +103 -0
- mnemo_claude-0.12.0/src/mnemo/core/paths.py +44 -0
- mnemo_claude-0.12.0/src/mnemo/core/pricing.py +36 -0
- mnemo_claude-0.12.0/src/mnemo/core/reflex/__init__.py +1 -0
- mnemo_claude-0.12.0/src/mnemo/core/reflex/bm25.py +100 -0
- mnemo_claude-0.12.0/src/mnemo/core/reflex/gates.py +74 -0
- mnemo_claude-0.12.0/src/mnemo/core/reflex/index.py +159 -0
- mnemo_claude-0.12.0/src/mnemo/core/reflex/stopwords.py +42 -0
- mnemo_claude-0.12.0/src/mnemo/core/reflex/tokenizer.py +44 -0
- mnemo_claude-0.12.0/src/mnemo/core/rule_activation/__init__.py +53 -0
- mnemo_claude-0.12.0/src/mnemo/core/rule_activation/activity_log.py +85 -0
- mnemo_claude-0.12.0/src/mnemo/core/rule_activation/globs.py +113 -0
- mnemo_claude-0.12.0/src/mnemo/core/rule_activation/index.py +316 -0
- mnemo_claude-0.12.0/src/mnemo/core/rule_activation/matching.py +232 -0
- mnemo_claude-0.12.0/src/mnemo/core/rule_activation/parsing.py +263 -0
- mnemo_claude-0.12.0/src/mnemo/core/session.py +66 -0
- mnemo_claude-0.12.0/src/mnemo/core/text_utils.py +27 -0
- mnemo_claude-0.12.0/src/mnemo/core/transcript.py +54 -0
- mnemo_claude-0.12.0/src/mnemo/hooks/__init__.py +0 -0
- mnemo_claude-0.12.0/src/mnemo/hooks/pre_tool_use.py +161 -0
- mnemo_claude-0.12.0/src/mnemo/hooks/session_end.py +304 -0
- mnemo_claude-0.12.0/src/mnemo/hooks/session_start.py +241 -0
- mnemo_claude-0.12.0/src/mnemo/hooks/user_prompt_submit.py +209 -0
- mnemo_claude-0.12.0/src/mnemo/install/__init__.py +0 -0
- mnemo_claude-0.12.0/src/mnemo/install/preflight.py +105 -0
- mnemo_claude-0.12.0/src/mnemo/install/scaffold.py +48 -0
- mnemo_claude-0.12.0/src/mnemo/install/settings.py +451 -0
- mnemo_claude-0.12.0/src/mnemo/statusline.py +319 -0
- mnemo_claude-0.12.0/src/mnemo/templates/HOME.md +53 -0
- mnemo_claude-0.12.0/src/mnemo/templates/README.md +34 -0
- mnemo_claude-0.12.0/src/mnemo/templates/__init__.py +0 -0
- mnemo_claude-0.12.0/src/mnemo/templates/graph-dark-gold.css +16 -0
- mnemo_claude-0.12.0/src/mnemo/templates/mnemo.config.json +10 -0
- mnemo_claude-0.12.0/src/mnemo_claude.egg-info/PKG-INFO +542 -0
- mnemo_claude-0.12.0/src/mnemo_claude.egg-info/SOURCES.txt +114 -0
- mnemo_claude-0.12.0/src/mnemo_claude.egg-info/dependency_links.txt +1 -0
- mnemo_claude-0.12.0/src/mnemo_claude.egg-info/entry_points.txt +2 -0
- mnemo_claude-0.12.0/src/mnemo_claude.egg-info/requires.txt +4 -0
- mnemo_claude-0.12.0/src/mnemo_claude.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 xyrlan
|
|
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.
|
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mnemo-claude
|
|
3
|
+
Version: 0.12.0
|
|
4
|
+
Summary: The Obsidian that populates itself so your Claude never forgets.
|
|
5
|
+
Author: xyrlan
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
12
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# mnemo
|
|
16
|
+
|
|
17
|
+
> The Obsidian that populates itself so your Claude never forgets.
|
|
18
|
+
|
|
19
|
+
**mnemo** is a Claude Code plugin that turns every coding session into a
|
|
20
|
+
self-organizing knowledge base — and then feeds that knowledge back into
|
|
21
|
+
Claude so it stops forgetting what you taught it last week.
|
|
22
|
+
|
|
23
|
+
It runs as a hooks-only, stdlib-only Python package. Zero third-party
|
|
24
|
+
dependencies, zero network calls. Identical on Linux,
|
|
25
|
+
macOS, and Windows.
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
One command:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx @xyrlan/mnemo install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
That installs the Python package (via `uv` / `pipx` / `pip --user`, whichever is available), prompts you to choose **global** (every Claude Code session) or **project** (this directory only), wires the hooks + MCP server + slash commands, and you're done.
|
|
36
|
+
|
|
37
|
+
Non-interactive variants:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx @xyrlan/mnemo install --yes # global, no prompts
|
|
41
|
+
npx @xyrlan/mnemo install --project --yes # project-scoped, no prompts
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`npx @xyrlan/mnemo uninstall [--scope global|project|both]` reverses everything; the vault is preserved.
|
|
45
|
+
|
|
46
|
+
**Prerequisites:** Python 3.8+ on your machine. Node is already there if you run `npx`. mnemo's npm wrapper is zero-dep and ~150 LOC — it's a thin bootstrap, not the runtime.
|
|
47
|
+
|
|
48
|
+
`mnemo init` (run automatically by `npx … install`) is idempotent and does four things:
|
|
49
|
+
|
|
50
|
+
1. Scaffolds a vault at `~/mnemo/` (or wherever you point it)
|
|
51
|
+
2. Injects four hooks into `~/.claude/settings.json`:
|
|
52
|
+
`SessionStart`, `SessionEnd`, `PreToolUse` (rule activation, v0.5),
|
|
53
|
+
and `UserPromptSubmit` (Prompt Reflex, v0.8)
|
|
54
|
+
3. Registers a stdio MCP server in `~/.claude.json` so Claude Code can call mnemo's tools
|
|
55
|
+
4. Wires an additive status line composer (preserves your existing one if you have it)
|
|
56
|
+
5. Writes `~/.claude/commands/<name>.md` slash command files so `/init`, `/status`, `/doctor`, etc. work inside Claude Code without a separate plugin install
|
|
57
|
+
|
|
58
|
+
That's it. Use Claude Code normally — your vault populates itself, the
|
|
59
|
+
HOME dashboard regenerates after every extraction, and Claude starts
|
|
60
|
+
consulting captured rules on its own.
|
|
61
|
+
|
|
62
|
+
### Alternative install paths
|
|
63
|
+
|
|
64
|
+
If you'd rather skip npm entirely:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pipx install mnemo-claude # or: uv tool install mnemo-claude
|
|
68
|
+
mnemo init # global
|
|
69
|
+
mnemo init --project # project-only
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The PyPI distribution is named **`mnemo-claude`** (the bare `mnemo` slot was already taken on PyPI by an unrelated package). The CLI binary, import name, and project repository are still `mnemo` — only `pipx install` / `pip install` see the dashed name.
|
|
73
|
+
|
|
74
|
+
If you'd rather wire the slash commands via Claude Code's marketplace:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
/plugin marketplace add xyrlan/mnemo
|
|
78
|
+
/plugin install mnemo@mnemo-marketplace
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
(The marketplace path requires `pipx install mnemo-claude` first — `/plugin install` registers slash commands but does not install the Python runtime.)
|
|
82
|
+
|
|
83
|
+
### Installation scope: global vs project (v0.12+)
|
|
84
|
+
|
|
85
|
+
By default `mnemo init` installs **globally** — every Claude Code session,
|
|
86
|
+
in any directory, fires mnemo. Pass `--project` (alias `--local`) to scope
|
|
87
|
+
the install to the current directory only:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
mnemo init --project
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
This writes to `<cwd>/.claude/settings.json` + `<cwd>/.mcp.json`, scaffolds
|
|
94
|
+
a self-contained vault at `<cwd>/.mnemo/`, and appends `.claude/` and
|
|
95
|
+
`.mnemo/` to your project's `.gitignore`. `~/.claude/settings.json`,
|
|
96
|
+
`~/.claude.json`, and `~/mnemo/` stay untouched. Claude Code only loads
|
|
97
|
+
mnemo when launched in that directory; sessions in any other path get the
|
|
98
|
+
unmodified global behavior (or no mnemo at all).
|
|
99
|
+
|
|
100
|
+
Use this when you want to:
|
|
101
|
+
|
|
102
|
+
- evaluate mnemo on a single project before committing to it globally,
|
|
103
|
+
- isolate per-project memory so different repos don't share a vault,
|
|
104
|
+
- ship a repo where mnemo is part of the dev environment without forcing
|
|
105
|
+
collaborators to install it globally — they get it automatically when
|
|
106
|
+
they `cd` into the project.
|
|
107
|
+
|
|
108
|
+
`mnemo uninstall --project` removes only the local install (the vault is
|
|
109
|
+
preserved, same as global uninstall). `mnemo status --scope project|global|all`
|
|
110
|
+
reports both scopes independently — Claude Code itself decides which is
|
|
111
|
+
"active" for any given session based on cwd.
|
|
112
|
+
|
|
113
|
+
> Note on portability: hook commands embed an absolute Python path
|
|
114
|
+
> (`sys.executable`), so `<cwd>/.claude/settings.json` is gitignored by
|
|
115
|
+
> default. Each developer runs their own `mnemo init --project` to wire
|
|
116
|
+
> their interpreter.
|
|
117
|
+
|
|
118
|
+
## How it works — Capture → Present → Inject → Reflex
|
|
119
|
+
|
|
120
|
+
mnemo's tagline is one sentence: *"so your Claude never forgets."* That
|
|
121
|
+
breaks into four stages, each shipped in a different release, all live
|
|
122
|
+
together from v0.8 on.
|
|
123
|
+
|
|
124
|
+
### 1. Capture (v0.2 → v0.3.1)
|
|
125
|
+
|
|
126
|
+
mnemo watches Claude Code's lifecycle hooks and writes a structured trail
|
|
127
|
+
into your vault as you work:
|
|
128
|
+
|
|
129
|
+
- **Session start / end markers** — `🟢` and `🔴` in `bots/<repo>/logs/YYYY-MM-DD.md`
|
|
130
|
+
- **Claude memory mirror** — anything Claude saves to `~/.claude/projects/*/memory/`
|
|
131
|
+
is mirrored into `bots/<repo>/memory/` so it lives next to the rest of the trail
|
|
132
|
+
- **Per-session briefings** *(opt-in, v0.3.1)* — at session end, an LLM pass
|
|
133
|
+
summarizes the full transcript into a structured handoff document under
|
|
134
|
+
`bots/<repo>/briefings/sessions/`. Briefings are the dense input that
|
|
135
|
+
feeds extraction; they're the difference between mnemo capturing
|
|
136
|
+
~1 file/day vs. capturing every meaningful decision.
|
|
137
|
+
|
|
138
|
+
The extraction pipeline (`mnemo extract`, also auto-run after sessions
|
|
139
|
+
when enabled) consolidates everything in `bots/` into canonical Tier 2
|
|
140
|
+
pages under `shared/{feedback,user,reference,project}/`. Single-source
|
|
141
|
+
pages auto-promote into the canonical layer; multi-source clusters
|
|
142
|
+
(cross-agent merges) stage in `shared/_inbox/<type>/` for review. Your
|
|
143
|
+
manual edits to auto-promoted files are protected by content-addressing —
|
|
144
|
+
a conflict produces a `.proposed.md` sibling instead of overwriting your
|
|
145
|
+
work.
|
|
146
|
+
|
|
147
|
+
### 2. Present (v0.4)
|
|
148
|
+
|
|
149
|
+
Capture without surfacing is just a dump. v0.4 added two consumer
|
|
150
|
+
surfaces over the same data:
|
|
151
|
+
|
|
152
|
+
- **HOME.md dashboard** — a managed block at the top of `HOME.md`
|
|
153
|
+
regenerates after every extraction. Pages are grouped by trust tier
|
|
154
|
+
(cross-agent synthesized first, single-source auto-promoted second) and
|
|
155
|
+
by topic tag, so you can scan the project brain in seconds inside
|
|
156
|
+
Obsidian. Everything below the managed block is yours to edit; mnemo
|
|
157
|
+
never touches it.
|
|
158
|
+
- **Dimensional tags** — extraction asks the LLM to tag each page with
|
|
159
|
+
topic kebab-case identifiers (`auth`, `react`, `package-management`),
|
|
160
|
+
using a controlled-vocabulary hint built from your existing vault tags
|
|
161
|
+
to prevent sprawl. Tags become the ontology Claude navigates in v0.5.
|
|
162
|
+
|
|
163
|
+
### 3. Inject (v0.5)
|
|
164
|
+
|
|
165
|
+
The loop closes. Claude Code itself reaches into mnemo at the start of
|
|
166
|
+
every session, no manual command needed.
|
|
167
|
+
|
|
168
|
+
- **MCP stdio server** — `mnemo init` registers a long-running JSON-RPC
|
|
169
|
+
server in `~/.claude.json` exposing three read-only tools. All three
|
|
170
|
+
default to `scope="project"` (only rules owned by the current repo);
|
|
171
|
+
pass `scope="vault"` for cross-project lookups:
|
|
172
|
+
- `list_rules_by_topic(topic, scope?)` — slugs sorted by source count desc
|
|
173
|
+
(multi-agent synthesized rules surface first)
|
|
174
|
+
- `read_mnemo_rule(slug, scope?)` — full body + frontmatter
|
|
175
|
+
- `get_mnemo_topics(scope?)` — sorted union of topic tags
|
|
176
|
+
- **SessionStart topic injection** *(opt-in)* — the SessionStart hook
|
|
177
|
+
emits a ~120-token instruction listing the topics in your vault and
|
|
178
|
+
telling Claude to call the MCP tools BEFORE writing code when the task
|
|
179
|
+
matches a known topic. ~120 tokens regardless of vault size: the topic
|
|
180
|
+
list is the only thing pre-loaded; rule bodies are fetched on demand.
|
|
181
|
+
- **Filter parity** — both the dashboard and the MCP tools call the same
|
|
182
|
+
`is_consumer_visible` predicate, so evolving and needs-review pages
|
|
183
|
+
never reach Claude.
|
|
184
|
+
|
|
185
|
+
The result: Claude consumes in real time the rules you taught it weeks
|
|
186
|
+
earlier in a different session, without you having to remember to copy
|
|
187
|
+
them in.
|
|
188
|
+
|
|
189
|
+
### 4. Reflex (v0.8)
|
|
190
|
+
|
|
191
|
+
SessionStart tells Claude *what topics exist*. PreToolUse fires *when Claude
|
|
192
|
+
touches a file*. **Reflex** closes the gap in between: it reacts to the
|
|
193
|
+
actual prompt you just typed and injects the single most relevant rule
|
|
194
|
+
before Claude thinks about the question.
|
|
195
|
+
|
|
196
|
+
- **BM25F retrieval** — the `UserPromptSubmit` hook tokenizes your prompt
|
|
197
|
+
(lowercase + fenced-code stripping + EN/PT stopwords), scores every
|
|
198
|
+
consumer-visible rule across five weighted fields (`name`, `topic_tags`,
|
|
199
|
+
`aliases`, `description`, `body`), and returns the top candidate. Pure
|
|
200
|
+
stdlib; p50 1.3 ms / p95 1.7 ms on a 500-rule vault.
|
|
201
|
+
- **Triple-gate confidence test** — silence is the default. A rule is
|
|
202
|
+
injected only if it clears all three gates: term-overlap ≥ 2, relative
|
|
203
|
+
gap ≥ 1.5× over the runner-up, and absolute score ≥ 2.0. Low-confidence
|
|
204
|
+
matches stay silent; wrong context is worse than no context.
|
|
205
|
+
- **`aliases:` bridges** — rules can declare a list of lowercase synonym
|
|
206
|
+
tokens (e.g. `aliases: [banco, database, db]`) so a prompt in Portuguese
|
|
207
|
+
activates an English-written rule. Extraction auto-emits aliases when
|
|
208
|
+
the rule body carries domain terms with bilingual synonyms.
|
|
209
|
+
- **Session-lifetime dedupe** — a rule injected once is not re-injected
|
|
210
|
+
the same day (`injected_cache` in `.mnemo/mcp-call-counter.json`). The
|
|
211
|
+
`PreToolUse` enrichment path reads the same cache so Reflex and
|
|
212
|
+
enrichment never double-surface the same rule in one session.
|
|
213
|
+
- **Cap** — each session emits at most `reflex.maxEmissionsPerSession`
|
|
214
|
+
(default 10). Hitting the cap logs `silence_reason: session_cap_reached`
|
|
215
|
+
for doctor to analyze.
|
|
216
|
+
- **Fail-open absolute** — any exception anywhere in the pipeline returns
|
|
217
|
+
exit 0 with empty stdout. Reflex can never stall a prompt.
|
|
218
|
+
|
|
219
|
+
### Last-briefing handoff (v0.10+)
|
|
220
|
+
|
|
221
|
+
When `briefings.injectLastOnSessionStart` is true (default), every new Claude
|
|
222
|
+
Code session in a project whose canonical agent has at least one briefing
|
|
223
|
+
on disk gets a `[last-briefing session=… date=… duration_minutes=…] … [/last-briefing]`
|
|
224
|
+
block appended to the SessionStart injection envelope. Worktrees of the same
|
|
225
|
+
repo share one briefing pool, resolved via `.git` worktree pointers.
|
|
226
|
+
|
|
227
|
+
If you have orphan worktree briefings from before this change, run
|
|
228
|
+
`mnemo migrate-worktree-briefings --repos /path/to/repo --dry-run` to preview
|
|
229
|
+
moves, then drop `--dry-run` to apply.
|
|
230
|
+
|
|
231
|
+
**Known limitation (early upgraders):** If you upgraded to v0.10 before any
|
|
232
|
+
canonical-repo session wrapped up, `mnemo doctor` cannot detect orphan
|
|
233
|
+
worktree briefings (the check requires the canonical agent to have at least
|
|
234
|
+
one briefing on disk). In that case, run the migration command manually and
|
|
235
|
+
inspect `bots/` for `<repo>-<suffix>` subdirectories.
|
|
236
|
+
|
|
237
|
+
### Cost telemetry (v0.10+)
|
|
238
|
+
|
|
239
|
+
Every `llm.call()` (briefing + extraction consolidations) writes a
|
|
240
|
+
`tool: "llm.call"` entry into `.mnemo/mcp-access-log.jsonl` with
|
|
241
|
+
`usage.input_tokens` / `usage.output_tokens`. Every SessionStart writes a
|
|
242
|
+
`tool: "session_start.inject"` entry with `envelope_bytes`. `mnemo telemetry`
|
|
243
|
+
aggregates both into per-purpose token totals + estimated USD (using a
|
|
244
|
+
hard-coded pricing table at `src/mnemo/core/pricing.py` — bump the table
|
|
245
|
+
when Anthropic prices change).
|
|
246
|
+
|
|
247
|
+
## Scope model (v0.7+)
|
|
248
|
+
|
|
249
|
+
Rules in `shared/{feedback,user,reference}/` are **local by default**: a rule
|
|
250
|
+
is visible only from projects that appear in its `sources[]` frontmatter. A
|
|
251
|
+
rule is automatically promoted to **universal** when it has been seen in at
|
|
252
|
+
least `scoping.universalThreshold` distinct projects (default: 2). Universal
|
|
253
|
+
rules are visible from every project.
|
|
254
|
+
|
|
255
|
+
MCP retrieval accepts three `scope` values:
|
|
256
|
+
|
|
257
|
+
| `scope` | Returns |
|
|
258
|
+
|---------------|------------------------------------------------------|
|
|
259
|
+
| `"project"` | local rules + universal rules (default) |
|
|
260
|
+
| `"local-only"`| local rules only (legacy v0.6.2 behaviour) |
|
|
261
|
+
| `"vault"` | every consumer-visible rule |
|
|
262
|
+
|
|
263
|
+
Promotion and demotion are automatic: the index is re-derived from `sources[]`
|
|
264
|
+
on every SessionStart. To change the threshold, set
|
|
265
|
+
`scoping.universalThreshold` in `mnemo.config.json`.
|
|
266
|
+
|
|
267
|
+
## Status line
|
|
268
|
+
|
|
269
|
+
After `mnemo init`, your Claude Code status line shows the brain's heartbeat:
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
mnemo mcp · 9 topics · 7↓ today · 3⚡
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
- `mnemo mcp` — MCP server is registered in `~/.claude.json`
|
|
276
|
+
- `9 topics` — topic tags currently known in your vault (live count)
|
|
277
|
+
- `7↓ today` — number of times Claude has called a mnemo MCP tool today
|
|
278
|
+
(resets at midnight, atomic write)
|
|
279
|
+
- `3⚡` — Reflex emissions today (v0.8). The bolt only appears when at
|
|
280
|
+
least one rule has been injected via `UserPromptSubmit` this day.
|
|
281
|
+
|
|
282
|
+
The status line is **additive**: if you already had a custom statusLine
|
|
283
|
+
in `~/.claude/settings.json`, mnemo wraps it instead of overwriting.
|
|
284
|
+
Your original output appears first, then ` · `, then mnemo's segment.
|
|
285
|
+
`mnemo uninstall` restores your original cleanly. If you manually edit
|
|
286
|
+
settings.json after `mnemo init`, `mnemo doctor` warns about the drift.
|
|
287
|
+
|
|
288
|
+
## Runtime flags
|
|
289
|
+
|
|
290
|
+
The Capture → Present → Inject → Reflex loop is **on by default** —
|
|
291
|
+
`mnemo init` gives you the full product, not an inert scaffold. The
|
|
292
|
+
five runtime flags can be flipped to `false` in `~/mnemo/mnemo.config.json`
|
|
293
|
+
if you want to disable specific behaviors:
|
|
294
|
+
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"extraction": {
|
|
298
|
+
"auto": {
|
|
299
|
+
"enabled": true,
|
|
300
|
+
"minNewMemories": 1,
|
|
301
|
+
"minIntervalMinutes": 60
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
"briefings": {
|
|
305
|
+
"enabled": true
|
|
306
|
+
},
|
|
307
|
+
"injection": {
|
|
308
|
+
"enabled": true
|
|
309
|
+
},
|
|
310
|
+
"enrichment": {
|
|
311
|
+
"enabled": true
|
|
312
|
+
},
|
|
313
|
+
"reflex": {
|
|
314
|
+
"enabled": true
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
- **`extraction.auto.enabled`** *(default `true`)* — at every session end,
|
|
320
|
+
if there are at least `minNewMemories` new files (default 1) and at
|
|
321
|
+
least `minIntervalMinutes` since the last run (default 60), spawn a
|
|
322
|
+
detached background extraction. The hook returns in <100ms; extraction
|
|
323
|
+
runs asynchronously. Check progress via `mnemo status`, diagnose with
|
|
324
|
+
`mnemo doctor`.
|
|
325
|
+
- **`briefings.enabled`** *(default `true`)* — at every session end,
|
|
326
|
+
generate a per-session briefing into `bots/<repo>/briefings/sessions/`.
|
|
327
|
+
Briefings feed the next extraction run as dense input.
|
|
328
|
+
- **`injection.enabled`** *(default `true`, v0.5)* — at every session
|
|
329
|
+
start, emit the MCP topic list into Claude's `additionalContext`. The
|
|
330
|
+
MCP tools are always available once `mnemo init` has run; this flag
|
|
331
|
+
controls only whether Claude is *told about* the topics at session start.
|
|
332
|
+
- **`enrichment.enabled`** *(default `true`, v0.5)* — when Claude is about
|
|
333
|
+
to `Edit`/`Write`/`MultiEdit` a file matching a rule's `path_globs`, the
|
|
334
|
+
PreToolUse hook injects the rule body as additional context before the
|
|
335
|
+
tool runs. See "Rule activation" below for details.
|
|
336
|
+
- **`reflex.enabled`** *(default `true`, v0.8)* — on every user prompt,
|
|
337
|
+
the `UserPromptSubmit` hook runs BM25F retrieval over the vault-wide
|
|
338
|
+
reflex index and injects the single highest-confidence rule preview
|
|
339
|
+
inline (triple-gate: overlap ≥ 2, relative gap ≥ 1.5×, absolute floor
|
|
340
|
+
≥ 2.0). Tune `reflex.thresholds.*`, `reflex.bm25f.fieldWeights`, and
|
|
341
|
+
`reflex.maxEmissionsPerSession` in `mnemo.config.json`. See "Prompt
|
|
342
|
+
Reflex" below.
|
|
343
|
+
|
|
344
|
+
## Rule activation *(v0.5)*
|
|
345
|
+
|
|
346
|
+
The three flags above tell Claude *that rules exist* at session start. **Rule
|
|
347
|
+
activation** makes mnemo push a rule directly into Claude's turn at the exact
|
|
348
|
+
moment it's about to run a tool — not just once per session. Two modes share
|
|
349
|
+
the same per-project index and the same `PreToolUse` hook:
|
|
350
|
+
|
|
351
|
+
- **Enforcement** — when Claude is about to run a `Bash` command that
|
|
352
|
+
matches a `deny_pattern` regex or a `deny_command` prefix from any rule
|
|
353
|
+
owned by the current project, the hook emits `permissionDecision: deny`
|
|
354
|
+
and Claude Code blocks the call with the rule's `reason` string visible to
|
|
355
|
+
the model. Use for hard guardrails: "never commit with Co-Authored-By",
|
|
356
|
+
"never run `drizzle-kit push`".
|
|
357
|
+
- **Enrichment** — when Claude is about to run `Edit`, `Write`, or
|
|
358
|
+
`MultiEdit` on a file path that matches one of a rule's `path_globs`, the
|
|
359
|
+
hook emits `additionalContext` containing the rule body preview (up to 3
|
|
360
|
+
matching rules, ordered by source count). Claude sees the text as a
|
|
361
|
+
`<system-reminder>` *before* performing the edit. Use for advisory rules
|
|
362
|
+
with file-level scope: "HeroUI v3 modals use the Drawer slot pattern",
|
|
363
|
+
"React key remount is required for these components".
|
|
364
|
+
|
|
365
|
+
Both modes are **strictly per-project** — a rule captured while working on
|
|
366
|
+
project A never fires while working on project B. Project ownership is
|
|
367
|
+
derived from the `sources:` frontmatter field (e.g. `bots/sg-imports/...`
|
|
368
|
+
belongs to `sg-imports`). Cross-project rules self-heal via repeated
|
|
369
|
+
capture.
|
|
370
|
+
|
|
371
|
+
### Defaults and kill switch
|
|
372
|
+
|
|
373
|
+
- **`enforcement.enabled`** defaults to **`true`**. This is safe because
|
|
374
|
+
enforcement is *inert until you own a rule with an `enforce:` block* — a
|
|
375
|
+
fresh vault has zero such rules, so the hook fires but matches nothing.
|
|
376
|
+
Rules gain activation metadata either by hand-editing the frontmatter or
|
|
377
|
+
when the extraction LLM emits it for a high-confidence rule (see "Rule
|
|
378
|
+
frontmatter shape" below).
|
|
379
|
+
- **`enrichment.enabled`** defaults to **`true`** during the dogfood
|
|
380
|
+
phase. Enrichment surfaces context every time you edit a file matching a
|
|
381
|
+
rule's `path_globs`. If you want to silence it temporarily while iterating
|
|
382
|
+
on rules, set to `false` in `mnemo.config.json`.
|
|
383
|
+
|
|
384
|
+
To disable enforcement (kill switch), add to `~/mnemo/mnemo.config.json`:
|
|
385
|
+
|
|
386
|
+
```json
|
|
387
|
+
{
|
|
388
|
+
"enforcement": { "enabled": false }
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
The `PreToolUse` hook is **absolutely fail-open**: any error at any stage
|
|
393
|
+
(missing index, corrupt JSON, exception in match logic) returns exit code 0
|
|
394
|
+
with empty stdout. The hook can never block Claude Code from running. You
|
|
395
|
+
can trust it not to brick your session even if mnemo itself is broken.
|
|
396
|
+
|
|
397
|
+
### Rule frontmatter shape
|
|
398
|
+
|
|
399
|
+
Both blocks are optional and live in a feedback page's YAML frontmatter:
|
|
400
|
+
|
|
401
|
+
```yaml
|
|
402
|
+
---
|
|
403
|
+
name: no-co-authored-by-in-commits
|
|
404
|
+
description: Never add Co-Authored-By trailers in git commits
|
|
405
|
+
type: feedback
|
|
406
|
+
stability: stable
|
|
407
|
+
sources:
|
|
408
|
+
- bots/mnemo/memory/feedback_no_coauthored.md
|
|
409
|
+
tags:
|
|
410
|
+
- git
|
|
411
|
+
- workflow
|
|
412
|
+
aliases:
|
|
413
|
+
- coauthor
|
|
414
|
+
- trailer
|
|
415
|
+
- commit-footer
|
|
416
|
+
enforce:
|
|
417
|
+
tool: Bash
|
|
418
|
+
deny_pattern: git commit.*Co-Authored-By
|
|
419
|
+
reason: No Co-Authored-By trailers in commits
|
|
420
|
+
activates_on:
|
|
421
|
+
tools: [Edit, Write, MultiEdit]
|
|
422
|
+
path_globs:
|
|
423
|
+
- '**/components/modals/**'
|
|
424
|
+
- '**/*modal*.tsx'
|
|
425
|
+
---
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
- `aliases` *(v0.8, optional)* — a list of 3-8 lowercase synonym tokens
|
|
429
|
+
used by the Reflex BM25F index (`aliases` field weight 2.5). Emit when
|
|
430
|
+
the rule carries domain terms a developer would naturally type in a
|
|
431
|
+
different language or abbreviation (PT↔EN, `db`↔`database`↔`banco`).
|
|
432
|
+
Omit for generic rules without natural synonyms; extraction auto-emits
|
|
433
|
+
aliases for high-signal rules.
|
|
434
|
+
|
|
435
|
+
- `enforce.tool` must be `"Bash"` in v0.5 (the only tool v1 supports
|
|
436
|
+
for hard-blocking).
|
|
437
|
+
- `enforce.deny_pattern` is a regex compiled with `re.IGNORECASE | re.DOTALL`
|
|
438
|
+
and pre-validated against ReDoS at index build time (a time-budget probe
|
|
439
|
+
rejects pathological patterns like `(a+)+b`).
|
|
440
|
+
- `enforce.deny_command` is an alternative to the regex: a list of command
|
|
441
|
+
prefixes; the hook normalizes the command (strips `sudo`, `env FOO=bar`,
|
|
442
|
+
shell inline env) before the match.
|
|
443
|
+
- `activates_on.tools` must be a subset of `{Edit, Write, MultiEdit}`.
|
|
444
|
+
- `activates_on.path_globs` supports `**` (match any number of path
|
|
445
|
+
segments), single `*` (no slash crossing), and bracket classes with
|
|
446
|
+
`[!...]` negation.
|
|
447
|
+
|
|
448
|
+
Rules tagged `needs-review` or with `stability: evolving`, and rules still
|
|
449
|
+
in `shared/_inbox/`, **never** become activation rules — they're gated
|
|
450
|
+
through the same `is_consumer_visible` predicate that the dashboard and
|
|
451
|
+
MCP retrieval use.
|
|
452
|
+
|
|
453
|
+
### Observability
|
|
454
|
+
|
|
455
|
+
- `mnemo status` — shows per-project rule counts, recent denials, recent
|
|
456
|
+
enrichments, and the last denied command.
|
|
457
|
+
- `mnemo doctor` — checks for malformed `enforce:`/`activates_on:` blocks,
|
|
458
|
+
stale activation index, suspicious `deny_pattern` regex, and overly
|
|
459
|
+
broad `path_globs` (`**/*`, `*`).
|
|
460
|
+
- `<vault>/.mnemo/denial-log.jsonl` — JSONL stream of every deny, with
|
|
461
|
+
slug, reason, tool, full command (truncated to 500 chars), timestamp.
|
|
462
|
+
- `<vault>/.mnemo/enrichment-log.jsonl` — JSONL stream of every enrichment,
|
|
463
|
+
with hit slugs, tool name, file path, timestamp.
|
|
464
|
+
- `<vault>/.mnemo/rule-activation-index.json` — the per-project index
|
|
465
|
+
written by `build_index` after every extraction and on session start. If
|
|
466
|
+
you suspect drift, delete it; the next session rebuilds it.
|
|
467
|
+
|
|
468
|
+
### Reflex observability *(v0.8)*
|
|
469
|
+
|
|
470
|
+
- `mnemo status` — shows whether `reflex.enabled` and today's emission count.
|
|
471
|
+
- `mnemo doctor` — three new checks:
|
|
472
|
+
- `reflex-index-stale` — flags when `reflex.enabled=true` but
|
|
473
|
+
`reflex-index.json` is missing (usually: never ran `mnemo extract`).
|
|
474
|
+
- `reflex-session-cap-hit` — scans the last 7 days of `reflex-log.jsonl`
|
|
475
|
+
and warns when >20% of sessions hit `session_cap_reached`. Tune
|
|
476
|
+
`reflex.maxEmissionsPerSession` up or raise `thresholds.absoluteFloor`.
|
|
477
|
+
- `reflex-bilingual-gap` — flags when 3+ rules have non-ASCII descriptions
|
|
478
|
+
but no `aliases:` field (probable recall loss on PT prompts).
|
|
479
|
+
- `<vault>/.mnemo/reflex-index.json` — the vault-wide BM25F index, rebuilt
|
|
480
|
+
on every `SessionStart`. Schema v1; `load_index` returns `None` on
|
|
481
|
+
version mismatch so the hook silences cleanly if you downgrade.
|
|
482
|
+
- `<vault>/.mnemo/reflex-log.jsonl` — per-prompt telemetry: session id,
|
|
483
|
+
project, SHA256-12 prompt hash, scores, emitted slugs, silence reason.
|
|
484
|
+
Never contains raw prompt text. Rotates at 1 MiB.
|
|
485
|
+
|
|
486
|
+
## Commands
|
|
487
|
+
|
|
488
|
+
```
|
|
489
|
+
npx @xyrlan/mnemo install one-command setup (recommended)
|
|
490
|
+
npx @xyrlan/mnemo uninstall remove mnemo (vault preserved)
|
|
491
|
+
mnemo init first-run setup if installed via pip directly
|
|
492
|
+
mnemo init --project scope the install to <cwd> only (v0.12+)
|
|
493
|
+
mnemo status [--scope ...] vault state + hook health + auto-brain state
|
|
494
|
+
(--scope project|global|all, default all)
|
|
495
|
+
mnemo doctor full diagnostic with actionable fixes
|
|
496
|
+
mnemo extract manually run the extraction pipeline (also rebuilds the dashboard)
|
|
497
|
+
mnemo open open vault in Obsidian / file manager
|
|
498
|
+
mnemo fix reset circuit breaker
|
|
499
|
+
mnemo uninstall [--project] remove hooks, MCP server, status line (vault preserved)
|
|
500
|
+
mnemo help list commands
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
## Where things live
|
|
504
|
+
|
|
505
|
+
```
|
|
506
|
+
~/mnemo/ your vault
|
|
507
|
+
├── HOME.md dashboard at the top, your notes below
|
|
508
|
+
├── bots/<repo-name>/
|
|
509
|
+
│ ├── logs/YYYY-MM-DD.md session start/end markers
|
|
510
|
+
│ ├── memory/ mirror of Claude memories for this repo
|
|
511
|
+
│ └── briefings/sessions/ per-session shift handoffs (opt-in)
|
|
512
|
+
├── shared/
|
|
513
|
+
│ ├── feedback/ auto-promoted preference rules
|
|
514
|
+
│ ├── user/ user-profile facts
|
|
515
|
+
│ ├── reference/ pointers to external systems
|
|
516
|
+
│ ├── project/ per-repo project context
|
|
517
|
+
│ └── _inbox/<type>/ drafts awaiting review
|
|
518
|
+
└── .mnemo/
|
|
519
|
+
├── extract.lock background extraction lock
|
|
520
|
+
├── last-auto-run.json background extraction telemetry
|
|
521
|
+
├── mcp-call-counter.json daily MCP tool call counter + reflex cache (v0.5/v0.8)
|
|
522
|
+
├── mcp-access-log.jsonl per-call MCP telemetry (v0.5.3, local only)
|
|
523
|
+
├── reflex-index.json vault-wide BM25F index for Prompt Reflex (v0.8)
|
|
524
|
+
├── reflex-log.jsonl per-prompt Reflex telemetry (v0.8, local only)
|
|
525
|
+
└── statusline-original.json preserved user statusLine (v0.5)
|
|
526
|
+
|
|
527
|
+
~/.claude/settings.json hooks + status line composer
|
|
528
|
+
~/.claude.json MCP server registration
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
See [docs/getting-started.md](docs/getting-started.md) for a deeper tour.
|
|
532
|
+
|
|
533
|
+
## Privacy
|
|
534
|
+
|
|
535
|
+
100% local. Zero network. No third-party Python packages
|
|
536
|
+
(`pyproject.toml` declares `dependencies = []` as a load-bearing
|
|
537
|
+
architectural choice). MCP access telemetry (`.mnemo/mcp-access-log.jsonl`)
|
|
538
|
+
stays on disk — nothing leaves your machine. Read the [source](src/mnemo).
|
|
539
|
+
|
|
540
|
+
## License
|
|
541
|
+
|
|
542
|
+
MIT — see [LICENSE](LICENSE).
|