A production-ready semantic memory system for AI agents.
Combines semantic search, keyword search, and structured metadata into a single, fast, local-first memory store. Built for Claude, OpenAI, and any LLM that needs long-term memory.
- π Hybrid Search β Semantic (embeddings) + keyword (FTS5) + metadata filters
- β‘ Fast β SQLite with WAL mode, prepared statements, FTS5 full-text search
- π― Smart Ranking β RRF fusion, confidence scoring, temporal decay, usefulness tracking
- π MCP Protocol β 8 tools for Model Context Protocol (Claude Code, mcporter)
- π₯οΈ CLI β Zero-dependency CLI for terminal workflows
- π¨ Presets β Domain-specific configurations (coding, research, personal assistant)
- βοΈ Edge Deployment β Cloudflare Workers + D1 + Workers AI
- π¦ Local-First β Your data stays on your machine (or your Workers)
# Install
cd unified-memory
pnpm install && pnpm build
# CLI
npx @unified/cli store "JWT tokens should use httpOnly cookies" --project auth --tags security
npx @unified/cli search "authentication best practices" --mode hybrid --limit 5
npx @unified/cli stats
# MCP Server
export OPENAI_API_KEY=sk-...
node packages/mcp/dist/cli.js ~/.unified-memory/main.db
# Or via mcporter
mcporter config add unified-memory --stdio "node /path/to/mcp/dist/cli.js /path/to/memory.db"
mcporter call unified-memory.memory_search --args '{"query": "React hooks patterns"}'| Package | Description |
|---|---|
@unified/core |
Abstract types, interfaces, retrieval algorithms |
@unified/sqlite |
SQLite storage backend with FTS5 |
@unified/mcp |
MCP server with 8 tools |
@unified/cli |
Command-line interface |
@unified/presets |
Domain-specific configurations |
@unified/cloudflare |
Cloudflare Workers deployment |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Applications β
β Claude Code β’ mcporter β’ Custom LLM apps β’ CLI scripts β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β @unified/mcp (MCP Server) β
β 8 tools: store, search, get, delete, update, feedback, β
β stats, cleanup β
β + OpenAI embedding adapter β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β @unified/sqlite (Storage) β
β SQLite + FTS5 + vector storage + migrations β
β WAL mode, prepared statements, hybrid search β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β @unified/core (Abstractions) β
β MemoryStore interface, EmbeddingAdapter, RRF fusion, β
β confidence scoring, temporal decay β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Store coding patterns, architecture decisions, and debugging solutions:
// Claude can store memories as you code
mcporter call unified-memory.memory_store --args '{
"content": "React Query cache invalidation: use queryClient.invalidateQueries with exact:true to target specific queries",
"metadata": {"project": "web-app", "tags": ["react-query", "caching"], "language": "typescript"}
}'
// Search when solving similar problems
mcporter call unified-memory.memory_search --args '{
"query": "react query cache management",
"mode": "hybrid",
"project": "web-app"
}'Track preferences, decisions, and conversations:
# Store a preference
unified-memory store "I prefer meetings after 2pm on Tuesdays and Thursdays" \
--source preferences --tags scheduling
# Recall it later
unified-memory search "when do I prefer meetings" --mode semanticBuild a semantic knowledge base:
# Import papers/notes
cat research-notes.jsonl | unified-memory import --project phd-thesis
# Search by concept (semantic)
unified-memory search "attention mechanisms in transformers" --mode semantic --limit 20
# Export for backup
unified-memory export > backup-$(date +%Y%m%d).jsonl| Mode | How It Works | Best For |
|---|---|---|
| keyword | FTS5 full-text search (BM25) | Exact terms, code snippets, file paths |
| semantic | OpenAI embeddings + cosine similarity | Natural language, conceptual queries |
| hybrid | Both, fused with RRF | General use (default, best overall) |
| auto | Query analysis β picks best mode | Let the system decide |
Example:
# Keyword: exact code terms
unified-memory search "useEffect cleanup function" --mode keyword
# Semantic: natural language
unified-memory search "how to prevent memory leaks in React" --mode semantic
# Hybrid: best of both
unified-memory search "React hooks memory management" --mode hybridDomain-specific configurations that tune search weights, scoring, metadata, and cleanup policies.
import { resolvePreset, presetToSearchOptions } from '@unified/presets';
// Use a preset
const preset = resolvePreset('coding-assistant');
const searchOpts = presetToSearchOptions(preset);
// Override specific fields
const custom = resolvePreset('coding-assistant', {
search: { defaultAlpha: 0.9 }, // More semantic
scoring: { sessionBoost: 1.5 } // Stronger session affinity
});Built-in presets:
- coding-assistant β Code patterns, RRF fusion, branch/session boost
- personal-assistant β Natural language, recency bias, weekly cleanup
- research β Deep semantic search, long retention, minimal cleanup
- norwegian-construction β Norwegian language, TEK17/NS standards, domain synonyms
See packages/presets for details.
# Store a memory
unified-memory store "Your memory content here" --project my-app --tags tag1,tag2
# Search (hybrid by default)
unified-memory search "your query" --limit 10 --min-score 0.3
# Get by ID
unified-memory get <uuid>
# Update
unified-memory update <uuid> "New content" --usefulness 0.9
# Feedback (adjust usefulness)
unified-memory feedback <uuid> up # or: down, helpful, unhelpful, +, -
# List memories
unified-memory list --limit 25 --offset 0
# Statistics
unified-memory stats
# Cleanup (dry run by default)
unified-memory cleanup --min-usefulness 0.1 --older-than 90
unified-memory cleanup --min-usefulness 0.1 --older-than 90 --confirm
# Import/Export (JSON lines)
unified-memory export > backup.jsonl
cat backup.jsonl | unified-memory import --project restored
# Global options
unified-memory search "query" --db ~/memory.db --json --verboseSee packages/cli for full documentation.
When running as an MCP server, unified-memory exposes 8 tools:
| Tool | Description |
|---|---|
memory_store |
Store a new memory with metadata |
memory_search |
Search with semantic/keyword/hybrid modes |
memory_get |
Get a memory by ID (increments access count) |
memory_delete |
Delete a memory |
memory_update |
Update content or metadata |
memory_feedback |
Mark helpful/unhelpful (adjusts usefulness) |
memory_stats |
Get store statistics |
memory_cleanup |
Remove old/low-value memories |
Example MCP config (Claude Code):
{
"mcpServers": {
"unified-memory": {
"command": "node",
"args": ["/path/to/unified-memory/packages/mcp/dist/cli.js", "/path/to/memory.db"],
"env": {
"OPENAI_API_KEY": "sk-..."
}
}
}
}See packages/mcp for details.
SQLite database on your filesystem. Fast, private, zero-cost.
export UNIFIED_MEMORY_DB=~/.unified-memory/main.db
export OPENAI_API_KEY=sk-...
# Run MCP server
node packages/mcp/dist/cli.js $UNIFIED_MEMORY_DBDeploy to the edge with D1 (SQLite) + Workers AI (embeddings).
cd packages/cloudflare
wrangler d1 create unified-memory
wrangler d1 migrations apply unified-memory
wrangler deploySee packages/cloudflare for details.
- SQLite database with WAL mode for concurrent access
- FTS5 virtual table for full-text keyword search (BM25)
- Vector embeddings stored as BLOB (Float32Array)
- Metadata as JSON with generated columns for fast filtering
- Keyword search β FTS5 matches, BM25 scoring
- Semantic search β OpenAI embeddings, cosine similarity
- Hybrid fusion β Reciprocal Rank Fusion (RRF) combines both
- Reranking β Confidence scoring (relevance + usefulness + access + recency + metadata)
- Filtering β Project, tags, date range, session
Memories start at 50% usefulness. When you mark helpful (+0.1) or unhelpful (-0.1), the score adjusts. High-usefulness memories rank higher in search and survive cleanup.
Automatically (or manually) remove:
- Low usefulness (
--min-usefulness 0.1) - Rarely accessed (
--min-access 0) - Old entries (
--older-than 90)
Dry run by default. Add --confirm to actually delete.
# Clone
git clone https://github.com/beeard/unified-memory.git
cd unified-memory
# Install
pnpm install
# Build all packages
pnpm build
# Run tests (when implemented)
pnpm test
# Clean
pnpm cleanunified-memory/
βββ packages/
β βββ core/ # Abstract types, interfaces, algorithms
β βββ sqlite/ # SQLite storage implementation
β βββ mcp/ # MCP server with 8 tools
β βββ cli/ # Command-line interface
β βββ presets/ # Domain-specific configurations
β βββ cloudflare/ # Cloudflare Workers deployment
βββ scripts/ # Utility scripts
βββ README.md # This file
import type { MemoryStore, StoreParams, SearchOptions } from '@unified/core';
// Store a memory
const entry = await store.store({
content: "Your memory content",
metadata: { project: "my-app", tags: ["tag1"] },
usefulness: 0.8,
embedding: await embeddings.embed("Your memory content")
});
// Search
const response = await store.search("your query", {
mode: "hybrid",
limit: 10,
minScore: 0.3,
project: "my-app",
tags: ["tag1"]
});
// Get by ID
const memory = await store.get("uuid");
// Update
const updated = await store.update({
id: "uuid",
content: "New content",
metadata: { confidence: 0.95 }
});
// Delete
const deleted = await store.delete("uuid");
// Feedback
const feedback = await store.feedback({
memoryId: "uuid",
wasHelpful: true
});
// Stats
const stats = await store.stats();
// Cleanup
const result = await store.cleanup({
minUsefulness: 0.1,
olderThanDays: 90,
dryRun: false
});See individual package READMEs for detailed API docs.
If you're migrating from wip-tool-recall, wip-episodic-memory, or memory-server:
# Export from recall (if you had export functionality)
# Then import to unified-memory:
cat recall-export.jsonl | unified-memory import --source recallKey changes:
- Usefulness is now 0-1 (was 0-10) β automatically normalized
- RRF fusion is built-in (no need to configure)
- Session/branch boost is now in presets
Episodic patterns are supported via metadata:
await store.store({
content: "Conversation turn content",
metadata: {
sessionId: "session-123",
archivePath: "/path/to/archive.txt",
lineStart: 42,
lineEnd: 50,
source: "episodic"
}
});Norwegian construction preset is included:
import { resolvePreset } from '@unified/presets';
const preset = resolvePreset('norwegian-construction');Synonym expansion, stop words, and term boosting are built-in.
Contributions welcome! Please:
- Fork the repo
- Create a feature branch (
git checkout -b feature/amazing) - Commit your changes (
git commit -am 'Add amazing feature') - Push to the branch (
git push origin feature/amazing) - Open a Pull Request
MIT Β© beeard
This project consolidates patterns from:
- wip-tool-recall β RRF fusion, confidence scoring, usefulness tracking
- wip-episodic-memory β Session grouping, archive paths, conversation context
- memory-server β Domain presets, Norwegian language support, tag hierarchies
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Project Board: Memory Consolidation #13