EngramEngramdocs
v0.1.0
Search docs…⌘K
GitHub
Getting Started

Configuration

Engram is configured entirely through environment variables. There is no config file to manage — set the variables you need and start the server.

Environment variable changes take effect on the next server start. If Engram is already running, restart it for changes to apply.

Environment variables

VariableDefaultDescription
PORT4901HTTP API port the server listens on.
HOST0.0.0.0Bind address. Use 127.0.0.1 to restrict to localhost only.
ENGRAM_DATABASEsqliteDatabase dialect: sqlite (default) or postgresql.
ENGRAM_DB_PATH./engram.dbPath to the SQLite database file (sqlite mode).
DATABASE_URLnonePostgreSQL connection URL (postgresql mode). Example: postgresql://user:pass@localhost:5432/engram
NODE_ENVdevelopmentSet to production for production deployments.
ENGRAM_DECAY_INTERVAL3600000Time between automatic decay sweeps in milliseconds. Set to 0 to disable auto-decay. Default: 1 hour.
ENGRAM_DECAY_THRESHOLD0.05Retention score below which memories are archived during a decay sweep (0–1).
ENGRAM_NAMESPACEnoneOptional namespace for memory isolation. When set, all operations are scoped to this namespace.
ENGRAM_INDEX_PATH{dbPath}.indexPath to persist the vector index for fast startup. Default: same path as DB with .index suffix.
ENGRAM_EMBEDDING_MODELXenova/all-MiniLM-L6-v2Embedding model for vectorization. Supported: Xenova/all-MiniLM-L6-v2 (384-dim), Xenova/bge-small-en-v1.5 (384), Xenova/bge-base-en-v1.5 (768).
OLLAMA_PROXY_PORT11435Port for the Ollama memory injection proxy.
OLLAMA_TARGEThttp://localhost:11434Real Ollama server URL the proxy forwards to.
ENGRAM_MAX_TOKENS1500Max context tokens injected per Ollama proxy request.

Starting with environment variables

Pass variables inline or export them before starting the server:

# Inline — start with a custom DB path
PORT=4901 ENGRAM_DB_PATH=/data/engram/prod.db node apps/server/dist/index.js

# Or export first
export PORT=4901
export ENGRAM_DB_PATH=/var/lib/engram/engram.db
export NODE_ENV=production
node apps/server/dist/index.js

# PostgreSQL mode
export ENGRAM_DATABASE=postgresql
export DATABASE_URL=postgresql://user:pass@localhost:5432/engram
node apps/server/dist/index.js

Running with PM2 (production)

PM2 keeps Engram alive across restarts and provides log management. Create an ecosystem.config.js or pass env vars directly:

# Install PM2 globally
npm install -g pm2

# Start with environment variables
pm2 start server.js --name engram \
  --env PORT=4901 \
  --env ENGRAM_DB_PATH=/var/lib/engram/engram.db \
  --env NODE_ENV=production

# Or use an ecosystem file
# ecosystem.config.js
module.exports = {
  apps: [{
    name: 'engram',
    script: 'server.js',
    env: {
      PORT: 4901,
      ENGRAM_DB_PATH: '/var/lib/engram/engram.db',
      NODE_ENV: 'production',
    },
  }],
}

# Then start with:
pm2 start ecosystem.config.js
pm2 save        # persist across reboots
pm2 startup     # generate system startup script

Running with systemd

For servers managed by systemd, create a unit file:

# /etc/systemd/system/engram.service
[Unit]
Description=Engram Memory Server
After=network.target

[Service]
Type=simple
User=engram
WorkingDirectory=/opt/engram
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5

Environment=PORT=4901
Environment=ENGRAM_DB_PATH=/var/lib/engram/engram.db
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable engram
sudo systemctl start engram

# Check status and logs
sudo systemctl status engram
journalctl -u engram -f

Database defaults

Engram uses SQLite with the following pragmas applied automatically at startup. These are hardcoded for optimal performance and cannot be changed.

PragmaValueEffect
journal_modeWALWrite-Ahead Logging enables 10k+ writes/sec and concurrent reads.
synchronousNORMALBalanced durability — safe with WAL mode, faster than FULL.
cache_size10000~40 MB page cache for faster repeated queries.
foreign_keysONEnforces referential integrity across tables.

The default embedding model is Xenova/all-MiniLM-L6-v2 (384 dimensions, FP16 storage). Override with ENGRAM_EMBEDDING_MODEL. After switching models, use the re-embedding pipeline to update existing vectors.

PostgreSQL (optional)

For team use or cloud deployment, switch from SQLite to PostgreSQL:

# 1. Set the dialect and connection URL
export ENGRAM_DATABASE=postgresql
export DATABASE_URL=postgresql://user:pass@localhost:5432/engram

# 2. Ensure pgvector extension is installed (for native vector search)
psql -d engram -c "CREATE EXTENSION IF NOT EXISTS vector;"

