Give Claude a persistent memory across sessions

Stores conversation context, decisions, and learned patterns locally so Claude remembers your project rules, past choices, and context across separate conversations without forgetting.

Best for: Teams running repetitive workflows where Claude should remember what happened last time.

Engineering / workflow-sprint-structuremetafor-engineersneeds-integrationfrom-repo

Skill file

Preview skill file
---
name: tencentdb-agent-memory
description: Local-first long-term memory for AI agents with symbolic short-term memory and layered long-term recall via a 4-tier progressive pipeline
triggers:
  - add agent memory to my project
  - implement long-term memory for my AI agent
  - set up TencentDB Agent Memory
  - configure agent memory with symbolic compression
  - enable memory layering for my agent
  - integrate agent memory with OpenClaw
  - reduce token usage with memory offloading
  - add persona and scenario memory
---

# tencentdb-agent-memory

> Skill by [ara.so](https://ara.so) — AI Agent Skills collection.

## What It Does

TencentDB Agent Memory provides **fully local** long-term memory for AI agents through a 4-tier progressive pipeline:

- **L0 Conversation**: Raw dialogue logs
- **L1 Atom**: Atomic facts extracted from conversations
- **L2 Scenario**: Scene blocks aggregated from atoms
- **L3 Persona**: User profile distilled from scenarios

It combines **symbolic short-term memory** (Mermaid canvas offloading) with **layered long-term memory** (persona/scenario pyramid) to:

- Cut token usage by up to **61.38%** (WideSearch benchmark)
- Improve task success by up to **51.52%** relative (WideSearch)
- Boost PersonaMem accuracy from **48%** to **76%**

**Zero external API dependencies** — runs entirely on local SQLite + sqlite-vec.

## Installation

### For OpenClaw

```bash
# Install the plugin
openclaw plugins install @tencentdb-agent-memory/memory-tencentdb

# Restart the gateway
openclaw gateway restart
```

### For Hermes (Docker)

```bash
# Build the image
docker build -f Dockerfile.hermes -t hermes-memory .

# Run with your LLM credentials
docker run -d \
  --name hermes-memory \
  --restart unless-stopped \
  -p 8420:8420 \
  -e MODEL_API_KEY="${YOUR_API_KEY}" \
  -e MODEL_BASE_URL="https://api.lkeap.cloud.tencent.com/v1" \
  -e MODEL_NAME="deepseek-v3.2" \
  -e MODEL_PROVIDER="custom" \
  -v hermes_data:/opt/data \
  hermes-memory
```

### As a Standalone Library

```bash
npm install @tencentdb-agent-memory/memory-tencentdb
```

```typescript
import { TencentDBMemory } from '@tencentdb-agent-memory/memory-tencentdb';

const memory = new TencentDBMemory({
  storage: {
    type: 'sqlite',
    dbPath: './data/memory.db'
  }
});

await memory.initialize();
```

## Configuration

### OpenClaw Zero-Config (Minimal)

```jsonc
// ~/.openclaw/openclaw.json
{
  "memory-tencentdb": {
    "enabled": true
  }
}
```

### Enable Short-Term Compression

```jsonc
{
  "memory-tencentdb": {
    "enabled": true,
    "config": {
      "offload": {
        "enabled": true
      }
    }
  },
  "plugins": {
    "slots": {
      "contextEngine": "openclaw-context-offload"
    }
  }
}
```

Then apply the runtime patch:

```bash
bash scripts/openclaw-after-tool-call-messages.patch.sh
```

### Full Configuration Schema

```jsonc
{
  "memory-tencentdb": {
    "enabled": true,
    "config": {
      // Storage backend
      "storage": {
        "type": "sqlite",  // or "postgres"
        "dbPath": "./data/memory.db",
        // For PostgreSQL:
        // "host": "localhost",
        // "port": 5432,
        // "database": "agent_memory",
        // "user": "postgres",
        // "password": "${POSTGRES_PASSWORD}"
      },
      
      // LLM for memory extraction
      "llm": {
        "provider": "custom",
        "apiKey": "${LLM_API_KEY}",
        "baseURL": "https://api.lkeap.cloud.tencent.com/v1",
        "model": "deepseek-v3.2"
      },
      
      // Embedding model (local by default)
      "embedding": {
        "provider": "local",  // or "openai"
        "model": "Xenova/all-MiniLM-L6-v2",
        "dimension": 384
      },
      
      // Memory extraction control
      "memory": {
        "autoExtract": true,
        "extractInterval": 10,  // Extract every 10 messages
        "personaUpdateThreshold": 50  // Update persona after 50 atoms
      },
      
      // Short-term offload
      "offload": {
        "enabled": true,
        "maxContextTokens": 100000,
        "compressionRatio": 0.3
      },
      
      // Recall settings
      "recall": {
        "topK": 5,
        "similarityThreshold": 0.6,
        "includePersona": true,
        "includeScenarios": true
      }
    }
  }
}
```

## Core Concepts

### Memory Layers

```
L3 Persona (user profile, preferences)
    ↑ aggregates from
L2 Scenario (scene blocks, common patterns)
    ↑ extracts from
L1 Atom (atomic facts)
    ↑ distills from
L0 Conversation (raw dialogue)
```

### Symbolic Memory (Mermaid Canvas)

Long tool outputs are:
1. **Offloaded** to external files (`refs/*.md`)
2. **Compressed** into Mermaid graph nodes with `node_id`
3. **Recalled** via `node_id` lookup when needed

```mermaid
graph LR
    A["Search Results (50k tokens)"] -->|offload| B[("refs/search-001.md")]
    A -->|symbolize| C["node_1234<br/>type: search<br/>summary: 3 key findings"]
    C -.recall via node_id.-> B
```

## Usage Examples

### Store a Conversation

```typescript
import { TencentDBMemory } from '@tencentdb-agent-memory/memory-tencentdb';

const memory = new TencentDBMemory({
  storage: { type: 'sqlite', dbPath: './memory.db' }
});

await memory.initialize();

// Store conversation turn
await memory.storeConversation({
  sessionId: 'session-123',
  userId: 'user-456',
  messages: [
    { role: 'user', content: 'I prefer tabs over spaces' },
    { role: 'assistant', content: 'Got it, I'll use tabs in code.' }
  ],
  metadata: { topic: 'coding-preferences' }
});
```

### Extract Atoms and Update Persona

```typescript
// Auto-extract runs every N messages (configurable)
// Or trigger manually:
await memory.extractAtoms('session-123');

// Check extracted atoms
const atoms = await memory.getAtoms('user-456', { limit: 10 });
console.log(atoms);
// [
//   { id: 'atom-1', content: 'User prefers tabs over spaces', category: 'preference' }
// ]

// Persona updates automatically after threshold
const persona = await memory.getPersona('user-456');
console.log(persona);
// {
//   userId: 'user-456',
//   profile: 'Prefers tabs, uses TypeScript, likes functional patterns',
//   preferences: { coding_style: 'tabs', language: 'TypeScript' }
// }
```

### Recall Relevant Memories

```typescript
// Before agent turn, recall relevant context
const recalled = await memory.recall({
  userId: 'user-456',
  query: 'how should I format this code?',
  topK: 5,
  includePersona: true,
  includeScenarios: true
});

console.log(recalled);
// {
//   persona: { profile: '...', preferences: {...} },
//   scenarios: [{ title: 'Code formatting', steps: [...] }],
//   atoms: [{ content: 'User prefers tabs', score: 0.89 }]
// }
```

### Offload Tool Output (Short-Term Memory)

```typescript
// Large tool output
const toolOutput = {
  tool: 'search',
  result: '...(50,000 tokens of search results)...'
};

// Offload and get symbolic reference
const offloaded = await memory.offloadContext({
  sessionId: 'session-123',
  content: toolOutput.result,
  metadata: { tool: 'search', timestamp: Date.now() }
});

console.log(offloaded);
// {
//   nodeId: 'node-1234',
//   mermaidNode: 'node-1234["🔍 Search: 3 findings"]',
//   refPath: 'refs/search-001.md',
//   summary: 'Found 3 relevant papers on neural memory'
// }

// Later, recover if needed
const recovered = await memory.recoverContext('node-1234');
console.log(recovered.content);  // Full original text
```

### Query Scenarios

```typescript
// Get common solution patterns
const scenarios = await memory.getScenarios('user-456', {
  topic: 'debugging',
  limit: 3
});

console.log(scenarios);
// [
//   {
//     id: 'scenario-1',
//     title: 'TypeScript type errors',
//     pattern: 'Check tsconfig, verify imports, run tsc --noEmit',
//     frequency: 12
//   }
// ]
```

## Common Patterns

### Agent Loop with Memory

```typescript
async function agentLoop(userId: string, userMessage: string) {
  const sessionId = `session-${Date.now()}`;
  
  // 1. Recall relevant context
  const memory = await memorySystem.recall({
    userId,
    query: userMessage,
    topK: 5
  });
  
  // 2. Build prompt with persona + recalled facts
  const systemPrompt = `
User Profile: ${memory.persona?.profile || 'No profile yet'}

Relevant memories:
${memory.atoms.map(a => `- ${a.content}`).join('\n')}

Recent scenarios:
${memory.scenarios.map(s => `- ${s.title}: ${s.pattern}`).join('\n')}
  `.trim();
  
  // 3. Call LLM
  const response = await llm.chat({
    messages: [
      { role: 'system', content: systemPrompt },
      { role: 'user', content: userMessage }
    ]
  });
  
  // 4. Store conversation
  await memorySystem.storeConversation({
    sessionId,
    userId,
    messages: [
      { role: 'user', content: userMessage },
      { role: 'assistant', content: response }
    ]
  });
  
  return response;
}
```

### Periodic Persona Refresh

```typescript
// Run nightly to update user personas
async function refreshPersonas() {
  const users = await memory.getAllUsers();
  
  for (const userId of users) {
    const atomCount = await memory.getAtomCount(userId);
    
    if (atomCount >= 50) {  // Threshold
      await memory.updatePersona(userId);
      console.log(`Updated persona for ${userId}`);
    }
  }
}

// Schedule with cron
// 0 2 * * * node refresh-personas.js
```

### Offload Long Tool Outputs

```typescript
async function handleToolCall(tool: string, args: any) {
  const result = await executeTool(tool, args);
  
  // If result is large, offload
  const tokenCount = estimateTokens(result);
  
  if (tokenCount > 10000) {
    const offloaded = await memory.offloadContext({
      sessionId: currentSession,
      content: result,
      metadata: { tool, args }
    });
    
    return {
      summary: offloaded.summary,
      nodeId: offloaded.nodeId,
      // Agent sees only Mermaid node in context
      mermaid: offloaded.mermaidNode
    };
  }
  
  return result;  // Small results stay inline
}
```

## Troubleshooting

### Memory not extracting

**Check extraction interval:**
```jsonc
{
  "memory": {
    "autoExtract": true,
    "extractInterval": 10  // Extracts every 10 messages
  }
}
```

**Manually trigger:**
```typescript
await memory.extractAtoms('session-id');
```

### Persona not updating

**Check threshold:**
```jsonc
{
  "memory": {
    "personaUpdateThreshold": 50  // Needs 50+ atoms
  }
}
```

**Force update:**
```typescript
await memory.updatePersona('user-id');
```

### Low recall quality

**Tune similarity threshold:**
```jsonc
{
  "recall": {
    "topK": 10,  // Return more results
    "similarityThreshold": 0.5  // Lower = more permissive
  }
}
```

**Check embedding model:**
```jsonc
{
  "embedding": {
    "provider": "openai",  // Try external embeddings
    "model": "text-embedding-3-small"
  }
}
```

### Offload not compressing

**Verify offload is enabled:**
```jsonc
{
  "offload": {
    "enabled": true,
    "maxContextTokens": 100000
  }
}
```

**For OpenClaw, check slot registration:**
```jsonc
{
  "plugins": {
    "slots": {
      "contextEngine": "openclaw-context-offload"
    }
  }
}
```

**Apply runtime patch:**
```bash
bash scripts/openclaw-after-tool-call-messages.patch.sh
```

### Database errors

**SQLite locked:**
- Ensure only one process accesses the DB
- Check file permissions on `dbPath`

**PostgreSQL connection failed:**
- Verify credentials and network access
- Check `storage.host`, `storage.port`, `storage.database`

### High memory usage

**Reduce embedding dimension:**
```jsonc
{
  "embedding": {
    "model": "Xenova/all-MiniLM-L6-v2",  // 384 dims (lighter)
    "dimension": 384
  }
}
```

**Limit recall scope:**
```jsonc
{
  "recall": {
    "topK": 3,  // Fewer results
    "includeScenarios": false  // Skip scenario recall
  }
}
```

## Environment Variables

```bash
# LLM API Key (required if using external LLM)
LLM_API_KEY=your-api-key-here

# PostgreSQL password (if using postgres storage)
POSTGRES_PASSWORD=your-db-password

# OpenAI API key (if using OpenAI embeddings)
OPENAI_API_KEY=your-openai-key
```

## Learn More

- **GitHub**: https://github.com/Tencent/TencentDB-Agent-Memory
- **Discord**: https://discord.gg/kDtHb5RW2
- **Benchmarks**: See README for WideSearch, SWE-bench, AA-LCR, PersonaMem results
- **Architecture**: 4-tier pyramid (L0 Conversation → L1 Atom → L2 Scenario → L3 Persona)

---

**Key Takeaway**: TencentDB Agent Memory lets agents remember user preferences, task context, and solution patterns across sessions — without dumping everything into context. Use symbolic compression for short-term overload and layered memory for long-term knowledge.

Source

Creator's repository · aradotso/ai-agent-skills

View on GitHub

Security

Security checks in progress
Results will appear here once audits complete
Checked by 3 independent security firms
Does it try to trick the AI?Not yet checkedPending · Gen Agent Trust Hub
Does it sneak in hidden code?Not yet checkedPending · Socket
Does it have known bugs?Not yet checkedPending · Snyk