@betterdb/memory
v0.5.0
Published
BetterDB Memory for Claude Code — Valkey-powered persistent memory across sessions
Downloads
834
Maintainers
Readme
BetterDB Memory for Claude Code
Persistent, semantic memory for Claude Code sessions — powered by Valkey.
Every time you start a new Claude Code session, context is lost. BetterDB Memory automatically captures what you did, embeds it as vectors in Valkey, and retrieves relevant history at the start of each new session.
Quick Start
Prerequisites
- Bun runtime — required (the CLI and all hooks run on Bun, not Node)
- Claude Code installed
- Valkey 8.0+ with the Search module
Install
# 1. Copy .env.example and fill in your settings
cp .env.example .env
# 2. Install
bunx @betterdb/memory installThe install will:
- Compile native hook binaries to
~/.betterdb/bin/ - Register 4 lifecycle hooks with Claude Code
- Register the MCP server for mid-conversation tools
- Create the Valkey search index
- Save your
.envvalues to~/.betterdb/memory.jsonfor runtime use
Don't have Valkey?
The setup skill will offer to spin one up in Docker for you. Or run it manually:
# Via CLI
bunx @betterdb/memory docker-valkey
# Or directly with Docker
docker run -d --name betterdb-valkey -p 6379:6379 -v betterdb-valkey-data:/data valkey/valkey-search:8 valkey-server --save 60 1How It Works
| Hook | What it does | |------|-------------| | SessionStart | Retrieves relevant memories via vector search, injects as context | | PostToolUse | Records every tool call to a temp JSONL file | | Stop | Summarizes the session, embeds it, stores in Valkey | | PreToolUse | Surfaces file-specific history when accessing known files |
MCP Tools
Claude can use these mid-conversation:
search_context— Semantic search over past sessions. Escalates project+branch → project → cross-project, and takes an optionaltagsfilter (decision,pattern,problem,open-thread)store_insight— Save a decision, pattern, or warninglist_open_threads— Show unresolved itemsforget— Delete a specific memory
CLI Commands
bunx @betterdb/memory install # Set up hooks + MCP server
bunx @betterdb/memory status # Check health + recall scoring config
bunx @betterdb/memory uninstall # Remove everything
bunx @betterdb/memory maintain # Run aging/compression manually
bunx @betterdb/memory forget # Bulk-delete by scope (dry run; --apply to delete)
# --project <name> | --all-projects --branch <b> --tags <a,b>
bunx @betterdb/memory docker-valkey # Manage Docker Valkey containerConfiguration
Copy .env.example to .env and fill in your values before running bunx @betterdb/memory install. They get saved to ~/.betterdb/memory.json and used by the compiled binaries at runtime.
Core
| Variable | Default | Description |
|----------|---------|-------------|
| BETTERDB_VALKEY_URL | redis://localhost:6379 | Valkey connection URL |
| BETTERDB_VALKEY_INDEX_NAME | betterdb-memory-index | Valkey search index name |
| BETTERDB_EMBED_DIM | 1024 | Embedding dimensions |
| BETTERDB_MAX_CONTEXT_MEMORIES | 5 | Max memories injected per session (after gating) |
| BETTERDB_CONTEXT_FILE | .betterdb_context.md | Context injection file |
| BETTERDB_ALLOW_REMOTE_FALLBACK | true | Fall back to remote APIs if local models unavailable |
Recall Gating
Recall over-fetches a candidate pool, gates it by relevance, and escalates on a
miss (project+branch → project → cross-project). Memories are stored with their
git branch as a native thread scope and content-type tags, so recall can narrow
to the current branch first and filter by type. search_context returns nothing
only when nothing clears the bar — so a miss is honest, not a silent drop.
The gate is relative, not an absolute similarity threshold: embed models
compress cosine similarity into different, narrow bands (mxbai-embed-large packs
everything into ~0.7–0.88), so a fixed threshold doesn't transfer across models.
Instead, floor drops genuine noise, and hits within margin of the top match
are kept; confidence comes from the scale-independent top-vs-next gap.
| Variable | Default | Description |
|----------|---------|-------------|
| BETTERDB_RECALL_FLOOR | 0.5 | Similarity floor — drops noise and loosens the store's own distance gate |
| BETTERDB_RECALL_MARGIN | 0.05 | Keep hits within this similarity of the top match |
| BETTERDB_RECALL_SEPARATION | 0.04 | Top-vs-next gap above which a match is "high" confidence |
| BETTERDB_RECALL_POOL_K | 10 | Rung-1 over-fetch pool (project) |
| BETTERDB_RECALL_POOL_K_WIDE | 20 | Rung-2/3 over-fetch pool (wider / cross-project) |
| BETTERDB_ALLOW_CROSS_PROJECT | true | Allow escalation / scope="all" to search across projects |
Ranking within the gated pool uses a composite score (similarity + recency +
importance), owned by @betterdb/agent-memory. Recency is the system's single
time-decay — a half-life applied at query time, not a stored per-memory aging
pass. These knobs tune it; defaults match the store's.
| Variable | Default | Description |
|----------|---------|-------------|
| BETTERDB_RECALL_HALF_LIFE_DAYS | 7 | Age at which a memory's recency term halves |
| BETTERDB_RECALL_WEIGHT_SIMILARITY | 0.6 | Weight of semantic similarity in the composite score |
| BETTERDB_RECALL_WEIGHT_RECENCY | 0.25 | Weight of recency |
| BETTERDB_RECALL_WEIGHT_IMPORTANCE | 0.15 | Weight of stored importance |
Model Providers
| Variable | Default | Description |
|----------|---------|-------------|
| BETTERDB_EMBED_PROVIDER | auto-detect | Force embed provider: local, ollama, voyage, openai, groq, together |
| BETTERDB_SUMMARIZE_PROVIDER | auto-detect | Force summarize provider: ollama, anthropic, openai, groq, together |
| BETTERDB_EMBED_MODEL | mxbai-embed-large | Ollama embedding model name |
| BETTERDB_SUMMARIZE_MODEL | mistral:7b | Ollama summarization model name |
| BETTERDB_OLLAMA_URL | http://localhost:11434 | Ollama API URL |
Embeddings work with zero config
If no embedding provider is detected (no Ollama models, no API keys), BetterDB falls back to on-device embeddings via @xenova/transformers (all-MiniLM-L6-v2, 384-dim, Apache-2.0). No API key, no running service — the model weights download once on first use and are cached thereafter. Auto-detected providers (Ollama, then API keys) take priority when available.
API Keys
Embeddings always work (on-device fallback above). A summarization provider is still required — Ollama is free and local; the others require API keys.
| Variable | Provider | Used for |
|----------|----------|----------|
| ANTHROPIC_API_KEY | Anthropic | Summarization only (no embeddings) |
| VOYAGE_API_KEY | Voyage AI | Embeddings only |
| OPENAI_API_KEY | OpenAI | Embeddings + summarization |
| GROQ_API_KEY | Groq | Embeddings + summarization |
| TOGETHER_API_KEY | Together AI | Embeddings + summarization |
Aging Pipeline
| Variable | Default | Description |
|----------|---------|-------------|
| BETTERDB_COMPRESS_THRESHOLD | 0.3 | Importance threshold for compression |
| BETTERDB_DISTILL_MIN_SESSIONS | 5 | Min sessions before knowledge distillation |
| BETTERDB_AGING_INTERVAL_HOURS | 6 | Hours between automatic aging runs |
License
MIT
