MemWal

RustWalrus MemorySuiAsyncSeal

Walrus Memory gives AI agents persistent, portable memory that works across apps, sessions, and workflows. Ownership and access are enforced onchain through Sui smart contracts, and all content is encrypted through Seal before reaching Walrus.

Use MemWal-rs, the official Rust SDK, to integrate this memory layer. You bring your own Ed25519 keys (or delegate keys), provision or reuse an on-chain account, and interact through remember, recall, analyze, and restore operations. The SDK handles relayer communication, request signing, and compatibility checks.

Concepts

  • Memory spaces: Identified by owner address + namespace. All operations are scoped to your space.
  • Accounts: Onchain MemWalAccount objects (one per owner) that track ownership and authorized delegate keys.
  • Delegate keys: Ed25519 keys registered onchain that allow agents or services to act on your behalf through the relayer.
  • End-to-end encryption: Seal encrypts payloads client-side (or via relayer). Only owners and authorized delegates can decrypt.
  • Decentralized storage: Encrypted blobs live on Walrus. The relayer + indexer provide fast semantic search via vectors.
  • Core operations:
    • remember: Store text. Relayer embeds, encrypts, uploads to Walrus, and indexes the vector.
    • recall: Semantic search by natural language query within your namespace.
    • analyze: Extract structured facts from text (each fact becomes its own memory).
    • restore: Rebuild your local index from Walrus blobs (e.g. after DB loss).
    • embed / manual flows: For client-controlled embedding + Seal.

Architecture (high level)

You (SDK) → signed requests → Relayer (embeds, Seal, Walrus I/O, vector DB) → onchain verification via contract (owner/delegate checks) → Walrus for durable encrypted blobs.

The relayer abstracts Web3 details. For maximum control you can use the manual client path and handle embedding/Seal/Walrus yourself.

See the official Walrus Memory architecture  for diagrams and component details.

Installation

Add the dependency:

Code
[dependencies] memwal-core = "0.1.0" tokio = { version = "1", features = ["full"] }

The crate publishes as memwal-core and re-exports its public API (e.g. MemWal, MemWalProvisionConfig, RecallParams, MemWalManual).

Provisioning

Call MemWal::provision to get a ready client. It:

  • Resolves relayer configuration (or uses explicit URLs)
  • Creates or reuses a MemWal account (via registry or explicit ID)
  • Registers your delegate key onchain (with optional label)
  • Returns a ProvisionedMemWal that gives you the MemWal client plus account helpers.
Code
use memwal_core::{MemWal, MemWalProvisionConfig}; let provisioned = MemWal::provision( MemWalProvisionConfig::new("suiprivkey...") // your delegate private key .delegate_label("my-agent-app") .registry_id("0x...") // or .account_id("0x...") // .wallet_suiprivkey("...") // optional separate wallet key for txs // .namespace("my-app") // .server_url("https://...") // .relayer_config_url("https://...") .mode(memwal_core::ProvisionAccountMode::ReuseOrCreate), ) .await?; let memwal = provisioned.memwal(); println!("account: {}", provisioned.account_id()); println!("delegate: {}", provisioned.delegate_address());

Later revoke:

Code
let digest = provisioned.revoke_delegate_key().await?;

Quick Start (Relayer-backed)

Code
use std::time::Duration; use memwal_core::{MemWal, MemWalProvisionConfig, RecallParams}; #[tokio::main] async fn main() -> Result<(), memwal_core::MemWalError> { let provisioned = MemWal::provision( MemWalProvisionConfig::new("suiprivkey...") .delegate_label("my-agent-app"), ) .await?; let memwal = provisioned.memwal(); // Remember (submits + waits for completion) let remembered = memwal .remember( "User prefers dark mode and uses Rust.", Duration::from_millis(1500), Duration::from_secs(60), ) .await?; println!("stored: {}", remembered.id); // Recall with natural language let recalled = memwal .recall(RecallParams { query: "What does the user prefer?".to_owned(), limit: Some(5), namespace: None, top_k: None, max_distance: None, }) .await?; for m in recalled.results { println!(" (dist {:.3}) {}", m.distance, m.text); } // Optional revoke let _ = provisioned.revoke_delegate_key().await?; Ok(()) }

Bulk, Analyze, and Restore

Code
// Bulk remember let bulk = memwal .remember_bulk(&[ memwal_core::RememberBulkItem { text: "Fact one".into(), namespace: None }, memwal_core::RememberBulkItem { text: "Fact two".into(), namespace: None }, ]) .await?; let results = memwal .remember_bulk_and_wait(&[...], Duration::from_secs(1), Duration::from_secs(120)) .await?; // Analyze extracts facts let analysis = memwal .analyze("Long paragraph with several key facts.", memwal_core::AnalyzeOptions::default()) .await?; // Restore index from Walrus let restored = memwal.restore("my-namespace", 100).await?;

Manual / Client-Side Mode (Zero-Trust Flow)

For strict security requirements, the MemWalManual client allows you to handle embeddings, encryption, and storage locally on your client machine before ever touching the relayer. The relayer will never see your plaintext data.

To use this flow, you must inject your own EmbeddingProvider (for local vector embeddings) and a WalrusBlobStore (for local Walrus interactions).

Code
use memwal_core::manual::{ MemWalManual, MemWalManualConfig, OllamaEmbeddingProvider, SuiNetwork, WalrusHttpStore, }; use memwal_core::sui::Ed25519Signer; use memwal_core::types::ManualRecallOptions; use std::sync::Arc; async fn manual_example( delegate_suiprivkey: &str, account_id: sui_sdk_types::Address, ) -> Result<(), Box<dyn std::error::Error>> { // 1. Setup local dependencies let signer = Arc::new(Ed25519Signer::from_suiprivkey(delegate_suiprivkey)?); let embedder = Arc::new(OllamaEmbeddingProvider::new("nomic-embed-text-v2-moe")); let store = Arc::new(WalrusHttpStore::new( "https://publisher.walrus-testnet.walrus.space", "https://aggregator.walrus-testnet.walrus.space" )); // 2. Configure manual client let config = MemWalManualConfig::new( account_id, "0x...package_id...", SuiNetwork::Testnet, signer, embedder, store, ).with_relayer_url("https://relayer.memory.walrus.xyz"); let memwal = MemWalManual::new(config); // 3. Embeds text locally, encrypts it with Seal locally, uploads to Walrus, then registers with Relayer let remembered = memwal.remember_manual("Top secret local text.", Some("default")).await?; println!("Stored secure memory: {}", remembered.blob_id); // 4. Searches relayer, downloads encrypted blob from Walrus, decrypts it locally with Seal let recalled = memwal.recall_manual(ManualRecallOptions { query: "What is secret?".to_owned(), namespace: Some("default".to_owned()), ..Default::default() }).await?; println!("Matches: {}", recalled.results.len()); Ok(()) }

Note: The OllamaEmbeddingProvider is great for testing this zero-trust workflow locally. If pointing it at the public MemWal relayer, the SDK handles automatically padding your local model’s embeddings to the required 1536-dimensional size so the transaction succeeds. For production, you can use OpenAiEmbeddingProvider or implement your own EmbeddingProvider trait.

Direct MemWal Construction

If you already have a delegate key and account ID:

Code
use memwal_core::{DelegateKey, MemWal, MemWalConfig}; let delegate = DelegateKey::from_suiprivkey("suiprivkey...")?; let memwal = MemWal::new(MemWalConfig::new( delegate, /* account address */, Some("https://relayer.memory.walrus.xyz".into()), Some("my-namespace".into()), )) .await?;

Health and Compatibility

Code
let health = memwal.health().await?; let meta = memwal.compatibility().await?; println!("delegate pubkey: {}", memwal.delegate_public_key_hex());

The SDK performs compatibility checks on first authenticated call.

Configuration Options (MemWalProvisionConfig)

  • new(delegate_suiprivkey) — delegate key used to sign relayer requests
  • .wallet_suiprivkey(...) — separate key for on-chain account transactions (optional)
  • .account_id(...) or .registry_id(...) — explicit account or registry for create/reuse
  • .namespace(...) — default namespace (falls back to “default”)
  • .delegate_label(...) — on-chain label for the delegate key
  • .server_url(...) / .relayer_config_url(...) — override discovery
  • .mode(...)ReuseOrCreate (default) or other ProvisionAccountMode

Resources

The Rust SDK mirrors the core flows of the TypeScript/Python SDKs while exposing a native async API. Crates.io: memwal-core.