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.
fact, observation, or decision, orthogonal to its type; retrieval reweights classes by situation (observations surface while debugging, decisions while designing)verify/doctor re-check what's still accurateBuild from source (requires a recent stable Rust toolchain):
cargo install --git https://github.com/egeapak/engramdb
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
# 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
EngramDB stores memories as structured files (TOML + markdown) in .engramdb/memories/ within your project. Each memory has:
When integrated with Claude Code:
| Command | Description |
|---|---|
init | Initialize a new EngramDB store |
add | Add a new memory |
get | Get a memory by ID |
query | Unified search: --mode filter requires a query signal; --mode rank browses by context |
list | List all memories |
update | Update an existing memory |
delete | Delete a memory |
challenge | Challenge a memory's validity |
review | Interactive review of challenged/stale memories |
verify | Confirm a memory is still accurate (stamps verified_at, clears doctor-flagged reviews) |
task | Declare or complete the task this session works on (current/complete) |
stats | Show store statistics |
doctor | Check environment and store health (--fix to repair, validate to test models) |
gc | Garbage collect low-relevance memories |
compress | List compression candidates |
reindex | Rebuild index and re-embed all memories |
migrate | Migrate memory files to latest format |
rollback | Roll back memory files to previous format |
serve | Start the MCP server |
daemon | Manage the shared embedding daemon (run/status/stop/restart) |
setup | Set up Claude Code integration |
hook | Claude Code plugin hook handler |
projects | Manage registered EngramDB projects |
completions | Generate 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.
When running as an MCP server (engramdb serve), the following tools are available:
| Tool | Description |
|---|---|
query | Unified search/retrieve. mode: "filter" narrows by query/logical/path/tags; mode: "rank" ranks memories by relevance to a context |
create | Store a new memory |
get | Fetch a specific memory by ID |
list | List all memories with optional filters |
update | Modify an existing memory |
delete | Remove a memory |
challenge | Flag a memory as potentially incorrect |
review | List memories needing review |
resolve | Accept, update, invalidate, or delete a challenged memory |
verify | Re-confirm a memory is still accurate, refreshing fact decay |
task_current | Declare (or read) the task this session is working on |
task_complete | Mark a task finished, demoting its task-scoped memories |
stats | Store statistics and health info |
doctor | Environment and store diagnostics |
gc | Garbage collect low-relevance memories |
reindex | Rebuild the vector index |
compress_candidates | List memories eligible for compression |
compress_apply | Merge multiple memories into a summary |
projects_list | List all registered projects, including hierarchy |
projects_info | Info about a specific project (id, name, path, memory count, scopes) |
projects_link | Link a registered project as a sub-project of another |
projects_unlink | Remove a project's parent link, promoting it back to a root project |
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
ollama running)Models are cached in the system cache directory (~/Library/Caches/engramdb/models on macOS).
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.
git clone https://github.com/egeapak/engramdb
cd engramdb
cargo build --release
Run tests:
cargo nextest run --workspace --all-features
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.Contributions are welcome. Please open an issue to discuss significant changes before submitting a PR.
cargo fmt --all and cargo clippy --workspace --all-targets --all-features -- -D warnings passMIT License — see LICENSE for details.
Rust
98.5%
Python
1.3%
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.
fact, observation, or decision, orthogonal to its type; retrieval reweights classes by situation (observations surface while debugging, decisions while designing)verify/doctor re-check what's still accurateBuild from source (requires a recent stable Rust toolchain):
cargo install --git https://github.com/egeapak/engramdb
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
# 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
EngramDB stores memories as structured files (TOML + markdown) in .engramdb/memories/ within your project. Each memory has:
When integrated with Claude Code:
| Command | Description |
|---|---|
init | Initialize a new EngramDB store |
add | Add a new memory |
get | Get a memory by ID |
query | Unified search: --mode filter requires a query signal; --mode rank browses by context |
list | List all memories |
update | Update an existing memory |
delete | Delete a memory |
challenge | Challenge a memory's validity |
review | Interactive review of challenged/stale memories |
verify | Confirm a memory is still accurate (stamps verified_at, clears doctor-flagged reviews) |
task | Declare or complete the task this session works on (current/complete) |
stats | Show store statistics |
doctor | Check environment and store health (--fix to repair, validate to test models) |
gc | Garbage collect low-relevance memories |
compress | List compression candidates |
reindex | Rebuild index and re-embed all memories |
migrate | Migrate memory files to latest format |
rollback | Roll back memory files to previous format |
serve | Start the MCP server |
daemon | Manage the shared embedding daemon (run/status/stop/restart) |
setup | Set up Claude Code integration |
hook | Claude Code plugin hook handler |
projects | Manage registered EngramDB projects |
completions | Generate 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.
When running as an MCP server (engramdb serve), the following tools are available:
| Tool | Description |
|---|---|
query | Unified search/retrieve. mode: "filter" narrows by query/logical/path/tags; mode: "rank" ranks memories by relevance to a context |
create | Store a new memory |
get | Fetch a specific memory by ID |
list | List all memories with optional filters |
update | Modify an existing memory |
delete | Remove a memory |
challenge | Flag a memory as potentially incorrect |
review | List memories needing review |
resolve | Accept, update, invalidate, or delete a challenged memory |
verify | Re-confirm a memory is still accurate, refreshing fact decay |
task_current | Declare (or read) the task this session is working on |
task_complete | Mark a task finished, demoting its task-scoped memories |
stats | Store statistics and health info |
doctor | Environment and store diagnostics |
gc | Garbage collect low-relevance memories |
reindex | Rebuild the vector index |
compress_candidates | List memories eligible for compression |
compress_apply | Merge multiple memories into a summary |
projects_list | List all registered projects, including hierarchy |
projects_info | Info about a specific project (id, name, path, memory count, scopes) |
projects_link | Link a registered project as a sub-project of another |
projects_unlink | Remove a project's parent link, promoting it back to a root project |
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
ollama running)Models are cached in the system cache directory (~/Library/Caches/engramdb/models on macOS).
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.
git clone https://github.com/egeapak/engramdb
cd engramdb
cargo build --release
Run tests:
cargo nextest run --workspace --all-features
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.Contributions are welcome. Please open an issue to discuss significant changes before submitting a PR.
cargo fmt --all and cargo clippy --workspace --all-targets --all-features -- -D warnings passMIT License — see LICENSE for details.
Rust
98.5%
Python
1.3%