ConceptioArchivearXiv CS
arXiv CSopen access

AMP: A Vendor-Neutral Wire Format for Agent Memory Operations

Unknown · 2026 · arxiv_cs
arXiv CS · Papers · License: Open Access · 2026
Open Source ↗Direct PDF ↓
cryptography, security, privacy, cybersecurity

memorywire: A Vendor-Neutral Wire Format for Agent Memory Operations Thamilvendhan Munirathinam∗ Independent Researcher

arXiv:2606.01138v1 [cs.CR] 31 May 2026

Repository: https://github.com/mthamil107/memorywire

Protocol rather than compete with it.

Abstract

Agent-memory frameworks — mem0, Letta/MemGPT, Cognee, Zep/Graphiti, MemoryOS, 1 Introduction MemTensor — each ship their own SDK, storage layout, and operational vocabulary. There is no 1.1 The problem: islanded memory frameworks shared wire format: every integration is bespoke, every migration rebuilds memory from scratch, and Agent runtimes that maintain memory across sesno framework ships a governance surface that lets sions are now a category. Open-source frameworks a human review writes before they enter long-term include mem0, Letta (formerly MemGPT), Cognee, storage. We present memorywire1 , a JSON-Schema Zep/Graphiti, MemoryOS, and MemTensor MemOS; 2020-12 wire format for five memory operations closed commercial offerings include Oracle’s AI Agent (remember, recall, forget, merge, expire) over Memory and the memory layers shipped inside major four memory types (semantic, episodic, procedural, hosted-agent platforms. What the category has not emotional), with a MemoryStore interface, a fan-out produced is a shared wire format. Each framework router, and an optional HITL governance channel. defines its own SDK surface, JSON shape for memory We describe an open-source reference implementation records, embedding-provider integration, taxonomy with five backend adapters (sqlite-vec, mem0, Letta, (or absence of taxonomy) for memory types, and imCognee, pgvector); a microbenchmark on a 100-fact / plicit lifecycle for record creation and deletion. The 50-query labelled corpus achieving recall@5 = 1.000 heterogeneity is non-trivial to bridge: mem0 stores on the 42 labelled queries with ingest p50 = 37.8 ms records under a memories[] list keyed by user_id and recall p50 = 40.6 ms; an adversarial-fusion with a heterogeneous created_at representation; experiment showing Reciprocal Rank Fusion holds Letta stores archival memory keyed by agent_id and recall@5 = 1.000 across a 1-of-N rank-0 injection exposes a tags list as the only structured-metadata sweep (K ∈ {0, 5, . . . , 50}) where max fusion collapses sink; Cognee mints internal data_id UUIDs that are to 0.500 with 80% leak at K ≥ 5; and a 16-scenario not surfaced through its public add API, making percross-adapter conformance suite passing 68 of 80 record deletion impossible from outside the pipeline; cells with zero failures. The contribution is not sqlite-vec stores tables keyed by a stable ULIDa new algorithm; it is a packaging of established shaped string; pgvector exposes records through an components (RRF, FSMs, STM/LTM consolidation, application-chosen SQL schema. Re-platforming an diff-and-approve workflows) into a venue-neutral agent from one framework to another therefore reprotocol with an empirically validated reference, quires a bespoke migrator and field-level losses where positioned to compose with the Model Context the source framework encodes more state than the target’s data model holds. The same heterogeneity means there is no shared governance surface. Each framework provides a write API and a read API; none mediate the write with a “diff against current state, present to a human, commit only on approval” workflow. The Co-memorize

