Skip to content

feat(history): audit timeline of memory changes - #3

Merged
qdequele merged 2 commits into
mainfrom
qdequele/infallible-einstein-f70acd
Jun 16, 2026
Merged

feat(history): audit timeline of memory changes#3
qdequele merged 2 commits into
mainfrom
qdequele/infallible-einstein-f70acd

Conversation

@qdequele

Copy link
Copy Markdown
Owner

What

Adds an audit timeline of memory changes to memd: a record of which memories were created, updated, deleted, or crawled — when, and by which source (cli, mcp, crawler).

Surfaced as a new memd history CLI command and a history MCP tool, both filterable by action / type / scope / since.

$ memd history --action delete --limit 5
2026-06-15T15:20:04Z  delete  [fact] smoke-test-history  —  cli · global · id 019ec…98e3

Why

Until now, once a memory was updated or forgotten its prior state was gone with no record the event ever happened. Users asked to see what changed over time. This gives an auditable, queryable feed of mutations.

How

  • Storage — a new memory_events Meilisearch index (no embedder; a plain log). One metadata-only document per event: action, memory_id, a title/type/scope snapshot, source, ts, plus detail for crawl summaries. Created idempotently at daemon startup alongside memories.
  • Recording — funneled through MemoryService, the single chokepoint every mutation already passes through:
    • save logs create only on a real write (the content-hash dedup early-return logs nothing).
    • update / forget gained a Source argument; forget snapshots the doc's metadata before deleting so the row stays readable afterward.
    • Writes are best-effort and off the critical path via a new insert_no_wait — a logging failure never blocks or fails a memory mutation (mirrors the existing bump_accessed pattern).
    • The crawler logs a single rolled-up summary per pass (only when something changed, so periodic reconciles don't flood the log); per-file watcher deletes are skipped in favor of that summary.
  • MeiliClient is now index-aware (for_index) so the log reuses the same upsert/search plumbing.
  • Scope is an audit timeline only — metadata, no content diffs and no undo/restore (explicitly out of scope). Design spec: docs/superpowers/specs/2026-06-15-memory-history-design.md.

Notes for reviewers

  • Migration: the memory_events index is created at daemon startup, so an existing daemon must restart on this build before the log goes live. History accrues from that point forward — past mutations are not backfilled (we can't reconstruct them).
  • The events index is included automatically in dumps and engine migrations (those are instance-wide).
  • memd status now shows an events: count.

Verification

  • cargo build, cargo test (36 pass, incl. 5 new history tests), cargo clippy (0 warnings), cargo fmt --check — all clean.
  • Live end-to-end against a running Meilisearch: addhistory showed the create; forgethistory --action delete showed the delete with the title preserved post-deletion; status reported the event count. Test artifacts cleaned up.

qdequele added 2 commits June 15, 2026 15:46
Add a memory_events Meilisearch index recording create/update/delete
events plus one rolled-up summary per crawl. Metadata only (no content
diffs). Recording is best-effort and off the critical path via a
no-wait insert, funneled through MemoryService so the CLI, MCP, and
crawler all log uniformly; crawler-sourced single-file mutations are
skipped in favor of the per-crawl summary.

Surface: 'memd history' CLI command and a 'history' MCP tool, both
filterable by action/type/scope/since. MeiliClient is now index-aware
(for_index) so the log reuses the same plumbing.
@qdequele
qdequele merged commit 722cad5 into main Jun 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant