Skip to main content

πŸ” Memwal Engine

MemwalMemory (@lighthouse-ai/engine-memwal) is the relayer engine: embedding, SEAL encryption, Walrus upload, and vector search all happen in the relayer. You keep tags, CIDs, and blob IDs locally. Every remember goes straight to the network - there is no batching and no flush().

import { MemwalMemory } from '@lighthouse-ai/engine-memwal'

const memory = await MemwalMemory.fromEnv() // MEMWAL_PRIVATE_KEY + MEMWAL_ACCOUNT_ID
await memory.remember('User prefers dark mode.', { tags: ['preference'] })
await memory.recall('what theme does the user like?')

Setup - MemwalMemory.fromEnv(env?)​

Env varRequiredPurpose
MEMWAL_PRIVATE_KEYYesHex delegate key from the dashboard
MEMWAL_ACCOUNT_IDYes0x... account id from the dashboard
MEMWAL_NETWORKNo (mainnet)mainnet or testnet (staging relayer; creds are per-network)
MEMWAL_SERVER_URLNoOverride relayer URL (defaults per network)
MEMWAL_NAMESPACENo (default)Relayer + local namespace
MEMWAL_AGENTNo (agent)Recorded on every memory
MEMWAL_MEMORY_DIRNo (./.memory-sdk/memwal)Local index dir
MEMWAL_REMEMBER_TIMEOUT_MSNo (60000)rememberAndWait timeout
LIGHTHOUSE_API_KEYNoPins a public IPFS mirror of each record
MEMWAL_IPFS_PINNo (pin)off skips IPFS pinning (local CIDs only)

Get credentials at https://memory.walrus.xyz (mainnet) or https://staging.memory.walrus.xyz (testnet). Testnet and mainnet credentials do not interoperate.

Or construct manually:

import { MemwalMemory, resolveNetwork, LighthouseIpfsPinner } from '@lighthouse-ai/engine-memwal'

const memory = new MemwalMemory(client, { // client: MemwalClient (e.g. MemWal.create({ key, accountId, serverUrl, namespace }))
network: resolveNetwork('mainnet'),
namespace: 'demo',
agent: 'support-bot',
dataDir: './.memory-sdk/memwal',
pinner: new LighthouseIpfsPinner(process.env.LIGHTHOUSE_API_KEY!),
rememberTimeoutMs: 60_000,
})

remember(content, opts?)​

const res = await memory.remember('Customer ACME is on enterprise.', { tags: ['customer'] })
// { id, blobId, cid, pinned, gatewayUrl?, walrusUrl, network, namespace }

The relayer embeds + SEAL-encrypts + uploads to Walrus and returns { id, blob_id }. The SDK then pins a canonical JSON record to IPFS (Lighthouse if LIGHTHOUSE_API_KEY is set, otherwise a locally computed CID) and appends it to <network>.<namespace>.index.json. If pinning fails, the record is kept with pinPending: true - retry with repinPending().

LIGHTHOUSE_API_KEY mirrors are plaintext; memwal blobs on Walrus are SEAL-encrypted.

recall(query, opts?)​

const matches = await memory.recall('how do I escalate for ACME?', {
tags: ['customer'], // applied locally after the relayer returns hits
limit: 5, // default 5
maxDistance: 1.2, // optional: drop matches with distance >= this value
})
// [{ blobId, content, distance, score, id?, tags?, cid?, pinned?, gatewayUrl?, walrusUrl, indexed }]
  • Search runs in the relayer; the SDK over-fetches (max(limit*4, 20)) when tag filters are present, then filters locally.
  • score is 1 βˆ’ distance clamped to 0..1.
  • indexed: false means the relayer knows the blob but this machine has no local record (written elsewhere, never snapshotted here).

analyze(text, opts?)​

Extract discrete facts from free text via the relayer; each fact becomes its own memory with its own IPFS CID.

const out = await memory.analyze('Alice moved to Lisbon in June and prefers dark mode.', {
occurredAt: '2026-06-15T00:00:00.000Z', // optional
})
// { factCount: 2, succeeded: 2, failed: 0, memories: [RememberResult, …] }

Facts are tagged ['analyzed']. Requires a client with analyzeAndWait - throws otherwise.

list(opts?)​

await memory.list({ limit: 20, tags: ['preference'] }) // newest first
// [{ id, blobId, cid, content, tags, createdAt, walrusUrl, gatewayUrl?, ... }]

Unlike batched, memwal list accepts tags natively.

get(ref)​

await memory.get('job-id-…') // by relayer id
await memory.get('baf…') // by IPFS CID (local index, else gateway fetch)
await memory.get('walrus-blob-id') // by Walrus blob id

Falls back to a gateway fetch for pinned CIDs not in the local index. Throws for unknown refs with guidance to use recall() (semantic search works without a local record).

verify(ref)​

await memory.verify('job-id-…')
// pinned: { id, cid, pinned: true, verified: true, method: 'gateway-fetch' }
// unpinned: { id, cid, pinned: false, verified: true, method: 'local-hash' }

Pinned records are fetched from the gateway and compared byte-for-byte; unpinned records are re-hashed locally (computeRawCid).

forget(ref)​

await memory.forget('job-id-…')
// { removed: true, blobDeleted: true|false, note: 'Removed from the local index…' }

Removes the local copy and unpins the IPFS mirror. The relayer has no delete API - the SEAL-encrypted blob stays on Walrus until its storage period lapses and may still surface in recall() as indexed: false.

blobIds(ref)​

await memory.blobIds('job-id-…')
// { memwalBlobId: '…', recordBlobIds: ['…'] }

The encrypted memwal blob plus Walrus-native blob IDs backing the pinned IPFS record (empty when unpinned).

restore(opts?)​

await memory.restore({ maxBlobs: 200 }) // { restored, skipped, total, calls }

Asks the relayer to rebuild missing vector-index entries from on-chain data. Pages exponentially (25 β†’ 50 β†’ … β†’ maxBlobs) until everything is inspected.

repinPending()​

await memory.repinPending() // { repinned: 2, remaining: 0 }

Retries IPFS pins for entries marked pinPending (see pendingPins in status()).

snapshotIndex() / rebuildLocal(snapshotCid)​

const snap = await memory.snapshotIndex()
// { cid, pinned, entries, gatewayUrl? }

await fresh.rebuildLocal(snap.cid) // { added, total }

Pins the entire local index as one memwal-index.<network>.<namespace>.json snapshot and merges it elsewhere. Snapshots are namespace- and network-checked, merge-only (known ids are skipped), and plaintext like pinned records.

status()​

await memory.status()
// {
// network: 'mainnet', relayerUrl: 'https://relayer.memory.walrus.xyz',
// relayer: 'ok (v1.2.3)', dashboardUrl: 'https://memory.walrus.xyz',
// namespace: 'demo', agent: 'agent',
// memories: 12, pinnedMemories: 10, pendingPins: 2,
// ipfs: 'lighthouse (pinned, publicly resolvable)' | 'local CIDs (computed, not pinned)',
// indexPath: '.memory-sdk/memwal/mainnet.demo.index.json'
// }

Networks​

mainnet (default)testnet
Relayerhttps://relayer.memory.walrus.xyzhttps://relayer-staging.memory.walrus.xyz
Dashboard / credentialshttps://memory.walrus.xyzhttps://staging.memory.walrus.xyz
Sui fullnode / aggregatormainnettestnet

Use resolveNetwork(name), walrusBlobUrl(config, blobId), and NETWORKS from the package when building URLs manually.