Memoria documentation

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.

What is Memoria?

A long-term memory engine for AI agents — modeled on how human memory works, not on vector search alone.

Every memory is a typed, scored node in a concurrent graph, connected to other memories by weighted, typed edges. Retrieval runs on spreading activation: a query lights up the most relevant memories, then activation flows outward across the graph so that causally, semantically, and temporally related memories surface too — even when their wording doesn't match the query.

Memories live in retention tiers (Buffer → Episodic → Semantic → Core) and are automatically promoted, demoted, or forgotten based on how important they are and how often they're used. Layered on top: consolidation (offline pattern extraction), reinforcement from feedback, safety filters (PII redaction + threat quarantine), and a metacognition layer that judges its own confidence. Every operation is isolated by namespace.

Graph, not just vectors

Spreading activation over weighted edges recalls related memories that vector similarity alone would miss.

Tiered retention

Memories are promoted from Buffer to Core (or forgotten) automatically, based on salience and use.

Namespace isolation

Your key maps to your namespace. Activation re-checks namespace on every edge — data never crosses tenants.

Three ways to use it: connect an MCP client (Claude Code, Cursor), call the HTTP API directly, or use an SDK. Start with the Quickstart.

Quickstart

From zero to your first recall in three steps.

1. Get an API key

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.

2. Connect your agent (MCP)

Add the Memoria MCP server to Claude Code with one command:

claude mcp add -s user --transport http memoria https://brain.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://brain.kolivri.com/v1/mcp",
      "headers": { "Authorization": "Bearer mem_dev_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }
    }
  }
}

3. Remember & recall

Your agent can now store and retrieve memories in your namespace. Or hit the HTTP API directly:

# store a memory
curl -X POST https://brain.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":"org:acme-3f9c2a"}'

# recall what you know
curl -X POST https://brain.kolivri.com/v1/memories/recall \
  -H "Authorization: Bearer $MEMORIA_KEY" -H "Content-Type: application/json" \
  -d '{"query":"when do we deploy?","namespace":"org:acme-3f9c2a"}'

Use your own namespace (shown in your account) in the namespace field — your key is scoped to it.

Core concepts

The ideas that make recall work. You don’t need all of this to start — but it explains why Memoria surfaces what it does.

Memory tiers

Every memory has a retention tier. Migration between tiers is automatic, driven by salience and access patterns.

TierRetentionPromotes whenNotes
Buffer~6h half-lifeaccessed ≥2× or salience > 0.6Garbage-collected once decay < 0.01 and ≥1 day old.
Episodic~7d half-life≥5 accesses, or 14d with salience > 0.4Demoted to Buffer if salience < 0.1.
Semantic~90d half-lifesalience > 0.9 and ≥20 accessesDistilled factual knowledge.
Corepermanent—Never decays, demotes, or GCs. Pinned memories are frozen at any tier.

Memory types

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).

TypeMeaning
BufferShort-lived scratch memory awaiting promotion.
EpisodicAn event or experience carrying temporal context.
SemanticDistilled factual knowledge.
CoreImmutable foundational knowledge.
ProceduralA learned action sequence or workflow.
ProspectiveA future-oriented intention or reminder.

Edge types & activation decay

Edges are typed and weighted. When activation spreads across an edge it is multiplied by the edge weight and the edge type's decay factor — so a strong Causal link (0.80) carries recall much further than a weak Contradicts link (0.30).

Edge typeDecayMeaning
Causal0.80One memory caused/led to another. Carries activation the furthest.
DerivedFrom0.80Source was derived from the target — a provenance trail.
DependsOn0.75Source requires the target to hold.
Assumes0.75Source depends on the truth of a target assumption.
Supersedes0.70Source replaces the target; superseded memories are down-ranked.
Evidence0.70Source provides evidence supporting the target.
Semantic0.60Shared meaning/topic. Created automatically at encode time.
CoRetrieval0.55Frequently retrieved together; strengthened on co-occurrence.
Schema0.50Linked through a shared category schema.
Contains0.50Structural containment (project → dir → file → definition).
Predicts0.45Source predicts the target will be needed.
Temporal0.35Sequential proximity in time. Created automatically.
Contradicts0.30The two conflict; invalidating one weakens the other.

Spreading activation