# 3. Run drizzle migrations
pnpm db:generate && pnpm db:migrate

# 4. Start the server
node apps/server/dist/index.js

The pg package is an optional dependency — it only loads when PostgreSQL mode is active. SQLite remains the default for local/single-user use.

Internal scoring algorithm

When recalling memories, Engram ranks results using a weighted composite score. These weights are hardcoded in the core scoring engine and provided here for reference.

FactorWeightDetails
Similarity45%Cosine similarity between the query embedding and stored memory embedding.
Recency25%Exponential decay with a 7-day half-life. Recently accessed memories score higher.
Importance20%User-assigned or auto-computed importance value (0–1).
Access frequency10%How often a memory has been recalled. Frequently accessed memories are boosted.

Recall defaults

ParameterDefaultContext
Similarity threshold0.3Minimum cosine similarity to include a result.
topK (search)10Maximum results for /api/search.
topK (recall)20Maximum results for /api/recall.
maxTokens (recall)2000Token budget for recall response content.
Graph expansion depth2Hops traversed in the knowledge graph when expanding results.

Decay & garbage collection

Engram includes an automatic memory decay and garbage collection system inspired by the Ebbinghaus forgetting curve. Memories that are old, rarely accessed, and low-importance are progressively decayed and eventually archived.

Retention score formula

retentionScore = importance × recencyFactor × accessFactor

Where:
  recencyFactor = exp(−ln(2) × daysSinceLastTouch / halfLifeDays)
  accessFactor  = min(1.0, 0.3 + 0.7 × log10(accessCount + 1) / 3)

When retentionScore < archiveThreshold → memory is archived (soft-deleted)

Default decay policy

ParameterDefaultDescription
halfLifeDays7Ebbinghaus half-life — how many days until recency factor halves.
archiveThreshold0.05Retention score below which a memory is archived.
decayIntervalMs3600000Auto-sweep interval (1 hour). Set to 0 to disable.
batchSize200Memories evaluated per batch during a sweep.
importanceDecayRate0.01Daily importance reduction (1% per day without access).
importanceFloor0.05Minimum importance value after decay.

Protection rules

The following memories are never archived by the decay engine, regardless of their retention score:

  • Semantic memories with importance ≥ 0.8
  • Procedural memories with confidence ≥ 0.9
  • Memories accessed in the last 24 hours
  • Memories tagged with "pinned" or "protected"

Auto-consolidation

After each decay sweep, Engram can automatically consolidate clusters of old episodic memories into semantic summaries. This is enabled by default and only runs on episodes older than 24 hours with at least 3 similar memories (similarity ≥ 0.6).

Use POST /api/decay with {"dryRun": true} to preview what would be archived before enabling auto-decay.

Contradiction detection

When a new memory is stored, Engram checks for conflicts with existing memories using vector similarity and content analysis (negation, value changes, temporal overrides, opposite sentiment). Configuration is managed at runtime via the API:

SettingDefaultDescription
enabledtrueToggle contradiction checking on/off.
similarityThreshold0.65Minimum vector similarity to consider two memories as same-topic.
confidenceThreshold0.4Minimum confidence to flag a contradiction.
maxCandidates10Max candidate memories to evaluate per store.
defaultStrategykeep_bothDefault resolution: keep_newest, keep_oldest, keep_important, keep_both, manual.
autoResolvefalseAutomatically resolve using the default strategy.

Update at runtime: PUT /api/contradictions/config

Index persistence

Engram persists the in-memory vector index to disk on shutdown and reloads it on startup. This enables fast incremental startup — only new memories since the last save are loaded from the database.

SettingDefaultDescription
ENGRAM_INDEX_PATH{ENGRAM_DB_PATH}.indexWhere to save the index file.

With a persisted index, startup for 1k memories goes from ~1.2s to ~45ms (27x faster). Use POST /api/index/rebuild to force a full rebuild if the index becomes stale.

Webhooks

Subscribe external systems to memory events. Configure via the API:

curl -X POST http://localhost:4901/api/webhooks \
  -H "Content-Type: application/json" \
  -d '{"url":"https://hooks.slack.com/...","events":["stored","contradiction"]}'

Events: stored, forgotten, decayed, consolidated, contradiction. Deliveries include HMAC-SHA256 signing when a secret is configured. Failed deliveries retry 3 times with exponential backoff. After 10 consecutive failures, the webhook is auto-disabled.

Plugins

Extend Engram with lifecycle hooks. Plugins run in-process and fire at 6 lifecycle points:onStore, onRecall, onForget, onDecay, onStartup, onShutdown.

// Register a plugin programmatically
brain.registerPlugin({
  id: 'my-org/logger',
  name: 'Memory Logger',
  version: '1.0.0',
  hooks: {
    onStore: async (ctx) => console.log('Stored:', ctx.memory.id),
  },
});

Plugin errors are isolated — a failing plugin never breaks core operations. See Plugin API for the full manifest format.

Configuration — Engram Docs