Skip to content

Releases: agentic-box/memora

0.3.3

Choose a tag to compare

@spokV spokV released this 13 Aug 04:28

Memora 0.3.3

Search accuracy and hardening release.

Search

  • Full-text search now queries the FTS index correctly, improving keyword relevance; substring matching remains only as an explicit fallback.
  • limit is honored on memory_hybrid_search and memory_semantic_search (top_k still accepted).
  • Searches and lists with lineage filtering (follow=active/latest) fill the requested result count even when top-ranked candidates are superseded, scanning beyond the previous 5,000-row window with a loud error at the safety bound instead of silent truncation.

Absorb & lineage

  • Absorb updates supersede the current version of a memory, resolving through the supersession chain to the leaf.
  • New classifier measurement harness: labeled fixture pairs, per-class precision/recall and confusion matrix, dry-run safe, with a --min-macro-f1 gate for regression testing.
  • All LLM calls are bounded by an explicit timeout (MEMORA_LLM_TIMEOUT, default 60s). Measurement mode fails loud; runtime absorb degrades gracefully.

Tag policy

  • The Cloudflare graph app validates tag writes (memory edit and chat) against a versioned policy stored per database, failing closed when the policy is unavailable.
  • Wildcards support slash namespaces (memora/*) alongside dot namespaces; tags are capped at 100 characters, counted identically (Unicode code points) in Python and TypeScript and guarded by a shared conformance fixture.

Graph UI

  • The WebGL canvas tracks its container through drawer transitions via ResizeObserver, fixing a sizing race under load.

CI

  • New clean-install workflow: builds the wheel, installs into an empty environment, and runs the suite — on push, tags, and a daily schedule.
  • New graph-ui workflow: browser tests for the graph UI (drawers, top bar, render-idle power behavior, database selector), tag-policy write tests, and lineage logic tests against a seeded local D1.

Docs

  • Install instructions lead with PyPI (pip install memora-mcp); absorb, supersession lineage, and digest documented in Features; MEMORA_TAG_FILE format corrected (JSON array).

v0.3.2

Choose a tag to compare

@spokV spokV released this 10 Aug 19:50

memora 0.3.2

Consolidated 0.3.x release. Notes for the earlier 0.3.x tags remain in the repo as
RELEASE_NOTES_0.3.0.md and RELEASE_NOTES_0.3.1.md.

Fresh installs work again

mcp 2.0.0 removed mcp.server.fastmcp, and our dependency was an unbounded mcp>=1.0.0, so every
fresh install resolved to the new major and the server died at import with
ModuleNotFoundError. Now constrained to mcp>=1.0.0,<2 (the 1.x line is maintained in parallel).

The failure was invisible from both sides: a dead stdio MCP server looks identical to one exposing no
tools, and existing environments had mcp pinned to a working 1.x, so every test suite passed.

Reported and fixed by @BillyBunn in
#44.

Breaking

Embeddings. memora could be configured — following its own installer and README — into a state
where no embedding was ever computed and nothing said so. install.sh generated
openai/text-embedding-3-small while the README recommended OpenRouter as the base URL, and
OpenRouter serves no embeddings endpoint. Every call 404'd, one warning went to a log nobody reads,
and stores silently filled with TF-IDF keyword bags. In the store where this was found, 756 memories
had been keyword vectors for months.

  • Every store needs one embedding rebuild. The model fingerprint now records backend, model,
    endpoint host and representation, so the old bare "openai" stamp no longer matches.
  • Dense backends no longer fall back to TF-IDF. A provider failure raises instead of persisting a
    wrong vector. Set tfidf explicitly if you want it.
  • MEMORA_EMBEDDING_API_KEY / MEMORA_EMBEDDING_BASE_URL are an atomic pair — set both or
    neither. A partial pair is rejected rather than borrowing the missing half from OPENAI_*, which
    could previously send one provider's secret to another provider's host.

Issues are no longer inferred. memory_create_issue and memory_create_todo are now the only
ways a memory becomes typed; memory_absorb and plain creates stay untyped knowledge. A keyword
classifier had mislabelled 130 knowledge memories as open issues. Existing typed memories are
untouched.

Added

  • memory_verify_integrity — read-only doctor reporting representation counts, coverage and
    offending ids, with concrete remediation.
  • MEMORA_EMBEDDING_STRICT=1 (recommended) turns a broken endpoint into a named error instead of
    silent degradation.
  • Integrity derived from SQL and invalidated by a DB-owned change epoch, so an external writer cannot
    leave a stale "healthy" verdict behind.

Fixed

  • Batch embedding responses are validated for cardinality, index coverage and uniform dimensions, and
    reconstructed by index — a reordered response could previously attach a vector to the wrong
    memory.
  • Coverage uses indexed anti-joins in both directions; counting by subtraction let one orphan cancel
    one missing embedding.
  • absorb no longer leaves untracked partial rows.
  • Concurrent ensure_schema no longer raises on duplicate columns.
  • install.sh and the README no longer generate or document the broken configuration.

memora-graph

  • Supersession is visible. Superseded memories render dimmed amber with a SUPERSEDED badge and
    directed lineage arrows; a toggle collapses to current-state only. Only supersedes edges count as
    lineage — references/contradicts/implements were previously drawn as supersession. Half-written
    crossrefs are detected rather than shown as current, and the page reports
    LINEAGE UNAVAILABLE instead of a confident zero when it cannot tell.
  • The 3D view no longer burns the CPU. Its render loop repainted 60×/sec forever, whether or not
    anything changed — measured at ~227% CPU on an idle page. The loop now stops once the layout
    settles and wakes on interaction: ~227% → 0.4%. Kill switch:
    localStorage.setItem("memora-graph.noIdle","1").
  • Resizable timeline and detail drawers with independently persisted widths; per-tab panel widths in
    the default view.
  • The database selector lists every configured database in both views (it was hardcoded in one).
  • The top bar no longer hides behind open drawers.

Known issues

  • Epoch time-of-check window — a query can use data that changed mid-call; the next call detects
    it. Transient, self-healing.
  • memories_embedding_repairs is unbounded with no foreign key to memory lifetime; explicit id
    reuse can mark an unrelated row as recurring.
  • D1 ownership recovery after a lost response lacks bounded retry and a unique operation record.
  • External writers must populate the new columns. A writer emitting a thresholded/sparse encoding
    of a dense vector is reported as an encoding fault by id, and auto-rebuild is skipped deliberately.
  • The default index.html view lacks force-graph's database-switch protection — after a switch or
    live refresh an already-rendered list can briefly show another store's authority state. Memory ids
    overlap across databases, so this is worth knowing.

Upgrading

  1. Upgrade, then run memory_verify_integrity before anything else.
  2. If it reports a repairable mismatch, run an embedding rebuild.
  3. Set MEMORA_EMBEDDING_STRICT=1.
  4. Verify by looking at a stored vector, not at your config — it should have your model's
    dimension count with numeric keys covering 0..N-1. Configuration that looks correct is what hid
    the original problem.

v0.2.29

Choose a tag to compare

@spokV spokV released this 27 May 11:24

Changes since v0.2.28:

  • Add memory_digest MCP tool
  • Tighten memory_digest aggregation and filtering
  • Make memory_update metadata updates merge safely by default

v0.2.28

Choose a tag to compare

@spokV spokV released this 29 Apr 20:36

Notable changes since v0.2.27

Fixes

  • MCP schema sanitizer (memora/server.py) — strips Pydantic-generated nullable anyOf combinators from tool input schemas before serving tools/list. Anthropic's tool validator rejected these, which 400'd the entire MCP handshake and made Claude Code disconnect the server. Reviewed end-to-end by an inter-agent bus loop (claude-B audit + codex review). 19 of 41 memora tools were affected; all clean after sanitize.
  • Embedding fallback observability (#457) — stops silent fallback to TF-IDF when the OpenAI embedding endpoint fails; warns visibly instead of degrading silently. Also adds explicit warn-on-fallback log path.
  • API issue filter tightening/api/memories issue filter now requires strict metadata.type match instead of fuzzy heuristic.
  • Graph spin fixes (5 commits) — vis-network physics now disables after stabilization, force-disables 1.5s after drag, re-enables on dragStart for elasticity, explicitly starts simulation on drag events, and stops endless spinning after memory_update realtime reload.
  • Favorites filter (#544) — fetches the full memory set from the server instead of filtering only the loaded page.

Features

  • Issues tab in web UI — inline status / category editing for memories of type: issue.

Reverts

  • Reverted Block 4 of duplicate-review UI action-buttons wiring (held back pending follow-up work).

v0.2.27

Choose a tag to compare

@spokV spokV released this 08 Apr 23:07

What's New

Structured Document Storage

  • memory_store_document — Store markdown documents as a root memory + searchable typed fragments (claims, plan items, references, risks, section chunks)
  • memory_get_document — Retrieve documents by key with optional fragment type filtering
  • memory_delete_document — Cascade delete a document and all its fragments
  • Structure-aware parser (document.py) — splits by headings, tables, numbered lists, URL lists, and risk sections instead of blind token chunking
  • Fragment integrity guards — protects document fragments from accidental delete, merge, absorb, duplicate detection, and supersession detection
  • Graph UI — document fragments hidden from visualization (local + cloud); only the document root node is visible

Auto-categorization Improvements

  • Auto-assign metadata.section from detected project at write time
  • Normalize generic tags to project-prefixed tags automatically
  • Backfill tag detection now catches subsection changes
  • Derive subsections from bare tags when no prefixed tags exist
  • Broader project detection with tag-based fallback and more content patterns

Bug Fixes

  • Fix find_duplicate_candidates type error when crossref entries have mixed ID types
  • Fix crossref computation to exclude document fragments from similarity graph
  • Skip typed link entries (supersedes, extends, etc.) in duplicate candidate scanning

v0.2.26

Choose a tag to compare

@spokV spokV released this 07 Apr 15:59

What's New

memory_detect_supersessions — Retroactive supersession detection

New MCP tool that scans existing memories for pairs where one updates/replaces another, then creates supersedes edges between them. Complements memory_absorb which only catches supersessions at write time.

  • Neutral LLM classification with 6-way relation enum (a_supersedes_b, b_supersedes_a, duplicate, related, contradicts, neither)
  • Conservative defaults: dry_run=True, min_confidence=0.75
  • 30s rate limit cooldown
  • No schema changes required

Bug fixes

  • Fix three bugs in memory_absorb that broke LLM classification and fact grouping
  • Consolidate related new facts into single richer memories via LLM synthesis
  • Bump graph cluster thresholds back to 0.4

Other improvements

  • Lineage-aware retrieval: follow parameter for supersession chain walking
  • Context-efficient retrieval: compact defaults, fields projection, hybrid filter fix
  • Add --version flag to memora-server CLI
  • Add install script for server, skill, and MCP config guidance

v0.2.25 — D1 latency collapse

Choose a tag to compare

@spokV spokV released this 05 Apr 11:28

Headline

`memory_create` / `memory_update` drop from 10s+ to ~2s per call on the D1 backend — 5× faster.

Three independent fixes, all landing together:

  • Cached `ensure_schema()` per backend instance — previously ran 7–9 D1 round-trips on every MCP tool call (~4–8s wasted each). Now runs once per backend per process. [`memora/schema.py`]
  • Single paginated LEFT JOIN for crossref/vector scan — replaces the old `list_memories(...) + _get_embeddings_for_ids(...)` two-step that cost ~10 sequential D1 round-trips on stores with many memories. [`memora/storage.py`]
  • Per-instance D1 session token + backend-level keep-max bookmark mirror — the old class-level token could be stomped by cross-thread code (`cloud_sync`'s `threading.Timer`), corrupting read-your-writes. Now safe under concurrency. [`memora/backends.py`]

Also in this release

  • Durable Object request reduction — WebSocket keepalive ping removed, broadcasts skipped when no clients connected, disconnect on hidden tab. Direct Cloudflare cost savings.
  • Schema cache correctness — `CloudSQLiteBackend.sync_before_use()` can `shutil.move` a fresh DB file over `cache_path`; the cache now invalidates via inode-based signature so long-lived processes don't run against a post-replacement DB with stale schema assumptions.
  • Security (merged from main) — XSS attribute injection fix in graph UI (#36), stale draft cancellation (#37).
  • Docs — eventual-consistency model of the `related` graph documented in `memory_related` and `memory_rebuild_crossrefs` MCP tool docstrings.

Upgrade notes

  • No schema migration required.
  • No public API signature changes.
  • No configuration changes required.
  • New optional env var `MEMORA_VECTOR_SCAN_PAGE_SIZE` (default: 1000) — rarely needs tuning.
  • 39/39 tests passing.

Verified performance

Measured against live D1 (steady-state, medium-length memory):

Operation Before After
`storage.connect()` 1st ~1.9s
`storage.connect()` 2nd+ ~4–8s (schema probe) ~0ms (cache hit)
`add_memory` 10s+ ~1.8s
`update_memory` 10s+ ~1.1s

v0.2.24 — Security Hardening

Choose a tag to compare

@spokV spokV released this 16 Mar 20:16

Security Hardening Release

Comprehensive security audit and fixes across critical, high, and medium severity findings.

R2 Proxy Lockdown

  • images/ prefix restriction on both cloud and local proxies
  • Path traversal (..) blocking
  • Image extension allowlist + Content-Type validation from R2 metadata

MCP Tool Rate Limiting

  • Single-flight + cooldown on 7 expensive operations (rebuild, export, import, insights, duplicates, migrate)
  • Prevents resource exhaustion via repeated calls

Prompt Injection Mitigation

  • Memory content moved from system prompt to user/context message across all 4 LLM callsites
  • Defensive markers on all memory-to-LLM paths

Upload Hardening

  • Symlink chain rejection, Pillow content verification
  • MIME derived from image content (not filename), no path disclosure in responses
  • Extension allowlist aligned with storage backend

Additional Fixes

  • Origin validation (urlparse-based) on SSE and chat endpoints
  • Chat rate limiting: 30 req/min per IP
  • Secure dedup cache: ~/.cache/memora/, SHA-256 filenames, fcntl locking
  • SQL hardening: alias-aware ORDER BY whitelist, LIMIT/OFFSET clamping
  • Error sanitization: generic messages for infrastructure errors
  • Dependencies: Pillow >= 10.4.0, openai >= 1.6.0, zod 3.24.2
  • Lock files: requirements.lock, requirements-local.lock, requirements-dev.lock
  • Security Model documentation in README

Codebase Health (from v0.2.23)

  • Full XSS sweep in graph UI (escapeHtmlAttr, CSS.escape, data-* delegation)
  • PATCH metadata shallow merge with null-delete semantics
  • FTS/embedding reindex on tag/metadata changes
  • Module extraction: embeddings.py, schema.py split from storage.py
  • Duplicate detection aligned to 0.85 threshold across all paths
  • 39 tests passing

Full Changelog: v0.2.23...v0.2.24

v0.2.23

Choose a tag to compare

@spokV spokV released this 13 Mar 16:47

Changes

  • Chat embeddings: Compute embeddings on memory create/update via chat UI, ensuring new memories appear in semantic search immediately
  • Robust search: Run semantic + keyword search in parallel with isolated error handling; recent memories fallback preserved
  • UI improvements: Pencil edit icon, hide complex metadata section by default
  • Sync: sync-to-d1.py now syncs memories_embeddings table with transaction wrapping
  • Query rewriting: Add RAG query rewriting for better retrieval

v0.2.22

Choose a tag to compare

@spokV spokV released this 19 Feb 13:03

What's Changed

  • Fix focused node centering — nodes no longer appear shifted left when the detail panel opens
  • Memora favicon — tab icon now uses the memora logo
  • Wider detail panel — default width increased from 450px to 560px
  • Scrubbed private data — removed hardcoded Cloudflare DB IDs from example scripts