Skip to content

amosdavis/drake-memory

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Drake Memory

A local-first AI memory agent written in Rust. Provides BM25 + vector hybrid search, a temporal knowledge graph, episodic/semantic memory layers, persona isolation, privacy-preserving tombstoning, and an HTTP API.

Features

  • Hybrid search — BM25 (0.5) + cosine vector (0.4) × Ebbinghaus decay
  • Temporal knowledge graph — entities, time-bounded relations, point-in-time queries
  • Persona isolation — all data scoped per persona; no cross-persona leakage
  • Right to be forgotten — SHA-256 tombstoning; content zeroed, hash preserved in audit log
  • MIP interop — JSON-LD export/import (Memory Interchange Protocol)
  • HTTP server — axum-based REST API on configurable port
  • Audit log — every create/read/tombstone/export is recorded

Install

cargo build --release
# binary at target/release/dm

PostgreSQL + pgvector

Drake Memory requires PostgreSQL with the pgvector extension for the memories.vector column and the HNSW cosine index. The schema apply (dm init, and every tool on first connect) hard-fails with extension "vector" is not available if pgvector is not installed.

Linux/macOS — install a PG distro that ships pgvector:

# Debian/Ubuntu (replace XX with your PG major version)
sudo apt install postgresql-XX-pgvector
# macOS (Homebrew)
brew install pgvector
# Or use the official Docker image
docker run -d --name pg -e POSTGRES_PASSWORD=pw -p 5432:5432 pgvector/pgvector:pg17

Windows — the scoop / EnterpriseDB installers do not ship pgvector. Run the helper script after installing PG:

# Requires Visual Studio 2022 BuildTools with the C++ workload
# (Microsoft.VisualStudio.Component.VC.Tools.x86.x64). The script is idempotent.
pwsh scripts\install-pgvector-windows.ps1

The script clones pgvector (pinned to v0.8.2), builds with MSVC against the local PG headers, installs vector.dll + extension files into the PG tree, and runs CREATE EXTENSION IF NOT EXISTS vector in drake_memory. See scripts/install-pgvector-windows.ps1 -? for parameters (-PgRoot, -PgvectorRef, -Database, -Force).

After installing the extension, verify with:

psql -d drake_memory -c "SELECT extname, extversion FROM pg_extension WHERE extname='vector';"

Quick start

dm init
dm store --content "The user prefers dark mode"
dm search --query "dark mode"
dm entity add --name "Alice" --type person
dm entity add --name "Acme" --type organization
dm relation add --subject Alice --predicate works-at --object Acme
dm kg query --name Alice
dm audit list
dm serve --port 8080

CLI reference

dm [--db <PATH>] <COMMAND>

Commands:
  init         Initialize DB + default persona
  store        Store a memory (--content, --confidence, --tags, --persona, --json)
  episode      Log an episode (--content, --role, --session, --persona, --json)
  search       Search memories (--query, --n, --persona, --as-of, --json)
  forget       Tombstone a memory (--id)
  mark         User-mark a memory (--id)
  entity       add --name --type --persona
  relation     add | invalidate
  kg           query --name --as-of --persona --json
  audit        list --limit --json
  consolidate  Run episode→memory consolidation (--persona, --json)
  export       MIP JSON-LD export (--persona, --output)
  import       MIP JSON-LD import (--file, --persona)
  persona      list | create
  serve        Start HTTP server (--port)
  status       DB statistics

HTTP API

Method Path Description
POST /memories Store memory
GET /memories/search Hybrid search
DELETE /memories/:id Tombstone memory
PUT /memories/:id/mark User-mark
POST /episodes Log episode
GET /episodes List recent episodes
POST /entities Add entity
POST /relations Add relation
GET /kg/query Query KG
GET /audit Audit log
POST /consolidate Run consolidation
GET /export MIP JSON-LD export
POST /import MIP JSON-LD import
GET /personas List personas
POST /personas Create persona
GET /status Status

BDD tests