Recall runs in two stages. Seeding: the query is matched to memories in your namespace by cosine similarity, plus BM25 keyword seeds (discounted to 80%). Spreading: activation flows outward from those seeds across edges — at each hop, activation = source activation × edge weight × edge-type decay × any intent boost. The spread is bounded (≈3 hops, with per-wave and total node caps and an activation floor). Every edge crossing re-verifies namespace membership, so activation can never leak into another tenant's data. The payoff: a memory whose text doesn't match your query can still be recalled because it's causally or semantically connected to something that does.

Scoring

Each activated candidate's final score multiplies several factors (in log space): activation level × salience × freshnessintent × tier boost × utility. Freshness decays with time since last access. The tier boost depends on query intent — factual queries favour Semantic (1.5×) and Core (2.0×). A popularity anti-bias multiplier gently penalises memories retrieved often but rarely confirmed useful. Superseded memories are down-ranked to 5% of their score.

Salience

Salience is a memory's importance (0–1). An explicit value you pass always wins. Otherwise it's computed from novelty (how different this is from what's stored), consequence (high-stakes keywords like production, incident, outage, security, breach, critical), and any hint — the loudest signal dominates, others nudge. Default with no signal: 0.3. Salience feeds scoring, decay resistance, and tier-promotion thresholds.

Consolidation

An offline replay pass (analogous to sleep). Over a recent window it runs four detectors: repetition (near-duplicate clusters distilled into one Semantic summary, linked by Supersedes), co-access (frequently co-retrieved pairs reinforced), temporal burst (memories created close in time grouped as an episode), and contradiction (conflicting near-identical memories flagged). It turns a pile of raw episodic captures into deduplicated semantic knowledge over time.

Feedback & reinforcement

Memoria learns from use. Every recall strengthens CoRetrieval edges among top results and bumps access counts. Explicit feedback marks a memory useful or not: a prediction-error update nudges its expected-utility (and, on a big surprise, its salience), and reward is propagated back along the activation path that produced the hit. Conversely, dampening quietly suppresses query–memory pairs that repeatedly prove unhelpful — without ever deleting anything.

Safety: PII & quarantine

Two layers run before storage. PII redaction replaces emails, phone numbers, API keys, credit-card and Social-Security numbers, IPs, URLs, and names with reversible placeholders ([EMAIL_1]). Quarantine classifies content for credential patterns, instruction-injection attempts (EN + HE), and suspicious URLs; confidence rises with signal count (1→0.4, 2→0.7, 3+→0.95) and flagged content is marked quarantined.

Metacognition

Retrieval judges itself. It auto-detects a context mode from your namespace shape (organizational, support, research, personal…), assesses its own confidence (High / Moderate / Low) from the score distribution, detects re-querying (a sign the last answer missed), and can intervene mid-pipeline — broadening when seeds are too few, narrowing when too many, or returning empty when nothing clears the bar.

Authentication

One key per request, scoped to your namespace.

API keys

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.

Namespaces & isolation

Each account gets one organization with a unique namespace, auto-generated as org:<you>-<hex> (e.g. org:alice-3f9c2a) — shown in your account. Your key resolves to that namespace, and all reads/writes are scoped to it. Spreading activation re-checks namespace membership on every edge, so one tenant's data can never surface in another's query. Pass your namespace in the namespace field of API calls.

Rotating & revoking keys

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.

Rate limits & quota

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.

Connect via MCP

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://brain.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://brain.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).

Memory tools

ToolParamsDoes
recall_memoriesquery, namespace?, token_budget?, mode?Retrieve relevant memories with metacognition.
build_contextquery, namespace?, token_budget?, mode?Assemble a token-budgeted context string for a query.
encode_memorycontent, type?, namespace?, salience?, context?Store a memory (type: episodic·semantic·buffer·core).
forget_memoryidDelete a memory by UUID.
feedbackid, usefulMark a recalled memory useful / not useful.
consolidatenamespaceMerge duplicates, detect patterns & edges.
statsnamespacePer-namespace memory count + tier breakdown.
health—Engine-wide health across namespaces.

Code-intelligence tools

Index a repository into a code/<project> namespace and these become available:

ToolDoes
search_codeSemantic search over indexed code definitions.
explain_codeWhat a symbol is, who calls it, its tests.
find_referencesEvery reference to a symbol (graded).
find_fileLocate a file/dir by path substring.
impactTransitive blast radius of changing a symbol.
call_treeCaller / callee tree for a symbol.
dead_code · test_gapsUncalled definitions · definitions with no test.
rename · diff_riskRename worklist · callers at risk for changed symbols.
implementorsTypes implementing a trait/interface.
explain_diff · explain_errorAnalyse a unified diff · an error/stack trace.
navigate · get_hierarchyWalk the containment map · a node’s full vertical context.

Calling a tool directly

The same tools are reachable over plain HTTP JSON-RPC at POST /v1/mcp:

curl -X POST https://brain.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.

HTTP API

Everything the agents do, over plain REST. Base URL https://brain.kolivri.com, all routes under /v1, Bearer auth.

Memory

POST/v1/memories
Encode one memory. Runs quarantine + dedup; returns its tier and salience.
Body{ content, type, namespace, salience?, context?, links? }
Returns201 { id, created_at, salience, tier, quarantined, is_duplicate, duplicate_of? }
curl -X POST https://brain.kolivri.com/v1/memories \
  -H "Authorization: Bearer $MEMORIA_KEY" -H "Content-Type: application/json" \
  -d '{"content":"user prefers dark mode","type":"Episodic","namespace":"org:acme-3f9c2a","salience":0.8,"context":{"user_id":"john-123"}}'
POST/v1/memories/recall
Recall memories for a query through the full pipeline; returns scored results + metacognition.
Body{ query, namespace, token_budget?=4096, min_salience?=0, context?, mode? }
Returns200 { results:[{ memory, score }], total_candidates, latency_ms, metacognition? }
curl -X POST https://brain.kolivri.com/v1/memories/recall \
  -H "Authorization: Bearer $MEMORIA_KEY" -H "Content-Type: application/json" \
  -d '{"query":"authentication tokens","namespace":"org:acme-3f9c2a","token_budget":4096}'
POST/v1/memories/context
Build a single token-budgeted context string from recalled memories.
Body{ query, namespace, token_budget?=4096, format?=Structured (Structured|Narrative|Raw), context?, mode? }
Returns200 { context, memories_used }
POST/v1/memories/recall/enhanced
Recall through the standalone pipeline (BM25 seeding, MMR diversity, tracing, caching).
Body{ query, namespace, token_budget?, diversity?=0.7, min_salience?, mode? }
Returns200 { results, total_candidates, latency_ms, cache_hit, trace_id?, metacognition? }
DELETE/v1/memories/:id
Forget a memory by UUID.
Body(none)
Returns200 { deleted }
GET/v1/memories/:id/neighbors
List a memory’s outgoing edges.
Body(none)
Returns200 { edges:[{ target_id, edge_type, weight }] }

Batch & bulk

POST/v1/memories/batch
Encode up to 1000 memories at once (plain or gzip+base64 body; ≤64 MiB decompressed).
Body{ memories:[{ content, type?, salience?, context?, namespace }] }
Returns201 { ids, encoded, failed, compressed_size, raw_size }
POST/v1/memories/recall/batch
Run several recall queries in one request.
Body{ queries:[{ query, namespace, token_budget? }] }
Returns200 { results: MemoryResult[][] }
DELETE/v1/memories/by-context
GDPR-style bulk delete: forget every memory whose context key equals a value. (POST /v1/memories/by-context/delete is an alias.)
Body{ namespace, context_key, context_value }
Returns200 { deleted }

Learning

POST/v1/consolidate
Run offline consolidation over a namespace.
Body{ namespace }
Returns200 { patterns_found, edges_created, memories_created, contradictions }
POST/v1/feedback
Submit retrieval feedback for a memory; drives reward + dampening.
Body{ memory_id? | recall_id?, useful?, score? }
Returns200 { updated }

Prospective memory (intentions)

POST/v1/intentions
Create an intention with a context / time / event trigger.
Body{ trigger_type, trigger_data, action, salience, expires_at?, namespace }
Returns201 { id }
GET/v1/intentions?namespace=NS
List active (unfired, unexpired) intentions.
Body(query)
Returns200 { intentions:[{ id, trigger_type, action, salience, expires_at?, created_at, namespace }] }
DELETE/v1/intentions/:id
Delete an intention.
Body(none)
Returns200 { deleted }

Introspection

GET/v1/health
Engine health / liveness: counts and tier distribution.
Body(none)
Returns200 { memory_count, edge_count, tier_distribution, namespace_count }
GET/v1/stats?namespace=NS
Per-namespace aggregate statistics.
Body(query)
Returns200 (MemoryStats)
GET/v1/meta/knowledge-map?topic=T&namespace=NS
Metamemory confidence/gap entry for a topic.
Body(query)
Returns200 (KnowledgeMapEntry)
GET/v1/meta/contradictions?namespace=NS
List detected contradictions in a namespace.
Body(query)
Returns200 { contradictions:[…] }
GET/v1/graph/dot?namespace=NS&max_nodes=50
Export the namespace graph as Graphviz DOT text.
Body(query)
Returns200 text/plain (DOT)
GET/v1/trace/:recall_id
Fetch a stored recall trace (from enhanced recall).
Body(none)
Returns200 (RecallTrace)
GET/v1/events/stream
Server-Sent Events stream of lifecycle events (30s keep-alive).
Body(none)
Returnstext/event-stream
GET/v1/events?since=RFC3339
Poll recent lifecycle events after a timestamp.
Body(query)
Returns200 [{ 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.

Code intelligence

Index a repository into a code/<project> namespace and Memoria becomes a queryable map of it — definitions, references, call graphs, blast radius.

Method · PathPurpose
POST /v1/code/searchSemantic search over indexed definitions (optional type filter).
POST /v1/code/explainWhat a symbol is, who uses it (live scan), and its tests.
POST /v1/code/referencesEvery reference to a symbol — call / definition / mention, graded.
POST /v1/code/findFind files/dirs whose path matches a name, shallowest first.
POST /v1/code/impactBlast radius: transitive reverse-call walk of what could break.
POST /v1/code/call-treeNested caller (in) or callee (out) tree.
POST /v1/code/dead-codeDefinitions with no in-namespace caller (removal candidates).
POST /v1/code/test-gapsNon-test definitions with no direct test caller.
POST /v1/code/renameReviewed line-level edit worklist for a rename (not an auto-patcher).
POST /v1/code/diff-riskFor a set of changed symbols, their direct callers at risk.
POST /v1/code/implementorsTypes whose impl Trait for Type names a symbol (Rust today).
POST /v1/code/diff · /errorNatural-language analysis of a unified diff · an error/stack trace.
POST /v1/code/build-edgesMaterialise Contains + DependsOn edges after indexing (idempotent).

Example: find everything a change would affect

curl -X POST https://brain.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.

SDKs

TypeScript / JavaScript

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://brain.kolivri.com",
  apiKey: process.env.MEMORIA_KEY,   // -> Authorization: Bearer <key>
  namespace: "org:acme-3f9c2a",      // required; default for every call
});

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");
MethodEndpoint
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 }.

