← Back to Blog
Engineering

Cross-Platform AI Memory: Architecture Decisions

Nexus Team July 2, 2026 8 min read

“Support every AI client” sounds like a checkbox until you actually try to design the system underneath it. Claude Code injects context through session hooks. Cursor and most chat clients only talk to the world through MCP tool calls. Some surfaces can write memory automatically in the background; others can only read on request, when a user or the model explicitly asks. Treat all of that as one uniform integration and you’ll ship something that half-works everywhere. We chose to design for the differences instead of papering over them.

The core problem: two very different write paths

The clean case is a client with hooks — something that runs on session start, on every user turn, on session end. That gives you a natural place to inject relevant memory automatically and to capture new context without the user doing anything extra. Claude Code and comparable IDE-integrated agents fall into this category.

The harder case is everything else. A pure MCP client has no lifecycle hooks to attach to — the model has to decide to call a recall_context or store_context tool, the same way it decides to call any other tool. That means memory quality on those surfaces depends on the system prompt nudging the model to actually use the tools, and on the tools themselves being cheap and obviously useful enough that the model reaches for them unprompted.

We didn’t try to force hook-based behavior onto MCP-only clients. Instead, each surface gets an integration shaped for what it can actually do:

  • Hook-native clients get automatic context injection and background capture — the user never has to ask.
  • MCP-only clients get a small, sharply-scoped set of tools (recall_context, store_context, and a few others) with descriptions written to make the model reach for them at the right moments — after a nontrivial decision, before starting unfamiliar work.
  • Clients with neither (a plain CLI wrapper, for instance) fall back to a detached background process pattern: a lightweight worker that watches for session boundaries from outside the client process and calls the same store/recall API the other surfaces use.

One system underneath, not five

The part that keeps this from becoming five separate memory systems is that every surface talks to the same backend through the same API. A persona routing decision, a stored architecture note, a recalled fact — none of it is client-specific. The client only decides when to call in and how much it can automate versus how much has to be model-initiated. That’s what makes the memory genuinely portable rather than “portable in principle, five different implementations in practice.”

What broke, and what we learned

The failure mode we hit most often wasn’t the architecture — it was assuming a new surface’s write path worked before verifying it live. A hook wired up to the wrong lifecycle event, or an MCP tool description too vague for the model to reliably invoke, produces something that looks integrated in code review and does nothing in practice. The fix wasn’t more abstraction; it was treating “does this surface actually write and recall memory in a live session” as a required proof step for every new client, not an assumption inherited from the surfaces that came before it.

Cross-platform memory isn’t one architecture wearing different skins. It’s one backend, one API contract, and a deliberate, surface-by-surface answer to “what can this client actually do, and how do we get the most out of that without pretending it can do more.”

The protocol-level loop is in How MCP-Based Persistent Memory Works. For a hook-native client, start with How to Add Persistent Memory to Claude Code with MCP.

Start your 14-day Nexus-Catalyst trial and connect the clients you already use.