egeapak/engramdb

Rust

2

151 commits

updated Sep 14, 2026

See the code

README

EngramDB

CI License: MIT

Project-scoped persistent memory for coding agents. Stores decisions, hazards, conventions, and context about your codebase so your agent remembers across sessions.

EngramDB gives your AI coding agent a memory layer that persists between conversations. It stores what the agent learns about your project — architectural decisions, known hazards, team conventions, debugging context — and surfaces relevant memories automatically when the agent reads or edits files.

Features

  • Semantic search — vector similarity search powered by LanceDB and all-MiniLM-L6-v2 embeddings
  • Automatic context injection — hooks surface relevant memories when your agent touches files
  • Contradiction detection — NLI-based challenge system flags conflicting information
  • Epistemic classes — every memory is a fact, observation, or decision, orthogonal to its type; retrieval reweights classes by situation (observations surface while debugging, decisions while designing)
  • Bi-temporal validity — outdated memories are invalidated instead of deleted; superseded and consolidated memories stay queryable as history
  • Task-scoped memories — declare the task a session works on; completing it demotes its task-scoped memories, re-confirmed ones get promoted, and verify/doctor re-check what's still accurate
  • Memory lifecycle — criticality scoring, garbage collection, compression of stale memories
  • MCP server — full Model Context Protocol integration (stdio and SSE transports)
  • Shared embedding daemon — auto-spawned and self-healing; loads models once machine-wide instead of once per agent session, stays resident while sessions are connected, and is usable from the CLI too, with graceful in-process fallback
  • Claude Code plugin — one-command install with hooks, MCP, and permissions
  • Offline-first — all embeddings run locally via ONNX Runtime (or optionally Ollama)
  • Multiple output formats — pretty, JSON, or plain text for scripting

Quick Start

Install

Build from source (requires a recent stable Rust toolchain):

cargo install --git https://github.com/egeapak/engramdb

Set up Claude Code integration

The recommended way is via the plugin:

# Add the marketplace
/plugin marketplace add egeapak/engramdb

# Install the plugin
/plugin install engram@engramdb

Or set up manually with hooks and MCP in settings.json:

engramdb setup --global

For project-scoped setup (writes to <project>/.claude/):

engramdb setup

Use the CLI directly

# Initialize a store in the current project
engramdb init

# Add a memory (summary is required; omit it and a terminal will prompt for one)
engramdb add --type decision --title "Use PostgreSQL for persistence" \
  --summary "Chose PostgreSQL over SQLite for concurrent write support" \
  "The app needs many concurrent writers and SQLite serializes all writes."

# Find memories by keyword (filter mode requires a query signal)
engramdb query --mode filter "database choice"

# Rank memories relevant to a file (rank mode browses by context)
engramdb query --mode rank --path src/db/connection.rs

How It Works

EngramDB stores memories as structured files (TOML + markdown) in .engramdb/memories/ within your project. Each memory has:

  • Type — decision, convention, hazard, context, intent, relationship, debug, preference
  • Epistemic class — fact, observation, or decision (defaults from the type), with a bi-temporal validity window: memories are invalidated, not deleted
  • Visibility — project, team, or personal scope
  • Criticality — 0.0 to 1.0 score that decays over time
  • Embeddings — vector representations stored in a LanceDB index for semantic search

When integrated with Claude Code:

  1. SessionStart hook — injects high-criticality memories into the conversation at startup
  2. PreToolUse hook — when the agent reads/writes/edits a file, relevant memories are surfaced as context
  3. UserPromptSubmit hook — surfaces memories relevant to the prompt, inferring the situation (e.g. debugging vs. design)
  4. PostToolUse hook — warns when an edit touches paths a memory's validity depends on
  5. SessionEnd / PreCompact hooks — housekeeping and a store-your-memories reminder before compaction
  6. MCP server — the agent can search, create, update, and manage memories through tool calls

CLI Reference