Python

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.

CLI

The memoria binary runs against a local SQLite database (default ~/.memoria/memoria.db). Global flags: --db PATH, --format text|json, --verbose.

CommandDoes
memoria healthGraph stats: memory/edge counts, tier distribution.
memoria encode --namespace NS --content T --type episodicEncode a memory; prints its id.
memoria recall --namespace NS --query T [--budget 4096]Recall ranked results for a query.
memoria search --namespace NS --query TBM25 lexical search (top 20).
memoria forget --id UUIDDelete a memory by UUID.
memoria stats --namespace NSPer-namespace stats + health assessment.
memoria consolidate --namespace NSRun offline consolidation.
memoria migrate --namespace NSRun tier promotion/demotion/GC.
memoria contradictions --namespace NSDetect contradictory memory pairs.
memoria meta --namespace NS --topic TMetamemory knowledge-map for a topic.
memoria export --namespace NSDump all memories in a namespace as JSON.
memoria import json|csv --file F --namespace NSImport memories from a file.
memoria graph dot|ascii …Export the graph (Graphviz DOT / ASCII neighborhood).
memoria backup|restore --file FChecksummed JSON backup / restore.
memoria trace --lastShow the most recent recall trace.
memoria pii-check --content TScan text for PII.

--db must come before the subcommand: memoria --db /path.db health. Memory types accept lowercase values.

FAQ & limits

Is my data isolated from other customers?

Yes. Your key resolves to your own namespace, and spreading activation re-verifies namespace membership on every edge it traverses — activation can never cross into another tenant’s data, even if two memories share a term.

What happens when I lose a key?

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.

Do I have to manage tiers or forgetting myself?

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.

How big can a batch be?

Up to 1000 memories per /v1/memories/batch call; the decompressed payload must be ≤64 MiB. For larger loads, send multiple batches.

What are the rate limits?

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.

Which memory-type casing do I use?

PascalCase (Episodic) over the HTTP API and TypeScript SDK; lowercase (episodic) over MCP, the Python SDK, and the CLI.

How do I use code intelligence?

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 shows your namespace and keys, and the Quickstart gets you connected in a minute.