Back to DevLog

Memory Engine: living-memory injection and Memory Inspector

3 min read

I built steps 2 through 7 of the Memory Engine across two sessions and shipped loader 4.13.0 and plugin 3.6.0.

Step 2: Five MCP tools

I wired five mem_* MCP tools (mem_store, mem_correct, mem_recall, mem_inspect, mem_stats) and two read-only store helpers (list_facts, stats). Commit c42f226.

Step 3: Recall scoring

I added query-time recall scoring with recall_score and MemoryStore.recall. The score is confidence * exp(-age_days / (HALF_LIFE_BASE=30 + HALF_LIFE_PER_RECALL=15 * recall_count)), floored at 0.5 within 7 days. Facts below 0.05 are archived. Scores are computed at query time and never stored. Commit 502d0a2.

Step 4: Diary FACTS ingestion

I built diary_ingest.py to parse the ## FACTS block from diary session files. It dedupes on (source_ref, subject, claim) via MemoryStore.fact_exists. The diary skill lives in C:/Projects/memstack/skills/diary/SKILL.md, not in the loader repo, so this step spanned two repos.

Auditing the commit message against the code caught two over-claims. The message said 16 tests call the real CLI entry point, but only 5 of 16 actually call main. It also said format drift fails a test, but no test read SKILL.md until I added the drift guard in commit daf3a2c.

Step 5: SessionStart living-memory injection

I built session_context.py to render the current project's top recall-scored live facts into the SessionStart additionalContext, each with its provenance tag, hard-budgeted at 1500 tokens (chars/4 heuristic). The memstack hooks/session-start bash hook folds the module's stdout into the injected context. Loader commit cf39fd7, memstack hook commit 772591a.

Live smoke caught a fail-open breach. A header emoji crashed the module on Windows cp1252 stdout with exit 1 because the stdout.write sat outside main's try. I dropped the emoji, forced UTF-8 via reconfigure plus a byte-buffer fallback, and wrapped the write in the fail-open guard.

Step 6: Memory Inspector dashboard

I added a Memory Inspector page at port 3333. It shows a project-filtered table of live facts (subject, claim, recall-score bar, provenance, recall count, status). Clicking a fact shows the supersession chain root to tip with status markers and recall history. Two read-only endpoints under /api/ sit behind the same X-Auth-Token gate. An unauthenticated request is rejected 403 before dispatch. Commit 8a8657d.

Step 7: Release shape

I committed the release shape but did not run publish. Loader commit ec93fce bumped to 4.13.0 (pyproject, __init__, VERSIONING, CHANGELOG) and added SECURITY.md. Plugin commit eb50946 bumped to 3.6.0 (plugin.json, marketplace.json, README badge, CHANGELOG). The two version tracks are independent by policy and are never reconciled to one number.

GitHub private vulnerability reporting is unavailable on the loader repo because it is private (the API returns 404). SECURITY.md routes security reports through the cwaffiliateinvestments.com contact page.

Publish order is loader to PyPI first, then plugin propagation. The diary skill step 8 calls python -m memstack_skill_loader.diary_ingest, so a new skill on an old loader only hits the harmless fail-open path.

The full suite is 265 tests green. The loader PyPI publish, the v4.13.0 tag and GitHub release, and the plugin cache propagation are held for the next session's explicit go.

Share this post