MemorySync
Integrations

Eve Memory

The first installable memory package for Eve, Vercel’s filesystem-first framework for durable backend AI agents. Three one-line files give any Eve agent persistent, per-user memory — idempotent fact extraction from the user’s messages, budgeted turn-scoped recall, and an auth-derived identity ladder.

Three one-line files: the channel stashes the utterance, instructions inject budgeted recall before the model runs, hooks send user messages idempotently — plus an optional search-only tool.

How it works

  1. Install eve-memorysync from npm.
  2. Eve agents are defined by files on disk — you mount memory by dropping three one-line files into agent/.
  3. The channel line records each inbound utterance; the hooks file sends the user’s messages for fact extraction; the instructions file injects the user’s relevant memories before the model runs.
  4. Memories persist across restarts, deploys, and sessions — and are shared with every other MemorySync surface.

Before you start

  1. A MemorySync API key. Create one in the dashboard under Settings → API Keys, inside a project.
  2. Node.js 24+ (Eve’s own minimum) and an Eve agent project (eve 0.40+).

Install

Terminal
npm install eve-memorysync

Mount the three files

Step 1 — capture user turns

Create agent/hooks/memorysync.ts — on message.received it sends the user’s message to MemorySync, which extracts the durable facts in it and stores only those; the message text itself is not stored. message.completed sends nothing: assistant replies are not stored as memories.

agent/hooks/memorysync.ts
import { createMemoryHooks } from 'eve-memorysync'
export default createMemoryHooks()

Step 2 — recall per turn

Create agent/instructions/memorysync.ts — resolves the user’s relevant memories into the prompt on every turn:

agent/instructions/memorysync.ts
import { createMemoryInstructions } from 'eve-memorysync'
export default createMemoryInstructions()

Step 3 — stash the utterance

Eve resolves dynamic instructions on turn.started before the resolver can see the inbound user text — so the channel records it first. One added line in onMessage:

agent/channels/eve.ts
import { eveChannel, defaultEveAuth } from 'eve/channels/eve'
import { localDev, vercelOidc } from 'eve/channels/auth'
import { stashUtterance } from 'eve-memorysync'
export default eveChannel({
auth: [vercelOidc(), localDev()],
async onMessage(ctx, message) {
stashUtterance(ctx, message) // ← the added line
return { auth: defaultEveAuth(ctx) }
},
})

Step 4 — run it

Set MEMORYSYNC_API_KEY in the agent’s environment and start:

Terminal
MEMORYSYNC_API_KEY=ms_... eve dev

Tell the agent a fact, restart it, ask again — it remembers. The recall block is turn-scoped: Eve replaces the previous turn’s block, so only the latest recall is ever in the prompt.

Why a package matters here

Engineering guarantees

  • A memory failure can never fail a turn. A thrown Eve hook fails the whole turn, so every handler is fully guarded: API errors, timeouts, quota limits, and dead networks degrade to a [memorysync] log line.
  • Facts, not turns. Each user message is sent with role: "user" to fact extraction; only the durable facts it yields are stored, and they keep this package’s metadata (surface: "eve", session_id, role, agent, channel). Assistant replies are not sent at all.
  • Retries are recognised. Deterministic user@eve::<session>#h<hash> seeds absorb Eve’s at-least-once redelivery: a redelivered message is not extracted twice.
  • Recall is budgeted. The turn.started resolver fails open after 1.2s (configurable) — slow memory cannot stall the agent.
  • Stash misses degrade, not die. On multi-isolate hosts where onMessage and turn.started may run in different processes, a stash miss falls back to a profile recall instead of silently skipping memory. Set fallbackRecall: 'skip' to opt out.
  • Identity comes from auth, never the model. Ladder: your resolveUserId(ctx) → session auth principal (current, then initiator) → defaultUserId → MEMORYSYNC_DEFAULT_USER_ID → default. Tool arguments cannot select another user’s memory.
  • Loud startup, silent runtime. Factories throw at agent build time when no API key is configured — a memory product silently running with memory off is worse than a visible failure.
  • Long turns are truncated at 16,000 characters before they are sent; recall prompts are clipped at 2,000.

Optional: an on-demand search tool

If you want the model to search memory explicitly (search-only — no deletes), mount a fourth file:

agent/tools/search_memories.ts
import { createMemoryTool } from 'eve-memorysync'
export default createMemoryTool()

Troubleshooting

  • Throws at startup about the API key — deliberate (loud startup). Set MEMORYSYNC_API_KEY in the agent’s environment.
  • Recall block missing on a turn — the 1.2s budget failed open, or the stash missed on a multi-isolate host (it falls back to a profile recall unless you set fallbackRecall: 'skip'). Check for [memorysync] log lines.
  • Same fact stored once despite retries — expected: deterministic seeds absorb Eve’s at-least-once redelivery.
  • Nothing stored for the agent’s replies — by design: message.completed sends nothing, because assistant replies are not stored as memories.
  • Wrong user’s memories — identity comes from the auth ladder, never model arguments; check what resolveUserId(ctx) / the session auth principal resolves to in your channel.

Supported versions

SurfaceRequiresVerified on
eve-memorysync 1.1.0Node.js 24+ (Eve’s own minimum); eve 0.40+ as a peer dependency34 CI checks against the REAL eve package (defineHook/defineDynamic/defineTool brand their definitions, so acceptance proves real-agent wiring): only the user turn sent (message.completed a no-op), honest extraction outcomes with no memory id, stash TTL/bounds and the create-session handoff, the fail-open recall budget, the identity ladder, 16k truncation, quota modes, and the search-only tool

How it compares

ZepMem0Supermemory / LettaMemorySync
Eve integration⚠ copy-paste example (no package)✗ none (generic Vercel env-var installer)✗ nothing at all✓ first installable package
Retry safety✗ at-least-once hooks duplicate turns——✓ idempotent seeds — a redelivered message is extracted once
Utterance stash✗ unbounded in-process Maps; multi-isolate = silent recall loss——✓ TTL + bounds + create-session queue, profile-recall fallback on misses
Recall budget✗ none — a slow search stalls the turn——✓ 1.2s fail-open
Message limits✗ silently rejects >4,096-char messages——✓ 16k with explicit truncation
Identity✗ shared demo-user fallback footgun——✓ auth-principal ladder, never model-provided

Where to go next

Was this page helpful?