Changelog
All notable changes to PRME will be documented in this file.
The format is based on Keep a Changelog , and this project adheres to Semantic Versioning .
Unreleased
Added
- Add opt-in single-file memory packs (#247). Set
pack_path(PRME_PACK_PATH), callprme.client.config_from_pack(), or giveMemoryClienta path that ends in.prmeand is not an existing directory;config.single_file_packreports the mode, and the now publicprme.client.is_pack_file(path)tells which layout a path selects. The pack is one DuckDB file that holds the event log, the graph, the vector payloads and snapshot, and the pack manifest. Directory packs remain the default, and their layout and behavior are unchanged. See single-file packs and the RFC-0014 single-file pack amendment. - Describe each single-file pack in a
prme_manifestrow: the pack format version (PACK_FORMAT_VERSION = 1), the PRME version that last opened it, the embedding model name, version and dimension, the scoring version, and created and updated times. Opening warns when the configured embedding model differs from the recorded one, andprme rebuildrecords the model that rebuilt the vectors. - Keep a single-file pack’s USearch snapshot in a
vector_snapshotrow, reconciled on open againstvector_payloadsexactly as the snapshot file is, and hold its Tantivy index in memory, rebuilt from active graph nodes inidorder before the engine serves any read. After every open the lexical index holds the documents the write path gave the pack, whichprme rebuildalso produces (see Changed), so a pack built withingest(), or migrated from such a directory pack, keeps its lexical documents across a reopen. Tied BM25 scores can come back in a different order than from a directory index. Engines in one process that open the same pack,MemoryClientobjects on their own event loops included, share one in-memory lexical index, so a node stored through one is found by BM25 through the others without a reopen; the last engine to close releases it. Vector removals count towardvector_save_intervalas additions do, instead of rewriting the whole snapshot row after each removal; a removal not yet saved survives a crash because the next open drops snapshot keys whose metadata is gone. A directory pack still savesvectors.usearchafter every removal. Vector hits are identical, and directory-pack retrieval is unchanged apart fromprme rebuild. - Encrypt single-file packs with DuckDB’s native encryption. DuckDB encrypts
the file and its write-ahead log with AES-256-GCM; it leaves temporary files
in clear text by default even for an encrypted database, so PRME turns on
DuckDB’s
temp_file_encryptionand keeps those files in<pack>.tmpbeside the pack. Stored text therefore does not appear in clear on disk while the engine runs. A raw key (theraw_key:prefix, or an unprefixed 44-character url-safe base64 Fernet key) is used without derivation; any other value, or one with thepassphrase:prefix, is derived with PBKDF2-HMAC-SHA256 (600,000 iterations) and the fixed, versioned saltprme-single-file-pack-v1, because a per-pack salt cannot live inside the encrypted file. Identical passphrases therefore give identical keys across packs. A missing or wrong key, or encryption configured for a plain pack, raisesEncryptionErrorand leaves the file unchanged. An encrypted pack can be open in only one engine per process, and a second open, under any spelling of its path, raisesPackInUseError;MemoryEngine.lock()andunlock()raiseRuntimeErrorfor a single-file pack. Directory packs keep Fernet file encryption. - Add
prme compact <pack>, with--encryption-key KEYand--format table|json, which copies a closed pack file into a fresh one withCOPY FROM DATABASEand replaces the original atomically, to give back the space DuckDB never returns. It takes a.prmefile or a directory pack’smemory.duckdb, refuses while<pack>.walexists, and keeps the source’s storage version and cipher. On a copy of a LoCoMo benchmark pack it tookmemory.duckdbfrom 743.5 MiB to 510.5 MiB in 1.0 s with identical retrieval results; 492.7 MiB of the remaining live data is 404 stored retrieval receipts. - Add
prme migrate <directory> <pack.prme>, with--encryption-key KEYand--format table|json, which copies a directory pack into a new single-file pack through the open source engine, so a legacy Fernet-encrypted source stays encrypted at rest. It builds the pack in a hidden temporary file, opens it once, checks its vector snapshot and manifest rows, and only then moves it into place. It never overwrites a file and leaves the source in place. With a key, the new pack is encrypted natively. The LoCoMo benchmark pack migrated into a 521.5 MiB.prmefile in 1.4 s. - Accept single-file packs across the tools.
prme init <path.prme>creates exactly one file and writes no.env.example, printing a hint instead;prme doctor <path.prme> [--encryption-key KEY]checks the file, its required tables and its manifest and warns about a missing or stale vector snapshot; and every command that takes adb_pathopens a.prmefile. Without--encryption-key,prme doctor,prme compactandprme migrateusePRME_ENCRYPTION_KEYfor a.prmepack whenPRME_ENCRYPTION_ENABLEDis true, asprme infodoes, but never for a directory pack’smemory.duckdb; an empty--encryption-keymeans no key.prme-mcp --db-path x.prmeserves a single-file pack throughPRME_PACK_PATH, ignoring an inheritedPRME_DATABASE_URL, and a directory--db-pathsetsPRME_PACK_PATHempty so an inherited pack path cannot replace the directory.MemoryWorkspace(..., single_file_packs=True), also accepted byMemoryWorkspace.open(), keeps each namespace’s pack in onememory.prmefile; the registry does not record the layout, so pass the flag consistently.
Changed
- Require
duckdb>=1.4.0(previously>=1.2.0). DuckDB 1.4.0 is the first release with native database encryption, which single-file packs use. rebuild_indexes()(prme rebuild) gives lexical documents to the same nodes as the write path, through one definition shared with ingestion and the open of a single-file pack (has_lexical_documentandLEXICAL_DOCUMENT_SQLinprme.storage.lexical_index): every active node with content, except an entity node that extraction created, which keeps its vector but gets no lexical document. Previously a rebuild indexed every active node, soprme rebuildon a pack built withingest(), directory packs included, added a lexical document for each extracted entity that the pack never had before; it no longer does. An entity stored directly withstore()keeps its lexical document. (#247)
0.14.2 - 2026-10-08
Fixed
- Fresh extraction plans recognize negative-polarity updates without
replaces_object, retiring the same known-positive prior claim. Bounded, unambiguous whole-word targets can matchpumptoinsulin pump, and explicitswitched_toupdates can replace positiveuses/useFACT claims. Unrelated predicates, ambiguous objects, numeric shorthand and conditional/speculative updates remain protected; denials never assume unknown prior polarity. Retirement and validity closure use the existing atomic derivation transaction on both backends.
Added
- Per-message
first_person_owner=Trueon async/sync ingest, batch message dictionaries, HTTP and MCP binds singular first-person references to one owner identity per scope without a display name. It requires a user/human role and no named speaker. Leave it false for pasted first-person text. - Add the fast, research-only Jev memory-admission assay from PR #244: 40 authored contrast cases, a frozen protocol, cached decisions and reproducible replay. It writes no memory and enables no provider or production policy.
Upgrade notes
- Fresh extraction records and plans use
speech_act_v14; older records and saved plans retain their policies and checksums. No old claims, identities or raw notes are migrated. Upgrade all readers before writing v14 records. - Raw notes and shared evidence sentences can still contain retired assertions. NOTE exclusion is available from v0.14.1; structured claim state remains the authority for lifecycle. See correction limits. Validation uses scripted provider outputs; the reported Bedrock model was not rerun, and no benchmark answer-quality gain is claimed.
0.14.1 - 2026-10-08
Added
- Add explicit
retrieve()filtersexclude_node_typesandsource_typesacross the async engine, synchronous client, HTTP API and MCP. Consumers can exclude raw NOTE messages and bare ENTITY nodes and allow only USER_STATED provenance. Filters apply before ranking and result limiting and to packed context, session expansion, evidence projection/augmentation and cross-scope hints, in both retrieval modes. An empty source allowlist returns no results; invalid enum values fail before pending materialization work is drained. Active filters are recorded in retrieval receipts and filter metadata.
Fixed
- Accept unnamed first-person singular forms (
I,me,my,mine,myself) as source mentions of each other. This keeps claims from “My name is Sam” and preferences from “Call me Sam” without enabling named-speaker grounding or binding those references to a personal name. Admission still requires source evidence and object support; bare imperatives without a first-person reference remain unsupported. - Default new assistant/system direct stores and raw-source notes to INFERRED instead of node-based ASSERTED or OBSERVED. Explicit epistemic assignments take precedence. INFERRED remains eligible in DEFAULT mode; the source allowlist can exclude generated content entirely.
- Keep derived claims when evidence projection encounters a source excluded by the request’s node or source filters, instead of replacing them with an ineligible raw note.
Validation
- The information-accumulation simulation now checks that its complete assistant-authored microservices decision reaches packed reader context. The new INFERRED default moved it below the old top-five keyword check while retaining its source text; no ranking weights or admission rules were relaxed.
Upgrade notes
- Raw user notes still use their existing modality default, so questions and hypotheticals may remain ASSERTED notes. Excluding NOTE nodes is opt-in; retrieval defaults and historical rows are not automatically rewritten. Source filters do not prove that pasted first-person text describes its owner or repair older extracted claims. USER_STATED includes participant roles.
- Fresh extraction records and prepared plans use
speech_act_v13for unnamed first-person support. Saved v11/v12 extractions retain v12 plan behavior; earlier plans preserve their policy, IDs and checksums. Earlier releases cannot read the new v13 records and plans. Upgrade every consumer of a shared store before ingesting with v0.14.1. - These changes address the PRME-side reports from Kio’s KAK-1114 investigation. The integration reference includes the filter call and its limits. Extraction behavior was verified with scripted provider outputs; the reported live Bedrock model was not rerun.
0.14.0 - 2026-10-06
Upgrade notes
-
ingest()and reader context defaults. Four defaults changed after v0.13.0 (all under Changed). An install upgrading from v0.13.0 gets:- claims whose text is their own sentences instead of the whole message
(
enable_claim_sentence_text=True); - a named speaker’s I, me and my bound to that speaker’s entity, so a
speaker’s claims connect across messages
(
enable_speaker_references=True). Only the caller knows that the named speaker, and not someone the turn quotes, is who says I, so setPRME_ENABLE_SPEAKER_REFERENCES=falsewhen a speaker’s turns quote others in the first person; - each source text packed once in reader contexts
(
packing.fold_repeated_text=True); - an exactly repeated extracted claim merged into one current record that
supersedes the earlier copies (
enable_claim_merge=True, #209).
The
ingest()settings apply to messages ingested after the upgrade, and records stored earlier keep their text, but a repeated claim ingested afterwards also supersedes a matching copy stored before it. Folding acts when a context is packed, so reader contexts over existingingest()stores change too.store()is unchanged. To restore the v0.13.0 behavior, setPRME_ENABLE_CLAIM_SENTENCE_TEXT=false,PRME_ENABLE_SPEAKER_REFERENCES=false,PRME_ENABLE_CLAIM_MERGE=falseandPRME_PACKING__FOLD_REPEATED_TEXT=false.docs/PACKING.md(“Default retrieval settings”) has the details. - claims whose text is their own sentences instead of the whole message
(
-
Receipts. Default retrievals write receipt schema version 22, or 19 with
PRME_PACKING__FOLD_REPEATED_TEXT=false. Earlier releases cannot read version 22 receipts. Stored receipts keep their bytes and replay unchanged.
Added
- Opt-in repository coding memory through a local Docker MCP service, with source-backed lesson/handoff capture, bounded recall, shared Git-worktree configuration, and an isolated local-model experiment harness. The first four-task development pilot passed 2/8 runs with memory versus 0/8 without; both gains repeated one task and do not establish general coding improvement. Automatic use is shelved after the final registered study stopped as inconclusive after a grader defect (#208): ordinary coding tasks no longer recall or capture memory, and the commands stay available for explicit manual use. See coding memory .
- Add
packing.fold_repeated_text(PRME_PACKING__FOLD_REPEATED_TEXT, reader format only; #231), which packs each source text once and is a default since 2026-10-06 (see Changed).ingest()keeps a turn’s own record beside the claims extracted from it, so a context could show one sentence several times. With the setting on, a record whose text a packed record from the same source event already shows is left out unless its line shows another date, tag or speaker, and its budget goes to other records. Retrieval receipts record the setting in schema version 22, and other receipts keep their version and bytes. On the offline evidence gate overingest()packs of all of LoCoMo, it raised the share of questions with all annotated evidence packed by 4.7 points with the defaults of the time and by 2.8 with speaker references and claim sentences. - Add opt-in windowed extraction (
enable_windowed_extraction, withextraction_window_turns, default 4; #218, part of #91).ingest()shows the extractor the preceding turns of the same session, so it can read what the new turn refers to. Only the new turn is extracted: grounding still checks each claim against it alone, and the evidence quote stays a span of it. A turn without a session gets no window. Providers receive the newcontextargument only when a window exists, so a provider written for the earlier signature keeps working while the option is off. - Add opt-in self-contained fact text (
enable_fact_text_resolution; #219, part of #91).ingest()asks the extractor for each fact’s text with a pronoun for a named person replaced by the name and a relative date by the date it means. A deterministic check keeps that text only when those replacements are its sole changes to whole sentences of the new turn; otherwise the fact keeps its source passage, which stays its evidence either way. An accepted text records grounding methodresolved_text_v1and lists each replacement inmetadata.resolution. With the option off, the prompt, the response schema and saved extraction output are unchanged. On the offline evidence gate over all of LoCoMo, a window of 4 turns with resolution raised evidence recall by 1.6 points, and the share of questions with all evidence packed by 1.0 point, which is not clearly above zero (#225). - Add opt-in speaker grounding (
enable_speaker_grounding, #230). In a turn that names its speaker, the speaker’s own I, me, my, mine or myself counts as a mention of the speaker when grounding checks that a claim’s subject and object occur in its quoted sentences, so a claim such as “Dana, lives in, Denver” for “I live in Denver” is no longer discarded. Extractions checked this way record grounding policyspeech_act_v12. On all of LoCoMo it kept 10,599 claims instead of 7,136, but the extra claims restate turns that retrieval already reaches: with the current defaults it lowered the share of questions with all evidence packed by 0.8 points on the offline evidence gate, so it stays off. - Add a browser memory explorer (
web/, #211). From a source checkout,uv run --extra api python -m web.serverserves a read-only interface beside the HTTP API, with filters, source evidence, each extracted claim’s subject, predicate and object (#226), and a relationship map. Its server adds a paged one-hop endpoint,GET /v1/explorer/nodes/{id}/connections, that checks owner and scope before paging. It needs no frontend build, keeps the API’s authentication and loopback default, and opens the pack inPRME_CHAT_DATA_DIR, the folderexamples/chat.pyuses; a missing folder stops it with an error instead of creating an empty pack.uv run python -m web.demo ./my_memories_demobuilds a small connected demo pack through the realingest()pipeline with scripted extraction output, so it needs no model or network. benchmarks.diagnostics.extracted_packsbuilds LoCoMo and LongMemEval-S memory packs throughingest()with an Ollama extraction model (local by default; an Ollama cloud model with--cloud), and the offline evidence gate replays them withgate --packs(#102, part of #91). Until now the gate could replay only packs built withstore(), which never runs extraction, so it could not measure changes to extraction or the graph.- Add a DeepSeek answer track over packs built through
ingest()(#232).benchmarks.integrations.gpt54_baselines prepare --contexts ingest --packs LABELanswers anextracted_packsbuild instead of the savedstore()packs, which cannot show an option that only changesingest(). The track keeps its own contexts, answers, run logs, A/A checks and verdicts,comparerefuses to pair results from the two tracks, and the default-change rule applies to it unchanged. The 2026-10-06 default change passed on it, and its baseline for the new defaults,prme@3389586b, scores LoCoMo 1,190/1,540 (77.3%) and LongMemEval-S 440/500 (88.0%) (#234). Its scores are reported separately from thestore()track’s. - Add a fixed development slice,
benchmarks/slices/dev-v1.json(#224): three LoCoMo conversations (466 questions) and 42 LongMemEval-S questions, chosen by rules inbenchmarks.diagnostics.dev_sliceand tagged from committed answer runs as stable failures, stable passes or noisy.gate --sliceandextracted_packs build --slicework on the slice alone for quick iteration; the full benchmarks stay the gates before a merge or a default change. - Add a chat probe (
benchmarks/diagnostics/chat_probe.py, #226). A 54-turn scripted chat with an answer key goes throughingest()in about three minutes, and the report counts repeated claim text, unlinked entities and the key’s links, and checks whether the answers to 18 probe questions reach the reader’s context. - The offline evidence gate reports each LoCoMo speaker separately (#217, part
of #84), and
gate-comparecompares two replays of built packs (#225).
Changed
-
ingest()now stores a claim’s own sentences as its text (enable_claim_sentence_text=True) and binds a named speaker’s I, me and my to the speaker’s entity (enable_speaker_references=True). The reader context packs each source text once (packing.fold_repeated_text=Truein the product packing defaults). Together they passed the default-change rule twice on the DeepSeek answer track overingest()packs (#227, #229, #231, #233): LoCoMo +1.69 and +1.82 points, LongMemEval-S +3.4 and +4.2, every interval excluding zero. Folding outside the reader format is ignored instead of refused. Default retrieval receipts are version 22. SetPRME_ENABLE_CLAIM_SENTENCE_TEXT=false,PRME_ENABLE_SPEAKER_REFERENCES=falseorPRME_PACKING__FOLD_REPEATED_TEXT=falseto restore the earlier behavior. -
ingest()now merges a repeated extracted claim into one current record instead of adding another copy (#209). The new fact keeps the earlier copies’ evidence and supersedes them, so their history stays readable. Only exact claim identity counts; quantities, conditional claims, unresolved relative dates and claims that are not observed or asserted stay separate.store()is unchanged. SetPRME_ENABLE_CLAIM_MERGE=falseto restore one fact per extraction.
Fixed
- Auditable and compact contexts escape Unicode line separators so stored text cannot introduce apparent records or section headings (#108). Exact token accounting includes the escapes. New contexts containing these characters have different rendered bytes; persisted receipt checksums, source text and reader-format output remain unchanged. See packing compatibility.
- The extracted-pack builder’s cache returns a cached extraction as it was stored (#226). A hit validated the stored result against its source again, which widened evidence quotes and discarded claims the live run had kept: 261 claims on 75 replayed turns in the first LongMemEval-S baseline build. The LongMemEval-S slice baseline was rebuilt from the same cache (#228). Since #230 the cache also keeps the provider’s parsed output and checks it again on replay, so one set of model calls can be measured under several grounding rules.
- Benchmark tools find the datasets from any clone or Git worktree instead of
the original research machine’s absolute path (#214).
PRME_ORIGINAL_ROOTandPRME_MATRIX_ROOToverride the two roots, and the registered harness files are unchanged, so they still match their recorded digests. scripts/download_benchmarks.pyalso downloads the LongMemEval-S full history (longmemeval_s_cleaned.json, about 265 MB) that the harnesses and the evidence gate read, and verifies both pinned datasets by SHA-256 (#215).
0.13.0 - 2026-09-25
Upgrade notes
-
Retrieval defaults. The retrieval defaults changed twice on 2026-09-25 (both entries are under Changed). An install upgrading from v0.12.0 gets:
- rank fusion scoring (
scoring.fusion="rrf",rrf_k=60) with a current-state recency boost of 0.25 and an event-time tie-break, and a rank fusion session decay of 0.6 (#177).PRME_SCORING__FUSION=weightedrestores the weighted formula; it also drops the recency boost and tie-break, and weighted scoring never applies the 0.6 session decay; - the
readercontext format, one plain line per record without node IDs or source types (#177).PRME_PACKING__CONTEXT_FORMAT=auditablerestores JSON records, which callers that parse the context as JSON need. Answerability checks andverify_bundle()need that setting orPRME_PACKING__CONTEXT_CITATIONS=true; balancedmulti-path ordering, as in v0.12.0. #177 had made score order the default and #187 madebalancedthe default again.PRME_PACKING__MULTIPATH_ORDERING=scorekeeps #177’s score order.
To go back to the v0.12.0 retrieval defaults, set
PRME_SCORING__FUSION=weighted,PRME_PACKING__CONTEXT_FORMAT=auditableandPRME_PACKING__MULTIPATH_ORDERING=balanced(the last only makes the current default explicit), or in code passscoring=ScoringWeights()andpacking=PackingConfig()toPRMEConfig.docs/PACKING.md(“Default retrieval settings”) has the details. - rank fusion scoring (
-
HTTP API network binds.
python -m prme.apiandprme.api.server.run_server()refuse a non-loopback address withoutPRME_API_USER_KEYSorPRME_API_API_KEY(#120); configure credentials before upgrading a network-reachable server (see Changed).
Added
-
Add an opt-in cross-encoder rank order for the reranked candidates (
PRMEConfig.reranker_prior_weight, orPRME_RERANKER_PRIOR_WEIGHT; issue #88). The reranker always ordered its prefix by 0.7 model score plus 0.3 of the candidate’s own score. At 0.0 the model’s score alone orders it, and withreranker_policy="score_envelope"or"anchored_score_envelope"the prefix keeps its rank-fused scores in that order. The default, 0.3, changes nothing. A weight other than 0.3 needs an envelope policy (configuration with"legacy"is refused) and is recorded in the receipt’s execution parameters and the reranker’s feature identity; at 0.3 neither records it, so receipts keep their bytes, and no new receipt schema is needed. The offline evidence gate now refuses reranker settings withoutenable_reranker, times the reranker per question (p50 and p95) and records the model runtime of a reranker run. On the gate, rank order over the top 100 packed all evidence for more LoCoMo questions at 4K (+1.7 points, multi-hop +3.9) and, with the anchored policy, more LongMemEval-S questions (+1.3 points), but no variant was higher on LongMemEval-S at 8K, and the top 300 lost LongMemEval-S evidence at both budgets. The reranker stays off until an answer comparison supports it. -
Add opt-in session context packing (
PackingConfig.session_context_packing, orPRME_PACKING__SESSION_CONTEXT_PACKING; issue #86). Session expansion gave a turn it added a single path and never counted its path on a turn another search had found, so packing put those neighbors behind every multi-path candidate, and in an exact replay of the 2026-09-23 LoCoMo retrievals none of the turns only expansion found was packed.trigger_tiercounts the session path when it joins a candidate and gives a turn that expansion added the multi-path tier of the result that brought it in.adjacentpacks the same records and places each neighbor beside that result in session order. Unset (the default), nothing changes. Results and bundles carry each neighbor’ssession_context_linkonly when the setting is on. Receipts that record it use schema version 21 under either scoring formula; to stop using it, unset the variable rather than returning to an earlier release, which cannot read version 21 receipts. The offline evidence gate now reports, per benchmark and category, how many packed records session expansion reached, found alone or scored, andgate-compareshows them before and after. On the gate at 4K both values packed all evidence for more questions with no category lost: LoCoMo +0.9 points (95% interval +0.1 to +1.8) and LongMemEval-S +0.4 (+0.0 to +1.1). Packing a trigger’s neighbors right after it instead lost LongMemEval-S evidence and was not kept. The setting stays off until the epic #77 paired answer run supports it. -
Add an opt-in reader context format (
PackingConfig.context_format="reader", orPRME_PACKING__CONTEXT_FORMAT=reader) that renders each packed record as one line: its event time or caller-supplied validity range, tags for non-default epistemic and lifecycle states, and the complete text as a JSON string. The renderer adds no node IDs, source type,created_ator admission-timevalid_from, and it excludes records that fit only as a fallback without their own text. The full record stays inMemoryBundle.sectionsand the retrieval receipt.context_citations=Trueadds[m3]references and fillscontext_references, which MCP now returns withinclude_context. Reader receipts use schema version 14; versions 1 to 13 keep their canonical bytes. It is now the default (see Changed). -
Add opt-in reciprocal rank fusion for retrieval ranking (
ScoringWeights.fusion="rrf", orPRME_SCORING__FUSION=rrf, withrrf_k, default 60). Each candidate is ranked within the pool on the semantic and lexical channels and scored by1/(k + rank)per channel, scaled so first place on both is 1.0. Epistemic, node-type and temporal adjustments then apply relative to the pool’s largest value. Graph proximity, recency, salience and confidence, which were constant or uninformative in the 2026-09-23 benchmark archive, are not used (recency is available through an opt-in, below). Score provenance records formula version 2 with the saved ranks and factors, and these receipts use schema version 16 (version 15 receipts from earlier development builds, which lacksemantic_relevance, stay readable). Because a fused score says where a result ranks rather than how relevant it is,min_scoreunder rank fusion compares against each result’ssemantic_relevanceinstead: the semantic cosine similarity of the memory behind it (for session, episode and evidence context, the memory that pulled it in), recorded on every result, cross-scope hint, selection exclusion and receipt candidate, and in the LangChain and LlamaIndex result metadata. A floor tuned on weighted scores does not carry over, cosine ranges depend on the embedding model, and a low-cosine exact keyword match is filtered out when a floor is set. Non-neutral request ranking multipliers are rejected before retrieval (HTTP 422); weighted ranking profiles are inapplicable with reasonrank_fusion_scoring; learning evaluation skips rank-fused receipts (rank_fusion_receipt_records); and thefeedback_applyjob reportsnot_applicableand keeps its signals.PRMEConfignow uses it by default (see Changed);ScoringWeights()remains the weighted sum, whose serialized settings, version ID and receipts are unchanged. As with earlier receipt versions, a release without version 16 support cannot read rank-fusion receipts. -
Add an opt-in session decay for rank fusion (
PackingConfig.session_context_rank_fusion_score_decay, orPRME_PACKING__SESSION_CONTEXT_RANK_FUSION_SCORE_DECAY). Rank-fused scores are compressed, so at the default session decay of 0.85 a first-place result’s adjacent turns outrank every result from about twelfth place down, and they crowded LongMemEval-S multi-session evidence out of the context. When set, it replacessession_context_score_decayfor results scored by rank fusion; the offline evidence gate favored 0.6, which is now the default (see Changed). None restores the previous behavior. Receipts that record it use schema version 17. -
Add a fail-open for a rank fusion
min_scorefloor, which used to empty every retrieval while vector search was failing or had detected an embedding model mismatch. No result has a semantic cosine then, so the floor is skipped for that request: results keep their fused order, andRetrievalMetadata.min_score_skipped(in the HTTP and MCPmetrics) is set next to thebackend_failuresentry for the vector path. Cross-scope hints skip it too unless one of them has a cosine. The floor still applies whenever a result has a cosine, and weighted scoring is unchanged. Receipts of these retrievals use schema version 18, which recordsmin_score_skipped. The LangChain and LlamaIndex retrievers accept an optionalmin_scoreand addmin_score_skipped: Trueto each result’s metadata when the floor was skipped. -
Add two opt-in rank fusion settings for conflicting memories (
ScoringWeights.rrf_recency_boostandScoringWeights.rrf_tie_break, orPRME_SCORING__RRF_RECENCY_BOOSTandPRME_SCORING__RRF_TIE_BREAK). Rank fusion ignores recency, so on a current-state question the older of two conflicting memories could rank above the newer one. With the recency boost set, those questions multiply each fused score by1 + boost x recency, relative to the pool’s largest value, where recency is the weighted formula’s current-state recency (with lambda at least 0.05). Withrrf_tie_break="event_time", equal fused scores are ordered newest first instead of by path count and node ID. Both apply only under rank fusion.PRMEConfignow sets a boost of 0.25 and the tie-break by default (see Changed);ScoringWeights()leaves both unset, and then nothing changes. A boost of 0.25 with the tie-break passed every simulation with the reader format, score order and a 0.6 rank fusion session decay, and changed no benchmark’s share of questions with all evidence packed significantly on the offline evidence gate. Receipts that record either use schema version 19. -
Add conversation participants (#84).
store(),store_with_receipt(),ingest(),ingest_batch(),ingest_fast()andFastIngestItemaccept an optionalspeakername, as do HTTPPOST /v1/store,/v1/ingestand/v1/ingest/fastand the MCPmemory_store,memory_ingestandmemory_ingest_fast_manytools. The newparticipantrole marks a human in the conversation other than the memory’s owner: likeuser, its sources areUSER_STATED(with the default confidence matrix, 0.80 for an asserted claim instead of the 0.60 anassistantsource gets), but its statements do not reinforce the owner’s instructions. The speaker is kept in the reservedmetadata.prme_speaker_v1key of the source event and its direct node or raw note, not yet on extracted claims; passing that key inmetadatais now rejected. The reader context format prints it as"Caroline": "text"unless the text already begins with it, and the auditable format adds aspeakerkey. Withenable_qa_pairing=True, a change of speaker within one role also creates a merged Q-A node, whose halves start with their speakers’ names. Contexts for records without a speaker keep their exact bytes. The legacy LoCoMo harness (benchmarks/locomo.py) now stores both people as participants, so its scores are not comparable with its earlier runs; the registered 2026-09-23 comparison and its saved packs are unchanged. -
Add an opt-in event-time clock for the weighted formula’s recency (
ScoringWeights.recency_time="event_time", orPRME_SCORING__RECENCY_TIME=event_timewithPRME_SCORING__FUSION=weighted). Unset, the weighted formula measures recency on questions that are not about the current state from when a memory was last updated or created, so history imported with a past event time and retrieved at a past reference time scored full recency on every memory (issue #83). With the setting, every memory is dated by when it was stated: its event time, else when it was stored, never when it was last updated and never its validity start. Questions that are not about the current state measure that back from the request’s reference time; current-state questions keep measuring back from the newest candidate. Memories without an event time, such as entity, consolidation and profile nodes, count from when they were stored. Rank fusion, the default, already uses this clock for its recency boost and tie-break, so it drops the setting with a warning, and nothing changes by default. Receipts that record it use schema version 20; to stop using it, unset the variable rather than returning to an earlier release, which cannot read version 20 receipts. On the offline evidence gate it lost LoCoMo evidence (-4.8 points of questions with all evidence packed with the previous auditable format and balanced order, -4.5 with the reader format, both intervals excluding zero) and left LongMemEval-S unchanged, so it stays off. -
Add an opt-in temporal-first query intent (
PRMEConfig.query_intent_order="temporal_first", orPRME_QUERY_INTENT_ORDER=temporal_first). By default a question that names a person, place or organization, such as “When did Caroline go to the support group?”, is classified as an entity lookup before its temporal wording is checked, so it never gets temporal affinity scoring (issue #85). With the setting, temporal wording or a date in the question makes it temporal first, so it gets temporal affinity. A present-tense question that only its wording put on the current-state path leaves it unless it says current, now, latest or similar, and the temporal context guidance is added where the question’s wording does not already select it. A lone capitalized month or weekday word that is part of a name (“Who is June dating?”) is read as the name, not a date. Entity names are extracted either way. Receipts record the setting only when it istemporal_first, so default receipts keep their bytes. The offline evidence gate now records, for each replayed question, whether its candidates share one temporal affinity and whether the current-state path applied; its comparison counts the first per category and lists the questions that enter or leave the path. On the gate the setting packed all annotated evidence for 5 more LoCoMo questions and 1 more LongMemEval-S question and for none fewer (+0.3 and +0.2 points); it stays off until the paired answer run. -
Publish the complete 2026-09-23 GPT-5.4 benchmark comparison, with
gpt-5.4-2026-03-05as reader and judge, the retrieval defaults of that date and a 3,996-token context: LongMemEval-S 430/500 (86.0%) and LoCoMo 985/1,540 (64.0%, categories 1 to 4, strict judge), with its registered protocol and evidence-retention diagnostics underbenchmarks/results/research/2026-09-23/. These remain the published reference.benchmarks.integrations.gpt54_baselinesadds full-context and plain-RAG (plain-vector,plain-bm25,plain-rrf) baseline arms that reuse its reader, judge, prompts and questions (issue #95). No arm has been answered with GPT-5.4 yet. -
Add an offline evidence gate for retrieval, packing and representation changes (issue #78).
python -m benchmarks.diagnostics.product_packing gatereplays the publicretrieve()for all 1,540 LoCoMo and 500 LongMemEval-S questions over copies of the saved 2026-09-23 memory packs and measures the context the product renderer produced: records per context, the memory-text share, packed records without text, the questions with all annotated evidence packed, evidence ranks, and a projected accuracy that is a planning estimate, not an answer score.gate-comparepairs two runs question by question with a bootstrap interval, and--plain vector,bm25orrrfmeasures a plain RAG reference (#95). It makes no reader, judge or paid API calls. Later changes added session expansion counts (#86), temporal and current-state observations (#85), and candidate recall per channel and retrieval latency (#87). A gate comparison of balanced and score order under the reader format is recorded inbenchmarks/results/research/2026-09-24/READER-PACKING-ORDER-GATE-V1.md(#81). SeeBENCHMARKS.md. -
Add a DeepSeek answer track for benchmark answer runs with no API cost (issue #117).
benchmarks.integrations.gpt54_baselines --provider ollamaanswers withdeepseek-v4.1-flash:cloudas reader and judge through a local Ollama server, with the registered prompts, questions and official LongMemEval-S judge. It prepares the defaults as theprmearm and a change as a named variant (--variantwith--set).run-pairanswers a variant and a fresh run of the defaults interleaved question by question (#129),comparereports the paired difference with a 95% interval, andverdictdecides a variant from the pairscomparerecorded (#144). The track measured its run-to-run floor (#118), records an interleaved A/A check (#129, #137), scores a looping answer or a garbled verdict as incorrect after one retry (#132), records a new defaults baseline after a default changes (#123), and ties each pair to the current baseline, the 4K budget, and the variant’s settings and context text (#125, #127, #130, #139, #143). Its scores are reported separately and are never compared directly with the GPT-5.4 results. On this track the defaults of the GPT-5.4 run scored LongMemEval-S 423/500 (84.6%) and LoCoMo 1,014/1,540 (65.8%) (#126). A new baseline was recorded after each default change (#182, #191); the current one,prme@d811e3ed, scores LongMemEval-S 453/500 (90.6%) and LoCoMo 1,250/1,540 (81.2%). SeeBENCHMARKS.md. -
Add a lenient LoCoMo judge score beside the strict one (issue #96).
benchmarks.integrations.lenient_judgesends the saved answers of a complete LoCoMo run to Mem0’s published LoCoMo judge prompt, with the judge model and settings that gave the strict verdicts; no reader is called. On the DeepSeek baselineprme@46647825it accepts 1,095/1,540 (71.1%) against the strict judge’s 1,007/1,540 (65.4%). The strict judge stays the primary score, and the lenient pass over the GPT-5.4 answers has not been run.
Fixed
- Accepted temporal relation guidance (
TemporalRelationConfig.enabled, opt-in) now keeps the bundle’s earlier packing exclusions after its repack and adds the records it displaced, without duplicate IDs. Aggregation coverage therefore still reports context limits when records were excluded before enrichment; the temporal metadata’sdropped_record_idsstill lists only the records that stage displaced. - The configuration reference now gives the candidate limit defaults that
retrieval uses:
PRME_PACKING__VECTOR_KandPRME_PACKING__LEXICAL_K500,PRME_PACKING__AGGREGATION_K_MULTIPLIER3.0 andPRME_PACKING__AGGREGATION_K_MAX2000. It listed 250, 250, 2.5 and 500. The offline evidence gate now reports each channel’s candidate recall at k and the retrieval latency (issue #87); smaller limits lost LongMemEval-S evidence there, so the defaults are unchanged. - The LlamaIndex chat store reads a session turn whose role LlamaIndex has no
value for, such as
participantorhuman, as a user turn instead of failing to read or clear the session. - The HTTP API docs and the example Dockerfile now start the server with
python -m prme.api. Theuvicorn prme.api:appcommand they showed never loaded the app, becauseprme.api:appnames theprme.api.appmodule. - Query reformulation (
enable_query_reformulation=True) now uses the extraction endpoint, credential and timeout as well as its provider and model. It used to build its own client from the provider and model alone, so its requests went to the provider’s default endpoint (for OpenAI,api.openai.comwithOPENAI_API_KEYfrom the process environment) even when extraction was pointed at another endpoint or credential. It also ignored provider settings in.env, used Instructor’s tool mode with Ollama models that list tool support, and had no time limit of its own. It now reaches the extractionbase_urlwith the extractionapi_key(or the provider’s own settings from the environment or.env, as extraction does), and returns no alternate queries when a call takes longer than the extractiontimeout(30 seconds by default). With Ollama it uses JSON mode and a reasoning effort of"none", as extraction does, and it passes the model on each call, which Bedrock requires. Its other sampling is unchanged: the provider’s default temperature and two schema-validation retries. Each engine keeps its own reformulation clients, so they are not reused on another event loop. - Extraction, answerability and reformulation now build their Instructor
clients in one place,
prme.model_runtime. An Anthropic endpoint (base_urlorANTHROPIC_BASE_URL) now works: Instructor 1.14 built Anthropic clients without it and passed it to every call, which failed. ExtractionConfig.timeoutmust now be a positive, finite number. Zero or a negative value made every extraction time out.- Context ablation now keeps a compact or reader bundle’s format and references instead of re-rendering the counterfactual as auditable JSON.
- A text-bearing
PackingConfig.min_fidelity(full,proseorstructured, set in code, withPRME_PACKING__MIN_FIDELITYor per request) now keeps every packed record’s memory text in the auditable and compact formats too. A record whose stored text is blank is excluded and listed inMemoryBundle.excluded_idsinstead of being packed with empty text, and it no longer takes the reserved first place under balanced ordering. Set such a floor to keep the text-freekey_valueandreferencefallbacks out of the context. The default floor staysreference, so default contexts are unchanged. - Aggregation coverage no longer reports a blank record’s exclusion as a
token_budgetlimit when the reader format or a text-bearing floor excludes it. - A per-request
min_fidelitypassed toMemoryEngine.retrieve()as a plain string is now converted toRepresentationLevel, so receipts serialize it without warnings and an unknown value fails before retrieval runs.
Changed
- Retrieval defaults.
PRMEConfig()now retrieves with rank fusion (scoring.fusion="rrf",rrf_k=60) with a current-state recency boost of 0.25 (scoring.rrf_recency_boost) and an event-time tie-break (scoring.rrf_tie_break="event_time"), the reader context format (packing.context_format="reader", previouslyauditable), score ordering (packing.multipath_ordering="score", previouslybalanced;balancedis the default again, see the next entry) and a rank fusion session decay of 0.6 (packing.session_context_rank_fusion_score_decay, previously unset). The context budget and session expansion are unchanged. The combination (the DeepSeek-track variantprme-reader-rrf-sd06-rec) passed the epic #77 default-change test twice on the DeepSeek answer track at a 3,996-token context: LoCoMo went from 65.7% to 80.9% and from 65.8% to 81.6% (+15.2 and +15.7 points, 95% intervals +13.0 to +17.4 and +13.5 to +17.9), and LongMemEval-S went from 85.8% to 86.8% and from 86.4% to 86.6% (+1.0 and +0.2 points, intervals -1.6 to +3.6 and -2.6 to +3.0). SeeBENCHMARKS.md. What this changes for existing installs:- Contexts are one plain line per record instead of JSON objects, so more
records fit in the same budget. The lines carry no node ID or source type.
Callers that parse the context text as JSON must set
PRME_PACKING__CONTEXT_FORMAT=auditable. - Answerability checks and
verify_bundle()raiseValueErrorfor a reader bundle without citations. SetPRME_PACKING__CONTEXT_CITATIONS=trueor use theauditableformat for those callers. - Rank fusion ignores the additive scoring weights, graph proximity,
salience and confidence, and uses recency only through the current-state
recency boost, so salience decay, reinforcement and confidence changes no
longer move a result’s rank. Candidates found only through the graph or a
pin score 0 (pins are still packed first), and
min_scoreis compared with the semantic cosine instead of the composite score. Non-neutral requestranking_multipliersare rejected (HTTP 422, MCP error), learned ranking profiles are not applied (rank_fusion_scoring), andfeedback_applyreportsnot_applicable. SetPRME_SCORING__FUSION=weightedto keep the weighted formula, including any tunedPRME_SCORING__W_*weights. - The new defaults live in
PRMEConfig(default_scoring_weights()anddefault_packing_config()), andPRME_SCORING__*andPRME_PACKING__*environment variables,.enventries and secrets that set only some values keep them. SettingPRME_SCORING__FUSION=weightedalso drops the rank fusion recency boost and tie-break, which weighted scoring cannot use.ScoringWeights()andPackingConfig()built in code keep their field defaults (the weighted formula;auditable,balancedand no rank fusion session decay), because stored receipts and configurations omit some of those values and must keep their meaning; code that builds them from scratch gets the previous behavior. Copyconfig.packingorconfig.scoringwithmodel_copy(update=...)to change one setting and keep the new defaults. - Default retrievals write receipt schema version 19. Stored receipts keep their bytes and replay unchanged.
- To restore the previous defaults, set
PRME_SCORING__FUSION=weighted,PRME_PACKING__CONTEXT_FORMAT=auditableandPRME_PACKING__MULTIPATH_ORDERING=balanced. The recency boost and tie-break are then dropped, and weighted scoring never applies the 0.6 session decay (its receipts omit it), so retrieval, contexts and receipts are those of the previous defaults. In code, passscoring=ScoringWeights()andpacking=PackingConfig()toPRMEConfig.
- Contexts are one plain line per record instead of JSON objects, so more
records fit in the same budget. The lines carry no node ID or source type.
Callers that parse the context text as JSON must set
- Multi-path ordering default.
PRMEConfig()now orders the ordinary multi-path tier withbalanced(packing.multipath_ordering="balanced") instead of score order. The other retrieval defaults above are unchanged.balancedwas also the ordering in v0.12.0, so an install upgrading from that release sees only the scoring, context format and session decay change above. Balanced reserves the highest-scored ordinary multi-path candidate and then orders the rest by score / full-entry tokens**0.25, so a context holds more short records than under score order. With the other defaults (the DeepSeek-track variantprme-rrf-rec-balanced), it passed the epic #77 default-change test twice on the DeepSeek answer track at a 3,996-token context, each pair against a fresh run of the score-order defaults: LongMemEval-S went from 86.8% to 90.0% in both pairs (+3.2 points, 95% intervals +0.6 to +6.0 and +0.6 to +5.8), and LoCoMo went from 80.1% to 80.6% and from 80.6% to 80.4% (+0.5 and -0.2 points, intervals -0.9 to +2.0 and -1.5 to +1.1). LongMemEval-S multi-session questions gained 7.5 and 11.3 points; LongMemEval-S knowledge-update questions (73 to 70 of 78 in both pairs, #169) and LoCoMo multi-hop questions (-1.8 and -4.3 points) fell, with intervals including zero. SeeBENCHMARKS.md. Candidate retrieval and scoring, the context budget and the receipt schema version (19) are unchanged; receipts record the ordering as before.- Upgrade note: to keep score order, set
PRME_PACKING__MULTIPATH_ORDERING=score. In code, copy the packing configuration withmultipath_ordering="score":config.packing.model_copy(update={"multipath_ordering": "score"}).
- Upgrade note: to keep score order, set
- Simulation checkpoints can require memory text in the context the reader
gets (
SimCheckpoint.context_keywords, reported asCheckpointResult.context_missing). Four checks that tested the weighted formula’s order rather than what reaches the reader now use it: the infrastructure question inconsolidation, the tools question inremention, and the database and observability questions insurprise_gating. - Receipt versions from 4, 6 and 8 on must state their ordering, guidance and episode settings instead of taking the current defaults. Stored receipts always include them.
- Installs that already set
min_fidelitytofull,proseorstructuredand store records with blank text (for example tool-call-only chat turns) now see those records excluded from the auditable and compact contexts instead of packed with empty text. - Upgrade note:
python -m prme.apiandprme.api.server.run_server()now refuse to start on a non-loopback address (such as0.0.0.0, including inside a container) when neitherPRME_API_USER_KEYSnorPRME_API_API_KEYis set. They used to log a warning and serve every request without authentication. The command exits with status 2 andrun_server()raisesprme.api.server.UnauthenticatedBindError(aValueError), before the app, the engine or a listener is created. Configure credentials before upgrading a network-reachable server. Per-user keys bind each request to its owner, so a backend that acts for many users needs the global key. Only literal loopback addresses (127.0.0.0/8,::1and IPv4-mapped loopback) andlocalhost(when it resolves only to loopback) count as loopback; other host names count as network addresses. A server that only an authenticating reverse proxy can reach can pass--allow-unauthenticated-external-bind(allow_unauthenticated_external_bind=True), which starts it with a warning and gives every caller operator access. The command no longer accepts abbreviated options. Hosting the app under another ASGI server skips the check, as the HTTP and deployment guides now explain. - The development
docker-compose.ymlpublishes its PostgreSQL test database (fixedprme_testcredentials) on127.0.0.1:5432only, instead of on all interfaces. CI connects to127.0.0.1. An existing container keeps its old mapping until it is recreated: rundocker compose up -donce. The deployment guide now separates this test database from a network-reachable one.
0.12.0 - 2026-09-22
Experimental retrieval and evaluation
- Add explicit reranker
score_envelopeandanchored_score_envelopepolicies to preserve the scored prefix’s original score scale during downstream packing. Add opt-in alternate-querymax_signalsmerging for existing candidates, with exact source-snapshot checks and atomic failure behavior. Both storage engines receive these throughPRMEConfig; ordinary defaults remain unchanged. - Record neural ordinal assignments in receipt schema 13, with exact score replay and distinct execution identities for ranking-profile compatibility. Stored schemas 1–12 keep their canonical bytes; older readers cannot read schema 13.
- Retain complete registered LongMemEval-S development results, including negative interactions, inactive features, provider failures and failed primary controls. Production scored 437/500. The anchor-preserving trial scored 430/500 versus its new control’s 429/500 (+0.2 points, 95% CI [−1.6,+2.0]); better source retention did not establish an answer gain. Ongoing ingestion/reformulation trials remain explicitly unfinished, with no partial-arm score or new default.
- Update the archived milestone-checklist test to its moved source path, fixing the existing mainline CI failure without weakening its 29 historical assertions.
Fixed
-
Grounded fact objects with one exact currency or bounded measurement unit no longer depend on model-authored quantity fields. PRME can derive the verbatim value and unit from the grounded object and evidence, while preserving the existing exclusions for approximations, ranges, identifiers and unsupported notation. A separate user-only path recovers one complete first-person conditional quantified action when the model drops the whole claim. Fresh outputs recorded
speech_act_v10. V10 also suppresses conditional fallback when an existing validated fact has the same evidence, predicate, polarity and quantity identity but quotes a different valid condition substring. Saved v9 through v6 outputs keep their bytes and continue to prepare v12 plans. Registered 20-case runs passed all zero-tolerance gates on both hosted DeepSeek and a distinct local Qwen 35B-A3B artifact: 40/40 cases, 24/24 expected quantity instances, no unexpected quantities and no provider errors. -
Fresh
speech_act_v11extraction can recover one leading exact measure from a user-authored first-person completed action in a bounded verb lexicon. The path retains the verbatim measured phrase as the fact object and runs the existing evidence, quantity and reference checks. It excludes modals, negations, examples, questions, conditions, approximations and ranges. Saved v10 through v6 extraction records remain byte-compatible and prepare v12 plans. -
Quantity aggregation accepts optional
predicate_prefixesfor explicit, token-bounded composition of model-authored predicate detail. A normalized prefix such asraisedmatchesraisedandraised_*, but notfundraised; no synonyms or embeddings are inferred. Responses distinguish this mode withsemantic_equivalence="normalized_exact_and_predicate_prefix". A preregistered end-to-end Qwen 35B-A3B confirmation passed all ten source contracts and all aggregation gates, returning the exact$3,750total from four real charity memories while excluding unrelated, negated, conditional, approximate, incompatible-unit and cross-owner controls. -
Python, HTTP and MCP now expose a fail-closed natural-language quantity planner/executor for a fixed set of complete, qualifier-free amount and count questions. It returns the exact structured query and assumptions alongside the result and preserves the question’s exact
Iorwesubject. Unsupported qualifiers, negation, future wording, named subjects, actions or units return a typed refusal without scanning memory; ordinary retrieval remains unchanged. A preregistered confirmation over a frozen end-to-end pack passed five executable questions and six refusal controls with zero refusal scans. -
Assertion and quantity aggregation queries now round-trip their serialized default empty scope selector. An empty scope list consistently means all scopes; duplicate scopes remain invalid.
-
A user-authored sentence such as
My final score was 3no longer disappears when the model omits its claim. A narrow deterministic path admits terminal exact score, count, rating and level attributes with a source-literal concept subject, then applies the normal evidence, quantity and reference checks. It excludes assistant messages, examples, unsupported attributes, approximations, ranges and multi-number values. This behavior was introduced underspeech_act_v8; fresh v10 outputs retain it, while saved v9 through v6 outputs retain their original bytes and still prepare v12 plans. -
Quantified claims now remain exact when a provider serializes a decimal as a JSON float: PRME discards the float and recovers only a single supported decimal token from the grounded source phrase. Surrounding approximation and range cues fail closed even when the provider clips them from
source_text. This behavior was introduced underspeech_act_v7; fresh v10 outputs retain it, while saved v9 through v6 outputs keep their original bytes and still prepare v12 materialization plans. -
Built-in extraction now preserves literal first-person attempts and intentions instead of admitting them under completed or current-state predicates, including component relationships inside the attempted action. The preregistered confirmation outputs recorded
speech_act_v6and preparedspeech_act_v12plans. A narrow source/entity recovery retains the target of an explicit nonactual clause when the model returns the entity but omits its claim, while preserving explicit conditions. Saved v5 outputs remain v11, v4 remain v10, v3 remain v9, v2 remain v8, and legacy extraction records recover undertemporal_validity_v7, so restart cannot claim a validator that did not run. A preregistered 14-case real-model development confirmation passed all 15 safety and utility targets with zero unsafe claims on both a hosted DeepSeek profile and a distinct local Qwen 35B-A3B artifact. -
Registered extracted BEAM ingestion now completes both durable raw-source materialization and structured extraction before acknowledging a source. Source-list timestamps come from the latest cited evidence event, and exact sibling passages are capped with
max_per_source=1. Schema-5 validation inspects each registered owner’s DuckDB work rows after execution, so a scored run with pending raw notes or extractions cannot pass again. -
Built-in extraction now sends source messages literally even when they contain Jinja expressions or blocks. Grounding context is task-local and isolated across concurrent calls, so Instructor cannot evaluate user code as a prompt template or alter the source before inference.
-
BEAM schema-4 extracted-run registrations now bind the extraction retry count, and adapter schema 3 reports the applied value. A library-default change can no longer silently alter an attested extraction run.
-
Exact integer and string decimal quantities from Instructor JSON responses now survive strict extraction validation. JSON float approximations and malformed quantities are still discarded without losing an otherwise grounded fact. Missing or ambiguous named references now discard only their affected claim, so one omitted entity declaration cannot exhaust retries and lose every grounded, reference-closed sibling in the provider response.
-
Preserve BEAM source-session boundaries when the upstream request exposes an observation timestamp, preventing adjacent-turn expansion from treating a complete multi-session history as one session.
-
Store-time oscillation dampening now revalidates the complete owner-scoped supersedence chain under lock and commits its confidence update with a deterministic, checksummed
PENALTYrecord in one DuckDB or PostgreSQL transaction. Concurrent, restarted, failed, and cancelled attempts cannot apply the same penalty twice or leave an unjournaled confidence change. -
Automatic question/answer pairing is now disabled by default. Every registered quality benchmark already excluded the in-process heuristic, whose extra derived node is not atomically journaled or recovered after restart.
enable_qa_pairing=Trueremains available for explicit hypothesis testing. -
TTL expiration now revalidates policy under lock and commits archival with a deterministic, checksummed
TOMBSTONE_SWEEPrecord in one DuckDB or PostgreSQL transaction. The record retains complete before/after state and RFC-0007 policy fields; concurrent, restarted, failed, and cancelled attempts cannot leave an unlogged archive or a tombstone without its transition. -
Unverified organizer alias proposals now publish their deterministic
RELATES_TOedge and a checksummed completeALIAS_PROPOSEDrecord in one DuckDB or PostgreSQL transaction. Exact, concurrent and restarted retries reuse one pair identity; incompatible current nodes are rejected, and legacy random-ID links are reused without fabricating historical journal inputs. -
Built-in embedding configuration now infers registered FastEmbed and OpenAI dimensions when omitted, selects a coherent OpenAI model/dimension pair when only that provider is chosen, and rejects unknown model dimensions before opening an index. Direct
FastEmbedProviderconstruction follows the same fail-early contract without loading model weights. -
Repeated single-vector archive cycles no longer stall in the native HNSW deletion path after roughly 192 operations. PRME now requires USearch 2.26.2, whose deletion implementation completes this churn pattern; a subprocess regression test keeps a native stall bounded and observable. A preregistered AgentMemBench confirmation completed 200/200 archive-retirement cases, with every memory visible before archival and absent from retrieval afterward.
Added
-
Added an optional local
ClaimVerifierthat checks explicit declarative claims against exact packed passages with a revision-pinned NLI cross-encoder. It scores individual evidence first, explores only bounded minimal groups, exposes supporting and refuting groups plus every model score and digest, preserves typed source/time/lifecycle provenance, and returnsincompletewithout a model call for derived exhaustive counts or lists. The verifier is available throughprme[verification]; it remains opt-in while representative claim evaluations establish domain thresholds. Its first registered 20-case real-model assay matched 17 cases and failed the all-cases gate. It produced zero unsafe supports and recovered both unseen two-passage claims, but overcalled two neutral passages as refutations. The default verifier now requires an explicit correction cue or incompatible concrete value in the exact evidence group before accepting a model contradiction; blocked raw contradictions remain auditable and returninsufficient. A registered same-cohort confirmation passed all eight targeted gates and changed only the two intended false refutations, yielding 19/20 expected statuses with zero unsafe supports. This is regression evidence on an observed development set, not a held-out accuracy result. A later 48-case previously unexecuted development assay then failed its safety gate with two unsafe supports: one desire was treated as a completed action and one explicit ownership conflict was missed. The failed result is retained. The verifier now blocks entailment when evidence has a nonactual speech act absent from the claim, retaining the raw score and an explicit limitation, and can surface narrowly matched explicit negation with a distinct deterministic decision basis. Claim verification remains opt-in. A registered same-cohort safety confirmation passed all eight gates: the raw scores were unchanged, exactly the two intended statuses changed, and unsafe supports fell from two to zero. Four implicit contradictions and two relation-composition cases remained unresolved. A follow-up diagnosed that bounded candidate ranking had also reordered evidence before NLI; group scoring now preserves caller order after selecting candidates. Its registered same-cohort confirmation passed all eight gates, recovered all 6/6 minimal groups and changed exactly the two intended statuses, reaching 44/48 with zero unsafe supports. A later 44-case previously unexecuted guard assay failed: four negative distractors about a different relation were treated as refutations or conflicts. The result is preserved and blocks promotion of claim verification. Evidence-side negation now requires every normalized non-generic claim token in the negated clause before either deterministic or model-assisted refutation, and reported questions share the direct-question speech-act mode. A registered same-cohort confirmation passed all eight gates at 43/44 with identical model scores: all four wrong-relation negatives becameinsufficient, the reported question becamesupported, and every true refutation and conflict was retained. The first external WiCE oracle-retrieval assay then failed precision, recall and balanced-accuracy gates across all 358 human-annotated test claims. It accepted 0/32 fully unsupported claims, but passage-wide speech-act and negation guards reduced supported recall to 10.91%. Result schema 3 now localizes those guards within multi-sentence passages and rechecks the retained exact text with the same model. It records one-based retained sentence numbers, premise digests, probabilities and a distinctlocalized_model_entailmentbasis; schemas 1 and 2 remain readable. The registered confirmation preserved all eight authored gates and improved WiCE supported recall from 10.91% to 30.91% and F1 from 19.35% to 43.59%, with no fully unsupported accepts. It still failed the fixed precision, recall and balanced-accuracy gates, so verification remains opt-in. A pinned MIT MiniCheck DeBERTa capacity trial improved WiCE F1 to 65.97% and balanced accuracy to 75.01% with no fully unsupported accepts, but failed the fixed 90% precision and 60% recall gates. No frozen-score threshold meets both, so that model is not integrated as a standalone verifier. The registered MIT MiniCheck Flan-T5 trial raised WiCE recall to 72.73%, F1 to 74.77%, and balanced accuracy to 81.52% with no fully unsupported accepts, but failed the 90% precision gate on 24 partially supported compound claims. No threshold meets both gates. A preregistered follow-up applied the unchanged model to all 958 WiCE human subclaims and required every subclaim to pass. Gold decomposition reconstructed 357/358 parent labels, but model errors limited parent precision to 76.04% and recall to 66.36%; no frozen threshold met both gates. This validates atomic decomposition as an architecture boundary on the named cohort while rejecting this verifier for integration. A fresh registered 100-case SummEdits trial tested a 675B reasoning model with exhaustive atoms and exact proof quotations across ten domains. It failed at 75.00% precision, 6.00% recall, 52.00% balanced accuracy and 23.00% quote integrity. The checks safely rejected paraphrased or invented proof, but the model also decomposed facts from the document instead of only the summary. This rejects free-form proof copying and motivates a separated, segment-ID protocol. The same-cohort causal v2 split summary-only decomposition from fixed-atom document verification. Reference integrity rose from 23.00% to 99.00%, supported recall from 6.00% to 72.00%, and balanced accuracy from 52.00% to 76.00%. It still failed safety at 78.26% precision and a 20.00% false-support rate, chiefly on entity changes and antonym swaps. A different-family DeepSeek critic over all 46 primary support candidates reduced false support to 8.00% but left precision at 78.95% and collapsed recall to 30.00%. A balanced 1,100-claim LLM-AggreFact development trial then rejected direct FactCG classification: the best threshold retaining 60% recall reached 79.44% precision, while 90% precision retained only 28.73% recall. A registered FactCG-ranked local-evidence Mistral cascade raised the corresponding operating point to 85.12% precision at 63.45% recall, but 90% precision still retained only 36.55% recall. Seven structured responses remained fail-closed, and the bound test cohort remains untouched. No provider verifier is integrated. -
Added an optional, provider-agnostic
AnswerabilityEvaluatorfor grounded abstention after retrieval. It decomposes compound questions and optional draft answers into independent requirements, resolves cited compact refs or default auditable UUIDs to exact packed memory IDs, fails closed on missing or invented citations, and derivesanswerable,partial,insufficient, orconflictingin code. Empty bundles avoid a model call; provider failures raise explicitly; every result binds the prompt version and query/context/answer hashes, plus separate fixed-input and actual-output digests, without changing retrieval receipts or memory state. Its first registered 120-assessment BEAM development trial failed every promotion gate. A speech-act-aware same-cohort rerun with exact evaluator and machine-gate bindings also failed all five gates, including 2 unsafe full answers and stable actions on only 26/40 questions, so it remains explicit and opt-in. A registered frozen-draft follow-up also failed all four gates: it fully accepted 5/36 samples from incorrect drafts, fully accepted only 13/84 samples from correct drafts, produced 7 citation errors, and was action-stable on 22/40 questions. Its systematic failures separate temporal task-label disagreement from exhaustive-count verification and block automatic enforcement of the current single-call architecture. -
Opt-in direct evidence projection lets extracted claims route retrieval while returning the complete active source passage. It replaces bounded exact evidence groups only after owner, scope, temporal, validity and epistemic checks, records replayable score inheritance, and reserves projected sources during packing. Receipt schema version 10 records the full disabled-by-default policy while versions 1–9 preserve their canonical bytes and disabled meaning. A registered all-top-50 development ablation improved event ordering to 2/2 but regressed three previously passing questions and reduced overall score to 11/20, so wholesale projection is explicitly rejected as a default.
-
Opt-in evidence augmentation preserves concise derived candidates while adding bounded direct sources under the same owner, scope, temporal, validity, lifecycle and epistemic checks. Projection and augmentation are mutually exclusive. Receipt schema version 11 records augmentation settings and exact score inheritance; versions 1–10 retain disabled semantics. A registered tuned BEAM ablation improved the accepted result from 13/20 to 14/20 with one pass-level win, zero losses and a +0.02916 mean-score delta. A preregistered untouched confirmation then scored 14/20 versus the fresh baseline at 15/20, with zero wins, one contradiction-resolution loss and a -0.03375 mean delta. Unconditional top-10 augmentation remains opt-in and is rejected as a default. A new
evidence_augmentation_anchor_policy="non_entity"mode prevents entity name matches from authorizing whole-passage injection and backfills the quota from non-entity evidence groups. Receipt schema version 12 records the policy; versions 1–11 preserveallsemantics and their canonical bytes. A registered two-conversation diagnostic fixed the observed contradiction regression but produced one win, one temporal loss and a -0.03000 combined mean delta, so the policy remains opt-in and is not a default candidate. A preregistered frozen-context follow-up rejected a stable interpretation of that temporal loss: the identical baseline context passed 3/5 repeats, the candidate passed 4/5, and both mean scores were 0.40. The BEAM integration now includes an answer-stability runner that pins both retrieval artifacts and alternates repeated answer/judge calls without retrieving again. -
A registered fixed-pack BEAM ablation found that a hard one-node cap per exact evidence set held pass accuracy at 13/20 but reduced mean rubric score from 0.56750 to 0.54833, with one pass-level win and one loss. The failure blocks a default cap and motivates the source-preserving projection policy.
-
The corrected schema-5 extracted-memory BEAM development run completed at 13/20 pass (65.0%) with a 0.56750 mean rubric score. Fail-closed validation confirmed 188/188 durable raw materializations and 188/188 extractions. Exact passage diversity rose from a 15-of-50 median in superseded dev3 to 48-of-50, while median retrieval latency fell from 486.0 ms to 198.05 ms. Against the accepted raw profile it gained three pass-level questions, lost two and tied fifteen. This tuned one-conversation result does not establish a default or cross-product leadership.
-
The schema-5 extracted BEAM dev4 run is retained as rejected evidence. A 14,181-character source exhausted four 120-second DeepSeek extraction calls; the run was stopped during ingestion and publishes no score. Controlled probes on the exact saved source completed with Mistral Large 3 in 44.63 seconds and DeepSeek V4.1 Flash in 106.42 seconds, identifying hosted latency variance and the registered timeout as the failure boundary.
-
Python, HTTP, and MCP retrieval now accept optional
max_per_sourceandmax_per_evidenceresult-selection bounds. The first collapses only byte-identical passages with the same exact nonempty evidence set. The second can cap differently worded nodes that cite the same exact evidence set. Both fill the requested count from later groups, record every exclusion, leave nodes without evidence untouched, and remain opt-in pending broader answer trials. -
The first scored extracted-memory BEAM execution produced 12/20 pass (60.0%) with a 0.51875 mean rubric score, but a later pack audit found only 66 of 188 raw-source materializations complete. The original validator checked all 188 structured extractions but missed the second durable work stream. The result is retained as superseded diagnostic evidence and is no longer accepted as a complete extracted-profile quality result.
-
Registered BEAM evaluation can now attest scored extracted-memory runs. The schema-3 launcher binds and verifies the extraction model and settings before ingestion, launches the selected durable extraction profile, and rejects adapter-profile or extraction-config drift while preserving earlier raw registration semantics.
-
The first registered extracted-memory BEAM attempt is retained as rejected evidence: DeepSeek V4.1 Flash completed 8 durable extractions but failed the complete schema on a longer source after the registered retry budget. The run was stopped before retrieval and publishes no score.
-
The second registered extracted-memory BEAM attempt is also retained as rejected evidence. It completed 11 durable extractions before a stored Jinja code example exposed Instructor prompt-context evaluation ahead of the model. The run was stopped during ingestion and publishes no score.
-
The first fail-closed scored BEAM execution now provides complete answer-quality evidence for one 100K raw-memory conversation: 12/20 pass (60.0%) with a 0.49833 mean rubric score, 94/94 ingested chunks, 20/20 nonempty answers, and 53/53 complete judge verdicts. Registration binds the source, dataset, selection, endpoint, and Ollama manifests before execution. Three precursor attempts remain published as rejected evidence, including a completed upstream result that the validator rejected for six silent empty answers. The accepted cohort identifies abstention and broad summarization as the largest measured gaps and does not establish official-scale or cross-product leadership.
-
Registered BEAM evaluation now supports complete scored runs as well as the earlier predict-only workflow. Schema-2 registrations bind distinct local answerer and judge models, full Ollama digests, endpoint, selection, concurrency, dataset, and runtime source before the first model call. The launcher and fail-closed validator reject model or protocol drift while preserving schema-1 predict-only artifacts unchanged.
-
AgentMemBench retrieval registrations now bind the exact Ollama judge model digest, endpoint, and generation/retry controls before execution. Verification checks both the saved harness arguments and the live model identity. The installed pinned harness disables reasoning for its 32-token JSON decision and aborts after malformed output or exhausted retries instead of silently scoring judge failures as retrieval misses. The first registered 100-record Qwen 35B development run completed at 95/100 recall@5 with a 90% to 99% bootstrap interval and 100/100 durable materializations. The preregistered official-size confirmation scored 979/1,000 with a 97.0% to 98.7% interval, including 98.8% personal-fact and 97.0% task-request recall, with all 1,000 writes durably materialized.
-
Current-state scoring now recognizes the newest record when it explicitly presents itself as an update and applies a configurable, relevance-capped, replayable multiplier. A 100-pair AgentMemBench development diagnostic moved new-fact-first retrieval from 20% to 100%; the default 1.30 multiplier remains provisional. Receipt schema version 9 records configured and applied values, while versions 1–8 preserve their canonical bytes and disabled semantics.
-
Atomic
ingest_fast_many()raw-source admission across the asynchronous engine, synchronous client, HTTP, MCP, DuckDB, and PostgreSQL. One owner is bound to the complete ordered batch, every item is validated before I/O, and all immutable events and restart-safe materialization jobs commit together or roll back together. An optional owner-scoped request UUID makes exact retries return the retained event IDs after restart and rejects changed inputs. MemoryAgentBench adapter schema 10 uses this path with a stable request UUID and drains the existing bounded materialization queue before publishing a pack. -
Opt-in deterministic two-stage episode routing for sources stored under meaningful session boundaries. It uses BM25 to route candidate-backed
(scope, session_id)groups, promotes a bounded local evidence set with replayable score provenance, and reserves that evidence during packing. It is disabled by default while matched answer trials test the EventQA hypothesis. Receipt schema version 8 records the complete policy while versions 1–7 retain their canonical bytes and disabled semantics. MemoryAgentBench schema 8 can preserve upstream source chunks as distinct registered episode partitions. New execution descriptors also hash the episode-routing module alongside the other retrieval stages. -
The registered EventQA episode-routing development trial scored 19/20 versus BM25 at 20/20 while using 90.48% fewer retrieved-context tokens. Against the earlier flat-session PRME arm on the same 20 questions and reader, it recovered three of four failures with no paired losses and essentially unchanged context size and query time. The one remaining miss contained the strongest routed evidence but not the answer verbatim. This supports the technique on the named slice. Registered follow-up arms preserved Banking77 at 20/20 and improved DetectiveQA from 13/20 to 15/20, with every receipt verified and no context expansion. The default remains disabled pending a larger cohort and another reader.
-
MemoryAgentBench registrations now bind the complete retrieval source map reported by execution descriptors. Verification compares every durable receipt with that frozen map, rejecting runs whose adapter came from the declared revision but whose PRME runtime resolved from another checkout.
-
The MemoryAgentBench installer now upgrades its previously generated reader configuration block in place. Reinstalling after a new reader contract no longer leaves both the old and new validators in
agent.py; managed markers make subsequent installs idempotent, and ambiguous edits still fail closed. -
MemoryAgentBench DetectiveQA trials can register a shared
choice-only-v1reader contract. It resolves the pinned task prompt’s conflict between an example JSON reasoning object and its option-text exact-match reference by requiring oneA. choice textline in both arms. Registration, runtime initialization and verification reject the contract outside DetectiveQA, and saved model output remains untouched. -
The matched DetectiveQA development trial completed on 20 questions under that contract. PRME and BM25 each scored 13/20, with one paired win and one loss. PRME used 90.52% fewer retrieved-context tokens and 89.27% fewer reader input tokens. Two PRME responses and three BM25 responses contained a reference answer but violated the exact format; saved outputs were scored without rewriting. The verified tie completes a first matched development pass across all four MemoryAgentBench competency families, with task-specific gaps and no general leadership claim.
-
A matched MemoryAgentBench Conflict Resolution development trial completed on 20 questions under the shared
answer-only-v1contract. PRME scored 1/20 and BM25 scored 0/20. Post hoc inspection found reference-answer text in 19 PRME contexts and all 20 BM25 contexts, isolating the Qwen 9B reader and task interpretation as the dominant failure. A separately preregistered check with the installed Qwen 35B A3B reader produced the same 1/20 and 0/20 scores, ruling out model size alone as the remedy. Both verified negative results are published without treating the single paired win as evidence of useful conflict-resolution quality. -
MemoryAgentBench trials can register a shared
answer-only-v1reader contract for strict-answer tasks where a local OpenAI-compatible reader otherwise adds explanations. PRME and BM25 receive the same prompt instruction, registrations bind it before inference, and saved model output is never parsed or rewritten. -
Real extraction diagnostics can now run the same qualifier and entity-reference probes through either Ollama or OpenAI. Checked worker processes forward the provider explicitly and record it in the report, enabling provider-diverse validation without changing the cases or weakening grounding checks.
-
MemoryAgentBench ICL trials may opt into a registered
numeric-label-v1reader contract shared by PRME and BM25. It resolves the pinned harness’s conflict between alabel: Nprompt and its documented digits-only exact-match metric by appending the same explicit instruction to both arms. Retrieval queries and raw model outputs remain unchanged, and manifests and captures bind the selected contract. The paired comparator now rejects cross-arm contract drift and derived retrieval-query drift, and reports the matched contract with the other reader settings. The matched BM25 path uses the same terminal ICL question extractor as PRME, with both derived queries bound before inference. -
The first corrected matched MemoryAgentBench answer trial completed on 20 Banking77 development questions: PRME scored 20/20 versus BM25 at 17/20 under the official strict metric while using 90.52% fewer retrieved-context tokens. Both independent verifiers and the strengthened paired comparator accepted the exact artifact chain. The paired interval includes zero, and PRME’s 5,897-node pack took 467.549 seconds to construct, so this remains bounded development evidence and exposes typed bulk ingestion as the next performance target.
-
The matched MemoryAgentBench EventQA development trial completed on 20 questions with independently verified PRME, BM25 and paired artifact chains. PRME scored 16/20 versus BM25 at 20/20 while using 90.48% fewer retrieved-context tokens. All four PRME misses omitted the reference answer from the packed context even though answer-bearing records remained in the durable store; flat limit and token-budget increases did not recover them consistently. This records episodic context reconstruction as a quality gap and preserves the negative result rather than treating compression as success.
-
MemoryAgentBench verification now authenticates each claimed durable retrieval receipt directly from the completed DuckDB pack, including its checksum, owner/request identity, replayable ranking, context hash, packing contract, scope, and included count. Reports commit an aggregate receipt hash instead of trusting the adapter’s persistence flag. Registration and both verifiers require their executing module bytes to match the frozen source they report.
-
MemoryAgentBench source ingestion now preserves blank-line units and serial-numbered facts as independent records, splitting only an overlong unit at the configured hard limit. Test-time-learning retrieval embeds the terminal classification question instead of its repeated reader instructions. Versioned manifests, preregistrations, captures, and durable receipt checks bind both policies and the exact derived retrieval query.
-
Session-context expansion now promotes adjacent turns even when broad vector or lexical generation already placed them in the candidate pool. Previously, those candidates were skipped before packing, making the default session window a no-op on sufficiently complete candidate sets. Inherited scores keep their trigger and decay in replayable receipt provenance. Built-in DuckDB and PostgreSQL stores fetch exact bounded neighborhoods, so older hits in sessions longer than 2,000 nodes are no longer silently missed; reused session IDs remain partitioned by exact memory scope.
-
Contract-correct LangChain and LlamaIndex chat persistence over the immutable event log. Versioned control events make clear, replacement, and deletion visible to framework callers without erasing source messages or creating retrievable control nodes. The adapters page beyond 1,000 events, isolate exact scopes, preserve structured message payloads, and now run against the locked current framework releases in a dedicated CI job.
-
Automatic adjacent question-answer pairing now includes exact scope in its session cache identity. A personal turn followed by a project turn can no longer produce a combined cross-scope memory, and chat-history control events reset the applicable cache before later messages are stored.
-
A registered, fail-closed MemoryAgentBench BM25 control for matched-reader trials. It binds the exact prepared sources, formatted BM25 documents, questions, answers, harness code, configuration, NumPy and
rank-bm25versions, and ranking source hash before inference. The verifier reconstructs every BM25 ranking and rejects missing, stale, reordered, or altered captures. Explicit retrieval run IDs isolate scratch outputs, while a fixed registered memory timestamp removes wall-clock text from otherwise reproducible indexes. -
Explicit MemoryAgentBench reader reasoning and seed controls shared by the PRME and pinned BM25 request paths. The installer validates both settings, forwards the task generation limit for non-OpenAI model names, and the PRME adapter binds the values into its pack identity and retrieval captures. This prevents a local common-reader comparison from silently using different thinking or sampling behavior between memory arms. Registrations also bind the dataset, NLTK and tiktoken versions, the English Punkt data, and the exact tokenizer table so preprocessing dependency drift cannot silently change task chunks. The canonical PRME agent name now selects the same upstream RAG question template as BM25 while still dispatching to the PRME adapter, removing a reader-prompt confound from matched trials.
-
Isolated MemoryAgentBench PRME state through a validated experiment slug.
prme_run_idparticipates in the saved-agent path, pack identity, retrieval capture, and verifier so multiple configurations using one reader cannot reuse or overwrite each other’s memory packs. -
Opt-in compact packed context for short-record workloads. It replaces repeated JSON keys and full in-prompt UUIDs with one declared array schema and deterministic bundle-local references while retaining type, scope, epistemic state, lifecycle, provenance, representation, temporal fields, and complete selected text.
MemoryBundle.context_referencesandresolve_context_ref()map citations back to full node IDs. Exact token accounting covers the complete output, and receipt schema version 7 records the format while versions 1–6 preserve their canonical bytes and historical auditable semantics. The auditable format remains default. -
A registered 149-question LongMemEval-V2 4K-budget development study. PRME scored 49/149 versus 10/149 without memory, while mean reader memory context fell 83.05% from the earlier 32K arm. The same-cohort PRME score fell from 80/149 to 49/149, so the result preserves the 4K preset as explicit and makes intermediate-budget answer retention the next gate rather than supporting a quality-default change.
-
Explicit LongMemEval-V2 renderer selection. The adapter accepts and reports
context_format, the full preset declaresauditable, and the compact preset now declarescompactso future runs cannot confuse a 4K budget with compact serialization. The registered comparator reports the effective format and rejects a declared format that differs from the saved configuration. -
A pinned MemoryAgentBench adapter for the benchmark’s four incremental memory competencies. It uses the public PRME client with the product-default 4K balanced packer, pins the upstream dataset revision, fences completed source ingestion for restart, and saves exact retrieved contexts and request identities. Task-qualified state paths prevent cross-suite pack reuse. The installer is idempotent, rolls back partial changes, and preserves list-valued references across upstream resume. Outcome-free registration hashes every prepared source, query, answer, context assignment, configuration and harness file; post-run verification requires exact registered inputs, complete metrics, bounded recounted contexts, durable receipts, and completed source manifests. Matched BM25 registrations bind preprocessing, ranking, and LangChain wrapper dependencies; the installer updates the pinned harness to the current
BM25Retriever.invoke()API. A paired comparator accepts only exact registrations, verified-complete arms and result hashes, applies each task’s official accuracy metric, and reports paired uncertainty without raw answers. Both arm verifiers accept the harness’s native boolean match metrics while retaining finite numeric validation for graded metrics. This is an evaluation path; task results retain their individual claim bounds. -
Durable, atomic hierarchical summary publication. Daily, weekly and monthly excerpts use stable owner/scope/level/period lineages, deterministic request generations, checksummed preparation, fenced index staging and transactional graph publication. Unchanged runs reuse one active identity; late selected sources atomically replace and archive the prior generation; interrupted runs recover without re-embedding; concurrent engines converge; and the first managed run atomically retires legacy excerpts for the same period. Stable-ID paging removes the prior 5,000-node daily and 1,000-summary rollup caps while keeping unscoped scans an explicit internal operator action.
-
Immutable owner/exact-scope ranking profiles with a two-stage activation gate. A profile must bind a positive explicit-feedback proposal to a separately positive full-retrieval holdout before it can be persisted and activated. Retrieval applies compatible profiles per request, records their identity and status in metadata and receipts, and safely falls back on feature or base-score drift. Append-only, retry-safe activation, deactivation and rollback work across DuckDB and PostgreSQL and are exposed through Python, HTTP and MCP. Serialized evaluations revalidate their coverage, aggregates, decisions and full-retrieval input identity; the query path reads a compact checksummed activation record rather than reparsing the complete evidence report.
-
A conservative full-pipeline retrieval holdout evaluator for learned ranking proposals. It compares separately executed baseline and candidate receipts, requires complete caller-supplied relevant-node sets, verifies identical owner, scope, clock, filters, limits, scoring, packing, execution parameters, and feature identity outside the declared multipliers, and reports grouped recall, NDCG, MRR, bootstrap uncertainty, regressions, and immutable input identities. Positive observed-candidate learning alone cannot activate a profile.
-
A preregistered MELT lifecycle launcher and fail-closed report validator. The launcher pins the held-out final profile, five-seed schedule, source commits, adapter and upstream file hashes before execution. Validation uses MELT’s own report loader and independently requires final status, exact protocol and SUT identity, five complete runs, all case checkpoints, and retained case I/O.
-
Opt-in
prme doctor --verify-extractionprovider diagnostics. It verifies endpoint reachability, hosted credentials, and the configured model through read-only model metadata APIs without generating or storing content, and reports sanitized status categories without response bodies or URLs. It explicitly leaves generation quota unverified. -
Explicit half-open validity intervals for direct writes across async/sync Python, HTTP, and MCP. New extracted facts start validity at their resolved source-effective time, and a source-grounded replacement closes the prior interval atomically when doing so cannot invert a legacy interval. Invalid or timezone-free intervals fail before source admission; historical derivation plans retain their original bytes and behavior.
-
Exact temporal assertion state across async/sync Python, HTTP, and MCP. A required owner, scope, structured subject/predicate, and timezone aware validity instant produce auditable current candidates plus stored history, supersedence, contradiction, epistemic, lifecycle, clock, and evidence data. The operation preserves differing unresolved values and never selects truth from recency; historical knowledge cutoffs retain an explicit non-replay boundary.
-
Exact decimal quantity aggregation across Python, HTTP, and MCP, with totals, minima, maxima, counts, temporal bounds, and source/evidence samples. Every group must retain its normalized unit, stored quantities are revalidated at read time, incompatible units are never mixed, and scaled-integer addition avoids decimal-context rounding.
-
Source-grounded decimal quantities for extracted facts. Built-in and custom grounding retain a quantity only when its exact decimal, quantified phrase, and verbatim unit occur in the claim object and evidence. New derivation plans version the metadata policy while historical plans and checksums remain unchanged; invalid optional quantities do not discard otherwise valid claims.
-
Exact owner-scoped assertion aggregation across Python, HTTP, and MCP. It counts every matching structured claim for an unchanged store, groups normalized subject/predicate/object/polarity values, retains bounded evidence samples and time/epistemic filters, and distinguishes stored-set completeness from extraction, semantic, and real-world completeness.
-
A fail-closed operational benchmark for p50/p95/p99 retrieval latency at declared pack sizes, exact fixed-clock repeatability, and 10,000-query owner isolation through public store/retrieve paths, with runtime and execution provenance in its artifact.
-
HTTP and MCP access to the existing bounded, owner-scoped offline learning evaluator. Both remote surfaces return the complete validation, uncertainty, coverage, exclusion, and input-identity report without activating weights.
-
Owner-required, cursor-based stored-record enumeration over HTTP and MCP.
GET /v1/nodes/scanandmemory_scan_nodesexpose scope, type, and lifecycle filters, immutable UUID ordering, explicithas_more/next_cursorfields, and page-level consistency so remote exports and counts do not depend on a bounded top-k query. -
A pinned BEAM benchmark service with source-only ingestion boundaries, owner isolation, source-time query clocks, restart-safe request idempotence, and separate raw and durable-extraction profiles. Its fail-closed validator rejects the upstream runner’s otherwise silent failed-chunk and empty-model completion paths and hashes every accepted artifact. A registered raw retrieval launcher additionally binds the clean PRME and upstream revisions, exact source files, normalized dataset cache, run identity, profile, and complete question selection before ingestion; validation checks the same registration, execution, dataset, and adapter identities.
-
Structured
store_with_receipt()results on async and synchronous Python. They expose the durable event, exact created node, and materialization status in one call while preserving the historicalstore()event-ID return. HTTP and MCP store responses now use the same provenance-based receipt path and expose direct materialization status. -
An official LongMemEval-V2 adapter for agent-trajectory memory. It preserves ordered state and transition semantics, creates compact hierarchical procedure traces alongside raw states, bounds downstream context items, returns source screenshots, fingerprints portable adapter state, and rejects changed or interrupted trajectory inserts. A pinned one-question web-small pipeline smoke covers the full 100-trajectory save/load path. Its installer verifies the pinned upstream revision, copies the adapter and configuration atomically, registers the backend, and safely handles repeat installation. A companion launcher durably checkpoints each reader response, preserves exact prompt rows across retries, rejects configuration drift, and supports explicit
reasoning_effort: nonefor Ollama development runs. Schema 3 packs persist a stable retrieval reference clock; schema 2 packs derive it without mutation and remain read-only, preventing saved-run ranking drift across wall-clock dates. Registered paired comparisons now bind the PRME and no-memory arms to their declared configuration paths, context budgets, frozen saved-memory configuration and pack manifest; a baseline that returns memory context fails validation. New schema-2 registered runs also write a launch-time execution manifest that binds both arms to clean PRME and pinned upstream revisions and hashes the exact launcher, installer, adapter, configuration, and harness; changed-source resumes and retroactive attribution fail before generation. -
The first preregistered held-out LongMemEval-V2 web-small answer comparison completed all 149 deterministic questions for PRME and the official no-memory adapter. With one fixed local Qwen 9B reader, PRME scored 80/149 versus 10/149, with 75 paired wins, 5 losses and a +37.58 to +55.70 point bootstrap interval. The fail-closed comparator verified both arms, official scores, source inputs, reader settings, saved pack/config bindings and the baseline’s zero-memory contract. The result used a mean 43,195 memory-context tokens and remains a named-cohort memory-utility result rather than a competitive leadership claim.
-
LongMemEval-V2 registered execution manifests now bind the configuration actually selected for each arm, including its launch-time hash, instead of attesting only the installed default. The installer atomically supplies both the 32K maximum-evidence profile and an explicit 4K product-default compact profile. Before opening loaded memory, the launcher also hashes every regular file by relative path, size and content and rejects symlinks; the comparator requires the complete initial artifact and both per-arm configuration identities for new schema-2 studies.
-
A matched raw-store versus real
ingest()evaluation profile for LongMemEval source evidence. Extracted runs freeze the local model digest and full configuration before generation, require durable extraction completion, report source/node materialization coverage, and support an explicit paired profile comparison without presenting source lineage as answer accuracy. -
Optional, token-counted context guidance with a non-displacement guarantee. The packer includes guidance only when it fits after record selection, exposes whether it was included, and preserves it through controlled ablation.
-
Exact, nonmutating packed-context ablation and citation-checked presence credit. Applications can re-answer after removing one cited memory, preserve both context hashes and token accounting, and distinguish load-bearing, redundant, misleading, and noncuring outcomes without changing retrieval, ranking, or retention.
-
Immutable, owner-scoped answer citation records across async/sync Python, HTTP, MCP, DuckDB, and PostgreSQL. Citations bind to saved content-bearing context, preserve optional answer digests, and use caller UUIDs for exact retry safety without changing memories or ranking.
-
Durable retry IDs for promotion and archival across sync/async Python, HTTP, and MCP. HTTP uses
Idempotency-Key; conflicting key reuse returns 409. -
Atomic, checksummed explicit corrections across sync/async Python, HTTP, MCP, DuckDB, and PostgreSQL. State, deterministic edge, and complete before/after audit record commit together; exact retries remain safe after restart.
-
A complete tenant-scoped contradiction lifecycle on sync/async Python, HTTP, and MCP. Marking and resolution atomically update claims, edges, and audit records; exact retries are idempotent across restarts and resolution evicts the deprecated claim from derived search indexes.
-
Atomic, evidence-aware condition evaluation across Python, HTTP, MCP, DuckDB, and PostgreSQL. Retry IDs are durable, state changes retain checksummed before/after records, and confirmed conditions receive asserted retrieval weight without losing their conditional classification.
-
MCP
memory_storeparity for role, session, metadata, confidence, epistemic type, and source type, allowing agents to create qualified memories directly. -
Tenant-scoped node provenance on sync/async Python, HTTP, and MCP, including owned source events, explicit missing-evidence signals, valid contradiction links, and bounded chronological operation pages with opaque cursors.
-
Explicit aggregation coverage on Python, HTTP, MCP, durable retrieval records, and packed model context. Natural-language counts/lists report candidate, selection and context truncation without claiming exhaustive enumeration.
-
A reproducible 8K-context Ollama profile for
qwen3.5:35b-a3b, with two successful strict extraction reports and an equal-context 9B comparison. -
Typed claim polarity and exact explicit conditions for built-in LLM extraction. Conditional claims retain an auditable state and stay out of default retrieval until confirmed.
-
MemoryWorkspaceand lease-scopedNamespaceMemoryfor named local projects, with stable pack identity, bounded idle-engine eviction, shared embeddings, process ownership and cancellation-safe lease cleanup. -
MemoryWorkspace.open_postgres()for named PostgreSQL projects sharing one bounded connection pool. Identity checks and a private-only search path protect routing; registry and schema creation publish atomically. Hosted grants remain separate. pgvector symbols now resolve explicitly even outsidepublic. -
Optional
duckdb_threads/PRME_DUCKDB_THREADScontrol for each open local database. The default preserves DuckDB’s setting; conflicting concurrent opens fail without reconfiguring the active pack.
Changed
-
Supplementary aggregation and entity-focused lexical searches now normalize their BM25 scores before composite ranking. Unbounded raw Tantivy scores can no longer overwhelm semantic, graph, recency, salience, and confidence signals or crowd relevant hybrid candidates out of a bounded result set.
-
Packing configuration now rejects negative candidate limits and graph depths outside the RFC’s 1-3 range. The legacy no-op
chars_per_tokenandcross_scope_token_budgetfields remain parseable for receipt compatibility, but non-default use warns that exact context tokenization andcross_scope_top_nare the active controls. Settingcross_scope_top_n=0now skips the secondary hint search entirely. -
The organizer registry now contains only implemented jobs. The unimplemented, unvalidated
centrality_boostno-op is no longer advertised or run during default maintenance; explicit requests fail as an unknown job instead of returning a misleading success result. -
Temporal reasoning guidance is now enabled by default when it fits after evidence selection. A registered 70-context confirmation improved temporal answers from 31/50 to 34/50. Personalization and current-state guidance remain experimental behind
packing.context_guidance_mode="all";"off"restores pre-guidance behavior. Receipt schema version 6 records the chosen mode while versions 1–5 preserve their canonical bytes and mean guidance was off. Elapsed-time questions no longer receive aggregation coverage warnings; time totals across records remain aggregation queries. -
knowledge_atnow exposes a machine-readablehistorical_coverageboundary in Python, HTTP, MCP, retrieval receipts, and the token-counted model context. It is explicitly an aware ingestion-time cutoff over current indexes; prior lifecycle and index state are not replayed. Naive datetimes fail immediately. -
Balanced multi-path context packing is now the default. A complete fixed 119-question answer trial scored 83 correct with balanced contexts versus 67 with density. A separately registered 381-question answer confirmation scored 250 versus 185, with 88 paired wins, 23 losses, and no lower category total. Explicit density and score policies remain available, while historical receipts retain their original density meaning and checksums.
-
Current-state retrieval now recognizes ordinary present-tense state questions, while inferred recency reweighting requires explicit update evidence and dated temporal queries remain historical. Decisions and instructions receive the same default semantic-node boost as facts and preferences.
-
Structured extraction now sends a configurable sampling temperature, defaulting to zero, and rejects uncertain or contingent future actions mislabeled as completed decisions. Explicit known-negative updates can retire the same known-positive claim without guessing legacy polarity.
-
PostgreSQL now honors the default
vector_exact_search=True, materializing eligible rows before distance ordering to prevent filtered HNSW starvation.Falseexplicitly permits approximate search. Broad exact queries may cost more; new receipts report the requested mode. -
Default organizer passes exclude the legacy global feedback tuner; session completion runs promotion only. Explicit scoped
feedback_applyrequests now raiseValueErrorbefore any work. Trusted operators can retain the legacy behavior with explicitorganize(jobs=["feedback_apply"])and no user scope.
Fixed
-
Extraction workers now immediately reclaim an expired, uncontested lease once before falling back to scheduled retry. Event-loop starvation after a provider response can no longer leave durable work indefinitely in
runningstate; a lost reclaim race or expired inline recovery also schedules the ordinary durable retry, while generation fencing prevents stale publication. -
Forgotten synchronous clients now close before Python shuts down its shared thread-pool executor, allowing vector and lexical indexes to flush cleanly at normal interpreter exit without late-executor errors.
-
Historical assistant and system events are now submitted to extraction models as input text while retaining their stored source role for provenance and epistemic typing. Role-aware admission guidance prevents local chat providers from returning an empty continuation and avoids promoting generic assistant recommendations, explanations, and examples into durable claims.
-
Extracted source-lineage benchmarks now complete and map the durable raw NOTE path before retrieval. Reports distinguish raw source nodes from derived semantic coverage, so an intentionally empty extraction remains retrievable as episodic evidence instead of disappearing from evaluation accounting.
-
Mixed-quality structured responses now retain source-supported claims while dropping malformed or unsupported proposals. A response with no admitted claims completes with an empty claim set while preserving the raw event and any grounded named mentions; missing or ambiguous named references on admitted claims still enter bounded validation retries. Condition and uncertainty validation is scoped to the cited source sentence and directly following qualifiers, preventing unrelated language elsewhere in a paragraph and indirect questions such as “see if” from contaminating the claim. Polite request language such as “could you help” is also excluded from claim modality checks while real possibilities remain hypothetical. Model overreach therefore reduces derived recall instead of failing ingestion availability.
-
Ollama structured extraction now defaults
reasoning_efforttonone, with an environment and typed-config override. This prevents thinking traces from exhausting the same context window needed for the validated response. Ollama also uses constrained JSON output, avoiding rejection of valid JSON that lacks a tool-call envelope. -
Built-in extraction now accepts source-grounded literal personal references such as
Iandwewithout requiring them to be named entities. Each unlisted reference receives one provenance-bound identity within its source event and cannot merge across messages; missing named entities and unsupported citations remain validation errors. Provider citations that differ only in straight or curly quote marks are canonicalized back to the exact source span. -
Recreate a loaded empty USearch index before its first new insertion, avoiding a reproducible native crash after deleting the last vector, closing, reopening, and storing another memory.
-
Make greedy consolidation clustering and source selection stable across equivalent histories with different generated UUIDs. Singular relational state questions use semantic answer-class relevance so generic subject words do not swamp the requested relation.
-
Make extractive consolidation publication durable and idempotent. Unchanged clusters reuse one summary; changed source snapshots atomically publish a new generation with its provenance edges and archive the predecessor. DuckDB journals and fences external index staging for restart and multi-engine recovery; PostgreSQL serializes concurrent publications through the generation head.
-
Keep unresolved personal references local to their source event during new ingestion. Historical prepared derivations retain their original replay policy.
-
Prevent organizer similarity matches from merging different claim text, validity or provenance; semantic entity aliases remain unverified links.
-
Initialize PostgreSQL vector columns and indexes against the selected table, without treating names in other schemas as an existing local installation.
-
Preserve relationship validity and provenance during organizer merges; failed copies keep the source active, and deterministic copy IDs make retries converge.
-
Publish organizer evidence unions, relationship copies, retirement and a single supersedence edge atomically, with a checksummed operation record and scoped, idempotent retries. Concurrent PostgreSQL merges lock shared nodes before reads.
0.11.0 - 2026-09-11
Added
- Tenant-scoped organizer execution through
organize(user_id=...)andprme organize --user-id, with cross-owner merge guards.
Benchmark measurement
- A registered exact-context ablation over all 37 development questions with one annotated source in the balanced bundle reduced the fixed reader from 29/37 to 7/37 correct. Twenty-three correct answers became wrong. The audit retained six redundant non-flips, seven noncuring reader errors, and one benchmark-reference inconsistency rather than converting them into negative memory labels.
- Preserve per-question evaluation failures in reports and retry selection.
- Report scored coverage and whole-benchmark failures; weight summary accuracy by measured questions and fail the CLI when any repeated run is incomplete.
- Propagate abstention-provider failures during evaluation instead of treating the application’s fallback as a measured verdict.
Fixed
-
Report the package version consistently in REST metadata and MCP resources.
-
Enforce node ownership for engine operations that accept node IDs.
-
Reapply scope, bi-temporal, and epistemic filters after late retrieval stages.
-
Serialize organizer SQL through the shared DuckDB connection lock.
-
Restore CI coverage for main, optional API/MCP dependencies, simulations, and live PostgreSQL tests on supported Python versions.
-
Disable redundant Tantivy background reader reloads so a closed lexical index cannot recreate metadata lock files during pack cleanup or movement.
-
Expand vector searches when tenant, scope, lifecycle, or temporal filters leave fewer than the requested number of distinct memory nodes.
Changed
- Schedule opportunistic organizer passes in the background and drain them on close.
- Pin dateparser language and gate temporal parsing to reduce retrieval overhead.
- Remove dataset observations, answer-revealing prompt examples, and benchmark-only query expansion from real-data evaluation.
- Replace stale accuracy headlines with a measurement contract and reviewed roadmap.
0.10.0 - 2026-07-15
Added
- Deterministic vector search +
prme rebuild(issue #45) — Reproducible vector retrieval and full reconstruction of derived indexes (vector, lexical) from the durable event/graph store viaprme rebuild - Multi-query reformulation (issue #43) — Opt-in retrieval mode that expands a query into multiple reformulations for broader candidate generation
Changed
- REST API hardening (issue #34) — Authentication, loopback-only bind by default, CORS restrictions, and error-message sanitization
- Encryption-at-rest lifecycle hardening (issue #37) — Tightened key handling and encrypt/decrypt lifecycle for memory pack files
- Stored memory neutralized in LLM context (issue #36) — Retrieved memory is delimited and neutralized before entering the LLM context to prevent prompt injection from stored content
- Ingestion index write path batched (issue #39) — Batched writes across the ingestion indexing path
- Retrieval hot path DB round-trips reduced — Fewer database round-trips on the retrieval hot path
- Benchmark measurement rigor (issue #44) — Pinned judge model, cached verdicts, and multi-run scoring for reproducible benchmark numbers
Fixed
- Bedrock provider extraction (issue #59) — Pass model through to
client.create()so the Bedrock provider works during extraction - Context formatter token budget + dedup (issue #42) — Enforce the token budget and deduplicate entries in the context formatter
- Index eviction on supersedence/archival (issue #41) — Evict superseded/archived content from the lexical and vector indexes
- Auto-promotion coverage (issue #40) — Auto-promote now reaches older eligible nodes, not just the newest batch
0.4.0 - 2026-03-16
Added
- Bi-temporal data model (issue #21) —
event_timefield distinguishes when something happened vs when system learned about it;knowledge_atparameter on retrieve() for point-in-time knowledge snapshots - Encryption at rest (issue #14) — Transparent Fernet (AES-128-CBC + HMAC) encryption of memory pack files; PBKDF2 key derivation; encrypt on close, decrypt on create
- Deduplication and entity alias resolution (issue #11) — Organizer jobs for vector-similarity-based duplicate detection (threshold 0.92) and alias resolution (threshold 0.85); merge logic with SUPERSEDES edges
- Evaluation harness (issue #16) — Precision@k, recall@k, nDCG@k, MRR metrics; ground truth support in simulation checkpoints; 3 evaluation scenarios (factual, temporal, supersedence)
- HTTP API layer (issue #17) — FastAPI REST API with endpoints for store, retrieve, organize, node operations, graph traversal, health, and stats
- CLI tooling (issue #15) —
prmecommand-line tool for memory inspection: info, nodes, edges, search, chain, organize, stats, export - Dual-stream ingestion (issue #25) —
ingest_fast()guaranteed sub-50ms path (event store + vector only); materialization queue for deferred graph writes - Memory quality self-assessment (issue #24) — Feedback signal tracking, gradient-free weight auto-tuning, per-namespace scoring profiles, quality metrics
- Procedural memory (issue #23) — INSTRUCTION node type for system instructions and procedural knowledge; Priority 0 packing into
system_instructionssection; epistemic inference support - Entity snapshot generation (issue #13) —
generate_entity_snapshot()produces structured entity state views from graph neighborhood;snapshot_generationorganizer job; simulation scenario - Predictive forgetting / consolidation (issue #22) — Semantic clustering of episodic memories; summary abstraction creation; redundant memory archival;
consolidateorganizer job - TTL-based archival (issue #12) —
ttl_daysfield on memory nodes; per-type default TTL configuration;tombstone_sweeporganizer job with operation logging; policy-based retention enforcement - Summarization pipeline (issue #10) — Hierarchical daily -> weekly -> monthly summarization; configurable thresholds; time-budget-aware processing;
summarizeorganizer job - Benchmark suite (issue #26) — LoCoMo long-conversation benchmark, LongMemEval 5-ability evaluation, custom epistemic benchmark (supersedence correctness, confidence calibration, contradiction detection, belief revision, abstention quality)
- Hybrid retrieval pipeline v2 — supersedence-aware scoring, lifecycle filtering (SUPERSEDED/ARCHIVED exclusion), query reformulation with LLM-generated alternative queries, session context expansion (top-20 with ±3 adjacent turns)
- Context formatter — temporal annotations (days-ago, COMPUTED offsets), chronological sorting for temporal queries, relevance-ranked formatting with date annotations
- Benchmark infrastructure — LLM-as-judge with configurable generation model, concurrent evaluation (semaphore-based throttling), resilient structured output for reasoning models
Fixed
- Integration test fixture (issue #18) — Added
examples/conftest.pywith engine/log fixtures - DuckDB segfault in concurrent tests (issue #19) — Isolated DuckDB connections per test with
conn_lockprotection - GeneratedAnswer schema resilient to reasoning models (gpt-5-mini) that embed answers in reasoning field
0.3.0 - 2026-03-08
Added
engine.reinforce()method — bumpsreinforcement_boost(+0.15, cap 0.5) andconfidence_base(+0.05, cap 0.95), updateslast_reinforced_at, appends evidence refs- Re-mention reinforcement in
store()— opt-in viareinforce_similarity_thresholdconfig; vector-searches for similar existing nodes and reinforces them automatically - Keyword-based supersedence detection in
store()— opt-in viaenable_store_supersedenceconfig;ContentContradictionDetectorwith 10 regex patterns for migration/replacement language - Oscillation detection for flip-flop supersedence patterns —
OscillationDetectorusing Jaccard keyword similarity on supersedence chains; applies confidence penalty (0.1 per cycle, cap 0.3) update_node()method onGraphStoreprotocol and all implementations (DuckPGQ, PostgreSQL) for field-level node updates- Ranking assertions in simulation harness (
SimCheckpoint.ranking_assertions) - Lifecycle assertions in simulation harness (
SimCheckpoint.lifecycle_assertions) - Deterministic rebuild verification (
SimulationRunner.run_deterministic_check()) - Surprise-gated storage — opt-in via
enable_surprise_gatingconfig;NoveltyScorercomputes novelty of incoming content against existing memory, boosting salience for novel content and penalizing redundant content - Four new simulation scenarios:
reinforcement,remention,oscillation,surprise_gating
Fixed
promotion_evidence_countdefault aligned withstore()behavior (default 1, matching the single evidence ref created per node)
Changed
store()pipeline now has 6 steps: event persistence, graph node creation, vector/lexical indexing, re-mention reinforcement (opt-in), supersedence + oscillation detection (opt-in), surprise gating (opt-in)
0.2.0 - 2026-02-27
Added
- Self-organizing memory system (RFC-0015) with virtual decay, maintenance runner, and organizer jobs
- Simulation harness for validating memory behavior without LLM dependencies
- Decay mechanics: exponential salience/confidence decay with per-type decay profiles
- Organizer jobs: promote, decay_sweep, archive, feedback_apply (plus stubs for future jobs)
- Opportunistic maintenance during retrieve/ingest operations
- Three simulation scenarios:
changing_facts,decay_mechanics,information_accumulation
0.1.0 - 2026-02-19
Added
- Append-only event store (DuckDB)
- Graph-based relational model with typed nodes and edges
- Vector index (usearch HNSW) with fastembed embeddings
- Lexical full-text search (Tantivy)
- Hybrid retrieval pipeline with deterministic scoring and context packing
- Epistemic state model with lifecycle transitions and confidence tracking
- LLM-powered ingestion pipeline (OpenAI, Anthropic, Ollama)
- Entity merge and supersedence handling
- Namespace and scope isolation
- Optional PostgreSQL backend
- Terminal chat example with persistent memory
- Quickstart example
Source: CHANGELOG.md in PRME at 58caddb1.