Skip to content

Commit 69312af

Browse files
authored
Merge pull request #1 from GRU-953/v1.2-hardening
v1.2.0 — fast mode, multi-agent hardening, cross-platform
2 parents 7475224 + 3dabfd5 commit 69312af

25 files changed

Lines changed: 431 additions & 79 deletions

.claude-plugin/marketplace.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
},
77
"metadata": {
88
"description": "Local, token-free file digestion → knowledge-graph memory for Claude.",
9-
"version": "1.1.0",
9+
"version": "1.2.0",
1010
"pluginRoot": "."
1111
},
1212
"plugins": [
1313
{
1414
"name": "memorised-them-all",
1515
"source": "./",
1616
"description": "Convert any attachment to Markdown locally, then digest it into a token-free knowledge graph + exportable memory + offline mind map. 100% local & open-source; auto-installing; Apple-silicon first.",
17-
"version": "1.1.0",
17+
"version": "1.2.0",
1818
"license": "MIT",
1919
"homepage": "https://github.com/GRU-953/memorised-them-all",
2020
"keywords": ["memory", "knowledge-graph", "mind-map", "markitdown", "ocr",

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "memorised-them-all",
3-
"version": "1.1.0",
3+
"version": "1.2.0",
44
"description": "Locally convert any attachment to Markdown and digest it into a token-free knowledge-graph memory for Claude — global synopsis, per-theme summaries, exportable Markdown notes, and an offline interactive mind map. 100% local, free & open-source, auto-installing, Apple-silicon first.",
55
"author": {
66
"name": "Aninda Sundar Howlader",

.github/workflows/ci.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ permissions:
1212

1313
jobs:
1414
test:
15-
runs-on: ubuntu-latest
15+
runs-on: ${{ matrix.os }}
1616
strategy:
1717
fail-fast: false
1818
matrix:
19+
os: [ubuntu-latest, macos-latest, windows-latest]
1920
python-version: ["3.10", "3.12"]
2021
env:
2122
# Fully offline: classical extraction + hashing embeddings. No models, no network.
@@ -33,7 +34,7 @@ jobs:
3334
- name: Install (package + test deps only — heavy converters are not needed offline)
3435
run: |
3536
python -m pip install --upgrade pip
36-
pip install numpy networkx rapidfuzz "mcp>=1.2" pytest
37+
pip install numpy networkx rapidfuzz "mcp>=1.2" psutil pytest
3738
pip install -e . --no-deps
3839
3940
- name: Run offline smoke + e2e tests

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,38 @@ All notable changes to **Memorised them All** are documented here. This project
44
adheres to [Semantic Versioning](https://semver.org/) and
55
[Keep a Changelog](https://keepachangelog.com/).
66

7+
## [1.2.0] — 2026-06-01
8+
9+
Fast mode + a multi-agent evaluation/hardening pass (accuracy, reliability,
10+
token-safety, reusability, cross-platform) and security review.
11+
12+
### Added
13+
- **Fast mode** (`MTA_FAST=on`, `mta digest --fast`, `fast=true` tool arg): skips
14+
the LLM (classical extraction + deterministic summaries, keeps the embedding
15+
model) for a fully **deterministic**, ~100× faster digest. The default path
16+
stays on the LLM for maximum accuracy.
17+
- **Cross-platform support beyond Apple silicon**: psutil-based physical-core and
18+
memory detection (correct pool sizing on Intel/Linux/Windows), platform-aware
19+
PATH healing, portable mind-map opener, `psutil` process-tree teardown for the
20+
idle-stop, CUDA Whisper on Linux/Windows GPUs, Linux package-manager install
21+
paths (apt/dnf/pacman), broadened platform metadata, and a CI matrix across
22+
Ubuntu/macOS/Windows × Python 3.10/3.12.
23+
- **Per-file size cap** (`MTA_MAX_FILE_MB`, default 200) — oversize files are
24+
skipped before being read into memory (bounds OOM/decompression-bomb risk).
25+
26+
### Fixed / Hardened (from agent reviews)
27+
- **Token-safety**: `recall(k=…)` is hard-clamped (≤50) so a caller can't pull the
28+
whole graph's text into context; LLM fact strings are length-capped.
29+
- **Accuracy**: facts attach to entities by **word boundary** (no "Cat" inside
30+
"Category"; CJK-aware), de-duplicated per chunk; stable community tiebreak.
31+
- **Reliability**: per-file isolation for the conversion process pool and
32+
per-chunk isolation for threaded extraction (one failure or a mid-run model
33+
death no longer aborts/redoes the whole digest); PDF OCR handle leak fixed;
34+
updater throttle stamped before work to avoid concurrent pip races.
35+
- **Reusability**: `graph.json` stores basenames (no absolute-path leakage —
36+
portable across machines); exports now include the vector store so recall works
37+
from a copied bundle; `load_graph` rejects an incompatible future schema.
38+
739
## [1.1.0] — 2026-06-01
840

941
### Added
@@ -81,6 +113,7 @@ The first public release.
81113
- **Distribution**: Claude Desktop `.mcpb`, Claude Code plugin/marketplace, PyPI
82114
package, and a Homebrew tap; CI and tagged releases with assets.
83115

116+
[1.2.0]: https://github.com/GRU-953/memorised-them-all/releases/tag/v1.2.0
84117
[1.1.0]: https://github.com/GRU-953/memorised-them-all/releases/tag/v1.1.0
85118
[1.0.1]: https://github.com/GRU-953/memorised-them-all/releases/tag/v1.0.1
86119
[1.0.0]: https://github.com/GRU-953/memorised-them-all/releases/tag/v1.0.0

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,18 @@ settings (Desktop).
189189
| `MTA_WORKERS` | `0` (auto) | parallel conversion workers |
190190
| `MTA_EXTRACT_WORKERS` | `0` (auto) | parallel extraction workers (memory-aware: 1–3 by RAM) |
191191
| `MTA_MAX_CHUNKS` | `1500` | safety cap on chunks per digest (truncation is reported) |
192+
| `MTA_MAX_FILE_MB` | `200` | skip files larger than this before reading (0 disables) |
192193
| `MTA_COMMUNITY_ALGO` | `auto` | `leiden` · `louvain` · `greedy` |
193194
| `MTA_AUTO_UPDATE` | `on` | auto-update MarkItDown & dependencies |
195+
| `MTA_FAST` | `off` | fast mode — skip the LLM (classical extraction, deterministic, keeps embeddings) |
194196
| `MTA_NO_OLLAMA` | unset | hard offline switch (classical + hashing) |
195197

198+
> **Accuracy vs speed.** The default path uses the local LLM for the highest
199+
> extraction accuracy. **Fast mode** (`MTA_FAST=on`, `mta digest --fast`, or the
200+
> `fast=true` tool arg) skips the LLM for a fully **deterministic**, ~100× faster
201+
> digest that still builds the graph and keeps semantic recall — ideal for large
202+
> or frequently-updated corpora.
203+
196204
## Apple silicon first
197205

198206
- Conversion fans out across **performance cores** (`hw.perflevel0.physicalcpu`),
@@ -227,6 +235,52 @@ and left alone. Only an instance *this tool* starts is stopped on idle.
227235
**Where are my files?** Under `MTA_HOME/projects/<project>/``graph.json`,
228236
`memory.md`, `memory/`, `mindmap.html`. `export_memory` copies them anywhere.
229237

238+
## Modes & performance
239+
240+
Two digest modes — the default favours **accuracy & consistency**, fast mode favours **speed & determinism**:
241+
242+
| | Default (accurate) | Fast (`--fast` / `MTA_FAST=on`) |
243+
| --- | --- | --- |
244+
| Extraction | local LLM (qwen2.5) | classical (deterministic) |
245+
| Theme summaries | local LLM | deterministic fact-join |
246+
| Embeddings / recall | local (nomic) | local (nomic) |
247+
| Reproducible | per-model | **byte-identical across runs** |
248+
| Relative speed | baseline | **~100× faster** |
249+
| Best for | highest fidelity | large or frequently-refreshed corpora |
250+
251+
Both are **token-free** and **fully local**. Digestion is incremental — pointing `digest` at another folder *extends* the same project; `reset=true` starts fresh. Degenerate/repetitive content is de-duplicated and a reported `MTA_MAX_CHUNKS` cap keeps even pathological inputs bounded.
252+
253+
## Platform support
254+
255+
Apple M-series is the primary, most-optimised target. Other platforms are supported with portable fallbacks:
256+
257+
| Platform | Status | Notes |
258+
| --- | --- | --- |
259+
| macOS (Apple silicon) | ✅ optimised | performance-core pool, MLX GPU Whisper, unified-memory-aware |
260+
| macOS (Intel) | ✅ supported | physical-core sizing via psutil, CPU Whisper |
261+
| Linux | ✅ supported | apt/dnf/pacman install paths, CUDA Whisper if a GPU is present |
262+
| Windows | 🧪 experimental | `pip install memorised-them-all` + run `mta serve`; psutil process management & PATH healing |
263+
264+
CI runs the offline test suite across **Ubuntu, macOS, and Windows** on Python 3.10 & 3.12.
265+
266+
## Generated files & reuse
267+
268+
Each project under `MTA_HOME/projects/<name>/` is self-contained and portable:
269+
270+
| File | What it is |
271+
| --- | --- |
272+
| `graph.json` | source of truth — nodes, edges, communities, layered summaries, stats (`version`-stamped; stores basenames, no absolute paths) |
273+
| `memory.md` | compact, layered digest for reading / pasting |
274+
| `memory/<doc>.md` | one note per source document |
275+
| `mindmap.html` | offline interactive graph (Cytoscape inlined) |
276+
| `vectors.npz` + `vectors.json` | local embeddings for recall |
277+
278+
A memory built once can be **copied to another machine** and reused read-only — recall and the mind map work with no rebuild. `export_memory` bundles all of the above (including the vector store) into a folder you choose.
279+
280+
## Quality & testing
281+
282+
This project is exercised hard: a multi-format corpus (Office, PDF, scanned PDF, OCR images, audio), **14 regression tests** (determinism, token-safety, fact attribution, accumulation, OCR, lifecycle, cross-platform), green CI on three OSes, and a multi-agent review pass covering accuracy, reliability, token-safety, reusability, cross-platform, and security. The token-free guarantee is enforced (recall slices are hard-capped) and the digest never returns document contents to the model.
283+
230284
## Acknowledgements
231285

232286
Built on the shoulders of excellent open-source work — see

install.sh

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,40 @@ fi
5555
# Install the package itself (provides the `mta` entry point).
5656
"$PYBIN" -m pip install --quiet -e "$DIR" >/dev/null 2>&1 || true
5757

58-
# --- 3. System applications via Homebrew -----------------------------------
58+
# --- 3. System applications (Homebrew on macOS/Linux; native pkg mgrs on Linux) ----
59+
# A non-interactive sudo helper: only elevates if it won't block on a password.
60+
SUDO=""
61+
if [ "$(id -u 2>/dev/null)" != "0" ] && command -v sudo >/dev/null 2>&1 && sudo -n true 2>/dev/null; then
62+
SUDO="sudo -n"
63+
fi
5964
if command -v brew >/dev/null 2>&1; then
6065
for app in ollama tesseract ffmpeg; do
6166
command -v "$app" >/dev/null 2>&1 || { log "brew install $app"; brew install "$app" || true; }
6267
done
6368
# Many OCR languages (incl. Bengali) + igraph C lib for python-igraph.
6469
brew list tesseract-lang >/dev/null 2>&1 || brew install tesseract-lang >/dev/null 2>&1 || true
70+
elif command -v apt-get >/dev/null 2>&1 && [ -n "$SUDO$( [ "$(id -u)" = 0 ] && echo root )" ]; then
71+
log "Installing system apps via apt…"
72+
$SUDO apt-get update -y >/dev/null 2>&1 || true
73+
$SUDO apt-get install -y tesseract-ocr tesseract-ocr-all ffmpeg >/dev/null 2>&1 || true
74+
if ! command -v ollama >/dev/null 2>&1; then
75+
# Download then execute (not curl|sh) so partial/garbled output can't run.
76+
_oll="$(mktemp)"; curl -fsSL https://ollama.com/install.sh -o "$_oll" \
77+
&& sh "$_oll" >/dev/null 2>&1; rm -f "$_oll" || true
78+
fi
79+
elif command -v dnf >/dev/null 2>&1 && [ -n "$SUDO$( [ "$(id -u)" = 0 ] && echo root )" ]; then
80+
log "Installing system apps via dnf…"
81+
$SUDO dnf install -y tesseract ffmpeg >/dev/null 2>&1 || true
82+
if ! command -v ollama >/dev/null 2>&1; then
83+
# Download then execute (not curl|sh) so partial/garbled output can't run.
84+
_oll="$(mktemp)"; curl -fsSL https://ollama.com/install.sh -o "$_oll" \
85+
&& sh "$_oll" >/dev/null 2>&1; rm -f "$_oll" || true
86+
fi
87+
elif command -v pacman >/dev/null 2>&1 && [ -n "$SUDO$( [ "$(id -u)" = 0 ] && echo root )" ]; then
88+
log "Installing system apps via pacman…"
89+
$SUDO pacman -S --noconfirm tesseract tesseract-data-eng ffmpeg ollama >/dev/null 2>&1 || true
6590
else
66-
log "Homebrew not found — install Ollama/Tesseract/ffmpeg manually for full features."
91+
log "No usable package manager (or sudo unavailable) — install Ollama/Tesseract/ffmpeg manually for full features."
6792
fi
6893

6994
# --- 4. Local models (background unless MTA_SKIP_MODELS=1) ------------------

manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"manifest_version": "0.3",
33
"name": "memorised-them-all",
44
"display_name": "Memorised them All (local, token-free)",
5-
"version": "1.1.0",
5+
"version": "1.2.0",
66
"description": "Convert any attachment to Markdown and digest it into a token-free knowledge-graph memory — locally.",
77
"long_description": "Memorised them All turns a folder of documents into durable, **token-free** memory for Claude, entirely on your machine. It converts every attachment (PDF, Word, Excel, PowerPoint, HTML, EPub, images, audio, and more) to Markdown locally using Microsoft's MarkItDown (kept up to date from upstream automatically), Tesseract OCR, on-device Whisper, and a local Ollama vision model. It then runs an original local pipeline — semantic chunking, local embeddings, local-LLM (with a classical fallback) extraction of entities/relations/facts, embedding+fuzzy entity resolution, and community detection — to build a layered knowledge graph: a global synopsis, per-theme summaries, per-document Markdown notes, an exportable memory bundle, and an offline interactive mind map. Every tool returns only compact metadata or a tiny relevant slice, never document contents, so digesting and recalling whole folders costs ~0 Claude context tokens. Everything is free and open-source and runs locally; the Ollama model server starts on demand and stops after 5 minutes idle. Tuned for Apple M-series silicon (performance-core parallelism, GPU Whisper via MLX, unified-memory-aware concurrency).\n\nTools: digest, recall, memory_overview, export_memory, list_digestible, memory_status, open_mindmap.",
88
"author": {
@@ -95,7 +95,7 @@
9595
}
9696
},
9797
"compatibility": {
98-
"platforms": ["darwin"],
98+
"platforms": ["darwin", "linux"],
9999
"runtimes": {"python": ">=3.10"}
100100
}
101101
}

mta/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
Clean-room implementation by GRU-953 (Aninda Sundar Howlader).
44
"""
55

6-
__version__ = "1.1.0"
6+
__version__ = "1.2.0"
77
__author__ = "Aninda Sundar Howlader"

mta/cli.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
import argparse
1616
import json
17-
import subprocess
18-
import sys
1917

2018
from .core import recall as recall_mod
2119
from .core import render, updater
@@ -36,6 +34,8 @@ def main(argv: list[str] | None = None) -> int:
3634
d = sub.add_parser("digest", help="convert + digest files/dirs/globs")
3735
d.add_argument("paths", nargs="+")
3836
d.add_argument("--reset", action="store_true")
37+
d.add_argument("--fast", action="store_true",
38+
help="skip the LLM (classical extraction); faster, fully deterministic")
3939

4040
r = sub.add_parser("recall", help="query the memory")
4141
r.add_argument("query")
@@ -62,7 +62,7 @@ def main(argv: list[str] | None = None) -> int:
6262
cfg = load_config().with_project(args.project)
6363

6464
if args.cmd == "digest":
65-
_print(run_digest(cfg, args.paths, reset=args.reset))
65+
_print(run_digest(cfg, args.paths, reset=args.reset, fast=args.fast))
6666
elif args.cmd == "recall":
6767
_print(recall_mod.recall(cfg, args.query, k=args.k or None))
6868
elif args.cmd == "overview":
@@ -77,8 +77,8 @@ def main(argv: list[str] | None = None) -> int:
7777
_print({"status": "no_memory", "project": cfg.project})
7878
else:
7979
if args.open:
80-
opener = "open" if sys.platform == "darwin" else "xdg-open"
81-
subprocess.run([opener, str(cfg.mindmap_html)], check=False)
80+
import webbrowser # portable across macOS/Linux/Windows
81+
webbrowser.open(cfg.mindmap_html.as_uri())
8282
_print({"status": "ok", "path": str(cfg.mindmap_html)})
8383
elif args.cmd == "update":
8484
_print(updater.run_check(cfg, force=args.force))

mta/core/config.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,18 @@ class Config:
5050

5151
# Extraction / digestion.
5252
extract_mode: str = field(default_factory=lambda: _env("MTA_EXTRACT", "auto")) # auto|llm|classical
53+
# Fast mode: skip the LLM entirely (classical extraction + deterministic
54+
# summaries), keeping the small embedding model for recall. Opt-in; the
55+
# default stays the accurate LLM path.
56+
fast: bool = field(default_factory=lambda: _env("MTA_FAST", "off").lower()
57+
in ("on", "1", "true", "yes"))
5358
community_algo: str = field(default_factory=lambda: _env("MTA_COMMUNITY_ALGO", "auto")) # auto|leiden|louvain|greedy
5459
chunk_chars: int = field(default_factory=lambda: _env_int("MTA_CHUNK_CHARS", 1200))
5560
recall_k: int = field(default_factory=lambda: _env_int("MTA_RECALL_K", 8))
5661
max_chunks: int = field(default_factory=lambda: _env_int("MTA_MAX_CHUNKS", 1500))
62+
# Skip individual files larger than this (MB) before reading them into memory,
63+
# bounding OOM/decompression-bomb risk. 0 disables the cap.
64+
max_file_mb: int = field(default_factory=lambda: _env_int("MTA_MAX_FILE_MB", 200))
5765
extract_workers: int = field(default_factory=lambda: _env_int("MTA_EXTRACT_WORKERS", 0)) # 0=auto
5866

5967
# Lifecycle & maintenance.
@@ -118,4 +126,6 @@ def ensure_dirs(self) -> None:
118126

119127
def load() -> Config:
120128
cfg = Config()
129+
if cfg.fast:
130+
cfg.extract_mode = "classical" # no LLM extraction or summaries
121131
return cfg

0 commit comments

Comments
 (0)