Engram has migrated to rust! New repo below!
https://github.com/Ghost-Frame/engram-rust
The cognitive layer for AI agents.
Why Engram? · Quick Start · Features · Eidolon · Architecture · API · CLI · SDK · MCP · Deploy
AI agents forget everything between sessions. Context windows aren't memory -- they're short-term buffers that vanish the moment the conversation ends. Markdown files and vector dumps don't forget, prioritize, or connect. They can't tell important memories from noise.
Engram is a cognitive memory system built on real neuroscience. It uses FSRS-6 spaced repetition to strengthen memories that matter and let irrelevant ones fade. It builds a knowledge graph that discovers connections on its own. It shapes every recall around who your agent is talking to.
One Node.js process. One SQLite database. Local embeddings. No OpenAI key. No cloud bills. Your hardware, your data.
# Docker (recommended)
git clone https://codeberg.org/GhostFrame/engram.git && cd engram
git config core.hooksPath .githooks # enable pre-commit safety checks
cp .env.example .env # set ENGRAM_GUI_PASSWORD
docker compose up -d
# Or run directly (Node 22+)
npm install
node --experimental-strip-types server.tsCreate an API key, then store and search:
# Bootstrap admin key (save the returned key)
curl -X POST http://localhost:4200/bootstrap \
-H "Content-Type: application/json" \
-d '{"name": "admin"}'
# Store a memory
curl -X POST http://localhost:4200/store \
-H "Authorization: Bearer eg_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"content": "Production DB is PostgreSQL 16 on db.example.com:5432", "category": "reference"}'
# Search with natural language
curl -X POST http://localhost:4200/search \
-H "Authorization: Bearer eg_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "database connection info"}'- FSRS-6 Spaced Repetition -- Memories strengthen with use and fade when ignored. Based on the algorithm behind 100M+ Anki reviews.
- 4-Channel Hybrid Search -- Vector similarity, full-text, personality signals, and graph traversal fused via Reciprocal Rank Fusion.
- Knowledge Graph -- Auto-linking, community detection, PageRank. Memories are a connected web, not flat files.
- Personality Engine -- Preferences, values, motivations, identity. Every recall shaped by who your agent is talking to.
- Self-Hosted, Zero Dependencies -- One Node.js process. One SQLite database. Local embeddings. No OpenAI key. No cloud bills.
- Not Another MCP Server -- A real server with a REST API, TypeScript SDK, and CLI. Also available via MCP for Claude Desktop and Cursor.
- Atomic Fact Decomposition -- Long memories broken into self-contained facts. Each independently searchable, all linked to source.
- Contradiction Detection -- When your agent learns conflicting information, Engram catches it and surfaces the conflict.
- Guardrails -- Agents check before they act. Stored rules return allow/warn/block before destructive operations.
- Episodic Memory -- Full conversation episodes as searchable narratives. Ask "what happened last Tuesday?" and get a real answer.
- Time-Travel Queries -- Query what your agent knew at any past moment. Debug decisions, audit context drift.
- Bulk Ingestion -- Markdown, PDFs, chat exports, ZIP archives. Full pipeline from raw documents to searchable memory.
Full Capabilities
- Dual-Strength Model -- Bjork & Bjork: storage strength never decays, retrieval strength resets on access
- Versioning -- Update memories without losing history. Full version chain preserved
- Auto-Deduplication -- SimHash 64-bit locality-sensitive hashing detects near-identical memories
- Auto-Forget / TTL -- Set memories to expire. Background sweep every 5 minutes
- Fact Extraction & Auto-Tagging -- Structured facts with temporal validity windows
- Conversation Extraction -- Feed raw chat logs, get structured memories
- Reflections & Consolidation -- Meta-analysis and cluster compression
- Abstention -- Search returns
abstained: truewhen confidence is below threshold - Assistant Recall -- Captures what the AI said, recommended, and produced
- MCP Server -- 25+ tools for Claude Desktop, Cursor, Windsurf, and other MCP clients
- TypeScript SDK -- First-class client with store, search, context, guard, inbox
- CLI -- Full access to every feature from your terminal
- REST API -- 80+ endpoints with OpenAPI 3.1 spec
- Multi-Tenant + RBAC -- Isolated memory per user with role-based access
- Webhooks & Digests -- Event hooks with HMAC signing and scheduled digests
- Cross-Instance Sync -- Keep multiple deployments in sync
- Audit Trail -- Every mutation logged with who, what, when, from where
- Scratchpad -- Ephemeral working memory with TTL auto-purge
- WebGL Galaxy Graph -- Interactive memory space visualization at /gui
- Episodic Memory -- Conversation episodes as embedded, searchable narratives
- Entities & Projects -- First-class people, servers, tools, and projects
- Review Queue / Inbox -- Approve, reject, or edit before memories enter recall
- Community Detection -- Label propagation surfaces memory clusters
- PageRank -- Structural importance scoring boosts search results
- Graph Timeline -- Weekly knowledge graph growth tracking
Eidolon is the guardian that pairs with Engram. Engram remembers. Eidolon protects.
- Action Gating -- Blocks dangerous operations before they execute. Your agent checks with Eidolon before doing anything destructive.
- Living Prompt Injection -- Relevant memory context injected into every agent session automatically. No manual retrieval needed.
- Credential Scrubbing -- Secrets never leak into prompts. Eidolon intercepts and sanitizes before your agent sees them.
Eidolon runs as an optional companion service. Same deployment, same auth, zero extra setup.
Recent Changes
Atomic fact decomposition - Long memories are broken into self-contained atomic facts, each independently searchable and linked to its source via has_fact edges. Search supports facts_only and exclude_facts filters. Context assembly groups facts under parents. Admin endpoints provide retroactive sweep and status monitoring.
Job queue hardening - The durable job queue now uses two-step transactional claiming (SELECT then UPDATE inside db.transaction()) instead of the subquery-UPDATE pattern that caused recurring SQLite B-tree corruption. WAL mode runs with synchronous=FULL for fsync protection. Cleanup is batched in small deletes with post-delete WAL checkpoints.
Non-destructive consolidation - Consolidation no longer archives source memories. Originals stay searchable. The consolidation summary links back to its sources but does not replace them.
Architecture
- Server: Node.js 22+ with
--experimental-strip-types - Database: libsql (SQLite fork with native FLOAT32 vector columns and FTS5)
- Embeddings: BAAI/bge-m3, 1024-dim, local ONNX inference in a Worker thread (swappable via
ENGRAM_MODEL_DIR) - Reranker: IBM granite-embedding-reranker-english-r2 INT8 quantized cross-encoder (optional, swappable via
ENGRAM_RERANKER_MODEL_DIR) - Decay: FSRS-6 with 21 trained parameters and power-law forgetting
- LLM: optional, any OpenAI-compatible endpoint (fact extraction, personality, consolidation, decomposition)
Every query runs through four parallel channels, then merges via Reciprocal Rank Fusion:
- Vector similarity: cosine distance against bge-m3 embeddings
- FTS5 full-text: BM25 ranking across content and tags
- Personality signals: match against extracted preferences, values, and identity markers
- Graph relationships: 2-hop traversal weighted by edge type and PageRank score
Question-type detection (fact recall, preference, reasoning, generalization, timeline) adapts channel weights before scoring. The cross-encoder reranker then reorders the top-K results for semantic precision.
- Store: SimHash (64-bit, Hamming distance <= 3) checks for near-duplicates. If unique, the configured embedding model (bge-m3 by default) embeds the content. Stored in libsql with FTS5 indexing.
- Auto-link: New memory is compared against existing ones via in-memory cosine similarity. Links form at >= 0.55 similarity with typed relationships: similarity, updates, extends, contradicts, caused_by, prerequisite_for.
- FSRS-6 init: Each memory gets initial stability, difficulty, storage strength, and retrieval strength. Power-law forgetting begins.
- Fact extraction: If an LLM is configured, structured facts with temporal validity windows (valid_at, invalid_at) are extracted. Contradicting facts automatically invalidate predecessors.
- Atomic decomposition: Memories longer than
DECOMPOSITION_MIN_LENGTHwords are split into self-contained atomic facts by the LLM. Each fact becomes its own memory linked to the parent viahas_fact. Up toDECOMPOSITION_MAX_FACTSfacts per memory. The parent stays intact and searchable. - Entity cooccurrence: Entities in the same memory update the weighted cooccurrence graph.
- Personality extraction: Six signal types scanned: preference, value, motivation, decision, emotion, identity.
- Recall: RRF fuses four channels. Every recalled memory receives an implicit FSRS review graded "Good", building stability.
- Spaced repetition: Archived or forgotten memories receive "Again". Stable memories can reach months or years between reviews.
- Dual-strength decay: Storage strength accumulates (never decays). Retrieval strength decays via power law. Retention score:
0.7 * retrieval + 0.3 * (storage/10). - Community detection and PageRank: Run automatically every 25th store. Label propagation groups related memories. Iterative weighted PageRank ranks memories by structural importance.
Any OpenAI-compatible provider via LLM_URL, LLM_API_KEY, and LLM_MODEL. Up to 10 providers with automatic failover or round-robin rotation.
| Provider | Example URL | Example Model |
|---|---|---|
| Gemini | https://generativelanguage.googleapis.com/v1beta/openai/chat/completions |
gemini-2.5-flash |
| MiniMax | https://api.minimax.io/v1/chat/completions |
MiniMax-M2.5 |
| Groq | https://api.groq.com/openai/v1/chat/completions |
llama-3.3-70b-versatile |
| DeepSeek | https://api.deepseek.com/v1/chat/completions |
deepseek-chat |
| OpenAI | https://api.openai.com/v1/chat/completions |
gpt-4o |
| Anthropic | https://api.anthropic.com/v1/messages |
claude-sonnet-4-20250514 |
| Ollama | http://127.0.0.1:11434/v1/chat/completions |
llama3 |
| LiteLLM | http://127.0.0.1:4000/v1/chat/completions |
Any routed model |
┌──────────────────────────────────────────────────────┐
│ Engram Server │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ FSRS-6 │ │ RRF │ │ FTS5 │ │
│ │ Engine │ │ Scorer │ │ Search │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌────┴──────────────┴──────────────┴────┐ │
│ │ libsql (SQLite + vector columns) │ │
│ │ FLOAT32(1024) + FTS5 │ │
│ └───────────────────────────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ bge-m3 │ │ Reranker │ │ Graph │ │
│ │ Embedder │ │ (Granite)│ │ Engine │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ SimHash │ │Personality│ │ Temporal │ │
│ │ Dedup │ │ Engine │ │ Facts │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Atomic │ │ Durable │ │Consolida-│ │
│ │ Decomp │ │ Job Queue │ │ tion │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└──────────────────────────────────────────────────────┘
API Reference
All endpoints require Authorization: Bearer eg_... by default. Set ENGRAM_OPEN_ACCESS=1 for unauthenticated single-user mode.
Use X-Space: space-name (or X-Engram-Space) to scope operations to a named memory space. Every response includes X-Request-Id for correlation.
| Method | Path | Description |
|---|---|---|
POST |
/store |
Store a memory |
POST |
/search |
RRF search across vector, FTS5, personality, and graph channels |
POST |
/recall |
Contextual recall with auto-injected personality profile |
POST |
/context |
Smart context builder (token-budget RAG with depth 1/2/3, personality at depth 2+) |
GET |
/list |
List recent memories |
GET |
/profile |
User profile (static facts + recent) |
GET |
/graph |
Full memory graph (nodes + edges) |
| Method | Path | Description |
|---|---|---|
POST |
/memory/:id/update |
Create new version |
POST |
/memory/:id/forget |
Soft delete |
POST |
/memory/:id/archive |
Archive (hidden from recall) |
POST |
/memory/:id/unarchive |
Restore from archive |
DELETE |
/memory/:id |
Permanent delete |
GET |
/versions/:id |
Version chain for a memory |
| Method | Path | Description |
|---|---|---|
POST |
/fsrs/review |
Manual review (grade 1-4: Again/Hard/Good/Easy) |
GET |
/fsrs/state?id=N |
Retrievability, stability, next review interval |
POST |
/fsrs/init |
Backfill FSRS state for all memories |
POST |
/decay/refresh |
Recalculate all decay scores |
GET |
/decay/scores |
View decay scores and FSRS state |
| Method | Path | Description |
|---|---|---|
POST |
/add |
Extract memories from conversations |
POST |
/ingest |
Extract facts from URLs or text |
POST |
/guard |
Pre-action guardrail check (allow/warn/block) |
POST |
/derive |
Generate inferred memories |
POST |
/reflect |
Generate period reflection |
GET |
/reflections |
List past reflections |
GET |
/contradictions |
Find conflicting memories |
POST |
/contradictions/resolve |
Resolve a contradiction |
POST |
/timetravel |
Query memory state at a past time |
GET |
/facts |
Query structured facts with filtering |
GET |
/preferences |
Get stored user preferences |
DELETE |
/preferences |
Delete preference entries (surgical cleanup) |
GET |
/state |
Get current user state |
DELETE |
/state |
Delete state entries (surgical cleanup) |
POST |
/profile/synthesize |
Synthesize personality profile from signals |
GET |
/memory-health |
Diagnostic report: stale, duplicates, unlinked, contradiction hints |
POST |
/feedback |
Submit retrieval feedback (used/ignored/corrected/irrelevant/helpful) |
GET |
/feedback/stats |
Feedback analytics: signal breakdown, precision estimate, top memories |
| Method | Path | Description |
|---|---|---|
GET |
/communities |
List and browse memory communities |
GET |
/graph/timeline |
Weekly graph growth: new memories, totals, link counts |
POST |
/admin/detect-communities |
Run community detection (admin) |
POST |
/admin/rebuild-cooccurrences |
Rebuild entity cooccurrence graph (admin) |
POST |
/admin/backfill-facts |
Re-extract facts from all memories (admin) |
| Method | Path | Description |
|---|---|---|
GET |
/tags |
List all tags |
POST |
/tags/search |
Search by tags |
POST |
/episodes |
Create episode |
GET |
/episodes |
List episodes |
POST |
/entities |
Create entity |
GET |
/entities |
List entities |
POST |
/projects |
Create project |
GET |
/projects |
List projects |
| Method | Path | Description |
|---|---|---|
POST |
/conversations/bulk |
Bulk store conversation (agent and messages required) |
POST |
/conversations/upsert |
Upsert by session_id |
GET |
/conversations |
List conversations |
GET |
/conversations/:id/messages |
Get conversation messages |
POST |
/messages/search |
Search across all messages |
| Method | Path | Description |
|---|---|---|
GET |
/export |
Export all memories and links (JSON/JSONL) |
POST |
/import |
Bulk import memories |
POST |
/import/mem0 |
Import from Mem0 |
POST |
/import/supermemory |
Import from Supermemory |
GET |
/sync/changes |
Get changes since timestamp |
POST |
/sync/receive |
Receive synced changes |
| Method | Path | Description |
|---|---|---|
POST |
/webhooks |
Create webhook |
GET |
/webhooks |
List webhooks |
POST |
/digests |
Create scheduled digest |
GET |
/digests |
List digests |
POST |
/digests/send |
Manually trigger a digest |
POST |
/pack |
Pack memories into token budget |
GET |
/prompt |
Generate prompt template |
| Method | Path | Description |
|---|---|---|
POST |
/users |
Create user (admin) |
GET |
/users |
List users (admin) |
POST |
/keys |
Create API key |
GET |
/keys |
List API keys |
DELETE |
/keys/:id |
Revoke key |
POST |
/keys/rotate |
Rotate an API key (atomically replace, preserving scopes) |
POST |
/spaces |
Create space |
GET |
/spaces |
List spaces |
DELETE |
/spaces/:id |
Delete space |
| Method | Path | Description |
|---|---|---|
GET |
/inbox |
List pending memories |
POST |
/inbox/:id/approve |
Approve a pending memory |
POST |
/inbox/:id/reject |
Reject (archive and set reason) |
POST |
/inbox/:id/edit |
Edit content and auto-approve |
POST |
/inbox/bulk |
Bulk approve/reject |
| Method | Path | Description |
|---|---|---|
GET |
/health |
Health check (30+ feature flags) |
GET |
/live |
Liveness probe |
GET |
/ready |
Readiness probe (503 when degraded) |
GET |
/stats |
Detailed statistics |
GET |
/metrics |
Prometheus-format metrics (admin) |
GET |
/openapi.json |
OpenAPI 3.1 spec |
GET |
/audit |
Query audit log (admin) |
POST |
/checkpoint |
Manual WAL checkpoint (admin) |
GET |
/backup |
Download SQLite database (admin) |
POST |
/backup/verify |
Verify backup integrity (admin) |
| Method | Path | Description |
|---|---|---|
GET |
/admin/tasks |
List all available admin operations |
GET |
/admin/quotas |
View per-tenant memory quotas |
PUT |
/admin/quotas |
Update tenant quota |
GET |
/admin/tenants |
List all tenants with usage statistics |
POST |
/tenants/provision |
Provision a new tenant |
POST |
/tenants/deprovision |
Deprovision a tenant |
GET |
/admin/providers |
View configured embedding and LLM providers |
GET |
/admin/schema |
Schema info, migration history, drift detection |
GET |
/admin/scale-report |
Scale tier assessment with recommendations |
GET |
/admin/cold-storage |
Memory access distribution and cold storage config |
POST |
/admin/maintenance |
Toggle maintenance mode (rejects non-admin writes) |
GET |
/admin/maintenance |
Check maintenance mode status |
POST |
/admin/reembed |
Re-embed all memories with current provider |
POST |
/admin/rebuild-fts |
Drop and rebuild full-text search index |
POST |
/admin/rebuild-cooccurrences |
Rebuild entity cooccurrence graph |
POST |
/admin/detect-communities |
Run Louvain community detection |
POST |
/admin/backfill-facts |
Extract facts from memories missing structured data |
POST |
/admin/refresh-cache |
Force reload embedding cache from DB |
POST |
/admin/compact |
VACUUM and ANALYZE database to reclaim space |
POST |
/admin/decompose-sweep |
Retroactively decompose existing memories into atomic facts (background) |
GET |
/admin/decompose-status |
Check decomposition sweep progress |
| Method | Path | Description |
|---|---|---|
POST |
/thymus/rubrics |
Create evaluation rubric with weighted criteria |
GET |
/thymus/rubrics |
List rubrics |
POST |
/thymus/evaluations |
Score agent output against a rubric |
GET |
/thymus/evaluations |
List evaluations (filter by agent, rubric) |
GET |
/thymus/agents/:agent/scores |
Aggregate score stats for an agent |
POST |
/thymus/metrics |
Record a quality metric |
GET |
/thymus/metrics |
Query metrics (filter by agent, metric, time range) |
GET |
/thymus/stats |
Rubric, evaluation, and metric counts |
| Method | Path | Description |
|---|---|---|
POST |
/soma/agents |
Register a new agent |
GET |
/soma/agents |
List agents (filter by type, status, capability) |
PATCH |
/soma/agents/:id |
Update agent metadata |
DELETE |
/soma/agents/:id |
Deregister agent (cascade deletes logs and group memberships) |
POST |
/soma/agents/:id/heartbeat |
Send heartbeat with optional status |
GET |
/soma/agents/stale |
Find agents that missed heartbeats |
POST |
/soma/agents/:id/logs |
Submit structured log entry |
GET |
/soma/agents/:id/logs |
Read agent logs |
POST |
/soma/groups |
Create agent group |
GET |
/soma/groups |
List groups |
POST |
/soma/groups/:id/members |
Add agent to group |
DELETE |
/soma/groups/:id/members/:agentId |
Remove agent from group |
GET |
/soma/agents/capability/:name |
Find agents by capability |
GET |
/soma/stats |
Registry statistics |
| Method | Path | Description |
|---|---|---|
POST |
/tasks |
Create a task |
GET |
/tasks |
List tasks (filter by status, agent, project) |
GET |
/tasks/:id |
Get task with audit trail |
PATCH |
/tasks/:id |
Update task status/summary |
DELETE |
/tasks/:id |
Delete task |
GET |
/tasks/stats |
Task counts by status |
GET |
/feed |
Activity feed of recent task updates |
| Method | Path | Description |
|---|---|---|
POST |
/axon/publish |
Publish event to a channel |
GET |
/axon/events |
Query events (filter by channel, type, source) |
GET |
/axon/channels |
List channels with counts |
POST |
/axon/channels |
Create channel |
POST |
/axon/subscribe |
Subscribe agent to channel |
POST |
/axon/unsubscribe |
Remove subscription |
GET |
/axon/subscriptions |
List subscriptions |
GET |
/axon/poll |
Cursor-based event consumption |
GET |
/axon/stream |
SSE real-time event stream |
GET |
/axon/stats |
Bus statistics |
| Method | Path | Description |
|---|---|---|
POST |
/loom/workflows |
Create workflow definition |
GET |
/loom/workflows |
List workflows |
POST |
/loom/runs |
Start workflow run |
GET |
/loom/runs |
List runs (filter by status, workflow) |
GET |
/loom/runs/:id |
Get run state |
POST |
/loom/runs/:id/cancel |
Cancel run |
GET |
/loom/runs/:id/steps |
Get step states |
GET |
/loom/runs/:id/logs |
Get execution logs |
POST |
/loom/steps/:id/complete |
Complete step (external callback) |
POST |
/loom/steps/:id/fail |
Fail step (external callback) |
GET |
/loom/stats |
Workflow statistics |
| Method | Path | Description |
|---|---|---|
POST |
/broca/actions |
Log action with auto-narration |
GET |
/broca/actions |
Query actions |
GET |
/broca/actions/:id |
Get single action |
GET |
/broca/actions/:id/narrate |
Generate narrative |
GET |
/broca/feed |
Activity feed with narratives |
POST |
/broca/narrate |
Bulk narrate actions |
POST |
/broca/ask |
Natural language query |
GET |
/broca/stats |
Action statistics |
Growth System
The growth system lets agents generate self-improving observations about their own behavior and store them as persistent memories. It runs via the /reflect API and an internal self-reflection cron.
POST /reflect -- Generate a growth observation from recent activity.
Request body:
{
"service": "engram",
"context": [
"Memory stats: 1200 total, 340 never accessed",
"Top categories (24h): reference(42), state(28), decision(14)",
"Recent contradictions: 2"
],
"existing_growth": "- Users tend to store most memories in reference category\n- ...",
"prompt_override": "Optional custom system prompt to override the service default"
}| Field | Required | Description |
|---|---|---|
service |
yes | Service identifier - selects domain-specific prompt |
context |
yes | Non-empty array of strings describing recent activity |
existing_growth |
no | Text of prior growth observations - used to avoid repetition |
prompt_override |
no | Custom system prompt, overrides the built-in service prompt |
Response:
{
"observation": "Search hit rate dropped 12% this hour -- 40% of queries returned zero results, suggesting a knowledge gap in infrastructure topics.",
"stored_memory_id": 1042,
"reflection_id": 88
}Returns { "observation": null } when the LLM is unavailable, nothing interesting was observed, or the observation was a duplicate of an existing growth memory.
Each accepted observation is written to two places:
memoriestable --category = "growth",source = "<service>-growth",importance = 7,is_static = 1. Fully searchable via all standard endpoints.reflectionstable -- also inserted viainsertReflection, making it visible atGET /reflections.
Engram runs a built-in self-reflection cron every hour (lease-protected to prevent duplicate runs in multi-process deployments). Each run applies two gates before calling the LLM:
- Activity threshold - requires >= 50 new memories in the past hour. Skips if the system is idle.
- Probability gate - 15% chance of firing even when the threshold is met. Keeps the signal sparse and meaningful.
When both gates pass, Engram assembles context from live memory stats (totals, access rates, top categories, recent contradictions) and calls the growth engine with service = "engram".
Each service has a built-in reflection prompt focused on what matters for that service. Unrecognized services fall back to a generic prompt.
| Service | Focus |
|---|---|
engram |
Memory access patterns, knowledge gaps, category growth, quality trends |
claude-code |
Session approaches, corrections from Master, codebase learnings, communication style |
eidolon |
Dream cycle results, over-correlated patterns, substrate quality |
chiasm |
Task patterns, estimate accuracy, agent reliability, recurring blockers |
thymus |
Compliance drift, agent improvement trends, quality signal predictiveness |
Before storing an observation, the engine embeds it and compares it via cosine similarity against the 20 most recent growth memories for that service. If any existing memory scores > 0.85 similarity, the observation is discarded. This prevents the growth log from accumulating minor restatements of the same insight.
Source: src/intelligence/growth.ts
CLI
Engram ships a full CLI that wraps the HTTP API. Zero external dependencies. Uses Node.js 22 built-in util.parseArgs.
npm install -g @ghost_frame/engramexport ENGRAM_URL=http://localhost:4200
export ENGRAM_API_KEY=eg_your_keyConfig can also be set in ~/.engram/config.json.
# Store
engram-cli store "Deployed auth migration to production" --category state --importance 9
# Search
engram-cli search "deployment history" --limit 5 --explain
# Context (RAG)
engram-cli context "current infrastructure state" --budget 4000
# Recall
engram-cli recall --context "what changed recently"
# Other commands
engram-cli list --limit 20
engram-cli forget 42 --reason "outdated"
engram-cli delete 42
engram-cli health
engram-cli statsAll commands support --json for raw API output and --quiet for minimal output (IDs and counts only).
TypeScript SDK
import { Engram } from "@ghost_frame/engram/sdk";
const engram = new Engram({ url: "http://localhost:4200", apiKey: "eg_..." });
// Store
await engram.store("User prefers dark mode", { category: "decision", importance: 8 });
// Search with presets
const results = await engram.search("dark mode", { mode: "preference" });
// Budget-aware context for RAG
const ctx = await engram.context("setting up the editor", { mode: "fast" });
// Guardrails
const check = await engram.guard("deploy to production on Friday");
if (check.verdict === "block") console.log("Blocked:", check.reasons);
// Inbox review
const pending = await engram.inbox();
for (const mem of pending.pending) {
await engram.approve(mem.id); // or: engram.reject(mem.id)
}MCP Server
Transport: JSON-RPC 2.0 over stdio. The MCP server connects to a running Engram instance via HTTP. Works with any MCP-compatible client.
The MCP server entry is the same across all clients. Add it to your client's MCP configuration:
{
"mcpServers": {
"engram": {
"command": "node",
"args": ["--experimental-strip-types", "path/to/engram/mcp-server.ts"],
"env": {
"ENGRAM_URL": "http://localhost:4200",
"ENGRAM_API_KEY": "eg_your_key"
}
}
}
}Where to put this depends on your client:
| Client | Config Location |
|---|---|
| Claude Desktop | claude_desktop_config.json |
| Claude Code | .mcp.json in project root or ~/.claude/settings.json |
| Cursor | .cursor/mcp.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| VS Code (Copilot) | .vscode/mcp.json |
| OpenCode | ~/.config/opencode/agents.json MCP section |
| Any stdio MCP client | Consult your client's docs for MCP server config format |
| Tool | Description |
|---|---|
memory_store |
Store a new memory with category, importance, and model attribution |
memory_recall |
Semantic and full-text search across memories |
memory_context |
Token-budget-aware context packing for LLM injection |
memory_list |
List recent memories, optionally filtered by category |
memory_delete |
Delete a memory by ID |
memory_guard |
Check a proposed action against stored rules (allow/warn/block) |
memory_inbox |
Review pending memories awaiting triage (approve/reject) |
memory_search_preset |
Search with opinionated presets: fact, timeline, preference, decision, recent |
memory_entities |
List or search tracked entities (people, servers, tools, services) |
memory_projects |
List or search tracked projects |
memory_episodes |
List conversation episodes (sessions of related work) |
memory_scratch |
Read/write scratchpad (short-term working memory, 30min TTL) |
structural_analyze |
Analyze a system in EN syntax: topology (Pipeline/Tree/DAG/Cycle), node roles, bridges |
structural_detail |
Deep analysis: concurrency metrics, critical path, flow depth, resilience |
structural_between |
Betweenness centrality for a node (0-1 score) |
structural_distance |
Shortest path between two nodes with subsystem annotations |
structural_trace |
Follow directed flow from A to B along yields->needs edges |
structural_impact |
Blast radius: what disconnects if a node is removed |
structural_diff |
Structural diff between two systems: topology changes, role changes, bridges |
structural_evolve |
Dry-run architectural changes and preview the structural delta |
structural_categorize |
Auto-discover subsystem boundaries via Louvain community detection |
structural_extract |
Extract a named subsystem as standalone EN source |
structural_compose |
Merge two EN graphs with entity linking |
structural_memory_graph |
Analyze Engram's own memory link graph structurally |
All tools support signed tool manifests for integrity verification when ENGRAM_SIGNING_SECRET is set.
Configuration
| Variable | Default | Description |
|---|---|---|
ENGRAM_PORT |
4200 |
Server port |
ENGRAM_HOST |
0.0.0.0 |
Bind address |
ENGRAM_DATA_DIR |
./data |
Data directory for DB and models |
ENGRAM_GUI_PASSWORD |
required | GUI login password unless ENGRAM_OPEN_ACCESS=1 |
ENGRAM_OPEN_ACCESS |
0 |
Set 1 for unauthenticated single-user mode |
ENGRAM_LOG_LEVEL |
info |
debug, info, warn, error, none |
OTEL_EXPORTER_OTLP_ENDPOINT |
unset | Enable OpenTelemetry tracing (e.g. http://localhost:4318) |
ENGRAM_CORS_ORIGIN |
unset | Optional allowed browser origin for cross-origin access |
ENGRAM_MAX_BODY_SIZE |
1048576 |
Max request body (bytes) |
ENGRAM_MAX_CONTENT_SIZE |
102400 |
Max memory content (bytes) |
ENGRAM_ALLOWED_IPS |
unset | Comma-separated IP allowlist |
The default models are BAAI/bge-m3 (embeddings, 1024-dim) and IBM granite-embedding-reranker-english-r2 (reranker, INT8 quantized). Both are drop-in replaceable with any ONNX model. For embeddings, set ENGRAM_MODEL_DIR and ENGRAM_EMBEDDING_DIM, then run POST /admin/reembed. For the reranker, set ENGRAM_RERANKER_MODEL_DIR. Each directory must contain tokenizer.json and a model ONNX file.
| Variable | Default | Description |
|---|---|---|
ENGRAM_EMBEDDING_PROVIDER |
local |
Embedding provider: local, google, vertex |
ENGRAM_EMBEDDING_DIM |
auto | Embedding dimension (1024 for local, 768 for google/vertex) |
ENGRAM_MODEL_DIR |
auto | Custom ONNX model directory (must contain tokenizer.json + model ONNX file) |
ENGRAM_RERANKER_MODEL_DIR |
auto | Custom ONNX reranker model directory (must contain tokenizer.json + model ONNX file) |
ENGRAM_CROSS_ENCODER |
1 |
Set 0 to disable the ONNX cross-encoder reranker |
ENGRAM_RERANKER |
1 |
Set 0 to disable all reranking in search results |
ENGRAM_RERANKER_TOP_K |
12 |
Rerank top K candidates |
ENGRAM_RERANKER_FP32 |
0 |
Set 1 for full-precision reranker instead of quantized INT8 |
GOOGLE_API_KEY |
unset | Google AI Studio API key (for google embedding provider) |
GOOGLE_CLOUD_PROJECT |
unset | GCP project ID (for vertex embedding provider) |
GOOGLE_APPLICATION_CREDENTIALS |
unset | Service account JSON path (for vertex) |
| Variable | Default | Description |
|---|---|---|
LLM_URL |
unset | OpenAI-compatible API URL |
LLM_API_KEY |
unset | API key for LLM |
LLM_MODEL |
unset | Model name (e.g., gpt-4o, claude-sonnet-4-20250514) |
LLM_STRATEGY |
fallback |
fallback or round-robin for multi-provider rotation |
| Variable | Default | Description |
|---|---|---|
ENGRAM_DECOMPOSITION |
1 (on) |
Set 0 to disable atomic fact decomposition |
ENGRAM_DECOMPOSITION_MIN_LENGTH |
20 |
Minimum word count before a memory is decomposed |
ENGRAM_DECOMPOSITION_MAX_FACTS |
8 |
Maximum atomic facts extracted per memory |
ENGRAM_DECOMPOSITION_RATE_LIMIT |
2 |
Max concurrent decomposition requests |
GEMINI_CLI_ENABLED |
0 (off) |
Set 1 to enable Gemini CLI as LLM fallback for decomposition |
GEMINI_CLI_PATH |
gemini |
Path to the Gemini CLI binary |
GEMINI_CLI_TIMEOUT |
30000 |
Gemini CLI timeout in milliseconds |
| Variable | Default | Description |
|---|---|---|
ENGRAM_DECAY_FLOOR |
0.3 |
Minimum decay multiplier (0-1). Lower values penalize stale memories harder |
ENGRAM_PAGERANK_WEIGHT |
0.15 |
PageRank boost weight in search scoring (0-15% boost for hub memories) |
ENGRAM_SEARCH_MIN_SCORE |
0.58 |
Min overall score for search results |
ENGRAM_SEARCH_FACT_VECTOR_FLOOR |
0.22 |
Min vector score for fact_recall queries |
ENGRAM_SEARCH_PREFERENCE_VECTOR_FLOOR |
0.12 |
Min vector score for preference queries |
ENGRAM_SEARCH_REASONING_VECTOR_FLOOR |
0.10 |
Min vector score for reasoning queries |
ENGRAM_SEARCH_GENERALIZATION_VECTOR_FLOOR |
0.12 |
Min vector score for generalization queries |
ENGRAM_SEARCH_PERSONALITY_MIN_SCORE |
0.30 |
Min score for personality signal matching |
AUTO_LINK_MAX |
6 |
Max auto-links created per memory |
Deployment
git clone https://codeberg.org/GhostFrame/engram.git && cd engram
cp .env.example .env # set ENGRAM_GUI_PASSWORD
docker compose up -dnpm install
node --experimental-strip-types server.tsAll data lives in a single libsql database (data/memory.db). Embedding BLOBs are stored alongside native FLOAT32(N) vector columns matching the configured EMBEDDING_DIM.
Backup: GET /backup returns a consistent SQLite snapshot via VACUUM INTO (admin required). Safe to call under write load. WAL checkpoints every 5 minutes and on graceful shutdown. Manual checkpoint via POST /checkpoint.
Audit: GET /audit shows all mutations with who, what, when, and from which IP.
Production source files are locked immutable (chattr +i). Direct writes are blocked at the kernel level.
-
Start staging (copies production into an unlocked staging directory, launches on port 4201):
/opt/engram/start-staging.sh
-
Edit and test in
/opt/engram/staging/, then verify:curl http://localhost:4201/health
-
Promote or discard:
- Promote (unlocks production, copies staged files over, re-locks, and restarts):
/opt/engram/promote.sh
- Discard (throws away staging, production untouched):
/opt/engram/stop-staging.sh
- Promote (unlocks production, copies staged files over, re-locks, and restarts):
server {
server_name memory.example.com;
location / {
proxy_pass http://127.0.0.1:4200;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}npm test
# or directly:
node --test tests/api.test.mjsThe built-in WebGL force graph is served at http://localhost:4200/graph-ui. Node size reflects PageRank score. Edge color reflects relationship type.
Contributing
See CONTRIBUTING.md for development setup and guidelines.
engram.lol · · Eidolon · Issues · Changelog · Security
Support: support@syntheos.dev
Elastic License 2.0

