
Memory
- 13 installs
- 610 repo stars
- Updated June 26, 2026
- alsk1992/cloddsbot
memory is a Claude Code skill that stores and recalls user preferences, facts, notes, and rules across conversations using vector-embedding semantic search.
About
This skill gives the clodds bot a persistent memory system for user preferences, facts, notes, and trading rules across conversations. A developer uses it to store and recall structured memories and run semantic search over them via embeddings. It supports LanceDB, SQLite, and PostgreSQL backends and a daily trading journal.
- Store preferences, facts, notes, and rules across conversations
- Semantic search over memories using vector embeddings
- Backends for LanceDB, SQLite, and PostgreSQL with pgvector
Memory by the numbers
- 13 all-time installs (skills.sh)
- Ranked #11,409 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
memory capabilities & compatibility
Requires an OpenAI key for embeddings; optional MEMORY_ENCRYPTION_KEY
- Capabilities
- persistent memory · semantic search · agent memory
- Works with
- postgres · openai
- Use cases
- memory
- Runs
- Runs locally
- Pricing
- Bring your own API key
What memory says it does
Semantic search powered by vector embeddings.
backend: 'lancedb', // 'lancedb' | 'sqlite' | 'postgres'
npx skills add https://github.com/alsk1992/cloddsbot --skill memoryAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 13 |
|---|---|
| repo stars | ★ 610 |
| Last updated | June 26, 2026 |
| Repository | alsk1992/cloddsbot ↗ |
What it does
Persist and semantically recall user preferences, facts, notes, and trading rules across bot conversations.
Who is it for?
Giving the bot durable memory of user preferences and trading rules
Skip if: General-purpose knowledge base outside the clodds bot context
When should I use this skill?
You need to remember, recall, or semantically search user context
What you get
Preferences, facts, notes, and rules persist and can be recalled by meaning.
By the numbers
- 5 memory types (preference, fact, note, rule, context)
- 3 storage backends (LanceDB, SQLite, PostgreSQL)
Files
Memory - Complete API Reference
Store and recall user preferences, facts, and notes across conversations. Semantic search powered by vector embeddings.
---
Chat Commands
Store Memories
/remember preference risk=conservative Save trading preference
/remember fact BTC halving is in April 2028 Store a fact
/remember note Check ETH before market open Save a note
/remember rule Never trade during FOMC Store trading ruleRecall Memories
/memory View all memories
/memory preferences View preferences only
/memory facts View facts only
/memory notes View notes only
/memory rules View trading rules
/memory search "bitcoin" Search memoriesForget Memories
/forget <key> Delete specific memory
/forget all preferences Clear all preferences
/forget all Clear everything (careful!)---
TypeScript API Reference
Create Memory Service
import { createMemoryService } from 'clodds/memory';
const memory = createMemoryService({
// Storage backend
backend: 'lancedb', // 'lancedb' | 'sqlite' | 'postgres'
// Embedding model
embeddings: {
provider: 'openai',
model: 'text-embedding-3-small',
},
// Options
encryptionKey: process.env.MEMORY_ENCRYPTION_KEY,
});Remember (Store)
// Store a preference
await memory.remember({
userId: 'user-123',
type: 'preference',
key: 'risk_tolerance',
value: 'conservative',
});
// Store a fact
await memory.remember({
userId: 'user-123',
type: 'fact',
content: 'BTC halving occurs approximately every 4 years',
metadata: { topic: 'crypto', confidence: 0.95 },
});
// Store a note
await memory.remember({
userId: 'user-123',
type: 'note',
content: 'Check Polymarket for election markets before Tuesday',
metadata: { priority: 'high' },
});
// Store a trading rule
await memory.remember({
userId: 'user-123',
type: 'rule',
content: 'Never trade more than 5% of portfolio on single position',
});Recall (Retrieve)
// Get all memories for user
const all = await memory.recall({ userId: 'user-123' });
// Get by type
const preferences = await memory.recall({
userId: 'user-123',
type: 'preference',
});
// Get specific key
const risk = await memory.recall({
userId: 'user-123',
type: 'preference',
key: 'risk_tolerance',
});Semantic Search
// Search by meaning (not just keywords)
const results = await memory.semanticSearch({
userId: 'user-123',
query: 'what is my risk appetite?',
limit: 5,
threshold: 0.7, // Similarity threshold
});
for (const result of results) {
console.log(`${result.type}: ${result.content}`);
console.log(` Similarity: ${result.score}`);
}Forget (Delete)
// Delete specific memory
await memory.forget({
userId: 'user-123',
type: 'preference',
key: 'risk_tolerance',
});
// Delete all of a type
await memory.forgetByType({
userId: 'user-123',
type: 'note',
});
// Delete all memories
await memory.forgetAll({ userId: 'user-123' });Daily Journal
// Log daily activity
await memory.logDaily({
userId: 'user-123',
date: new Date(),
trades: 5,
pnl: 123.45,
notes: 'Good day, caught BTC rally',
});
// Get journal entries
const journal = await memory.getDailyLogs({
userId: 'user-123',
from: '2024-01-01',
to: '2024-01-31',
});---
Memory Types
| Type | Purpose | Example |
|---|---|---|
| preference | User settings | risk=conservative |
| fact | Stored knowledge | "ETH gas is cheaper on weekends" |
| note | Reminders/todos | "Check election markets" |
| rule | Trading rules | "Max 5% per position" |
| context | Conversation context | Auto-saved by system |
---
Storage Backends
| Backend | Description | Best For |
|---|---|---|
| LanceDB | Vector DB with hybrid search | Production, semantic search |
| SQLite | Local file-based | Development, single user |
| PostgreSQL | Distributed with pgvector | Multi-user, production |
---
Best Practices
1. Be specific with keys — max_position_size not just size 2. Use types correctly — Preferences for settings, rules for constraints 3. Semantic search — Ask questions naturally, embeddings will match 4. Regular cleanup — Delete outdated notes and facts 5. Backup memories — Export before major changes
/**
* Memory CLI Skill
*
* Commands:
* /memory - Show recent memories
* /memory add <type> <key> <value> - Add a memory
* /memory search <query> - Search memories
* /memory forget <key> - Delete memory
* /memory types - Show memory types
* /memory clear <type> - Clear all memories of a type
* /memory context - Build context string
*/
import { logger } from '../../../utils/logger';
const DEFAULT_USER = 'cli';
const DEFAULT_CHANNEL = 'terminal';
function helpText(): string {
return `**Memory Commands**
/memory - Show recent memories
/memory add <type> <key> <value> - Store a memory
/memory recall <key> - Recall a specific memory by key
/memory search <query> - Search memories by keyword
/memory forget <key> - Delete a memory
/memory types - Show memory types
/memory clear <type> - Clear all memories of a type
/memory context - Build full context string
/memory list [type] - List memories (optionally by type)
**Memory types:** fact, preference, note, summary, context, profile
**Examples:**
/memory add fact trading-style "Prefers high-frequency scalping"
/memory add preference risk-level "Conservative, max 2% per trade"
/memory search trading
/memory recall risk-level
/memory forget old-note`;
}
async function execute(args: string): Promise<string> {
const parts = args.trim().split(/\s+/);
const cmd = parts[0]?.toLowerCase() || 'list';
try {
const { createDatabase } = await import('../../../db/index');
const { createMemoryService } = await import('../../../memory/index');
const db = createDatabase();
const memory = createMemoryService(db);
switch (cmd) {
case 'list':
case 'recent': {
const typeFilter = parts[1];
const entries = typeFilter
? memory.recallByType(DEFAULT_USER, DEFAULT_CHANNEL, typeFilter as any)
: memory.recallAll(DEFAULT_USER, DEFAULT_CHANNEL);
if (entries.length === 0) {
return typeFilter
? `**Memories (${typeFilter})**\n\nNo memories of type "${typeFilter}". Use \`/memory add ${typeFilter} <key> <value>\` to store one.`
: '**Recent Memories**\n\nNo memories stored yet. Use `/memory add <type> <key> <value>` to add one.';
}
const label = typeFilter ? `Memories (${typeFilter})` : 'Recent Memories';
let output = `**${label}** (${entries.length})\n\n`;
for (const entry of entries.slice(0, 20)) {
const age = timeSince(entry.updatedAt);
output += `- [${entry.type}] **${entry.key}**: ${entry.value} (${age})\n`;
}
if (entries.length > 20) {
output += `\n... and ${entries.length - 20} more`;
}
return output;
}
case 'add':
case 'store':
case 'remember': {
const type = parts[1];
const key = parts[2];
const value = parts.slice(3).join(' ');
if (!type || !key || !value) {
return 'Usage: /memory add <type> <key> <value>\n\nTypes: fact, preference, note, summary, context, profile\n\nExample: /memory add fact name "John"';
}
const validTypes = ['fact', 'preference', 'note', 'summary', 'context', 'profile'];
if (!validTypes.includes(type)) {
return `Invalid memory type "${type}".\n\nValid types: ${validTypes.join(', ')}`;
}
memory.remember(DEFAULT_USER, DEFAULT_CHANNEL, type as any, key, value);
return `**Memory Stored**\n\n- Type: ${type}\n- Key: ${key}\n- Value: ${value}`;
}
case 'recall':
case 'get': {
const key = parts[1];
if (!key) return 'Usage: /memory recall <key>';
const entry = memory.recall(DEFAULT_USER, DEFAULT_CHANNEL, key);
if (!entry) {
return `No memory found with key "${key}".`;
}
return `**Memory: ${entry.key}**\n\n- Type: ${entry.type}\n- Value: ${entry.value}\n- Created: ${entry.createdAt.toISOString()}\n- Updated: ${entry.updatedAt.toISOString()}${entry.expiresAt ? `\n- Expires: ${entry.expiresAt.toISOString()}` : ''}`;
}
case 'search': {
const query = parts.slice(1).join(' ');
if (!query) return 'Usage: /memory search <query>';
const results = memory.search(DEFAULT_USER, DEFAULT_CHANNEL, query);
if (results.length === 0) {
return `**Search: "${query}"**\n\nNo matching memories found.`;
}
let output = `**Search: "${query}"** (${results.length} results)\n\n`;
for (const entry of results.slice(0, 15)) {
output += `- [${entry.type}] **${entry.key}**: ${entry.value}\n`;
}
return output;
}
case 'forget':
case 'delete':
case 'remove': {
const key = parts[1];
if (!key) return 'Usage: /memory forget <key>';
const deleted = memory.forget(DEFAULT_USER, DEFAULT_CHANNEL, key);
if (!deleted) {
return `No memory found with key "${key}".`;
}
return `Memory "${key}" deleted.`;
}
case 'clear': {
const type = parts[1];
if (!type) return 'Usage: /memory clear <type>\n\nTypes: fact, preference, note, summary, context, profile';
const validTypes = ['fact', 'preference', 'note', 'summary', 'context', 'profile'];
if (!validTypes.includes(type)) {
return `Invalid memory type "${type}".\n\nValid types: ${validTypes.join(', ')}`;
}
const count = memory.forgetByType(DEFAULT_USER, DEFAULT_CHANNEL, type as any);
return `Cleared ${count} memories of type "${type}".`;
}
case 'types': {
return `**Memory Types**\n\n- **fact** - Factual information about the user\n- **preference** - User preferences and settings\n- **note** - Free-form notes and observations\n- **summary** - Conversation or session summaries\n- **context** - Contextual information for sessions\n- **profile** - User profile data`;
}
case 'context': {
const context = memory.buildContextString(DEFAULT_USER, DEFAULT_CHANNEL);
if (!context) {
return '**Context**\n\nNo context available. Add some memories first.';
}
return `**Context String**\n\n${context}`;
}
case 'cleanup': {
const cleaned = memory.cleanup();
return `Cleaned up ${cleaned} expired memories.`;
}
default:
return helpText();
}
} catch (error) {
logger.debug({ error }, 'Memory skill init failed');
return helpText();
}
}
function timeSince(date: Date): string {
const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
if (seconds < 60) return `${seconds}s ago`;
const minutes = Math.floor(seconds / 60);
if (minutes < 60) return `${minutes}m ago`;
const hours = Math.floor(minutes / 60);
if (hours < 24) return `${hours}h ago`;
const days = Math.floor(hours / 24);
return `${days}d ago`;
}
export default {
name: 'memory',
description: 'Persistent memory system for preferences, facts, and notes',
commands: ['/memory', '/mem'],
handle: execute,
};
Related skills
FAQ
How does semantic search work here?
It matches queries by meaning using vector embeddings with a configurable similarity threshold.
What storage backends are supported?
LanceDB, SQLite, and PostgreSQL with pgvector.