[email protected] Originally drafted as “Agent Memory Protocol (AMP)” in May 2026; renamed to memorywire before launch to avoid collision with an unrelated, prior project of the same name (https://github.com/akshayaggarwal99/amp, created Dec 2025). See docs/PRIOR-WORK.md in the repository for the long version. 1

1

human-in-the-loop pattern, formalized in the Govlabelled queries against a real sentence-transformer erned Memory line of work [9], has no production embedder, (b) an adversarial-fusion experiment implementation an off-the-shelf agent can drop in. that sweeps a 1-of-N rank-0 injection attack across Operators who want auditability over what enters three fusion algorithms (RRF, MAX, weighted), long-term memory must build it themselves and acand (c) a cross-adapter conformance suite of 16 cept that the framework can bypass them. protocol-invariant scenarios run against all five This is the gap memorywire addresses. It is not “we shipped adapters (68 PASS / 12 SKIP / 0 FAIL need a better retrieval algorithm” — the algorithms out of 80 cells). in the category (vector search, hybrid lexical-semantic RRF fusion, graph hop boosts, FSM-encoded proce- • C5. A six-adversary threat model with linedures, STM/LTM consolidation) are well understood. level mitigation citations into the reference It is “we need a shared protocol so any client can implementation, plus an open-data artifact talk to any backend, any agent can carry its memory (docs/adversarial-results.{rrf,max,weighted}.json, across runtimes, and any write can be diffed and apthe labelled microbench corpus, the conformance proved.” Structurally it is the gap MCP closed for scenario list) sufficient to reproduce every empirical tool use, applied to memory. claim without re-running paid evaluators.

1.2

Contributions

1.3

Limitations, front-loaded

This paper makes five contributions:

We state up front what this paper is not. It is not a new algorithm: RRF is from Cormack et al. [2], the four-type taxonomy is from Tulving [10] and Squire [8], procedural FSMs use pytransitions, and STM/LTM consolidation predates the frameworks we cite — the contribution is composition and standardization, not new substrate. It is not an LLM contribution: we do not train models or propose model-dependent heuristics, and we report only pre• C2. A reference implementation in Python 3.11+ liminary LongMemEval [11] and LoCoMo [4] numbers with five production-backend adapters (sqlite-vec, (Section 5.5); the full 5-seed × 200-question run and mem0, Letta, Cognee, pgvector), all implementing BEAM are v2 replacement deliverables (Section 8). a single MemoryStore Protocol. The reference in- And it is not a stabilization paper: memorywire v0 cludes a memory router that fans operations across reserves the right to break wire-format compatibility N stores in parallel and fuses recall results via Re- through v0.5 (Section 3.7); the IETF Internet-Draft ciprocal Rank Fusion (k = 60) [2] with an optional and MCP-WG extension paths in Section 2 and Secone-hop graph boost, plus a tolerant partial-failure tion 8 are intent, not commitment. • C1. A wire format for five memory operations over four memory types, expressed as JSON Schema 2020-12 [3] (docs/spec/v0.md). The operations are remember, recall, forget, merge, expire; the types are semantic, episodic, procedural, emotional. The schemas are vendor-neutral, transport-agnostic, and explicitly versioned with a breaking-change policy through v0.5.

model where a single rogue or unavailable backend cannot crash the operation. 1.4 Paper roadmap • C3. A governance UI implementing the Section 2 places memorywire against prior work in Co-memorize diff-and-approve pattern over agent memory frameworks, cross-vendor protocols remember, forget, and merge. Writes flagged (particularly MCP), and the Governed Memory line. approval_required are staged behind a Section 3 specifies the wire format: operations, types, PENDING_APPROVAL_DELETED_AT = -1 sentinel the MemoryStore Protocol, router semantics, and and remain invisible to recall until a reviewer the governance channel. Section 4 describes the refcommits or rejects them through the UI. The erence implementation including the five backend same audit log is the single source of truth for all adapters, the procedural-memory FSM backend, the governance and mutation events. STM↔LTM transformer, and the governance UI. Sec• C4. An empirical evaluation comprising (a) a mi- tion 5 reports the empirical evaluation. Section 6 is crobenchmark on 100 hand-authored facts × 50 the threat model. Section 7 details the relationship 2

to MCP. Section 8 and Section 9 lay out future work flatten into opaque tools, the type taxonomy coland the bet we are making. lapses into a string parameter, and the governance channel sits entirely outside MCP. We discuss the memorywire–MCP relationship at length in Section 7; 2 Background and Related Work the short version is that memorywire is what MCP would be if MCP had a memory primitive, built as 2.1 Memory in LLM agents a standalone spec so the design can stabilize withThe first wave of LLM-agent frameworks treated out blocking on MCP-WG governance, with intent memory as a side-effect of the conversation log; the to propose it as an MCP extension at v0.5. The next externalized it into a vector store (“RAG over standalone-first, propose-upstream-later pattern folyour own logs”); the current wave, beginning roughly lows Cloudflare’s Web Bot Auth precedent [5]. with MemGPT [7] and continuing through mem0 [1], Cognee, Zep/Graphiti, MemoryOS, and MemTen- 2.3 Reciprocal Rank Fusion sor, separates memory into named tiers (short-term working, long-term semantic, episodic, procedural) The memory router’s default fusion algorithm is Rewith explicit lifecycle operations (consolidate, expire, ciprocal Rank Fusion (RRF) from Cormack, Clarke, and Buettcher [2], who showed that RRF outperforms merge). The frameworks differ in which tiers they empha- Condorcet and individual rank-learning methods on size. MemGPT/Letta exposes a hierarchical “core TREC tasks. The formula is X memory” + “archival memory” model with explicit 1 score(d) = core_memory_append / archival_memory_insert k + ri (d) i∈S tools. Mem0 emphasizes user-scoped facts with an internal LLM-assisted dedupe pass. Cognee constructs where S is the set of ranked lists, ri (d) is the rank of a knowledge graph and exposes traversal as the pri- document d in list i, and k is a smoothing constant mary recall primitive. Zep/Graphiti adds temporal (60 in the original paper; memorywire uses the same edges over a graph. MemoryOS positions itself as value as a sensible default). RRF has two properties an OS-shaped memory layer; MemTensor MemOS that matter for our setting: (a) it is score-independent extends this with multi-tenant scoping. — the input lists’ raw scores do not enter the fusion, None of these frameworks publishes a wire format only their ranks do; (b) it is additive across stores — that another framework adopts. The closest thing to the contribution of an item to the fused score is the a shared shape is mem0’s request structure, informally sum of its per-list contributions. These two properties copied by smaller projects, but mem0’s API is the together give RRF a robustness against rogue stores surface of one library, not a specification — it can that score-sensitive fusion methods do not have. We change between releases. exploit this in Section 5.2.

2.2

Cross-vendor protocols: MCP as tem- 2.4 plate

Human-memory taxonomy

memorywire’s four memory types — semantic, The Model Context Protocol [6] is the most successful episodic, procedural, emotional — are drawn recent cross-vendor protocol in the agent space. MCP from the human-memory taxonomy in cognitiveis a JSON-RPC protocol over stdio or HTTP stan- science literature. Tulving [10] introduced the sedardizing how an agent runtime exchanges context mantic / episodic distinction; Squire [8] elaborated with a server process; its public surface is five primi- the declarative / nondeclarative hierarchy in which tives — tools, resources, prompts, sampling, and root- procedural memory sits as a nondeclarative subtype. s/elicitation — and it has been adopted by Anthropic, The emotional type is included as a first-class tag OpenAI, Google’s Gemini ecosystem, Cloudflare, and rather than buried in metadata because affective assomany smaller server implementations. ciations are operationally distinct in agent workflows MCP does not define a memory primitive. A back- (they often trigger or suppress specific tools) and beend can be wrapped in MCP — exposing remember cause the alternative — encoding them as semantic / recall / forget as three tools is a fifteen-minute facts with a sentiment field — collapses the distinction integration — but the wrapping is lossy: operations at the wire-format layer where it matters most. 3

We do not claim that the four-type taxonomy is the correct one in any deep sense. We claim only that it is the taxonomy most often referenced by the existing memory frameworks (Letta, MemoryOS, MemTensor all cite Tulving/Squire) and that pinning it at the wire-format layer is more useful than leaving the choice to each backend.

2.5

src/memorywire/schemas/operations/. Validation runs at the boundary; backends accept already-parsed pydantic models that mirror the schemas exactly. The schemas are the source of truth, the models are the convenience layer. Stateless. Each operation request carries the agent_id (and optional user_id) it operates under; the router does not keep per-session state. This is what makes the protocol portable across transports — REST today, JSON-RPC tomorrow, any future crosslanguage port without redesigning the wire format. Async-first. The MemoryStore Protocol’s methods are async def. The router uses asyncio.gather with return_exceptions=True for fan-out, so perstore failures do not cascade. Sync convenience wrappers are layered above through asgiref for callers who want them; the canonical path is async.

Human-in-the-loop approval for agent actions

The governance channel in memorywire implements the Co-memorize diff-and-approve pattern formalized in the Governed Memory line of work [9]. The pattern is: when an agent proposes to write a memory, the system computes a structured diff between the proposed write and the current state, presents the diff to a human reviewer, and commits the write only on approval. The pattern generalizes to any state mu- 3.2 Operations tation; memorywire applies it to remember, forget, Each operation has a request schema and and merge, and excludes recall and expire from a response schema. We summarize the the default approval surface (with recall flagged for request side here; full schemas live in v0.2 reconsideration; see Section 6). src/memorywire/schemas/operations/ and The Co-memorize pattern is not novel to worked examples in docs/spec/examples/. this paper. What is new is its standardremember writes a new memory. Required: ization at the wire-format layer: memorywire agent_id, type (one of four type tags), content. defines a governance JSON schema for the Optional: user_id, metadata (free-form JSON), diff-and-approve message and ships a reference confidence (float in [0, 1], default 1.0), source, UI that any backend adapter inherits transparexpires_at (Unix epoch ms), approval_required ently. An agent calling remember(content="...", (bool, default false). type is pinned at write time so approval_required=true) gets the governance flow the router can route procedural writes to the FSM regardless of which of the five backends actually stores backend; confidence is first-class because every surthe row. veyed framework either has a confidence equivalent or asks for one. recall reads memories. Required: agent_id, 3 The memorywire Wire Format query. Optional: k (1–1000, default 5), types (filter subset), hops (0–3, default 0), 3.1 Design goals fusion (rrf/max/weighted, default rrf), filter, Four explicit goals shaped the v0 surface. fresher_than_days. fusion is exposed because the Small surface. Five operations, four types, one right choice depends on the operator’s trust model optional governance channel. The operations are the (see Section 5.2). smallest set we found that cover every workflow exhibforget deletes memories. Required: agent_id, ited by the surveyed frameworks: remember (write), plus at least one of ids or filter (the spec rejects recall (read), forget (delete), merge (deduplicate), requests with neither — no-scope-mass-delete protecexpire (apply a TTL policy). Adding more opera- tion). Optional: hard_delete (bool, default false), tions is straightforward; we resisted doing so in v0 reason. Default soft delete preserves the audit trail; because every new operation is a new schema to keep hard delete is available for GDPR takedowns. stable through the v1.0 freeze. merge collapses duplicates. Required: Schema-pinned. Every operation agent_id, canonical, duplicates. Ophas a JSON Schema 2020-12 file in tional: strategy (one of keep_canonical / 4

Table 1: The four memorywire memory types with example content. Type

Definition / Example

semantic

Declarative facts. “Alice is allergic to peanuts” Past events with time/place. “On 202605-20 Alice told me she was nervous about her flight” How-to / FSM-encoded procedures. State machine for “book a flight” Affective associations. “Alice expressed anxiety when discussing flights”

episodic

async def merge(self, req: MergeRequest) -> MergeResponse: ... async def expire(self, req: ExpireRequest) -> ExpireResponse: ... async def health(self) -> dict[str, Any]: ... @property def capabilities(self) -> set[str]: ...

capabilities declares the optional surface a backend supports — e.g. {"semantic", "episodic", "vector", "fts", "graph", "procedural", procedural The router consults "recall_tracking"}. emotional capabilities to skip stores that do not support a given operation. This is what lets a single router compose a vector-only adapter with a graph-only adapter without the caller needing to merge_content / keep_highest_confidence, deknow which fields each backend honors. fault keep_canonical). Pinning the strategies at the wire-format layer means portable agent code does not need to know which framework’s internal 3.5 The memory router dedupe will fire. The router (src/memorywire/router.py) is itself a expire applies a TTL policy. Required: agent_id. MemoryStore. It is constructed over N child stores Optional: policy (ANDed older_than_days, and fans each operation across them. For remember, type, confidence_below, no_recall_in_days pred- the default policy is fan_out: write to every child icates) and action (forget/archive/demote, de- store. For recall, every store is queried in parallel fault forget). Every framework has some notion of and the results are fused. For forget, merge, expire, “delete old episodics” or “down-rank cold facts,” each fan-out aggregates per-store responses with per-store expressed differently; memorywire pins the predicate errors preserved. DSL and action vocabulary. Fusion math. Three fusion algorithms are exposed:

3.3

Memory types

• RRF (default). Per the formula in Section 2.3, with k = 60: X 1 score(d) = 60 + ri (d)

The four memory types are drawn from Section 2 above. Their definitions in memorywire v0 are summarized in Table 1. Backends may store all four types in a single table with a type column or shard by type. The wire format does not constrain storage strategy; it does require that the type tag round-trips through remember → recall losslessly.

i∈S

The item’s own per-list score is ignored; only its rank in each list contributes (src/memorywire/router.py:415–444).

• MAX. score(d) = maxi∈S si (d) where si (d) is the 3.4 The MemoryStore Protocol and caparaw score in list i. Score-sensitive. bility declarations P • WEIGHTED. score(d) = i∈S wi ·si (d) with perA backend adopts memorywire by implementing the store weights wi from router config. Score-sensitive. MemoryStore Protocol (Python; the same shape ports Graph-hop boost. When a recall request sets trivially to other languages): hops > 0 and at least one child store declares graph class MemoryStore(Protocol): async def remember(self, req: RememberRequest) -> capability, the router applies a multiplicative boost to fused items whose neighbours are also in the fused RememberResponse: ... async def recall(self, req: RecallRequest) -> set: RecallResponse: ...   0.1 async def forget(self, req: ForgetRequest) -> final(d) = rrf(d) · 1 + ForgetResponse: ... 1 + hop_dist(d) 5

The boost only fires for items already in the fused set; new neighbours are not introduced (per src/memorywire/router.py:482–501). This avoids amplifying a malicious graph store’s ability to inject content (see Section 6.3). Partial-failure model. Fan-out uses asyncio.gather(..., return_exceptions=True) (src/memorywire/router.py:261–264, 353–356). A backend that throws or times out is logged but does not abort the operation; the router proceeds with results from the surviving stores. This is what makes a five-adapter router tolerant in practice — a transient mem0 outage does not blank the recall.

3.6

pose adoption as an MCP extension (mcp.memory.v0 or similar; see Section 7). Both outcomes are acceptable; neither is committed.

4

Reference Implementation

The reference implementation lives in src/memorywire/ (the SDK and adapters) and ui/ (the governance UI). It is Python 3.11+, Apache-2.0 licensed for the protocol and reference; the Pro UI ships under the Fair Source License (FSL). Non-test source totals roughly 15k lines of Python (8.4k in src/memorywire/, 2.4k in ui/src/, 4.2k in scripts/) plus the JSON-Schema files and the HTMX templates, with another 10k lines of test code under tests/.

The governance channel

When the host wires in a GovernanceClient, remember / forget / merge operations carrying approval_required: true (or matching a policy 4.1 Architecture overview rule) are routed through governance before commit. The full runtime is shown in Figure 1. A client The governance review request is a JSON object car- (the amp.Memory SDK or the amp CLI) issues one rying operation (one of remember/forget/merge), of the five spec operations against the Memory faagent_id, the original request, a structured diff cade (src/memorywire/api.py), which validates the against current state, and an optional reasoning request against the operation’s JSON Schema and delstring. The governance response carries approved egates to the MemoryRouter. The router fans the op(bool), reviewer (identity), reviewed_at (Unix eration across the configured backend adapters in parepoch ms), and an optional reason. The reference allel; for recall it fuses the per-store result sets via UI layers an opt-in approval-learning loop on top: RRF (k = 60) with an optional one-hop graph boost. track which patterns the reviewer always approves / Five adapters ship out of the box: sqlite-vec, mem0, rejects and auto-allow after N consistent decisions, Letta, Cognee, pgvector. Procedural memory takes with every fired decision still journaled to the audit a side path: type=procedural writes are normalized log. into a pytransitions-compatible FSM blob and perExcluding recall from the default governance sur- sisted via sqlite-vec. The STM↔LTM transformer face is a v0 trade-off. Recall budgets and read-side is an async background task that scores short-term approval are tracked for v0.2 (Section 8); until then, items and promotes or evicts them through the router. the audit log captures every recall call (operation An optional governance plane (UI + append-only au= ’recall’) so high-rate exfiltration is observable dit log) intercepts writes that require human review post-hoc, if not preventable. and shares the SQLite database with the sqlite-vec adapter so reviewers can diff a pending write against 3.7 Spec versioning and backwards- the live state without a separate sync channel.

compatibility rules 4.2

The five backend adapters

memorywire v0 is a draft. Breaking changes are allowed through v0.5; v0.5 stabilizes; v1.0 freezes. Table 2 summarizes the five shipped adapters, the The rules are: new optional fields are allowed at capabilities each declares, and the memorywire fields any time; new required fields require a minor ver- each can losslessly round-trip versus the fields each sion bump with a deprecation period; removed fields encodes as backend metadata. “Native” means the require a major version bump only; new memory field is stored in a first-class column or property of types require a minor version bump. The intent is to the backend’s data model; “encoded” means the field publish memorywire v0.5 as an IETF Internet-Draft is round-tripped through a backend metadata sink (draft-<name>-memorywire-00) and, in parallel, pro- (e.g. Letta’s tags list, mem0’s metadata dict). 6

Table 2: Backend adapters and their fidelity against the memorywire wire format. Adapter

URL scheme

Capabilities confidence

source

expires_at

Metadata

sqlite-vec

sqlite-vec://

native

native

native (JSON)

mem0

mem0://

encoded

encoded

native (lossless)

Letta

letta://

encoded (tags)

encoded (tags)

lossy (flat KV)

Cognee

cognee://

encoded

encoded

lossy (graph attrs)

pgvector

pgvector://

semantic, native episodic, procedural, emotional, vector, fts, recall_tracking semantic, encoded episodic, vector semantic, encoded (tags) episodic, vector semantic, encoded episodic, vector, graph semantic, native episodic, procedural, emotional, vector, recall_tracking, governance

native

native

native (JSONB)

The two adapters with full lossless fidelity (sqlite- transitions, current, metadata — so backends vec, pgvector) are the SQL-backed ones; they own may extend it with their own state-machine semantics; their schema and can add the columns memorywire v0 deliberately does not standardize action handlers. needs. pgvector ships every memory type plus recallIn v0 the FSM JSON is carried as a string tracking and the governance sentinel; sqlite-vec adds inside RememberRequest.content; promoting FTS5 keyword indexing on top of the vector path. it to a structured typed field is tracked for The three SDK-wrapping adapters (mem0, Letta, v0.2. The FSM backend wraps pytransitions Cognee) inherit whatever fidelity their upstream offers with a strict-validation layer that allow-lists and back-fill the rest through metadata encoding. transition keys to {trigger, source, dest, The conformance suite in Section 5.3 quantifies what conditions, unless} and rejects before / after each adapter can and cannot do. / prepare — the three pytransitions keys that

4.3

resolve dotted-string callbacks via __import__ and would otherwise enable RCE at trigger time (src/memorywire/procedural.py:44–59). conditions and unless strings are restricted to bare identifiers (no .) so they resolve only to attributes on a private _ProcedureModel. The sandbox is enforced at two layers: validation at parse time and key-stripping at construction time.

The FSM procedural-memory backend

Procedural memory in memorywire is stored as a JSON-serialized finite-state machine compatible with the pytransitions library. The shape is intentionally minimal — name, initial, states, 7

shares the sqlite-vec adapter’s SQLite database, so a reviewer sees pending writes as rows with the PENDING_APPROVAL_DELETED_AT = -1 sentinel in deleted_at and a pending: yes badge in the UI. Reviewers can approve (clear the sentinel; the row becomes live), reject (hard-delete or soft-delete depending on the policy), or apply a Co-memorize transformation — typically a merge against an existing canonical row or a forget of a similar row that the new write supersedes. Authentication is opt-in via the Figure 1: memorywire architecture. A client (SDK MEMORYWIRE_UI_TOKEN environment variable. or CLI) issues one of the five spec operations against When set, every request requires either an the Memory facade, which validates the request and Authorization: Bearer <token> header or an delegates to the MemoryRouter. The router fans out memorywire_ui_session cookie; comparison uses across heterogeneous backend adapters (sqlite-vec, hmac.compare_digest for constant-time matching. mem0, Letta, Cognee, pgvector) and fuses recall re- CSRF is enforced through a double-submit-cookie sults with Reciprocal Rank Fusion (k = 60) plus pattern signed with HMAC-SHA256 over nonce.ts an optional one-hop graph boost. Procedural writes with a 24-hour TTL. Without MEMORYWIRE_UI_TOKEN take a parallel FSM path. The STM↔LTM trans- the UI is unauthenticated; binding a non-loopback former runs as an async background task. An optional host without a token fires a stderr warning on boot governance plane (UI + append-only audit log) inter- (ui/src/memorywire_ui/middleware.py:55–66). cepts writes that require human review and shares The UI’s full authorization model is one global the SQLite database with the sqlite-vec adapter. bearer token; per-agent_id ACLs are tracked for v0.2 (Section 8). Per-row authorization is enforced at the SQL layer: every state-changing han4.4 The STM↔LTM transformer dler runs against WHERE id = ? AND agent_id = Short-term memory in memorywire is the most recent ? AND deleted_at = ? with the sentinel value, so N items per (agent_id, user_id) window; long- an attacker who guesses a row id but does not control term memory is everything else. The transformer the matching agent_id cannot pivot across tenants is an always-on async background task that runs (Section 6.5). on an interval (default 60 s) and, for each window, scores STM items along recency, salience (frequencyof-mention), and confidence axes, promotes top items 5 Evaluation into LTM with a type=semantic write, and evicts cold items. It does not block the request path; it The evaluation has three parts. Section 5.1 reports consumes from the same Memory facade the agent a microbenchmark on a labelled corpus to estabuses, so promoted items appear in subsequent recall lish baseline recall and latency. Section 5.2 reports an adversarial-fusion experiment that quantifies the calls without additional plumbing. The transformer is deliberately simple. The point robustness premium RRF provides over MAX and is not to invent a new consolidation algorithm but to weighted fusion under a 1-of-N rank-0 injection atshow that the wire format can carry consolidation as a tack. Section 5.3 reports a cross-adapter conformance sequence of standard operations rather than a vendor- suite that empirically validates the protocol’s vendorspecific tier-promotion API. A more sophisticated neutrality claim. Section 5.4 enumerates threats to consolidator drops in as a plugin without changing validity. the wire format.

5.1 4.5

The governance UI

Microbenchmark

Methodology. The corpus is 100 hand-authored The governance UI (ui/src/memorywire_ui/) is a facts spread across roughly 10 distinct users, mixStarlette server with HTMX-driven templates. It ing all four memory types in proportions chosen 8

Table 3: Microbenchmark results. n = 50 queries, remember SLA target (50 ms) but not by an order of k = 5, corpus size = 100 facts, embedder = magnitude. all-MiniLM-L6-v2, backend = sqlite-vec :memory:. Honest framing. This is a microbenchmark, not LongMemEval, LoCoMo, or BEAM. The handMetric Valueauthored corpus is small enough that FTS5 keyword Recall@5 mean (labelled queries) 1.000matching alone would surface many of the gold ids, Precision@5 mean 0.214and the dataset rewards systems that combine seIngest latency p50 / p95 / p99 37.8 / 46.0 / 69.1 msmantic embeddings with keyword recall — which is Recall latency p50 / p95 / p99 40.6 / 46.6 / 55.7 msexactly what memorywire’s intra-store RRF does. At No-match probes correctly empty 0 / 8100 facts the ANN path is doing a brute-force vec0 Total benchmark runtime ∼5.9 s scan, not an HNSW workload. The 0/8 “no-match correctly empty” number reflects a deliberate v0 design choice: recall(k=5) always returns up to k hits to mirror the distribution we observed across the because v0 ships no calibrated relevance-threshold surveyed frameworks’ default workloads (skewed secutoff; that knob is tracked for v0.2. Preliminary mantic, with episodic, procedural, and emotional LongMemEval and LoCoMo numbers under a real in long tail). Fifty hand-authored queries carry ex(gpt-4o-mini) grader appear in Section 5.5; the full plicit gold-id labels, distributed as 24 paraphrase 5-seed × 200-question paper-grade run is a v2 replacequeries (e.g. “what foods should I avoid serving Alment deliverable. ice?” mapping to “Alice is allergic to peanuts and tree nuts”), 10 exact / near-exact match queries, 8 multi-hit queries with two or three gold ids, and 8 5.2 Adversarial fusion experiment no-match probes whose gold-id list is empty. The This is the experiment that makes the security claim 8 no-match probes are included specifically to mea- in Section 6.3 quantitative. The threat is a “1-ofsure how often the system surfaces a confident wrong N malicious backend”: one of the N child stores answer when nothing actually matches. Embed- under the router has been compromised, is a malicious der: sentence-transformers/all-MiniLM-L6-v2 adapter fork, or sits behind a MITM that rewrites its (384-dim) on CPU; the first call’s model-load cost is responses. The attack is rank-0 injection: the rogue excluded from per-call latency through a warm-up call. store returns K attacker-controlled ids (disjoint from Backend: a single SqliteVecStore(":memory:") the gold corpus) at the top of its result list and is exercising the full intra-store RRF fusion of otherwise quiet. The question is how much each vec0 ANN and FTS5 keyword search. Dataset fusion algorithm lets the rogue store move the fused and runner: tests/benchmarks/dataset.py and output. scripts/run_microbench.py. The full benchmark Methodology. Three child stores: two benign is reproducible with a single command and runs in + one adversarial. Each benign store returns each roughly six seconds. query’s gold ids at the top ranks with an indepenResults. Numbers measured on 2026-05-27, Win- dent random distractor tail (different distractor dows 11 AMD64, Python 3.13.13, CPU-only inference. permutations across benign stores, simulating Results are in Table 3. different embedders / indexes). The adversarial The headline number — recall@5 = 1.000 on the store returns K attacker-controlled ids (a*** 42 labelled queries — means every paraphrase, exact- prefix, disjoint from the gold corpus) at ranks 0 match, and multi-hit query surfaced all its gold ids in to K − 1 then optionally a benign tail so it still the top 5 results. The precision number is bounded “looks normal” past rank K. The query suite is by the ratio of gold ids per query: most queries have 20 queries, each with two gold ids drawn without a single gold id (which pins precision@5 at 1/5 = 0.2), replacement from a synthetic corpus of 50 memoand a minority of multi-hit queries lift the mean above ries. For K ∈ {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50} that floor — the reported mean of 0.214 is consistent the script issues every query through a real with that mix and is not a bug. Recall latency p50 MemoryRouter.recall(k=5) and records recall@5 (40.6 ms) is roughly an order of magnitude below the against the gold set, adversarial leak rate (fraction of spec’s two-store fused recall SLA target (300 ms); returned ids that are attacker-controlled), and goldingest latency p50 (37.8 ms) is comfortably below the displacement rate (fraction of gold ids in the K = 0 9

Table 4: Adversarial fusion sweep. N = 3 backends (2 benign + 1 adversarial), corpus M = 50, Q = 20 queries, k = 5, seed 1337. K is the attacker budget; recall@5 is against the gold set; leak is the fraction of returned ids that are attacker-controlled. K

R@5 RRF

leak RRF

R@5 MAX

leak MAX

0 5 10 25 50

1.000 1.000 1.000 1.000 1.000

0.000 0.000 0.000 0.000 0.000

1.000 0.500 0.500 0.500 0.500

0.000 0.800 0.800 0.800 0.800

the adversary has full knowledge of the router’s k · 4 over-fetch and fills exactly that block, so a blackbox attacker would do worse; (c) only the 1-of-N case is swept by default — once n_adversarial >= n_benign the RRF consensus argument fails. The MAX result is not a negative finding about MAX in R@5 W. MAX leak W. general; is the right choice when the operator’s trust model says 1.000 0.000the highest-scoring store is the most authoritative. The result is a finding about MAX in 1.000 0.000 0.000 the1.000 malicious-backend model, which is the threat we 1.000 0.000 evaluate. 1.000

5.3

0.000

Cross-adapter conformance

baseline top-5 that were pushed out). The same The cross-adapter conformance suite is the empirsweep is run for fusion="rrf", fusion="max", and ical evidence for the protocol’s vendor-neutrality fusion="weighted". Seed is fixed at 1337 for repro- claim. Sixteen scenarios run against every shipped ducibility. Runner: scripts/run_adversarial.py. adapter; the scenarios encode protocol invariants Machine-readable outputs: that any compliant MemoryStore MUST satisfy. docs/adversarial-results.{rrf,max,weighted}.json. Each scenario is a ProtocolScenario dataclass Results. Numbers measured 2026-05-27 with the (tests/conformance/scenarios.py) with a deterdefault config; see Table 4. ministic setup, an action, and a predicate; the runner The RRF curve stays flat at the no-attack baseline parametrizes the list across every adapter id and across the entire sweep. The MAX curve collapses skips scenarios whose required_capabilities are immediately at K = 5 and stays collapsed: recall@5 not satisfied by the candidate store. halves to 0.500, and 80% of returned ids are attackerTable 5 summarizes the 16 scenarios × 5 adapters = controlled. The weighted result with equal per-store 80 cells. ✓= passes; □ = SKIPPED for a documented weights is identical to RRF. adapter limitation; × = fails. Aggregate: PASS 68 Why RRF is robust here. The mechanism is / SKIP 12 / FAIL 0. exactly the score-independence and additivity propEvery non-skipped cell passes; zero scenarios fail erties from Section 2.3. Under RRF, the consensus on any adapter. of two benign rank-0 votes for a gold id contributes Per-adapter analysis. The two SQL-backed 1/60 + 1/61 ≈ 0.0330 to the fused score. A sin- adapters (sqlite-vec, pgvector) clear the entire suite — gle rogue rank-0 vote for an attacker id contributes these are the adapters whose data models memorywire 1/60 ≈ 0.0167. The benign consensus provably out- directly designed against, so it would be surprising points the rogue vote regardless of what raw score if they did not. The three SDK-wrapping adapters the rogue store reports — because RRF ignores the (mem0, Letta, Cognee) each skip a documented set raw score. Under MAX the same rogue vote can tie of scenarios. or beat the benign rank-0 raw score (the rogue store Spec ambiguities surfaced. The 12 SKIP cells is free to report any score it wants), pull 4 of 5 fused are not random; they cluster into three classes, and top-5 slots, and halve recall. Under weighted fusion each class is a v0.2 spec-tightening signal. with equal per-store weights the math degenerates close to RRF for this attack shape. • No user_id namespace. Letta and Cognee skip Operating point and caveats. The defensible remember_recall_by_user_filter because neiclaim is “RRF tolerates an arbitrarily large 1-of-N ther backend has a user_id namespace separate rank-0 injection as long as the majority of backends from its top-level scope (Letta scopes by agent_id; are benign and agree on the gold set,” not “RRF Cognee by dataset). memorywire’s user_id dimentolerates K up to some specific number.” The experision is lost on these backends. The v0.2 spec should ment isolates the fusion-math property and assumes either require user_id support for full conformance (a) benign stores are perfect by construction — alor define an explicit “scoped-by-agent-only” fallways return gold at top, modulo distractor tail; (b) back. 10

Table 5: Cross-adapter conformance matrix. Per- suite makes visible, and the v0.2 spec resolves them adapter totals at the bottom row. ✓ = passes; □ = by raising the floor. skipped (documented limitation); × = fails.

5.4 Scenario

sqlite

mem0

letta

Threats to validity

cognee

pg

The evaluation has several limitations we want named basic_remember_recall ✓ ✓ ✓ ✓ ✓ remember_recall_by_user_filter ✓ ✓ □ explicitly. □ ✓ Synthetic type_filter ✓ ✓ ✓ ✓ ✓corpora. The microbench corpus is facts; the adversarial-fusion corforget_by_ids ✓ ✓ ✓ 100 hand-authored □ ✓ forget_no_scope_raises ✓ ✓ ✓ pus is✓50 synthetic ✓ memories. Real-world workloads expire_empty_policy_raises ✓ □ □ — millions □ ✓ of memories per agent, heavy-tailed query expire_empty_policy_object_r. ✓ □ □ distributions, □ ✓latency interference from a real proexpire_by_age ✓ □ ✓ □ ✓ duction embedding service — will produce different merge_keep_canonical ✓ ✓ ✓ □ ✓ numbers. The 100k-memory recall scaling test is approval_required_pending ✓ ✓ ✓ ✓ ✓ tracked for v0.2. capabilities_declared ✓ ✓ ✓ ✓ ✓ Adversary health_returns_status ✓ ✓ ✓ ✓ ✓has full knowledge. The Section 5.2 isinstance_protocol ✓ ✓ ✓ attacker ✓ knows ✓ the router’s k · 4 over-fetch and fills recall_returns_score_metadata ✓ ✓ ✓ exactly ✓ that block ✓ at rank 0. A black-box attacker — fresher_than_days_filter ✓ ✓ ✓ one that ✓ does ✓ not know the over-fetch and has to guess multi_remember_then_recall ✓ ✓ ✓ — would ✓ do worse. ✓ We did not evaluate the converse pass / skip 16/0 13/3 13/3case10/6 16/0attacker that, for instance, fabricates (a smarter ids that also appear in the benign stores’ result sets to bump their rank); that case is the v0.2 hardening with • No empty-policy guard. mem0, Letta, and signed RecallHit envelopes from docs/THREATS.md Cognee skip expire_empty_policy_raises and §3.3. expire_empty_policy_object_raises — only Single-machine measurements. Every number the SQL adapters defensively raise on an empty reported here was measured on one developer-class ExpirePolicy. The three SDK-wrapping adapters Windows 11 laptop. Distributed deployment, multisilently fall through to “match everything,” which process router fan-out across machines, and the adis the wrong default and a real footgun. The v0.2 ditional latency of a real network hop to a hosted spec should require every adapter to raise on empty mem0 / Letta instance are unmeasured. The numbers policy; this is the highest-priority spec tightening should be read as a microbenchmark of the protofrom the conformance run. col’s intrinsic overhead, not as a SLA against any deployment topology. • No stable per-record id. Cognee skips Authors-as-evaluators. Neither the conforforget_by_ids, expire_by_age, and mance suite nor the microbench corpus has been merge_keep_canonical because Cognee’s forget audited by a third party. A user study with external primitive requires a pipeline-assigned data_id operators (n = 10–20) using the governance UI is in UUID that the public add API does not surface. scope for v0.2 (docs/paper/user-study/ materials, The Cognee adapter mints synthetic cog:<sha1> NASA-TLX instrument, IRB pipeline — currently a ids at write time, so per-id deletes (and the v0.2 deliverable; the materials directory does not yet operations that depend on them) become no-ops. exist). The v0.2 spec should require backends to surface Benchmark scope. This paper reports prelima stable per-record id from their write primitive; inary LongMemEval and LoCoMo numbers in Secthis is the largest-impact protocol change the tion 5.5. The full 5-seed × 200-question paper-grade conformance run motivates. run is deferred to a v2 replacement on arXiv: the perquestion Memory construction pattern that protects These three spec-tightening signals are exactly the against cross-question memory leakage (a Wave-E corkind of finding a conformance suite is supposed to rectness invariant that we validated with a separate diproduce. They are not bugs in the suite or in the agnostic, scripts/diag_eval_ingest.py) imposes a adapters; they are real gaps in the v0 spec that the per-iteration sentence-transformers reload cost that 11

Table 6: Preliminary post-fix LongMemEval and Lo- +8.3× relative on LoCoMo — the bug was real and CoMo (v1 preprint; v2 replacement will land 5-seed the fix is real. × 200-question numbers). Benchmark

nq

seeds

LongMemEval (stratified) LoCoMo (single episode)

12 10

1 1

Threats to validity for the preliminary numgrader meanbers

0.417The numbers above are reported as preliminary 0.150and should be read with three caveats. First, nq = 10–12 at nseed = 1 is too small to support statistical claims; per-task means with n = extrapolates to 10–15 hours of wall time on a single 2–3 have wide enough confidence intervals that CPU laptop, out of scope for v1. BEAM remains the 0.00 scores on multi_session_reasoning and unevaluated — no canonical dataset manifest was temporal_reasoning should not be read as “memfound at v1. orywire scores zero on these tiers” but as “the small-embedder reference configuration scores zero 5.5 Preliminary LongMemEval and Lo- on the few examples sampled.” Second, the grader (gpt-4o-mini) is a single LLM-as-judge with no CoMo human-graded calibration on this draw, so absolute After the conformance-suite section’s spec-tightening scores are not comparable across papers that use signals were folded into the eval harness, we ran different graders — the only safe comparison is the a preliminary pass at nq = 10–12 and nseed = 1 pre-fix / post-fix delta on the same harness, which against the canonical LongMemEval [11] and Lo- is what the +46% and +8.3× numbers above meaCoMo [4] datasets. Pre-paper validation surfaced one sure. Third, the embedder (all-MiniLM-L6-v2) is a bug (sqlite-vec’s vector-ANN top-k is computed deliberately weak reference, chosen to keep the harbefore the row-level agent_id filter, so a DB shared ness reproducible on a CPU laptop; the protocol is across questions returns zero hits once cross-question embedder-agnostic and the v2 replacement will rerows dominate the top-k); the fix is per-question iso- port numbers under at least one stronger embedder lated DB files under .memorywire-eval-dbs/, ap- so the contribution of wire-format vs. embedder is plied in the eval harness only without touching separable. src/memorywire/. Grader is gpt-4o-mini; embedder is 6 Threat Model all-MiniLM-L6-v2; backend is sqlite-vec://. Results in Table 6. The threat model below is condensed from Per-task LongMemEval breakdown is in- docs/THREATS.md, which is the canonical version formative: single_session_preferences and which carries the line-level mitigation citations 0.90, single_session_user 0.75, into the reference implementation. Six adversaries single_session_assistant 0.50, map onto established OWASP and CWE categories: knowledge_update 0.35, multi_session_reasoning OWASP A01 (Broken Access Control), A03 (Injec0.00, temporal_reasoning 0.00. Single-session recall tion), A04 (Insecure Design), A07 (Auth Failures), on a single small embedder works; the remaining A09 (Logging Failures); CWE references are noted gap on multi_session and temporal tiers is a inline. known weakness of all-MiniLM-L6-v2 on the harder tiers, not a harness bug. Swapping the 6.1 Malicious memory injection (CWEembedder for a larger model (bge-m3, gte-large, 20; OWASP A03 / LLM-01) or text-embedding-3-large) is the v0.2 path; the protocol is embedder-agnostic, so this measurement Capability. Submits remember() calls — as the reflects the reference embedder’s recall ceiling, not agent itself (prompt-injected upstream) or as an upmemorywire’s wire format. Compared to a pre-fix stream system feeding the agent. Motivation. Plant run (LongMemEval 0.286, LoCoMo 0.018 with "(no adversarial “facts” that subsequent recall() surfaces relevant memories surfaced)" dominating), the — the memory analogue of prompt injection. Preconpost-fix lift is +46% relative on LongMemEval and ditions. Can influence any string the agent passes 12

through remember(). memorywire cannot tell a real stance, a malicious adapter fork, or a MITM on the fact from a planted one. backend HTTP. Motivation. Dominate the fused Current mitigation. approval_required=true output of recall() so the agent receives attackeron RememberRequest stages the row be- chosen results. Preconditions. Can return crafted hind the PENDING_APPROVAL_DELETED_AT RecallHit rows with high score or fabricated ids = -1 sentinel in memories.deleted_at not seen in other stores. Current mitigation. RRF is (src/memorywire/store/sqlite_vec.py:88–98, score-independent by construction — 440). All recall paths filter deleted_at IS NULL, so pending rows cannot influence retrieval until a _fusion_contribution uses 1/(rrf _k + rank) human approves. confidence is a first-class field; (src/memorywire/router.py:428–429), so a malievery remember() is journaled with the inserted cious backend cannot dominate by inflating score; it memory_id, so a poisoned memory is traceable to can only return an item at rank 0. RRF sums across the call that planted it. Residual risk. Default stores, so a single rogue store contributes at most approval_required is false; the protocol guarantees 1/60 ≈ 0.0167 per item, while a two-store consensus only that what the agent wrote is what the agent item scores at least 1/60 + 1/61 ≈ 0.0330. MAX and reads back. Prompt-injected calls from a trusted weighted fusion are score-sensitive — operators agent are out of scope (Section 6.7). v0.2 hardening. picking them accept more backend trust. Per-store A privacy_intent block on RememberRequest so failures are logged but do not abort the operation. operators can require approval by source, type, or Residual risk. With fusion="max" or "weighted", content predicate without instrumenting every caller. one malicious backend can dominate (Section 5.2). Even with RRF, a backend that fabricates an 6.2 Recall exfiltration (CWE-200; attacker-controlled id that also exists in other stores can bump it by reporting it at rank 0. There is no OWASP A01) cross-store identity proof. v0.2 hardening. Signed Capability. Issues recall() against an agent’s RecallHit envelopes per backend; an optional router — directly (compromised SDK caller) or in- quorum_k parameter requiring an item to appear in directly (manipulating the prompt that drives the k distinct stores before fusion considers it. agent’s own recall). Motivation. Read private memMeasured. See Section 5.2. RRF holds recall@5 ories stored under agent_id / user_id. Precondi- = 1.000 across the K ∈ {0, 5, . . . , 50} sweep; MAX tions. Can issue recall(query, agent_id) for an halves to 0.500 with 80% leak at K = 5. agent with data. k defaults to 5; the schema caps at 1000. 6.4 Audit log tampering (CWE-117 / Current mitigation. Recall is hard-bound to CWE-778; OWASP A09) agent_id at the adapter SQL layer — every recall path in SqliteVecStore filters WHERE agent_id = Capability. Has write access to the SQLite file or can ? AND deleted_at IS NULL. recall() is itself au- run arbitrary SQL against audit_log. Motivation. dited (audit_log.operation = ’recall’), so high- Hide a previous forget() / merge() / approve() or rate exfiltration is observable post-hoc. The schema fabricate one to frame an operator. Preconditions. caps k at 1000 so a single call cannot drain a store. Filesystem access to the memorywire DB. Current mitigation. The audit log is appendResidual risk. A caller with the right agent_id can only by code convention. SqliteVecStore._audit extract everything that agent stored. No recall rate limit, no field-level redaction, no approval on reads. is the only writer in the OSS adapter v0.2 hardening. Per-agent_id recall budgets, op- (src/memorywire/store/sqlite_vec.py:401–424); tional approval_required on recall, and a redact it only performs INSERT INTO audit_log(...). No UPDATE or DELETE against audit_log filter for secrets-labelled rows. exists anywhere in src/memorywire/ or ui/src/memorywire_ui/. Every governance 6.3 Poisoned backend in RRF fusion action emits a dedicated audit row with the re(CWE-345) viewer’s identity. Residual risk. SQLite is a single Capability. Controls one of the N child stores in file with filesystem semantics — anyone with write a MemoryRouter — a compromised hosted mem0 in- access can DELETE FROM audit_log or mutate rows. 13

memorywire enforces append-only at the code layer, loopback bind without a token fires a stderr warning not the DB layer. v0.2 hardening. Merkle-chained on boot. Current mitigation (b) proceduralaudit rows (audit_log.prev_hash column) so memory RCE. validate_procedure_dict tampering breaks the chain; periodic export to allow-lists transition keys to exactly an append-only object store (S3 object-lock); a {trigger, source, dest, conditions, unless} read-only DB role for the UI connection. (src/memorywire/procedural.py:57–59), rejecting before / after / prepare (the three 6.5 Cross-tenant leakage / IDOR (CWE- pytransitions keys that resolve dotted-string callbacks via __import__). conditions / 639; OWASP A01) unless strings are restricted to bare identiCapability. Legitimate operator scoped to agent_id fiers. ProcedureRunner._expand_transitions = A with a valid UI session who guesses or harvests strips disallowed keys at construction time as a memory ids belonging to agent_id = B. Motivation. defense-in-depth layer. Residual risk. Single shared Approve, reject, forget, or merge another agent’s bearer with manual rotation; CSRF is bypassed memories. Preconditions. UI session as agent A for any Authorization: Bearer request (a stolen plus a memory id known to belong to agent B. bearer is already a fatal compromise); the procedural Current mitigation. Every state- sandbox is purely static allow-listing, so a future changing UI handler is scoped to (agent_id, transitions release adding a new code-execution memory_id, sentinel). approve() runs UPDATE sink under a currently-allowed key would silently memories SET deleted_at = NULL WHERE id miss validation. v0.2 hardening. Per-operator = ? AND agent_id = ? AND deleted_at = ? tokens with rotation; Secure cookie flag for HTTPS; (ui/src/memorywire_ui/services.py:502–511); a CI snapshot of the transitions callback-key reject() and apply_co_memorize() carry the same surface. triple-key guard (commit c828d76). The merge branch additionally verifies the canonical row belongs 6.7 Residual risks the protocol cannot to the agent before touching the secondary. On mitigate any mismatch the response returns an identical opaque reason, so the error itself does not leak which Three classes of risk are out of scope for the memcondition fired. Residual risk. The UI uses a single orywire v0 protocol and are noted here for honest global bearer; the IDOR fix prevents cross-agent framing: pivoting by id but not multi-tenant isolation by operator. v0.2 hardening. Per-session multi-tenant • Insider attacks on the audit DB. Anyone with filesystem write access can rewrite history (see Secagent_id scoping; SSO-shaped reviewer identity; tion 6.4 residual). Mitigated only by deployment per-operator allowed-agent_id ACL. hygiene.

6.6

Approval bypass (CWE-94 / CWE- • Prompt injection in the calling agent. mem862; OWASP A04 / A07) orywire is downstream of the LLM. If the

agent is fooled into remember("Alice is in the Capability (a). Reaches the UI on an unauthentibuilding", confidence=1.0), memorywire faithcated bind. Capability (b). Crafts the proceduralfully stores and recalls it. The audit log captures memory payload so the FSM definition itself triggers the call exactly; memorywire makes the threat aucode execution. ditable, not preventable. Current mitigation (a) UI no-auth. BearerAuthMiddleware gates every request be- • Side-channel timing on recall. Latency varies hind a bearer when MEMORYWIRE_UI_TOKEN is set with k, fusion mode, and per-store result counts; a (ui/src/memorywire_ui/middleware.py:74–103), patient attacker can in principle distinguish “agent accepting either an Authorization: Bearer has memory matching X” from “no match” by obheader or an memorywire_ui_session cookie with serving latency. hmac.compare_digest. CSRFMiddleware enforces a double-submit-cookie pattern signed with HMACThe full threat model, including the OWASP / SHA256 over nonce.ts with 24-hour TTL. Non- CWE / MITRE ATT&CK cross-mapping and the 14

per-CVE commit references for every fix, lives in docs/THREATS.md.

7

Relationship to MCP and Other Protocols

five tools — one per operation — and route the JSON-Schema-validated payload straight into the memorywire request models. Roughly ten lines of glue code; any MCP-aware agent can use memorywire through its existing client.

• memorywire-as-MCP-resource. For agents The single question every reader asks first is: why that prefer to read memory rather than call it, didn’t you just add memory operations to MCP? The expose recall() results as MCP resources. The honest answer has three parts. resource URI carries the query; the resource body Memory is not a tool. It is not a resource, is the structured RecallResponse. Writes still go not a prompt, not a sampling primitive. It is a disthrough the tool mode. tinct primitive with its own lifecycle (write, recall, forget, merge, expire), its own taxonomy (seman- • memorywire-as-MCP-extension (proposed, v0.5). memorywire becomes a published MCP tic, episodic, procedural, emotional), and its own extension — mcp.memory.v0 or similar — with the governance surface (diff-and-approve, audit). MCP five operations and four memory types lifted into can absolutely wrap a memory backend — exposing MCP’s own type system, the governance channel remember / recall / forget as three tools is a fifteenbecoming an MCP sub-protocol. This is the path minute integration — but the wrapping is lossy: the we expect to propose once the wire format has five operations flatten into five opaque tools, the four settled. memory types collapse into a string parameter, and the governance channel ends up living entirely outside This is not a fork. memorywire and MCP adMCP. memorywire exists to give memory the same dress adjacent problems — tool-use and memory — first-class treatment MCP gave tool-use. Iteration speed. A v0 draft wire format needs to and the agents we build use both at the same time. break things. memorywire explicitly reserves the A realistic agent loop calls mem.recall() to gather right to break wire-format compatibility through context, runs the model with that context and the v0.5 (docs/spec/v0.md §9). Pushing those breaking MCP tool list, dispatches any tool calls via the MCP changes through a working-group governance cycle be- client, and calls mem.remember() for anything worth fore the design has stabilized would slow the iteration retaining (routing it to the governance channel when the design needs. Once the spec is frozen, working- sensitive). The two protocols never overlap in this group governance becomes a help rather than a brake code. Adopting one does not preclude adopting the — which is why the v0.5 plan submits the spec to both other. Open questions on which we welcome exterthe MCP-WG (as an extension proposal) and the nal input. (a) JSON-RPC vs REST shape: memoIETF (as an Internet-Draft) at the same time. Multi-protocol portability. Memory matters in rywire’s schemas are written against JSON Schema places MCP does not reach. The web platform (W3C) 2020-12 with a REST-friendly request/response idwill need an agent-memory primitive when browsers iom; MCP is JSON-RPC. Bridging is mechanical but ship on-device models capable of multi-session rea- there is real design space in how to express memorysoning. Cross-language ports (Rust, Go, TypeScript) wire operations as JSON-RPC methods while keeping want a JSON-Schema spec they can codegen against, JSON-Schema as the source of truth for validation. not a JSON-RPC method signature tied to one trans- (b) Core vs extension: should memory live in core port. The IETF Internet-Draft route, by analogy to MCP, as one of the primitives, or always as an extenCloudflare’s Web Bot Auth, needs a spec document sion? We lean toward “extension first, core later if that stands on its own. Designing memorywire as a usage warrants” but defer to the working group. (c) standalone wire format keeps all three doors open; Mapping the type taxonomy: should the four types surface as separate resource schemas, as tags, or as folding it into MCP first would close two of them. Three composition modes work today, today. filter parameters on a unified recall verb? (d) Governance plane: MCP’s elicitation primitive is the closest • memorywire-as-MCP-tool. Wrap an memory- existing analogue, but it is designed for synchronous wire Memory facade as an MCP server that exposes user-input mid-tool-call, not asynchronous review of 15

pending writes. A future MCP-native memory exten- recall budgets; stable per-record id surfaced from sion may need a new sub-protocol for governance — every backend’s write primitive. or delegate it back to the application layer entirely. v0.5 spec freeze and standards engagement. The full version of this discussion lives in v0.5 is the freeze point: wire format stable, breaking docs/MCP-RELATIONSHIP.md, which carries the com- changes prohibited. In parallel with v0.5: file an plete composition examples, the overlap table, and MCP RFC proposing memory as an extension primthe calls to action for MCP working-group members. itive with memorywire as the candidate reference; submit memorywire v0.5 as an IETF Internet-Draft (draft-<name>-memorywire-00). Both outcomes — 8 Future Work acceptance as an MCP extension and stabilization as a parallel standard — are acceptable. memorywire is a draft. The roadmap below lists the v1.0 stable. Frozen wire format; federated multiconcrete deliverables we have planned through v1.0; tenant primitives (a cross-agent share operation unwe list them as intent, not commitment. der discussion); enterprise governance (SSO, rolev0.2 evaluation: full-scale memory benchbased ACLs, signed audit exports); production-grade marks. LongMemEval [11] and LoCoMo [4] are adapters for the long tail of backends not in v0. the canonical long-context memory benchmarks; BEAM is the consolidated benchmark suite. v1 of this preprint reports preliminary numbers (Sec- 9 Conclusion tion 5.5) using scripts/run_longmemeval.py and scripts/run_locomo.py, both shipped in the arti- We have presented memorywire, a vendor-neutral fact. A v2 replacement on arXiv will land the full 5- wire format for agent memory operations: five operaseed × 200-question runs once per-question sentence- tions, four memory types, a MemoryStore Protocol, a transformers reload overhead is amortized via an fan-out router with three fusion algorithms (with Reembedder-sharing harness change (estimated addi- ciprocal Rank Fusion as the defensible default under tional wall time: 6–10 h on a single CPU machine; a 1-of-N malicious-backend model), and an optional estimated grader cost at gpt-4o-mini: under $1). human-in-the-loop governance channel. The reference v0.2 user study. A user study with external op- implementation ships with five backend adapters coverators (n = 10–20) is in scope for v0.2. The study ering the major open-source memory frameworks; a materials — NASA-TLX cognitive-load instrument, microbenchmark (recall@5 = 1.000 on 42 labelled IRB protocol, consent forms, recruitment script — are queries, ingest p50 = 37.8 ms), an adversarial-fusion tracked under docs/paper/user-study/; that direc- experiment (RRF holds recall@5 = 1.000 where MAX tory does not exist at the time of this draft and is a collapses to 0.500 with 80% leak), and a 16-scenario v0.2 deliverable. The study targets operators of agent cross-adapter conformance suite (68 PASS / 12 SKIP runtimes who would actually use the governance UI; / 0 FAIL out of 80 cells) establish the protocol’s the headline metric is whether the diff-and-approve empirical viability. flow reduces median review time below the alternative We are honest about the bet. The algorithmic subof “approve everything blindly.” strate (RRF, FSMs, STM/LTM, diff-and-approve) is v0.2 spec tightenings. Three spec tighten- prior art; the contribution is composition and stanings the v0 evaluation directly motivates: (a) a dardization, and standards races have uncertain outprivacy_intent block on RememberRequest so op- comes. Whatever the market outcome, the cumulaerators can require approval by source, type, or tive artifact — spec, reference implementation, threat content predicate without instrumenting every caller; model, conformance suite, open-data evaluation — (b) multi-tenant agent_id scoping in the UI (per- lowers the cost for any future protocol effort in this operator allowed-agent_id ACL and SSO-shaped re- space, including one that supersedes memorywire. viewer identity); (c) a required expire(policy={}) memorywire is to memory what MCP is to tool-use. empty-policy guard on every adapter (the Section 5.3 Whether memorywire itself becomes that protocol conformance run surfaced this as the highest-priority or input material to whichever protocol the working spec tightening). Additional v0.2 hardening from groups settle on, the design work collected here is docs/THREATS.md: signed RecallHit envelopes per intended to compose with — not compete against — backend; Merkle-chained audit rows; per-agent_id the existing ecosystem. 16

[8] Larry R. Squire. Declarative and nondeclarative memory: Multiple brain systems supporting learning and memory. Journal of Cognitive Neuroscience, 4(3):232–243, 1992.

Acknowledgments

We acknowledge the open-source projects memorywire composes with: mem0, Letta (formerly MemGPT), Cognee, Zep/Graphiti, MemoryOS, MemTensor MemOS, sqlite-vec, pgvec- [9] Hamed Taheri. Governed memory: A production architecture for multi-agent workflows, 2026. tor, pytransitions, Starlette, HTMX, sentencetransformers, and the Model Context Protocol com[10] Endel Tulving. Episodic and semantic memory. munity. The Co-memorize diff-and-approve pattern In Endel Tulving and Wayne Donaldson, edidraws on the Governed Memory line of work. RRF tors, Organization of Memory, pages 381–402. as a fusion primitive is from Cormack, Clarke, and Academic Press, New York, 1972. Büttcher. The human-memory taxonomy mapping follows the cognitive-science literature established by [11] Di Wu, Hongwei Wang, Wenhao Yu, Yuwei Tulving and Squire. Zhang, Kai-Wei Chang, and Dong Yu. LongMemEval: Benchmarking chat assistants on longterm interactive memory, 2024. References [1] Prateek Chhikara, Dev Khant, Saket Aryan, Taranjeet Singh, and Deshraj Yadav. Mem0: Building production-ready AI agents with scalable long-term memory, 2025. [2] Gordon V. Cormack, Charles L. A. Clarke, and Stefan Büttcher. Reciprocal rank fusion outperforms Condorcet and individual rank learning methods. In Proceedings of the 32nd International ACM SIGIR Conference on Research and Development in Information Retrieval (SIGIR ’09), pages 758–759. ACM, 2009. [3] JSON Schema authors. JSON Schema 202012 release notes. https://json-schema.org/ draft/2020-12/release-notes, 2020. [4] Adyasha Maharana, Dong-Ho Lee, Sergey Tulyakov, Mohit Bansal, Francesco Barbieri, and Yuwei Fang. Evaluating very long-term conversational memory of LLM agents (LoCoMo), 2024. [5] Thibault Meunier and Watson Ladd. Web bot authentication architecture. IETF Internet-Draft draft-meunier-web-bot-auth-architecture-05, March 2026. Revision 05, dated 2 March 2026. [6] Model Context Protocol working group. Model context protocol specification, version 202511-25. https://modelcontextprotocol.io/ specification, 2025. [7] Charles Packer, Sarah Wooders, Kevin Lin, Vivian Fang, Shishir G. Patil, Ion Stoica, and Joseph E. Gonzalez. MemGPT: Towards LLMs as operating systems, 2023. 17

Record · ID 246450 · SHA-256 ca84de26582ae1d2
Retrieved via Conceptio — every document is proof-bundled with source, license, and retrieval metadata.