Long-term memory for AI agents — connect a client, call the API, and your agent remembers across sessions. Grounded, graph-based recall with automatic tiering and consolidation.
A deterministic long-term memory engine for AI agents — built to replace probabilistic vector guesswork and LLM write-wrappers.
Every memory is a typed, scored node connected to related memories by typed relationships (Supersedes, Causal, Semantic, DependsOn, Temporal). Unlike LLM memory wrappers that call a stochastic model on every write, Memoria's encode and recall paths are 100% deterministic: the same sequence of events produces the exact same state, the exact same Supersedes belief revisions, and the exact same recall trace in 12–17 ms with zero LLM tokens.
Memories live in retention tiers (Buffer → Episodic → Semantic → Core) and are automatically promoted, demoted, or forgotten based on importance and usage. Layered on top: 15-language multilingual reasoning, offline consolidation, reinforcement from feedback, safety filters (PII redaction + threat quarantine), and confidence scoring. Every operation is isolated by namespace.
Zero LLM calls on encode or recall. Supersedes belief revision, multi-session counting, and temporal queries execute deterministically in <15 ms.
Recall traverses causal, semantic, and temporal relationships to surface facts that flat vector similarity misses.
Every recall emits a reproducible trace (/v1/trace/recent), and every query enforces strict organization and namespace isolation.
Three ways to use it: connect an MCP client (Claude Code, OpenCode, Cursor), call the HTTP API directly, or use an SDK. Start with the Quickstart.
From zero to your first recall in three steps.
Create an account (or log in). You'll get an isolated namespace and your first key — it starts with mem_dev_ and is shown once. Generate more anytime from your account.
Add the Memoria MCP server to Claude Code with one command:
claude mcp add -s user --transport http memoria https://memoria.kolivri.com/v1/mcp \ --header "Authorization: Bearer mem_dev_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
…or paste this into your MCP client config (Cursor, Claude Desktop, etc.):
{
"mcpServers": {
"memoria": {
"type": "http",
"url": "https://memoria.kolivri.com/v1/mcp",
"headers": { "Authorization": "Bearer mem_dev_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }
}
}
}Your agent can now store and retrieve memories in your namespace. Or hit the HTTP API directly:
# store a memory
curl -X POST https://memoria.kolivri.com/v1/memories \
-H "Authorization: Bearer $MEMORIA_KEY" -H "Content-Type: application/json" \
-d '{"content":"We deploy on Fridays after 2pm","type":"Episodic","namespace":"my-project"}'
# recall what you know
curl -X POST https://memoria.kolivri.com/v1/memories/recall \
-H "Authorization: Bearer $MEMORIA_KEY" -H "Content-Type: application/json" \
-d '{"query":"when do we deploy?","namespace":"my-project"}'Organization isolation is handled automatically behind the scenes from your API key — pass any project or workspace name (e.g. my-project or default) in the namespace field.
The concepts you work with when storing and recalling memories.
Every memory has a retention tier. Migration between tiers is automatic, driven by salience and access patterns.
| Tier | Retention | Lifecycle | Notes |
|---|---|---|---|
| Buffer | Short-term | Promotes on repeated access or high salience | Automatically expired when unused. |
| Episodic | Medium-term | Promotes with sustained usage across sessions | Captures session events and task history. |
| Semantic | Long-term | Promotes when confirmed as durable knowledge | Distilled project facts and conventions. |
| Core | Permanent | Pinned or created as core rules | Never decays or expires. |
The type you assign at encode time. Over the HTTP API and TypeScript SDK these are PascalCase (Episodic); over MCP, the Python SDK, and the CLI they're lowercase (episodic).
| Type | Meaning |
|---|---|
Buffer | Short-lived scratch memory awaiting promotion. |
Episodic | An event or experience carrying temporal context. |
Semantic | Distilled factual knowledge. |
Core | Immutable foundational knowledge. |
Procedural | A learned action sequence or workflow. |
Prospective | A future-oriented intention or reminder. |
Memories are connected by typed relationships so recall can follow causal chains, dependency trees, and belief revisions.
| Edge type | Meaning |
|---|---|
Causal | One memory caused or led to another. |
DerivedFrom | Source was derived from the target — a provenance trail. |
DependsOn | Source requires the target to hold. |
Assumes | Source depends on the truth of a target assumption. |
Supersedes | Source replaces the target; outdated memories are automatically suppressed. |
Evidence | Source provides evidence supporting the target. |
Semantic | Shared meaning or topic, linked automatically at encode time. |
CoRetrieval | Frequently retrieved together and reinforced on co-access. |
Schema | Linked through a shared category schema. |
Contains | Structural containment (project → dir → file → definition). |
Predicts | Source predicts the target will be needed. |
Temporal | Sequential proximity in time, linked automatically. |
Contradicts | Marks conflicting statements so stale or contradictory state is surfaced. |
Recall matches your query against your isolated namespace and traverses connected relationships (Causal, DependsOn, Semantic, Supersedes) to surface relevant context — even when an important decision does not share exact keywords with the prompt. Every traversal strictly enforces your organization namespace boundary.
Candidates are ranked deterministically using relevance, salience, recency, retention tier, and historical utility. When a newer memory Supersedes an older one, the outdated fact is automatically suppressed so your agent always receives current state.
Salience is a memory's importance (0–1). An explicit value you pass always wins; otherwise Memoria assigns it automatically based on novelty and high-consequence signals. Salience guides ranking and retention tier promotion.
Consolidation merges near-duplicate episodic captures into clean Semantic knowledge linked by Supersedes, reinforces co-accessed memories, groups related session events, and flags contradictions.
Calling /v1/feedback or the feedback MCP tool marks a memory as useful or unhelpful, immediately adjusting its future ranking priority without deleting history.
Before storage, Memoria can redact sensitive identifiers (emails, phone numbers, API keys, payment cards) and quarantine suspected prompt-injection payloads so poisoned inputs do not corrupt agent context.
Every recall evaluates result confidence and emits an auditable trace (GET /v1/trace/recent) so you can inspect why specific memories were returned.
One key per request, scoped to your namespace.
Authenticate every request with your key as a Bearer token:
Authorization: Bearer mem_dev_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Keys look like mem_dev_ followed by 43 URL-safe characters. The raw key is shown once at creation and never stored — only a SHA-256 hash is kept, so if you lose a key you mint a new one. The token is opaque: it carries no embedded namespace; your scope is looked up server-side.
Every API key is automatically scoped to your organization behind the scenes — you never pass an org: identifier. The namespace field in API and MCP calls is purely for your own project, repository, or agent wing name (e.g. my-project, backend, or default). One organization's data can never surface in another's query.
Mint additional keys and revoke any key instantly from your account. Revocation takes effect on the very next request (nothing is cached). You can only see and revoke keys under your own account.
Requests are rate-limited per key (a token bucket). Exceed it and you get 429 Too Many Requests with a Retry-After header and a JSON body {code:"RATE_LIMIT_EXCEEDED", status:429, message}. Each organization also has a rolling usage quota; once it's exhausted, requests return 402 Payment Required until the window advances. The exact throughput and quota scale with your plan — check your account.
The Model Context Protocol is the fastest path — your agent gets memory tools automatically.
Add Memoria to Claude Code:
claude mcp add -s user --transport http memoria https://memoria.kolivri.com/v1/mcp \ --header "Authorization: Bearer mem_dev_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Or configure any MCP client (Cursor, Claude Desktop, VS Code) with:
{
"mcpServers": {
"memoria": {
"type": "http",
"url": "https://memoria.kolivri.com/v1/mcp",
"headers": { "Authorization": "Bearer mem_dev_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }
}
}
}The connection speaks JSON-RPC 2.0 over streamable HTTP (protocol 2024-11-05). Namespace is chosen per call via the namespace argument (or the x-memoria-namespace header default).
| Tool | Params | Does |
|---|---|---|
recall_memories | query, namespace?, token_budget?, mode? | Retrieve relevant memories with metacognition. |
build_context | query, namespace?, token_budget?, mode? | Assemble a token-budgeted context string for a query. |
encode_memory | content, type?, namespace?, salience?, context? | Store a memory (type: episodic·semantic·buffer·core). |
forget_memory | id | Delete a memory by UUID. |
feedback | id, useful | Mark a recalled memory useful / not useful. |
consolidate | namespace | Merge duplicates, detect patterns & edges. |
stats | namespace | Per-namespace memory count + tier breakdown. |
health | — | Engine-wide health across namespaces. |
Index a repository into a code/<project> namespace and these become available:
| Tool | Does |
|---|---|
search_code | Semantic search over indexed code definitions. |
explain_code | What a symbol is, who calls it, its tests. |
find_references | Every reference to a symbol (graded). |
find_file | Locate a file/dir by path substring. |
impact | Transitive blast radius of changing a symbol. |
call_tree | Caller / callee tree for a symbol. |
dead_code · test_gaps | Uncalled definitions · definitions with no test. |
rename · diff_risk | Rename worklist · callers at risk for changed symbols. |
implementors | Types implementing a trait/interface. |
explain_diff · explain_error | Analyse a unified diff · an error/stack trace. |
navigate · get_hierarchy | Walk the containment map · a node’s full vertical context. |
The same tools are reachable over plain HTTP JSON-RPC at POST /v1/mcp:
curl -X POST https://memoria.kolivri.com/v1/mcp \
-H "Authorization: Bearer $MEMORIA_KEY" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"recall_memories",
"arguments":{"query":"auth flow","namespace":"code/myapp"}}}'Successful results come back as {content:[{type:"text", text:<json>}]}. Call tools/list to see everything the server advertises.
Everything the agents do, over plain REST. Base URL https://memoria.kolivri.com, all routes under /v1, Bearer auth.
/v1/memories{ content, type, namespace, salience?, context?, links? }201 { id, created_at, salience, tier, quarantined, is_duplicate, duplicate_of? }curl -X POST https://memoria.kolivri.com/v1/memories \
-H "Authorization: Bearer $MEMORIA_KEY" -H "Content-Type: application/json" \
-d '{"content":"user prefers dark mode","type":"Episodic","namespace":"my-project","salience":0.8,"context":{"user_id":"john-123"}}'/v1/memories/recall{ query, namespace, token_budget?=4096, min_salience?=0, context?, mode? }200 { results:[{ memory, score }], total_candidates, latency_ms, metacognition? }curl -X POST https://memoria.kolivri.com/v1/memories/recall \
-H "Authorization: Bearer $MEMORIA_KEY" -H "Content-Type: application/json" \
-d '{"query":"authentication tokens","namespace":"my-project","token_budget":4096}'/v1/memories/context{ query, namespace, token_budget?=4096, format?=Structured (Structured|Narrative|Raw), context?, mode? }200 { context, memories_used }/v1/memories/recall/enhanced{ query, namespace, token_budget?, diversity?=0.7, min_salience?, mode? }200 { results, total_candidates, latency_ms, cache_hit, trace_id?, metacognition? }/v1/memories/:id(none)200 { deleted }/v1/memories/:id/neighbors(none)200 { edges:[{ target_id, edge_type, weight }] }/v1/memories/batch{ memories:[{ content, type?, salience?, context?, namespace }] }201 { ids, encoded, failed, compressed_size, raw_size }/v1/memories/recall/batch{ queries:[{ query, namespace, token_budget? }] }200 { results: MemoryResult[][] }/v1/memories/by-context{ namespace, context_key, context_value }200 { deleted }/v1/consolidate{ namespace }200 { patterns_found, edges_created, memories_created, contradictions }/v1/feedback{ memory_id? | recall_id?, useful?, score? }200 { updated }/v1/intentions{ trigger_type, trigger_data, action, salience, expires_at?, namespace }201 { id }/v1/intentions?namespace=NS(query)200 { intentions:[{ id, trigger_type, action, salience, expires_at?, created_at, namespace }] }/v1/intentions/:id(none)200 { deleted }/v1/health(none)200 { memory_count, edge_count, tier_distribution, namespace_count }/v1/stats?namespace=NS(query)200 (MemoryStats)/v1/meta/knowledge-map?topic=T&namespace=NS(query)200 (KnowledgeMapEntry)/v1/meta/contradictions?namespace=NS(query)200 { contradictions:[…] }/v1/graph/dot?namespace=NS&max_nodes=50(query)200 text/plain (DOT)/v1/trace/:recall_id(none)200 (RecallTrace)/v1/events/stream(none)text/event-stream/v1/events?since=RFC3339(query)200 [{ event_type, data, timestamp, id }]An interactive OpenAPI spec is served at /v1/openapi.json (Swagger UI at /v1/docs). Auth/rate-limit errors return {code, status, message}; most other errors are a bare status code.
Index a repository into a code/<project> namespace and Memoria becomes a queryable map of it — definitions, references, call graphs, blast radius.
| Method · Path | Purpose |
|---|---|
POST /v1/code/search | Semantic search over indexed definitions (optional type filter). |
POST /v1/code/explain | What a symbol is, who uses it (live scan), and its tests. |
POST /v1/code/references | Every reference to a symbol — call / definition / mention, graded. |
POST /v1/code/find | Find files/dirs whose path matches a name, shallowest first. |
POST /v1/code/impact | Blast radius: transitive reverse-call walk of what could break. |
POST /v1/code/call-tree | Nested caller (in) or callee (out) tree. |
POST /v1/code/dead-code | Definitions with no in-namespace caller (removal candidates). |
POST /v1/code/test-gaps | Non-test definitions with no direct test caller. |
POST /v1/code/rename | Reviewed line-level edit worklist for a rename (not an auto-patcher). |
POST /v1/code/diff-risk | For a set of changed symbols, their direct callers at risk. |
POST /v1/code/implementors | Types whose impl Trait for Type names a symbol (Rust today). |
POST /v1/code/diff · /error | Natural-language analysis of a unified diff · an error/stack trace. |
POST /v1/code/build-edges | Materialise Contains + DependsOn edges after indexing (idempotent). |
curl -X POST https://memoria.kolivri.com/v1/code/impact \
-H "Authorization: Bearer $MEMORIA_KEY" -H "Content-Type: application/json" \
-d '{"namespace":"code/myapp","symbol":"calc_total","max_depth":5,"limit":200}'
# -> { symbol, affected:[{ qualified_name, file, line, depth, min_confidence }], total, truncated }All code tools are also exposed as MCP tools (see Connect via MCP) and in the TypeScript SDK under memoria.code.*. Findings are graded (exact / heuristic / ambiguous) with confidence scores — treat rename and dead-code output as a reviewed worklist, not an automatic edit.
A thin, zero-dependency fetch client for the HTTP API (Node 18+ or the browser). Enum values are PascalCase (Episodic).
import { Memoria } from "@memoria/sdk";
const memoria = new Memoria({
baseUrl: "https://memoria.kolivri.com",
apiKey: process.env.MEMORIA_KEY, // -> Authorization: Bearer <key>
namespace: "my-project", // project / workspace name (org scoping is automatic)
});
const { id, tier } = await memoria.encode({ content: "Deployed v2 to prod", type: "Episodic" });
const hits = await memoria.recall({ query: "deployment", token_budget: 2048 });
const { context } = await memoria.buildContext("deployment", 4096);
// code intelligence over an indexed namespace:
const refs = await memoria.code.findReferences("calc_total");| Method | Endpoint |
|---|---|
encode(req) | POST /v1/memories |
recall(req) | POST /v1/memories/recall |
buildContext(query, budget?, format?) | POST /v1/memories/context |
forget(id) · neighbors(id) | DELETE · GET /v1/memories/:id[…] |
encodeBatch(…) · recallBatch(…) | POST /v1/memories/batch[…] |
consolidate(ns?) · feedback(req) | POST /v1/consolidate · /v1/feedback |
deleteByContext(req) · health() | DELETE /v1/memories/by-context · GET /v1/health |
navigate(…) · hierarchy(node) | POST /v1/navigate · /v1/hierarchy |
code.search / explain / findReferences / impact / callTree / … | POST /v1/code/* |
Non-2xx responses throw MemoriaError { message, status, body }.
A native (PyO3) module that links the engine in-process — embedded, no server or HTTP. Build with maturin develop. Enum-like strings are lowercase (episodic). Surface: encode · recall · build_context · forget · health.
from memoria import Memoria
m = Memoria() # in-process; wraps the engine directly
mid = m.encode("Deployed v2 to prod", "episodic", "myapp")
out = m.recall("deployment", "myapp", token_budget=2048)
for r in out["results"]:
print(r["score"], r["content"])
print(m.build_context("deployment", "myapp", 4096)["context"])The Python SDK is for embedding the engine locally. For the hosted cloud service, use MCP, the HTTP API, or the TypeScript SDK.
The memoria binary runs against a local SQLite database (default ~/.memoria/memoria.db). Global flags: --db PATH, --format text|json, --verbose.
| Command | Does |
|---|---|
memoria health | Graph stats: memory/edge counts, tier distribution. |
memoria encode --namespace NS --content T --type episodic | Encode a memory; prints its id. |
memoria recall --namespace NS --query T [--budget 4096] | Recall ranked results for a query. |
memoria search --namespace NS --query T | BM25 lexical search (top 20). |
memoria forget --id UUID | Delete a memory by UUID. |
memoria stats --namespace NS | Per-namespace stats + health assessment. |
memoria consolidate --namespace NS | Run offline consolidation. |
memoria migrate --namespace NS | Run tier promotion/demotion/GC. |
memoria contradictions --namespace NS | Detect contradictory memory pairs. |
memoria meta --namespace NS --topic T | Metamemory knowledge-map for a topic. |
memoria export --namespace NS | Dump all memories in a namespace as JSON. |
memoria import json|csv --file F --namespace NS | Import memories from a file. |
memoria graph dot|ascii … | Export the graph (Graphviz DOT / ASCII neighborhood). |
memoria backup|restore --file F | Checksummed JSON backup / restore. |
memoria trace --last | Show the most recent recall trace. |
memoria pii-check --content T | Scan text for PII. |
--db must come before the subcommand: memoria --db /path.db health. Memory types accept lowercase values.
Yes. Your key resolves to your own organization and namespace, and every read, write, and graph traversal enforces strict tenant boundaries — one organization’s data can never surface in another’s query.
You can’t recover it — only a hash is stored. Mint a new key from your account and revoke the old one. Revocation is effective on the next request.
No. Promotion, demotion, and garbage-collection between Buffer → Episodic → Semantic → Core happen automatically from salience and access patterns. Pin a memory or set it to Core to keep it forever.
Up to 1000 memories per /v1/memories/batch call; the decompressed payload must be ≤64 MiB. For larger loads, send multiple batches.
Requests are rate-limited per key (429 with a Retry-After header when you exceed it), and each org has a rolling usage quota (402 when it’s exhausted, until the window advances). The exact numbers scale with your plan — see your account.
PascalCase (Episodic) over the HTTP API and TypeScript SDK; lowercase (episodic) over MCP, the Python SDK, and the CLI.
Index a repo into a code/<project> namespace, then call the /v1/code/* endpoints or the corresponding MCP tools. Findings are graded by confidence — treat rename/dead-code as a reviewed worklist.
Still stuck? Your account has your API keys and Memory Explorer, and the Quickstart gets you connected in a minute.