Skip to content

Architecture overview

Engram is a NestJS application (apps/mcp-server) that speaks the Model Context Protocol on one side and drives a small set of storage services on the other. Every capability — storing, recalling, consolidating, decaying, reindexing — is exposed as an MCP tool, and every tool boils down to the same pipeline: validate input with a strict Zod schema → resolve the acting tenant → call a service → persist to Postgres (source of truth) and derived indexes.

The pages in this section explain why the system is shaped the way it is. For operational steps, see the how-to guides; for exact tool and variable listings, the reference.

flowchart LR
subgraph Clients
A["MCP client<br/>(Claude Code, Copilot, Cursor, ...)"]
end
subgraph Server["apps/mcp-server (NestJS)"]
T["Transport<br/>stdio | streamable-http"]
AUTH["McpAuthMiddleware<br/>JWT / API key"]
RATE["McpRateLimitMiddleware"]
MC["MemoryController<br/>TOOL_MANIFEST + handlers"]
MS["MemoryService"]
CONS["ConsolidationService<br/>DecayService<br/>CorpusConsolidationService"]
end
subgraph Storage
STM["STM: Postgres<br/>(memories table, TTL)"]
LTM["LTM: Postgres<br/>(source of truth)"]
VS["Vector store: pgvector<br/>(embedding_vec in Postgres)"]
EMB["Embeddings<br/>ollama | openai | local | disabled"]
end
A -->|tools/call| T --> AUTH --> RATE --> MC --> MS
MS --> STM
MS --> LTM
MS --> VS
MS --> EMB
CONS --> STM
CONS --> LTM

(Mermaid source — renders as a diagram on GitHub and in Mermaid-aware viewers.)

Postgres is the source of truth; everything else is derived or ephemeral. Long-term memories live in the single Memory table (memory model). The vector index can be rebuilt from Postgres at any time (reindex & backfill), and short-term memories are deliberately allowed to expire (memory tiers). This ordering means a lost or corrupted vector index is an inconvenience, never data loss.

One binary, two deployment profiles. The same server runs single-user (lite, with the auth/organization stack left unwired) or multi-tenant (standard, the default). Both run on the same Postgres (with the pgvector extension) — the only backing service — and differ only in whether the auth stack is active. Modules are wired conditionally from ProfileCapabilities (deployment profiles).

Degrade, don’t fail. Embeddings are optional at every seam: if the provider is disabled or unreachable, writes still succeed (vector-less) and recall falls back to what is available (embeddings, vector store).

The tenant boundary is the credential, not the request body. With auth enabled, the verified key’s userId overrides anything the client sends, and a multi-tenant HTTP server refuses to boot unauthenticated in every NODE_ENV (auth & multi-tenancy).

Background jobs must never clobber a concurrent edit. Every lifecycle mutation — decay, dedup annotation, contradiction marking, corpus consolidation — goes through version-guarded compare-and-set writes (consolidation & decay, concurrency policy).

Page Explains
Memory model The Memory row, its metadata JSON, versioning, and the supporting tables
Memory tiers STM vs LTM, TTLs, access counting, promotion
Deployment profiles lite / standard and ProfileCapabilities
Vector store pgvector and the runtime-managed embedding_vec column
Embeddings Providers, dimensions, null-safe degradation
Reindex & backfill Cursor-resumable rebuilds, the job queue
Auth & multi-tenancy Boot fail-safe, per-agent keys, scopes, delegation
Consolidation & decay STM→LTM promotion, corpus consolidation, dedup, contradictions