Skip to content

Repository files navigation

memwal-agent-memory

Durable long-term memory for AI agents, powered by Walrus Memory (memwal) — with an IPFS CID for every memory.

This is the successor to walrus-agent-memory. That project implemented its own memory layer (local embeddings, batching, index snapshots) on top of raw Walrus blob storage. This one delegates the memory layer itself — embedding, SEAL encryption, Walrus upload, and semantic search — to the Walrus Memory relayer, and adds the pieces the relayer doesn't provide:

  • 🧾 An IPFS CID for every memory — each memory gets a canonical JSON record that is content-addressed on IPFS (pinned via the Lighthouse x Walrus integration, or computed locally)
  • 🏷️ Tags + metadata on top of memwal's plain-text memories
  • 🔍 Verification — check any memory byte-for-byte against its CID
  • 🌐 Testnet & mainnet — one env var switches everything (relayer, aggregator, dashboard, local index)
  • 🔌 MCP server — drop-in memory tools for Claude Code, Claude Desktop, or any MCP-capable agent

How it works

remember("user prefers dark mode", tags: ["preference"])
        │
        ├─► Walrus Memory relayer ──► embed ──► SEAL-encrypt ──► Walrus blob (blob_id)
        │                                                        ownership anchored on Sui
        │
        └─► canonical JSON record {id, content, tags, metadata, blobId, ...}
                  │
                  ├─ LIGHTHOUSE_API_KEY set  → pinned via Lighthouse x Walrus
                  │                            (Walrus-backed, IPFS CID, gateway-resolvable)
                  └─ otherwise               → CIDv1 computed locally (deterministic)

Recall goes through the relayer's semantic search (owner + namespace scoped, decrypted server-side in a TEE) and results are enriched with the local record — id, tags, CID, gateway URL.

Setup

1. Get Walrus Memory credentials

Create an account and delegate key on the dashboard for the network you want:

Network Dashboard Relayer
mainnet https://memory.walrus.xyz https://relayer.memory.walrus.xyz
testnet (staging) https://staging.memory.walrus.xyz https://relayer-staging.memory.walrus.xyz

Credentials are per-network — a mainnet account does not work on testnet and vice versa.

2. Configure

npm install
cp .env.example .env   # then fill in:
Variable Required Description
MEMWAL_PRIVATE_KEY Ed25519 delegate private key (hex)
MEMWAL_ACCOUNT_ID Walrus Memory account object id on Sui (0x...)
MEMWAL_NETWORK mainnet (default) or testnet
MEMWAL_SERVER_URL Override the relayer URL (self-hosted relayers)
MEMWAL_NAMESPACE Memory isolation boundary (default default)
MEMWAL_AGENT Agent name recorded on each memory
MEMWAL_MEMORY_DIR Local index dir (default ~/.memwal-agent-memory)
LIGHTHOUSE_API_KEY Pin memory records via the Lighthouse x Walrus integration (create with your Sui wallet at files.lighthouse.storage)
MEMWAL_IPFS_PIN Set to off to force local (unpinned) CIDs even when a Lighthouse key is set — for namespaces whose records must stay private

3. Use it

import { MemwalMemory } from 'memwal-agent-memory'

const memory = await MemwalMemory.fromEnv()

const stored = await memory.remember('User prefers dark mode.', {
  tags: ['preference'],
  metadata: { source: 'onboarding' },
})
// { id, blobId, cid: 'bafkrei...', pinned, gatewayUrl?, walrusUrl, network, namespace }

