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

## Eternal Memory — ElizaOS Plugin

Cloud persistence API for ElizaOS agents. Complements local memory with durable, portable, cross-agent storage.

**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).

### Install

```bash
npm install @eternal-memory/sdk ethers
```

### Plugin Setup

Load your private key from `runtime.getSetting()`, not `process.env`:

```typescript
import { EternalMemory } from '@eternal-memory/sdk';
import type {
  Plugin, Action, Provider, IAgentRuntime,
  Memory, State, HandlerCallback,
} from '@elizaos/core';

let memoryClient: EternalMemory | null = null;

function getClient(runtime: IAgentRuntime): EternalMemory {
  if (!memoryClient) {
    memoryClient = new EternalMemory({
      baseUrl: runtime.getSetting('ETERNAL_MEMORY_URL') || 'https://api.eternal-memory.xyz',
      privateKey: runtime.getSetting('AGENT_PRIVATE_KEY'),
    });
  }
  return memoryClient;
}
```

### Character Configuration

```json
{
  "name": "MyAgent",
  "plugins": ["eternal-memory-plugin"],
  "settings": {
    "AGENT_PRIVATE_KEY": "0xYOUR_PRIVATE_KEY",
    "ETERNAL_MEMORY_URL": "https://api.eternal-memory.xyz"
  }
}
```

### Actions

Full example — `STORE_MEMORY`:

```typescript
const storeMemoryAction: Action = {
  name: 'STORE_MEMORY',
  description: 'Store a piece of information in persistent Eternal Memory',
  similes: ['SAVE_MEMORY', 'REMEMBER', 'PERSIST'],

  validate: async (runtime: IAgentRuntime) => !!runtime.getSetting('AGENT_PRIVATE_KEY'),

  handler: async (
    runtime: IAgentRuntime, message: Memory, state: State,
    _options: Record<string, unknown>, callback: HandlerCallback,
  ) => {
    const client = getClient(runtime);
    const content = message.content as { key?: string; value?: unknown; namespace?: string };
    if (!content.key || !content.value) {
      await callback({ text: 'I need a key and value to store.' });
      return false;
    }
    const result = await client.store(content.key, content.value, {
      namespace: content.namespace || 'facts',
    });
    await callback({
      text: `Stored "${content.key}" in ${content.namespace || 'facts'} namespace. Cost: ${result.cost_usdc || 'free'}`,
    });
    return true;
  },

  examples: [
    [
      { user: '{{user1}}', content: { text: 'Remember that the API rate limit is 100 req/min' } },
      { user: '{{agent}}', content: { text: 'Stored "api-rate-limit" in facts namespace.' } },
    ],
  ],
};
```

Additional actions follow the same pattern — validate the key exists, call the SDK, report back:

```typescript
// RECALL_MEMORY — retrieve by key
const recallMemoryAction: Action = {
  name: 'RECALL_MEMORY',
  similes: ['GET_MEMORY', 'RECALL', 'FETCH_MEMORY'],
  validate: async (runtime) => !!runtime.getSetting('AGENT_PRIVATE_KEY'),
  handler: async (runtime, message, _state, _opts, callback) => {
    const { key, namespace } = message.content as { key?: string; namespace?: string };
    if (!key) { await callback({ text: 'I need a key to recall.' }); return false; }
    const result = await getClient(runtime).retrieve(key, namespace || 'facts');
    await callback({ text: result.data ? `Recalled "${key}": ${JSON.stringify(result.data)}` : `No memory found for "${key}"` });
    return true;
  },
  // ...examples
};

// LIST_MEMORIES — list entries in a namespace
const listMemoriesAction: Action = {
  name: 'LIST_MEMORIES',
  similes: ['SHOW_MEMORIES', 'BROWSE_MEMORIES'],
  validate: async (runtime) => !!runtime.getSetting('AGENT_PRIVATE_KEY'),
  handler: async (runtime, message, _state, _opts, callback) => {
    const { namespace, limit } = message.content as { namespace?: string; limit?: number };
    const result = await getClient(runtime).list({ namespace, limit: limit || 20 });
    const keys = result.entries.map((e: { key: string }) => e.key).join(', ');
    await callback({ text: `Found ${result.total} memories${namespace ? ` in "${namespace}"` : ''}. Keys: ${keys}` });
    return true;
  },
  // ...examples
};
```

### Provider

Inject memory context into prompts. Cache the status call to avoid per-prompt API costs:

```typescript
let cachedStatus: { text: string; ts: number } | null = null;

const eternalMemoryProvider: Provider = {
  get: async (runtime: IAgentRuntime) => {
    if (cachedStatus && Date.now() - cachedStatus.ts < 300_000) return cachedStatus.text;
    try {
      const status = await getClient(runtime).status();
      const s = status.storage;
      const text = `[Eternal Memory] ${s.totalEntries} entries across ${s.namespaces?.length || 0} namespaces.${
        s.namespaces?.length ? ` Namespaces: ${s.namespaces.join(', ')}` : ''}`;
      cachedStatus = { text, ts: Date.now() };
      return text;
    } catch { return '[Eternal Memory] Not connected.'; }
  },
};
```

### Plugin Export

```typescript
export const eternalMemoryPlugin: Plugin = {
  name: 'eternal-memory',
  description: 'Persistent cloud memory for cross-session continuity and knowledge sharing',
  actions: [storeMemoryAction, recallMemoryAction, listMemoriesAction],
  providers: [eternalMemoryProvider],

  async initialize(runtime: IAgentRuntime) {
    try {
      const client = getClient(runtime);
      // Restore soul data on boot
      const soul = await client.list({ namespace: 'soul', include: 'values' });
      for (const entry of soul.entries) {
        runtime.setState(entry.key, entry.value);
      }
      if (soul.entries.length > 0) {
        console.log(`[eternal-memory] Restored ${soul.entries.length} soul entries`);
      }
    } catch (e) {
      console.warn('[eternal-memory] Could not restore state on init:', e);
    }
  },
};

export default eternalMemoryPlugin;
```

### 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.

```typescript
await client.store('pattern', { text: 'retry with backoff' }, {
  namespace: 'procedures', embeddingText: 'retry with exponential backoff for API calls',
});

const results = await client.query(undefined, { queryText: 'API error handling', threshold: 0.7 });
```

### Namespaces

- `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