CommandDescription
initInitialize a new EngramDB store
addAdd a new memory
getGet a memory by ID
queryUnified search: --mode filter requires a query signal; --mode rank browses by context
listList all memories
updateUpdate an existing memory
deleteDelete a memory
challengeChallenge a memory's validity
reviewInteractive review of challenged/stale memories
verifyConfirm a memory is still accurate (stamps verified_at, clears doctor-flagged reviews)
taskDeclare or complete the task this session works on (current/complete)
statsShow store statistics
doctorCheck environment and store health (--fix to repair, validate to test models)
gcGarbage collect low-relevance memories
compressList compression candidates
reindexRebuild index and re-embed all memories
migrateMigrate memory files to latest format
rollbackRoll back memory files to previous format
serveStart the MCP server
daemonManage the shared embedding daemon (run/status/stop/restart)
setupSet up Claude Code integration
hookClaude Code plugin hook handler
projectsManage registered EngramDB projects
completionsGenerate shell completions

stats --daemon shows the embedding daemon's cumulative request metrics (falling back to the last persisted snapshot when no daemon is running). doctor groups its report into Project (current project health), Projects (all registered projects), Global settings & models (binaries, integration, the active models with a short description of what each is for, and whether the embedding daemon is enabled and running), and Stats (global disk usage). When the current directory isn't an EngramDB project, the report collapses to just the "not set up" notice.

engramdb doctor --fix offers to repair the issues it finds (reindex, download the embedding model, prune stale projects, re-key a project whose ID drifted, or initialize the project) — it prompts on a terminal and applies non-interactively with --fix --yes. A run that applies fixes re-checks afterwards and exits on the post-fix state, and a run where nothing was fixable — or where you declined every fix — still exits on the checks themselves. The one deliberate exception is the non-interactive listing path (--fix without --yes off a terminal), which only reports the available fixes and exits 0. Flagging memories for review (the epistemic checks) is asked for separately, since it is the one part of --fix that edits memories. engramdb doctor validate loads each downloaded model and runs a test inference to confirm it actually works.

Use engramdb <command> --help for detailed options.

MCP Tools

When running as an MCP server (engramdb serve), the following tools are available:

ToolDescription
queryUnified search/retrieve. mode: "filter" narrows by query/logical/path/tags; mode: "rank" ranks memories by relevance to a context
createStore a new memory
getFetch a specific memory by ID
listList all memories with optional filters
updateModify an existing memory
deleteRemove a memory
challengeFlag a memory as potentially incorrect
reviewList memories needing review
resolveAccept, update, invalidate, or delete a challenged memory
verifyRe-confirm a memory is still accurate, refreshing fact decay
task_currentDeclare (or read) the task this session is working on
task_completeMark a task finished, demoting its task-scoped memories
statsStore statistics and health info
doctorEnvironment and store diagnostics
gcGarbage collect low-relevance memories
reindexRebuild the vector index
compress_candidatesList memories eligible for compression
compress_applyMerge multiple memories into a summary
projects_listList all registered projects, including hierarchy
projects_infoInfo about a specific project (id, name, path, memory count, scopes)
projects_linkLink a registered project as a sub-project of another
projects_unlinkRemove a project's parent link, promoting it back to a root project

Configuration

EngramDB reads configuration from .engramdb/config.toml:

Each section is optional, but a section you do write must be complete: once a section header appears, every field in it that has no built-in default is required. In particular, an [embeddings] table must set provider, dimensions, and max_tokens (no defaults — this keeps a partial embeddings config from silently mismatching the index), and any [retrieval.scoring] or [thresholds] table must set all of its fields. The example below parses as-is; see docs/users/configuration.md for the complete, copy-pasteable schema with every field and its default.

[embeddings]
backend = "auto"   # "auto" (default), "onnx", or "ollama"
provider = "onnx"  # required when [embeddings] is present
dimensions = 384   # required; must match the provider
max_tokens = 256   # required

