-
v6.7.1
StableSome checks failedSecurity Scans / Bandit SAST (pull_request) Successful in 22sSecurity Scans / Dependency Audit (mcp_server) (pull_request) Successful in 1m5sSecurity Scans / Dependency Audit (rss_worker) (pull_request) Successful in 28sSecurity Scans / Test Coverage (pull_request) Failing after 1m32sSecurity Scans / Secret Scan (pull_request) Successful in 5sSecurity Scans / Dependency Audit (web_ui) (pull_request) Successful in 26sDocker Build & Push / Build mcp_server (push) Successful in 15m20sDocker Build & Push / Build web_ui (push) Successful in 5m58sDocker Build & Push / Build rss_worker (push) Successful in 6m48sreleased this
2026-09-15 07:59:27 +00:00 | 2 commits to v6.7.x since this releaseThe 6.6 and 6.7 lines in one release: projects that say what kind of work they hold, memories that say where they came from and whether they can be shared, an embedding backend that's three times faster with no PyTorch in sight, and a recall that stops padding its answers with noise. This release rolls up 6.6.0 through 6.7.1.
A third of the latency, a third of the image (6.7.0)
Embeddings now run on ONNX Runtime instead of sentence-transformers on PyTorch. Same model (all-MiniLM-L6-v2), same vectors: cosine 1.0000 on every sampled text and an identical top-10 on every benchmark query, so nothing you've stored needs re-embedding and no threshold moves.
Measured on arm64 with a 400-memory corpus and 44 queries:
6.6.2 (PyTorch) 6.7.0 (ONNX) Model load 7.8 s 0.8 s Peak memory 924 MB 301 MB embed()p5022.3 ms 7.9 ms remember()p5025 ms 11 ms recall()p5035 ms 23 ms MCP server image 2.04 GB 634 MB PyTorch isn't installed in any image any more. If you need the old path,
EMBEDDING_BACKEND=torchplusrequirements-torch.txtbrings it back. The default model is pinned to a known commit so an upstream re-export can't shift vectors under a live store,EMBEDDING_MODELaccepts a local directory for air-gapped hosts, and the benchmark behind these numbers ships asscripts/embedding_bench.pyso you can check any other model or quantised graph the same way.Recall stops padding (6.7.1)
recall()used to filltop_kwith whatever was left, so two good matches came back with three unrelated memories attached, all headed straight into an agent's context. There's now a relevance floor (RECALL_MIN_SCORE, 0.15), andtop_kis a ceiling: fewer results, or none, is a normal answer.The floor is deliberately low. On the real embedder, correct and incorrect matches overlap between roughly 0.19 and 0.24, and the 0.4 cut first proposed dropped two of eight correct answers. So rather than hide that band, results between the floor and
RECALL_WEAK_SCORE(0.35) come back flaggedweak_match: true, and the agent instructions say to read those but not build on them. The floor gates raw similarity, not the adjusted score, so extracted facts and abandoned experiences that are scored down on purpose still come back when they genuinely match.find_skills()gets its own floor (SKILL_MIN_SCORE, 0.25) and ahigh/lowconfidence on each result. Before,find_skills("python")on a store with no Python skill cheerfully returned a preferences skill, and a skill loads whole.Also fixed in 6.7.1:
- Phantom index entries (#28): an index row whose record had gone could reach recall as an empty result taking a
top_kslot. It's skipped now, and index drift is logged at startup and surfaced inbriefing()instead of only inhealth(), which is how 762 orphans built up unnoticed reindex()covers all five namespaces (#29):preferenceandskillwere missing from the docs, andmemory_audit()silently skipped preferences on an unscoped run- Full
held_backrule text (#32): the list you choose what tobless()from was cut at 80 characters, mid-word - The stale list stopped nagging about your best memories (#34): memories compiled into a skill stop getting touched because the skill carries them, so they were being flagged as stale. They're exempt now
compile_skill()explains an empty compile (#33): when every candidate in a domain comes from one project, it says so and points atbless()or a narrower domain rather than suggesting you lower the gate
Where a memory came from, and whether you can share it (6.6.1, 6.6.2)
Every memory now carries two new fields.
licencerecords redistribution rights:own,open,restrictedorunknown. It's decided at write time. The RSS worker stamps each article from its feed's newlicence:declaration in feeds.yml (ogl-3.0,cc-by-4.0and friends resolve to a class and keep the identifier as a note), andRSS_REQUIRE_LICENCE=truerefuses undeclared feeds outright. When recall returns something stillunknown, alicence_noticeasks you to classify it while it's in front of you, andset_licence(feed_name="...", licence="...")does a whole feed in one call.provenancerecords who's speaking:asserted(you said it),concluded(the system's own reasoning or write-up) orretrieved(an external source). Without it, an inference from last month gets recalled and read as independent evidence for the reasoning that produced it.set_provenance(..., "asserted")is how you vouch for a memory.Both are indexed, returned on every read surface, editable in the web UI, and inherited by extracted facts. Neither changes ranking: landing a field and changing what recall does with it are separate releases, so any future benchmark move can be attributed. Licence is about redistribution rights, not who can see a memory; that's a different axis and a later release.
Projects declare their kind of work (6.6.0)
A project context can now list work-type domains (
python,docker,wcag-accessibility), andrecall(query, domain_filter="python")searches every Python project at once. That reaches the lessons that never cleared a skill's reinforcement gate, which used to need an unfiltered search of everything. Domains use the same vocabulary as compiled skills, so the two can't drift apart.compile_project_domains()suggests them from your stack and recurring tags, with the evidence for each, and the projects page filters on them.Fixed: index migration never worked (6.6.0)
_migrate_indexes()has failed silently on every upgrade since it was written. valkey-py'sdropindex()sends a trailing empty argument that valkey-search rejects, and the error was swallowed by the handler for "index doesn't exist". Any field added to an index in a past release, the knowledge namespace'sprojecttag among them, was only searchable on fresh installs. It now issues the raw command, logs real failures, and the test fake raises the same error the server does so this can't pass the suite again.Upgrading
- The first start rebuilds indexes. Between the migration fix and the two new fields, most instances will drop and recreate their indexes on first boot. It's data-safe: only the index goes, and valkey-search re-indexes the existing records itself. Recall can be incomplete for a short while as that happens, and the startup drift check expects this and stays quiet
- Backfills run once. Episodic, project and preference memories become
licence=own; RSS articles and untraceable knowledge becomeunknown. Provenance lands asretrievedfor articles,assertedfor preferences and project context, andconcludedfor everything else, every episodic memory included. That last one is deliberately conservative, not a judgement on the work - First start downloads an 86 MB ONNX file into a new shared
hf_cachevolume. Air-gapped hosts need to fetch it online first or pointEMBEDDING_MODELat a local directory: a cache filled by the old torch backend doesn't contain it - Building from source? The RSS worker image now builds from the repo root (
-f rss_worker/Dockerfile), like the web UI. The bundled compose files already do this; a hand-rolled one needs the same change and thehf_cachevolume - Expect shorter recall results. That's the floor doing its job.
RECALL_MIN_SCORE=0andSKILL_MIN_SCORE=0restore the old behaviour if you need it
The suite is up to 1913 tests, with
memory/andtools/at 100% line coverage, and the index, backfill and tag-filter paths verified against a real valkey-search rather than only the fakes.Self-hosted, open source, runs on Docker Compose. Python 3.12, FastMCP, Valkey.
Full detail in CHANGELOG.md.
Downloads
-
Source code (ZIP)
2 downloads
-
Source code (TAR.GZ)
2 downloads
- Phantom index entries (#28): an index row whose record had gone could reach recall as an empty result taking a