How one user's experiences become an interrogable, explainable memory. The five layers, the bi-temporal model, the "why" trail, and proportional forgetting. Read this first to learn the primitives.
How the same primitives scale to a company: scope trees, four-tier authorization, workspaces, manager and exec views, a worked engineering RCA application, and a rollout playbook.
Source documents: API_DESIGN_V1.md and CORTEXDB_FOR_THE_ENTERPRISE.md. This deck distills both for someone building on top of the API.
Agents submit experiences as they happen. CortexDB captures them losslessly, derives structured memory from them in five distinct layers, and lets the agent — or anyone with the right authorization — recall, explain, revise, and forget any of it later. With full bi-temporal history and a provenance trail back to the original events.
Vector search is one signal of many. We rank with six.
Chat history is one modality of one layer.
An AI system that learns from its own experience over time.
The write-ahead log is the source of truth. Every derived layer can be rebuilt by replay. No API mutates a stored event payload.
Five distinct, addressable layers: Events, Episodes, Facts, Beliefs, Understanding. Each has its own lifecycle. Each points back to the experiences that produced it.
When the system says "Acme is likely to renew," it can tell you why — which facts, which episodes, which raw events. Memory without an audit trail is gossip.
| System | What they have | What they can't answer |
|---|---|---|
| Mem0 | Flat facts only — really, ranked sentences | "Why did this result rank where it did?" — the derivation isn't stored. |
| Zep | Facts + episodes, bi-temporal facts | "What did we observe vs. what did we conclude?" — Belief folded into Fact. |
| Letta | Tiered memory, archival passages | No explicit Belief layer at all; no synthesized Understanding. |
| CortexDB | Events · Episodes · Facts · Beliefs · Understanding | "Why does the system think that?" — Beliefs cite Facts, Facts cite Episodes and Events, Understanding cites everything. The trail is always walkable. |
The five layers are the minimum set that lets us answer every recall mode an enterprise will ask of a memory system.
| Stage | What happens | Synchronous? | Latency |
|---|---|---|---|
| Capture | Event appended to the WAL | yes | ~5 ms |
| Extract | LLM pulls structured facts and entities | no | ~200–500 ms after |
| Index | Content indexed for retrieval (BM25 + vector) | no | ~50–100 ms after extract |
| Reconcile | Conflicting facts supersede; beliefs revise | no | ~100–300 ms after extract |
| Consolidate | Episodes seal; understanding nodes update | no | background, periodic |
A high-volume agent can fire hundreds of events a minute because Capture is the only synchronous guarantee. The lifecycle stream surfaces the rest as SSE events — clients that need read-after-write can opt into ?wait=indexed or ?wait=consolidated.
POST /v1/experienceSubmit a structured experience envelope. Returns 202 with an event ID and a lifecycle stream URL. Triggers the async pipeline.
+ /v1/experience/bulk · /v1/blobs
POST /v1/recallReturns the stratified pack — facts, beliefs, episodes side-by-side with a synthesized prose context block and full provenance trail.
+ layer reads: /v1/events · /v1/episodes · /v1/facts · /v1/beliefs · /v1/understanding
POST /v1/answerRecall composed with an LLM call. Same provenance contract. The LLM selects from the pack — it cannot invent citations.
+ /v1/beliefs/why — explainability graph
POST /v1/forgetProportional removal. Default keeps events, drops derived layers. GDPR-grade erasure lives at /v1/erasures with preview, manifest, and audit.
+ /v1/erasures/preview · /v1/erasures/{id}
Everything else is read-only introspection: /v1/lifecycle/stream (SSE), /v1/audit, /v1/scopes, /v1/admin/*.
One user. One agent. One week. Every primitive in motion.
Alice is a sales rep at Initech. She uses an AI agent — support_bot — for note-taking, follow-ups, and recall.
Alice doesn't talk to CortexDB. She talks to her agent. Her agent talks to CortexDB.
support_bot packages that single sentence as an experience envelope and submits it.
POST /v1/experience Authorization: Bearer *** X-Cortex-Actor: agent:support_bot { "scope": "org:initech/dept:sales/team:enterprise/user:alice", "observed_actor": {"id":"user:alice", "type":"user"}, "subject": {"id":"user:alice", "type":"user"}, "modality": "conversation", "content": { "kind": "message", "role": "user", "text": "Just got off a call with Priya..." }, "context": { "observed_at": "2026-05-08T13:14:00Z", "intent": "deal_status_update", "labels": ["acme", "sales", "q3-launch"] }, "directives": { "extract": ["facts", "entities", "beliefs"] }, "idempotency_key": "alice-chat-2026-05-08-001" }
Collapsing them is the most common API design mistake in this space. CortexDB keeps them explicit.
Derived from the token's sub claim. Used for policy, audit, and rate-limit attribution.
agent:support_bot
May differ from caller — delegated agents, import jobs, admin writes all break the moment you collapse this.
user:alice
Often the same as observed_actor — but when Alice takes notes about Priya, subject becomes Priya.
user:alice
agent:ingester, observed_actor = user:alice, subject = user:aliceuser:admin_bob, observed_actor = user:admin_bob, subject = user:aliceservice:importer_v1, observed_actor preserved from source, subject preserved from sourceWatched live over the lifecycle SSE stream. None of this existed before.
1 event
evt_01HX_msg_001
Raw message, immutable, in the WAL
1 opened
ep_01HX_acme_deal
"Acme Q3 deal pursuit" — chain begins
3 extracted
(acme, primary_contact, priya)
(acme, deal_stage, poc_complete)
(acme, procurement_blocker, true)
1 opened
will_close_q3 = uncertain @ 0.42
Mixed evidence — POC ✓, procurement ✗
1 seeded
B2B SaaS Sales Cycle
Partial — needs more episodes to firm up
event: captured → evt_01HX_msg_001 · wal_offset 134892 event: extracted → entities:[acme,priya] facts:[a,b,c] beliefs:[01HX_a] event: indexed → layers_indexed:[events,facts,beliefs] event: consolidated → beliefs_updated:1 episodes_touched:[ep_01HX_acme_deal]
POST /v1/recall { "scope": "org:initech/.../user:alice", "view": "holistic", "query": "What's the current status of the Acme deal?", "include": ["beliefs", "facts", "episodes"], "temporal": { "natural": "last 30 days" }, "budgets": { "max_tokens": 2000, "per_layer_limits": { "facts": 8, "beliefs": 3, "episodes": 2 } }, "citation_mode": "inline_with_markers", "diagnostics": "summary" }
"context_block": "Acme Corp signed this afternoon for 200 seats [1]. The deal stage went from poc_complete to signed at 3:42pm [2]. The will_close_q3 belief revised from uncertain (0.42) to supported (0.94) as a result [3]. Primary contact remains Priya..." "layers": { "beliefs": [/* will_close_q3 @ 0.94 */], "facts": [/* deal_stage=signed, seats=200, ... */], "episodes": [/* ep_01HX_acme_deal */] } "provenance": { "trail": [/* ARIL → hybrid → score → mmr */], "citations": { "[1]": { "layer":"fact", "id": "fact_seats_200" }, "[2]": { "layer":"fact", "id": "fact_signed" }, "[3]": { "layer":"belief", "id": "belief_01HX_a" } } }
context_block goes into the LLM prompt. layers renders in the UI. provenance is what you show when someone asks "why?". The LLM cannot invent citations — it can only select from what recall returned.
The sales manager presses harder: "Why did will_close_q3 jump from 0.42 to 0.94?"
GET /v1/beliefs/why?belief_id=belief_01HX_a
Returns a full support graph — nodes for the belief, the supporting facts and episodes, the events those came from. Each edge labeled. Each weight shown. Plus a natural-language narrative on top.
narrative: "Confidence rose from 0.42 to 0.94 because two new high-weight facts landed on May 13: deal_stage=signed (weight 0.45) and seat_count=200 (weight 0.30). The pre-existing procurement_blocker fact lost weight because its blocking condition is moot post-signature. Net evidence shift: +0.52, well above the 0.05 minimum delta in the revision policy."
Every record carries two time intervals — when the claim was true in the world, and when CortexDB knew about it. That distinction is what makes time-travel queries possible.
valid_from | First moment the claim is true in the world |
valid_to | When it ceased being true (null = open) |
recorded_from | First moment CortexDB learned the claim |
recorded_to | When CortexDB superseded its own record |
The query "what did the system believe about Acme on April 15, when looked at from May 1?" needs both axes. Single-axis systems can only answer one or the other.
// Sarah, after the deal signed: // "What did we believe about Acme // at lunch on May 12, before the signature?" POST /v1/recall { "scope": "org:initech/.../user:alice", "view": "holistic", "query": "What did we know about Acme?", "include": ["beliefs", "facts"], "temporal": { "as_of": "2026-05-12T12:00:00Z" } } // returns the pre-signature state: // deal_stage = poc_complete // will_close_q3 = uncertain @ 0.42 // Same data. Different temporal lens.
Alice writes a Slack post about Acme that ends with "honestly I think Priya might leave the company soon." Her agent extracts a belief. That night she realizes she shouldn't have said it. She asks her agent to forget.
POST /v1/forget { "scope": "org:initech/.../user:alice", "layers": ["beliefs"], "selector": { "memory_ids": ["belief_01HX_b"] }, "cascade": "derived_only", "audit_note": "User retracted speculation" }
The belief is gone. The underlying event — Alice's Slack post — is not. That distinction is load-bearing.
Two weeks later, if Priya genuinely starts hinting at leaving, the new event + the retained old event might re-derive the belief. The system isn't pretending the past didn't happen — it's saying "the conclusion was premature."
| Mode | What stays | What goes |
|---|---|---|
| derived_only (default) | All events | Selected facts, beliefs, episodes, understanding |
| redact_events | Event IDs and WAL slots | Event content — replaced with [REDACTED] |
| forget.gdpr (separate endpoint) | Cross-scope refs (redacted) | True erasure where unreferenced |
Pure deletion would invalidate shared workspaces — facts colleagues rely on would lose citation anchors. Pure preservation would violate the right to erasure. Reference counting threads the needle.
Same primitives. Different questions. 3,000 humans, one accumulating substrate.
B2B SaaS. EU + US presence. Subject to GDPR. Five operators, five different relationships with the same database.
Sales rep · enterprise team. Uses maya_bot. Asks about her pipeline.
Sales VP, enterprise. Reads across her team via view=descend. Coaches on patterns.
VP Engineering. Tracks systems, not humans. Watches belief deltas.
CTO. Doesn't query. Reads exec_brief_bot's morning summary.
Audits. Approves erasures. Owns GDPR. Reads policy, not content.
In every scenario: humans don't talk to CortexDB directly. Their agents do. Every API call carries the agent's signed token; every call also declares who the experience is about.
ws:acme-account, not "hoping" the CSM can read her personal scope.view=descend aggregates her team's scopes. Sarah doesn't write into them.POST /v1/scopes is for adding members or custom policy.Every API call is evaluated through all four tiers. Each can only restrict — none can re-expand.
ws:acme-account lists exactly six humans and three agents as members.csm_bot is scoped to dept:cs/*, denied forget.gdpr.When denied, the response says which tier denied it and which capability would have allowed it.
X-Cortex-Policy: tier=scope; decision=deny;
capability=scope.read.holistic
| Operator | Primary scope | Primary view | What they ask |
|---|---|---|---|
| Maya individual |
user:maya |
view=local |
"What's my pipeline?" · "What did Priya say about procurement?" · "Why does the bot think Acme will close?" |
| Sarah manager |
team:enterprise |
view=descend |
"Which deals slipped this week?" · "Belief deltas > 0.2 across my team" · "Top concepts in Understanding this quarter (coaching)" |
| Diego VP eng |
dept:engineering |
view=descend |
"What's our top operational risk?" · "What systems do we know less about than a month ago?" (staleness) |
| Priya CTO |
org:initech |
saved recalls in briefing | "What did the company change its mind about today?" — top belief deltas, concept evolution, sealed episodes |
| Lana DPO |
/v1/audit + /v1/erasures |
audit, not content | "Run DSR preview for departing employee" · "Anomalies in policy denials this quarter" · "Validate legal holds" |
A workspace like ws:acme-account is structurally identical to user:alice. It differs only in convention and membership:
POST /v1/scopesThere is no API distinction. A scope is a scope. This single design choice is what lets multiple departments share a customer account, an incident war room, or a project workspace without inventing a separate "workspace" concept.
POST /v1/scopes { "path": "ws:initech-acme-account", "members": [ {"actor": "user:alice", "role": "owner"}, {"actor": "user:bob", "role": "writer"}, {"actor": "agent:support_bot", "role": "writer"}, {"actor": "agent:bob_bot", "role": "writer"} ], "policies": { "consolidation": "merge_compatible_beliefs", "conflict_resolution": "latest_wins_within_confidence_band", "inherit_from": [], "audit": "full" } }
When Alice's agent and Bob's agent both submit beliefs about Acme into this workspace, the workspace's conflict_resolution policy — not the agents — decides how to merge. Each agent's submissions need not agree; the workspace presents a coherent view.
When an incident fires, the next four slides walk one war room through CortexDB at every API call.
Without CortexDB: dump Slack logs into Confluence, write a postmortem nobody re-reads, repeat. With CortexDB: the postmortem is a first-class memory that the next incident retrieves automatically.
POST /v1/scopes { "path": "ws:incident-2027-01-15-payments", "members": [ {"actor": "user:diego", "role": "owner"}, {"actor": "user:on_call_alice", "role": "writer"}, {"actor": "agent:oncall_bot", "role": "writer"}, {"actor": "agent:rca_copilot", "role": "writer"} ], "policies": { "inherit_from": ["dept:engineering/team:sre"], "audit": "full" } }
inherit_from is doing real work — it tells CortexDB that recalls against this fresh war room can also pull from the SRE team's accumulated knowledge. The room doesn't start from zero.
It's March. A different team, a different service. notifications-api starts misbehaving. The on-call engineer is a new hire — three weeks in, has never seen the payments incident.
RCA-Copilot fires. Its very first recall against the new war-room workspace pulls in the payment_retry_storm concept. The concept's supported_by array now includes the January postmortem.
RCA-Copilot: "This may relate to the payment_retry_storm pattern. The org has seen three prior instances; the working hypothesis is that exponential backoff with jitter prevents it. Check the retry configuration of notifications-api first."
The new engineer skips ten minutes of confused debugging and goes straight to the retry config.
Not "we store memories." Not "we have a vector database." It's:
Every postmortem is queryable, citable, and reachable by every future incident — automatically, with provenance, with confidence intervals, with cross-incident concept synthesis.
No incumbent tool ships this. Confluence has none of it. Mem0 has facts but no concepts. Zep has temporal facts but no Understanding layer.
| ~100 metric pings (bulk) | trivial |
| 300 war-room messages | ~$3 in LLM extraction |
| 27 recalls + 6 answers | ~$0.05 |
| 1 structured postmortem | ~$0.10 |
| Total per incident | ~$3.50 |
15 minutes saved on the next related incident = several orders of magnitude ROI.
| Application | Workspace | Writer agents | The "after" story |
|---|---|---|---|
| Customer 360 | ws:customer-{id} |
csm, sales, support | Every team that touches a customer sees one accumulating record. New CSM onboarding to an account: hours not weeks. |
| Roadmap memory | ws:roadmap-{year} |
PM bots, design bots | "Why did we deprioritize feature X in Q1?" — walk the belief trail to the user-research events that revised it. |
| Hiring decisions | ws:hire-{req_id} |
recruiter, panelist bots | Every signal is an event. Hire/no-hire is a belief with cited supports. Post-hire, the belief updates with 90-day outcome data — closing the calibration loop. |
| Vendor risk register | ws:vendor-{name} |
security, procurement | Every questionnaire, audit, breach notice is an event. "Vendor X is acceptable risk" is a continuously-revised belief. SOC2 becomes a query, not a fire drill. |
| Sales objection library | dept:sales/concept-store |
all rep bots write up | Understanding layer surfaces objection patterns no individual rep sees alone. The coaching content writes itself. |
| "Ask the company" search | org:initech + descend |
company_search_bot |
"Has anyone here worked with vendor Y?" — recall across the whole org, filtered by what the asker is allowed to see. The intranet finally becomes useful. |
The pattern: 1. pick a workspace scope and members → 2. wire writer agents → 3. build the UI around recall + answer + citations → 4. let Understanding accumulate. Institutional memory compounds over months.
Week 0–1
org + top departmentsWeeks 2–6
/v1/experienceWeeks 6–12
Months 4–12+
Trying to design the perfect scope tree before any team has actually used the system. Start with three teams and one workspace; let the tree grow organically; refactor once at month 3. Scope renames are safe — the WAL replays cleanly under a renamed scope.
Today: written, filed, forgotten. Read by maybe three people. Lost in Confluence within six months.
With CortexDB: the postmortem is a database mutation that the next incident surfaces automatically. Writing a good one is finally worth the engineer's time. Quality climbs within two quarters.
Today: confidence shifts surface via a Slack message or board-prep doc — informal, undated, uncited.
With CortexDB: q4_revenue_target_met moving from 0.71 → 0.58 with full citation back to three specific deal events. The leading indicator is machine-readable. Forecasting accuracy climbs.
Today: GDPR deletion is a manual scramble. A 30-day project.
With CortexDB: a documented /v1/erasures job with preview, manifest, legal sign-off, permanent audit row. A 30-minute task. Compliance load drops; willingness to grant genuine erasure rights goes up.
pip install cortexdbai · npm install cortexdbaicortexdb-mcp on PyPI — any MCP-capable agent gets memory tools without writing codedocker run -p 3141:3141 cortexdb/cortexdb — single-node, zero external depssubject explicitly. The default (subject = observed_actor) is usually wrong for ingestion and admin writes. Future you will thank you./v1/beliefs/why is the killer feature; if your UI doesn't render the support graph, users won't trust the system.Three identities per call. Two time axes per record. One rule above all: every claim has a trail. Get those right and you can build everything in this deck.
The hard part isn't the API — the API is small enough to teach in a day. The hard part is the cultural one: convincing a company that its institutional memory deserves the same care it gives its accounting ledger.