[daemon]
enabled = true            # Delegate embedding/NLI/rerank to the shared daemon
use_for_cli = true        # Also use the daemon from model-needing CLI commands
idle_timeout_secs = 900   # Daemon reaps this long after the last session disconnects
# socket_path = "/run/user/1000/engramdb/daemon.sock"  # optional override

Embedding backends

  • auto (default) — tries ONNX first, falls back to Ollama
  • onnx — local ONNX Runtime with all-MiniLM-L6-v2, no external dependencies
  • ollama — uses a local Ollama instance for embeddings (requires ollama running)

Models are cached in the system cache directory (~/Library/Caches/engramdb/models on macOS).

Embedding daemon

Each engramdb serve (stdio MCP) process is one-per-agent-session, so without coordination every concurrent session loads its own copy of the embedding (and optional NLI/reranker) models — hundreds of MB and a ~240 ms ONNX init each.

When [daemon].enabled is true (the default), MCP processes delegate all model work to a single long-lived daemon over a per-user Unix domain socket, so each model loads exactly once machine-wide. Storage stays in the MCP process (it is already cross-process safe), so only inference is delegated.

  • Auto-spawned on demand. You never start it manually. When an MCP process needs the daemon and none is reachable, it spawns one (engramdb daemon run) detached, waits briefly, and connects. Concurrent spawns are race-safe (only one binds the socket).

  • Stays alive while sessions are connected, then reaps. Each serve process runs a background heartbeat that pings the daemon every idle_timeout_secs / 3 (min 30 s), keeping it resident as long as any session is running. It exits idle_timeout_secs after the last session disconnects.

  • Self-healing. If the daemon idle-exits, crashes, or is replaced, the heartbeat re-spawns a fresh one and live sessions route to it on their next request — no agent restart needed.

  • Usable from the CLI. Model-needing CLI commands use a running daemon when reachable (connect-only by default — they don't spawn one). Override with --in-process / ENGRAMDB_IN_PROCESS=1 / [daemon].use_for_cli = false, or let the CLI spawn one with --spawn-daemon.

  • Graceful fallback. If the daemon is disabled or unreachable, MCP and the CLI load models in-process exactly as before — operations never fail because of the daemon.

  • Manage it directly (rarely needed):

    engramdb daemon status     # running? pid, uptime, request metrics
    engramdb daemon stop       # graceful shutdown (next MCP run respawns it)
    engramdb daemon restart    # stop + start a fresh one
    engramdb daemon run        # run the loop in the foreground (debugging)
    engramdb stats --daemon    # cumulative request metrics (persisted)
    

    The socket path resolves with precedence --socket flag > ENGRAMDB_DAEMON_SOCKET env > [daemon].socket_path config > the default per-user runtime path. status/stop/restart/run all accept --socket to target a non-default daemon.

Daemon request metrics are persisted to the global store's LanceDB, so stats --daemon reports figures even when no daemon is currently running, and counts stay cumulative across daemon restarts.

Building from Source

git clone https://github.com/egeapak/engramdb
cd engramdb
cargo build --release

Run tests:

cargo nextest run --workspace --all-features

Documentation

Comprehensive docs live in docs/, organized by audience:

  • docs/users/ — install, CLI reference, configuration, Claude Code integration, projects/worktrees, embeddings, daemon, troubleshooting.
  • docs/agents/ — MCP tool reference and workflows for AI agents using engramdb.
  • docs/contributors/ — architecture, code organization, testing conventions, extension recipes.

Contributing

Contributions are welcome. Please open an issue to discuss significant changes before submitting a PR.

  1. Fork the repository
  2. Create a feature branch
  3. Ensure cargo fmt --all and cargo clippy --workspace --all-targets --all-features -- -D warnings pass
  4. Submit a pull request

License

MIT License — see LICENSE for details.

Contributors

egeapak

143 commits

claude

5 commits

egeapak/engramdb

Rust

2

151 commits

updated Sep 14, 2026

See the code

README

EngramDB

CI License: MIT

Project-scoped persistent memory for coding agents. Stores decisions, hazards, conventions, and context about your codebase so your agent remembers across sessions.

EngramDB gives your AI coding agent a memory layer that persists between conversations. It stores what the agent learns about your project — architectural decisions, known hazards, team conventions, debugging context — and surfaces relevant memories automatically when the agent reads or edits files.

Features

  • Semantic search — vector similarity search powered by LanceDB and all-MiniLM-L6-v2 embeddings
  • Automatic context injection — hooks surface relevant memories when your agent touches files
  • Contradiction detection — NLI-based challenge system flags conflicting information
  • Epistemic classes — every memory is a fact, observation, or decision, orthogonal to its type; retrieval reweights classes by situation (observations surface while debugging, decisions while designing)
  • Bi-temporal validity — outdated memories are invalidated instead of deleted; superseded and consolidated memories stay queryable as history
  • Task-scoped memories — declare the task a session works on; completing it demotes its task-scoped memories, re-confirmed ones get promoted, and verify/doctor re-check what's still accurate
  • Memory lifecycle — criticality scoring, garbage collection, compression of stale memories
  • MCP server — full Model Context Protocol integration (stdio and SSE transports)
  • Shared embedding daemon — auto-spawned and self-healing; loads models once machine-wide instead of once per agent session, stays resident while sessions are connected, and is usable from the CLI too, with graceful in-process fallback
  • Claude Code plugin — one-command install with hooks, MCP, and permissions
  • Offline-first — all embeddings run locally via ONNX Runtime (or optionally Ollama)
  • Multiple output formats — pretty, JSON, or plain text for scripting

Quick Start

Install

Build from source (requires a recent stable Rust toolchain):

cargo install --git https://github.com/egeapak/engramdb

Set up Claude Code integration

The recommended way is via the plugin:

# Add the marketplace
/plugin marketplace add egeapak/engramdb

# Install the plugin
/plugin install engram@engramdb

Or set up manually with hooks and MCP in settings.json:

engramdb setup --global

For project-scoped setup (writes to <project>/.claude/):

engramdb setup

Use the CLI directly

# Initialize a store in the current project
engramdb init

# Add a memory (summary is required; omit it and a terminal will prompt for one)
engramdb add --type decision --title "Use PostgreSQL for persistence" \
  --summary "Chose PostgreSQL over SQLite for concurrent write support" \
  "The app needs many concurrent writers and SQLite serializes all writes."

# Find memories by keyword (filter mode requires a query signal)
engramdb query --mode filter "database choice"

# Rank memories relevant to a file (rank mode browses by context)
engramdb query --mode rank --path src/db/connection.rs

How It Works

EngramDB stores memories as structured files (TOML + markdown) in .engramdb/memories/ within your project. Each memory has:

  • Type — decision, convention, hazard, context, intent, relationship, debug, preference
  • Epistemic class — fact, observation, or decision (defaults from the type), with a bi-temporal validity window: memories are invalidated, not deleted
  • Visibility — project, team, or personal scope
  • Criticality — 0.0 to 1.0 score that decays over time
  • Embeddings — vector representations stored in a LanceDB index for semantic search

When integrated with Claude Code:

  1. SessionStart hook — injects high-criticality memories into the conversation at startup
  2. PreToolUse hook — when the agent reads/writes/edits a file, relevant memories are surfaced as context
  3. UserPromptSubmit hook — surfaces memories relevant to the prompt, inferring the situation (e.g. debugging vs. design)
  4. PostToolUse hook — warns when an edit touches paths a memory's validity depends on
  5. SessionEnd / PreCompact hooks — housekeeping and a store-your-memories reminder before compaction
  6. MCP server — the agent can search, create, update, and manage memories through tool calls

CLI Reference

CommandDescription
initInitialize a new EngramDB store
addAdd a new memory
getGet a memory by ID
queryUnified search: --mode filter requires a query signal; --mode rank browses by context
listList all memories
updateUpdate an existing memory
deleteDelete a memory
challengeChallenge a memory's validity
reviewInteractive review of challenged/stale memories
verifyConfirm a memory is still accurate (stamps verified_at, clears doctor-flagged reviews)
taskDeclare or complete the task this session works on (current/complete)
statsShow store statistics
doctorCheck environment and store health (--fix to repair, validate to test models)
gcGarbage collect low-relevance memories
compressList compression candidates
reindexRebuild index and re-embed all memories
migrateMigrate memory files to latest format
rollbackRoll back memory files to previous format
serveStart the MCP server
daemonManage the shared embedding daemon (run/status/stop/restart)
setupSet up Claude Code integration
hookClaude Code plugin hook handler
projectsManage registered EngramDB projects
completionsGenerate shell completions

stats --daemon shows the embedding daemon's cumulative request metrics (falling back to the last persisted snapshot when no daemon is running). doctor groups its report into Project (current project health), Projects (all registered projects), Global settings & models (binaries, integration, the active models with a short description of what each is for, and whether the embedding daemon is enabled and running), and Stats (global disk usage). When the current directory isn't an EngramDB project, the report collapses to just the "not set up" notice.

engramdb doctor --fix offers to repair the issues it finds (reindex, download the embedding model, prune stale projects, re-key a project whose ID drifted, or initialize the project) — it prompts on a terminal and applies non-interactively with --fix --yes. A run that applies fixes re-checks afterwards and exits on the post-fix state, and a run where nothing was fixable — or where you declined every fix — still exits on the checks themselves. The one deliberate exception is the non-interactive listing path (--fix without --yes off a terminal), which only reports the available fixes and exits 0. Flagging memories for review (the epistemic checks) is asked for separately, since it is the one part of --fix that edits memories. engramdb doctor validate loads each downloaded model and runs a test inference to confirm it actually works.

Use engramdb <command> --help for detailed options.

MCP Tools

When running as an MCP server (engramdb serve), the following tools are available:

ToolDescription
queryUnified search/retrieve. mode: "filter" narrows by query/logical/path/tags; mode: "rank" ranks memories by relevance to a context
createStore a new memory
getFetch a specific memory by ID
listList all memories with optional filters
updateModify an existing memory
deleteRemove a memory
challengeFlag a memory as potentially incorrect
reviewList memories needing review
resolveAccept, update, invalidate, or delete a challenged memory
verifyRe-confirm a memory is still accurate, refreshing fact decay
task_currentDeclare (or read) the task this session is working on
task_completeMark a task finished, demoting its task-scoped memories
statsStore statistics and health info
doctorEnvironment and store diagnostics
gcGarbage collect low-relevance memories
reindexRebuild the vector index
compress_candidatesList memories eligible for compression
compress_applyMerge multiple memories into a summary
projects_listList all registered projects, including hierarchy
projects_infoInfo about a specific project (id, name, path, memory count, scopes)
projects_linkLink a registered project as a sub-project of another
projects_unlinkRemove a project's parent link, promoting it back to a root project

Configuration

EngramDB reads configuration from .engramdb/config.toml:

Each section is optional, but a section you do write must be complete: once a section header appears, every field in it that has no built-in default is required. In particular, an [embeddings] table must set provider, dimensions, and max_tokens (no defaults — this keeps a partial embeddings config from silently mismatching the index), and any [retrieval.scoring] or [thresholds] table must set all of its fields. The example below parses as-is; see docs/users/configuration.md for the complete, copy-pasteable schema with every field and its default.

[embeddings]
backend = "auto"   # "auto" (default), "onnx", or "ollama"
provider = "onnx"  # required when [embeddings] is present
dimensions = 384   # required; must match the provider
max_tokens = 256   # required

[daemon]
enabled = true            # Delegate embedding/NLI/rerank to the shared daemon
use_for_cli = true        # Also use the daemon from model-needing CLI commands
idle_timeout_secs = 900   # Daemon reaps this long after the last session disconnects
# socket_path = "/run/user/1000/engramdb/daemon.sock"  # optional override

Embedding backends

  • auto (default) — tries ONNX first, falls back to Ollama
  • onnx — local ONNX Runtime with all-MiniLM-L6-v2, no external dependencies
  • ollama — uses a local Ollama instance for embeddings (requires ollama running)

Models are cached in the system cache directory (~/Library/Caches/engramdb/models on macOS).

Embedding daemon

Each engramdb serve (stdio MCP) process is one-per-agent-session, so without coordination every concurrent session loads its own copy of the embedding (and optional NLI/reranker) models — hundreds of MB and a ~240 ms ONNX init each.

When [daemon].enabled is true (the default), MCP processes delegate all model work to a single long-lived daemon over a per-user Unix domain socket, so each model loads exactly once machine-wide. Storage stays in the MCP process (it is already cross-process safe), so only inference is delegated.

  • Auto-spawned on demand. You never start it manually. When an MCP process needs the daemon and none is reachable, it spawns one (engramdb daemon run) detached, waits briefly, and connects. Concurrent spawns are race-safe (only one binds the socket).

  • Stays alive while sessions are connected, then reaps. Each serve process runs a background heartbeat that pings the daemon every idle_timeout_secs / 3 (min 30 s), keeping it resident as long as any session is running. It exits idle_timeout_secs after the last session disconnects.

  • Self-healing. If the daemon idle-exits, crashes, or is replaced, the heartbeat re-spawns a fresh one and live sessions route to it on their next request — no agent restart needed.

  • Usable from the CLI. Model-needing CLI commands use a running daemon when reachable (connect-only by default — they don't spawn one). Override with --in-process / ENGRAMDB_IN_PROCESS=1 / [daemon].use_for_cli = false, or let the CLI spawn one with --spawn-daemon.

  • Graceful fallback. If the daemon is disabled or unreachable, MCP and the CLI load models in-process exactly as before — operations never fail because of the daemon.

  • Manage it directly (rarely needed):

    engramdb daemon status     # running? pid, uptime, request metrics
    engramdb daemon stop       # graceful shutdown (next MCP run respawns it)
    engramdb daemon restart    # stop + start a fresh one
    engramdb daemon run        # run the loop in the foreground (debugging)
    engramdb stats --daemon    # cumulative request metrics (persisted)
    

    The socket path resolves with precedence --socket flag > ENGRAMDB_DAEMON_SOCKET env > [daemon].socket_path config > the default per-user runtime path. status/stop/restart/run all accept --socket to target a non-default daemon.

Daemon request metrics are persisted to the global store's LanceDB, so stats --daemon reports figures even when no daemon is currently running, and counts stay cumulative across daemon restarts.

Building from Source

git clone https://github.com/egeapak/engramdb
cd engramdb
cargo build --release

Run tests:

cargo nextest run --workspace --all-features

Documentation

Comprehensive docs live in docs/, organized by audience:

  • docs/users/ — install, CLI reference, configuration, Claude Code integration, projects/worktrees, embeddings, daemon, troubleshooting.
  • docs/agents/ — MCP tool reference and workflows for AI agents using engramdb.
  • docs/contributors/ — architecture, code organization, testing conventions, extension recipes.

Contributing

Contributions are welcome. Please open an issue to discuss significant changes before submitting a PR.

  1. Fork the repository
  2. Create a feature branch
  3. Ensure cargo fmt --all and cargo clippy --workspace --all-targets --all-features -- -D warnings pass
  4. Submit a pull request

License

MIT License — see LICENSE for details.

Contributors

egeapak

143 commits

claude

5 commits

Languages

Rust

98.5%

Python

1.3%