const matches = await memory.recall('what are the user's preferences?', { limit: 5 })
// [{ content, score, distance, tags, cid, gatewayUrl?, blobId, indexed }]

Or run the demo / tests:

npm test           # offline smoke test (no credentials needed)
npm run demo       # live demo (needs credentials)
npm run test:live  # live end-to-end round trip

MCP server

npm run mcp        # stdio transport

Claude Code / Claude Desktop config:

Once the package is published to npm, "args": ["-y", "memwal-agent-memory"] works directly; from a checkout use:

{
  "mcpServers": {
    "memwal-memory": {
      "command": "npx",
      "args": ["-y", "tsx", "/path/to/memwal-agent-memory/src/mcp-server.ts"],
      "env": {
        "MEMWAL_PRIVATE_KEY": "<delegate-key-hex>",
        "MEMWAL_ACCOUNT_ID": "0x...",
        "MEMWAL_NETWORK": "mainnet",
        "LIGHTHOUSE_API_KEY": "<optional>"
      }
    }
  }
}
Tool Description
memwal_remember Store a memory (encrypted on Walrus) + IPFS CID
memwal_analyze Extract facts from free-form text, one memory + CID each
memwal_recall Semantic search, optional tag filter and max distance
memwal_list_memories List locally indexed memories, newest first
memwal_get_memory Fetch a record by id, CID, or Walrus blob id
memwal_verify_memory Verify a memory against its IPFS CID
memwal_forget Remove a memory from the local index + unpin its IPFS record
memwal_restore_index Rebuild the relayer's vector index from on-chain data
memwal_repin_pending Retry IPFS pins that failed at store time
memwal_snapshot_index Pin the whole local index to IPFS (portability)
memwal_rebuild_local Restore the local index from a snapshot CID on a new machine
memwal_memory_status Network, relayer health, counts (incl. pending pins), pinning mode

API

MemwalMemory methods (all async):

Method What it does
remember(content, {tags, metadata}) Relayer stores + indexes the memory; record is content-addressed on IPFS
analyze(text, {occurredAt}) Relayer extracts discrete facts; each becomes a memory with its own CID
recall(query, {tags, limit, maxDistance}) Semantic search via relayer, enriched with local records
list({limit, tags}) Locally indexed memories, newest first
get(ref) Full record by id / CID / blob id (falls back to IPFS gateway for pinned CIDs)
verify(ref) Pinned: gateway round-trip byte comparison. Unpinned: local re-hash vs CID
forget(ref) Remove from the local index + unpin the IPFS record (see caveats)
restore({maxBlobs}) Heal the relayer's vector index from on-chain Walrus data
repinPending() Retry pins that failed at store time (memories are never lost to a pin failure — they get a local fallback CID and a pinPending flag)
snapshotIndex() / rebuildLocal(cid) Pin the whole index to IPFS and restore it on another machine — makes tags/CIDs portable, not just the relayer's semantic index
blobIds(ref) Walrus-native blob IDs: the memwal blob + the pinned record's blobs
status() Network, relayer health, counts, pinning mode, index path

IPFS CIDs: pinned vs computed

Every memory always has a CID over its canonical record JSON:

  • With LIGHTHOUSE_API_KEY — the record is uploaded through the Lighthouse x Walrus integration: stored as a Walrus blob on Sui, addressed by an IPFS-compatible CID, resolvable at gateway-walrus.lighthouse.storage/ipfs/<cid>. verify() does a full gateway round-trip, and blobIds() maps the CID to its Walrus-native blob IDs. ⚠️ The pinned record is plaintext (content, tags, metadata). The memwal memory blob itself stays SEAL-encrypted, but this mirror is public — skip the API key for sensitive memories.
  • Without it — the CID is computed locally (CIDv1, raw codec, sha2-256; verified against the multiformats reference implementation). It is deterministic and independently checkable: ipfs add --raw-leaves --cid-version=1 on the same bytes yields the same CID. It just isn't resolvable until someone pins those bytes.

Caveats

  • forget cannot delete from the relayer. It removes the local record and unpins the IPFS mirror, but the Walrus Memory relayer currently has no delete API; the encrypted blob persists on Walrus until its storage epochs lapse and may still surface in recall (marked indexed: false).
  • The local index is per machine. Memories written elsewhere are still recallable semantically (the relayer holds the vector index), but they arrive without tags/CID until you sync the local index — use snapshotIndex() on the source machine and rebuildLocal(cid) on the new one. restore() heals the relayer's index, not the local one.
  • Walrus Memory is in beta — free during the launch period with usage limits.

License

MIT

About

Durable long-term memory for AI agents, powered by Walrus Memory (memwal), with an IPFS CID for every memory

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages