---
name: eternal-memory
description: "Cloud persistence for agent memories, data, and embeddings — survives sandbox lifecycle events, enables cross-agent knowledge sharing"
compatibility: "Requires Rust 1.75+ and Node.js 18+"
metadata:
  platform: rig
  version: "0.3.0"
---

## Eternal Memory

Cloud persistence API for AI agents. Durable storage that outlives your local environment — plus cross-agent knowledge sharing via lineage.

**Base URL:** `https://api.eternal-memory.xyz`

**First 100 operations free (up to 10 MB total) — no USDC required to start.**

### Endpoints & Pricing

| Method | Endpoint | Cost (USDC) | Description |
|--------|----------|-------------|-------------|
| `POST` | `/v1/store` | $0.001 + $0.001/KB (+$0.0005 for server-side embed) | Store key-value, blob, or vector |
| `GET` | `/v1/retrieve/:key` | $0.0005 | Retrieve by key |
| `POST` | `/v1/query` | $0.001 (+$0.0005 for server-side embed) | Semantic vector search |
| `GET` | `/v1/list` | $0.0005 | List entries (filterable, `?include=values` for bulk restore) |
| `DELETE` | `/v1/delete/:key` | Free | Delete an entry |
| `POST` | `/v1/share` | $0.001 | Grant access to another agent |
| `GET` | `/v1/export` | $0.01 | Export all data (always requires payment — not free-tier eligible) |
| `GET` | `/v1/status` | Free | Usage summary |

Payment is automatic via x402 (HTTP 402 flow). First 100 paid operations are free per wallet (10 MB total).

### Setup

Download the SDK bridge (one-time):

```bash
curl -o sdk-bridge.mjs https://api.eternal-memory.xyz/sdk-bridge.mjs
```

Requires `node >= 18` in PATH (already available in most agent runtimes).

### Dependencies

```toml
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
```

### Rust Wrapper

The bridge delegates all auth, signing, and payment handling to the JS SDK — zero crypto dependencies in Rust.

```rust
use std::io::{BufRead, BufReader, Write, BufWriter};
use std::process::{Command, Child, Stdio};
use std::sync::atomic::{AtomicU64, Ordering};
use serde_json::Value;

pub struct EternalMemory {
    child: Child,
    writer: BufWriter<std::process::ChildStdin>,
    reader: BufReader<std::process::ChildStdout>,
    next_id: AtomicU64,
}

impl EternalMemory {
    pub fn new(private_key: &str, base_url: &str) -> std::io::Result<Self> {
        let mut child = Command::new("node")
            .args(["sdk-bridge.mjs", "--base-url", base_url, "--private-key", private_key])
            .stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::inherit())
            .spawn()?;
        let writer = BufWriter::new(child.stdin.take().unwrap());
        let reader = BufReader::new(child.stdout.take().unwrap());
        Ok(Self { child, writer, reader, next_id: AtomicU64::new(1) })
    }

    fn call(&mut self, method: &str, args: Vec<Value>) -> Result<Value, String> {
        let id = self.next_id.fetch_add(1, Ordering::Relaxed);
        let msg = serde_json::json!({"id": id, "method": method, "args": args});
        writeln!(self.writer, "{}", msg).map_err(|e| e.to_string())?;
        self.writer.flush().map_err(|e| e.to_string())?;
        let mut line = String::new();
        self.reader.read_line(&mut line).map_err(|e| e.to_string())?;
        let resp: Value = serde_json::from_str(&line).map_err(|e| e.to_string())?;
        if let Some(err) = resp.get("error") { return Err(err.to_string()); }
        Ok(resp["result"].clone())
    }

    pub fn store(&mut self, key: &str, value: Value, opts: Value) -> Result<Value, String> {
        self.call("store", vec![key.into(), value, opts])
    }
    pub fn retrieve(&mut self, key: &str, ns: &str) -> Result<Value, String> {
        self.call("retrieve", vec![key.into(), ns.into()])
    }
    pub fn query(&mut self, embedding: Value, opts: Value) -> Result<Value, String> {
        self.call("query", vec![embedding, opts])
    }
    pub fn list(&mut self, opts: Value) -> Result<Value, String> {
        self.call("list", vec![opts])
    }
    pub fn delete(&mut self, key: &str, ns: &str) -> Result<Value, String> {
        self.call("delete", vec![key.into(), ns.into()])
    }
    pub fn share(&mut self, opts: Value) -> Result<Value, String> {
        self.call("share", vec![opts])
    }
    pub fn status(&mut self) -> Result<Value, String> {
        self.call("status", vec![])
    }
}

impl Drop for EternalMemory {
    fn drop(&mut self) { let _ = self.child.kill(); }
}
```

### Usage

```rust
use serde_json::json;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut mem = EternalMemory::new(
        "0xYOUR_PRIVATE_KEY",
        "https://api.eternal-memory.xyz",
    )?;

    // Store
    mem.store("agent-config", json!({"model": "llama-3", "temp": 0.7}),
        json!({"namespace": "soul"}))?;

    // Retrieve
    let data = mem.retrieve("agent-config", "soul")?;
    println!("{}", data);

    // List
    let entries = mem.list(json!({"namespace": "soul", "limit": 50}))?;

    // Semantic search — server-side embedding
    let results = mem.query(json!(null),
        json!({"queryText": "what patterns have I learned?", "threshold": 0.7}))?;

    // Delete (free)
    mem.delete("old-key", "default")?;

    // Share
    mem.share(json!({"granteeId": "0xChild...", "accessLevel": "inherit"}))?;

    // Status (free)
    println!("{}", mem.status()?);

    Ok(())
}
```

### Vector Search

**Server-side embedding (recommended):** Send `embeddingText` on store, `queryText` on query. 384-dim all-MiniLM-L6-v2. Surcharge: +$0.0005. Free tier included.

**Client-side embedding:** Send `embedding` + `embeddedWith` (model name). Model consistency enforced — cross-model queries return empty results.

### Namespaces

Organize data by purpose:
- `soul` — identity, SOUL.md backup, core values
- `procedures` — learned techniques and skills
- `goals` — active tasks and objectives
- `facts` — observations, API patterns, environmental constants
- `sessions` — continuity state, checkpoints
- `episodic` — high-importance events worth preserving long-term
- `relationships` — trust scores, interaction history across agents
- `reputation` — social layer feedback scores, agent discovery

### Notes

- **No encryption support** via bridge — encryption uses Node.js `crypto` and is only available in the TypeScript SDK
- Timestamp tolerance is 5 minutes — keep your system clock synchronized
- All endpoints accept and return JSON — the full request/response shapes match the [OpenAPI spec](https://api.eternal-memory.xyz/v1/docs)
- For Rig agents, create the `EternalMemory` struct once in setup and reuse it across tool calls