Requires Go 1.21+ and the dm binary on $DM_BINARY.

cd bdd-tests/steps
DM_BINARY=../../target/release/dm go test -v ./...

Design tenets

See TENETS.md — eight failure modes the design explicitly avoids.

Configuration

Default config at ~/.config/drake-memory/config.toml. Override DB with --db <PATH> or DM_DB env var.

Environment variables

Variable Default Description
Database
DM_DATABASE_URL postgres://localhost/drake_memory PostgreSQL connection string. Overrides config.toml.
DM_DB (none) Legacy DB path / connection override accepted on the CLI.
DM_FORCE_SCHEMA false When 1 / true, force re-apply schema even if _dm_schema version matches.
DM_DB_POOL_SIZE auto Postgres connection pool size. Auto-sized as max(DM_UPSERT_CONCURRENCY, DM_FOLDER_CONCURRENCY) + 10. Override if you raise the concurrency vars beyond their defaults.
DM_DB_ACQUIRE_TIMEOUT_SECS 15 How long to wait for a free pool connection before erroring. Raise if you see acquire timeouts under heavy indexing.
Indexing concurrency
DM_REPO_CONCURRENCY 8 Max number of git repositories indexed in parallel during a wake/auto-index pass.
DM_PLAIN_DIR_CONCURRENCY 2 Max number of non-git subdirectories indexed in parallel. Capped low because each subdirectory itself fans out by DM_FOLDER_CONCURRENCY; raising this beyond 2 will likely require also raising DM_DB_POOL_SIZE to avoid pool starvation (see TENETS.md #10).
DM_FOLDER_CONCURRENCY 16 Max number of file indexing tasks per subdirectory.
DM_UPSERT_CONCURRENCY 16 Max concurrent memory upserts to PostgreSQL. Also drives the auto pool size.
LLM / embedding backend
DM_LLM_BACKEND mcp mcp = use the MCP host's connected LLM via sampling/createMessage for KG extraction and the built-in FNV/TF-IDF embedder for vectors (current default behavior). custom = call a local Ollama-compatible HTTP server for both KG extraction and embeddings.
DM_LLM_ENDPOINT http://localhost:11434 Base URL of the Ollama-compatible server when DM_LLM_BACKEND=custom.
DM_KG_MODEL qwen2.5:instruct Model passed to /api/generate for knowledge-graph entity / relation extraction.
DM_EMBEDDING_MODEL nomic-embed-text Model passed to /api/embeddings for memory vectors.
DM_LLM_TIMEOUT_SECS 60 Per-request timeout (KG generate and embeddings).

Concurrency tuning. The peak number of in-flight file tasks during an auto-index is approximately DM_REPO_CONCURRENCY + DM_PLAIN_DIR_CONCURRENCY × DM_FOLDER_CONCURRENCY, each of which may issue an upsert (capped further by DM_UPSERT_CONCURRENCY). Stay within DM_DB_POOL_SIZE or you will see acquire-timeout errors. If you raise DM_PLAIN_DIR_CONCURRENCY or DM_FOLDER_CONCURRENCY, also raise DM_DB_POOL_SIZE (or rely on the auto formula by raising DM_UPSERT_CONCURRENCY in lockstep).

Switching backends. Set DM_LLM_BACKEND=custom and (optionally) override the endpoint / model names above. If the custom embedder produces a different native dimension than the memories.vector column (512), output vectors are truncated or zero-padded and re-normalized to fit; for best recall, re-index after a swap. On any HTTP error the indexer falls back to the regex-based KG extractor and the FNV embedder so indexing never stalls on a flaky local model server.

Example — run with Ollama locally:

ollama pull qwen2.5:7b-instruct
ollama pull nomic-embed-text
DM_LLM_BACKEND=custom \
DM_KG_MODEL=qwen2.5:7b-instruct \
DM_EMBEDDING_MODEL=nomic-embed-text \
dm wake --background

About

Local AI memory agent in Rust backed by PostgreSQL — MCP server for GitHub Copilot CLI

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors