# Memory model

Understand durable facts, decisions, handoffs, and source attribution before choosing an integration.

- Canonical: https://docs.xmemo.dev/docs/concepts/memory-model
- Locale: en-US
- Content-Locale: en-US
- Canonical-Content-Digest: 9ffe2da573b664ce4e37254715ed959c138dfd6b89262c6d0a1bda8dd473291a
- Edition-Digest: 2e73a139c157f57b8985b7750b9855c4bd63a4c238f2d6319b47a297b2313a10
- Source-Revision: sha256:310bf66a9ffcf2384ebc6400fad1b1da9d01fa0cdadc9d129c9084e880334e73

## What XMemo stores

XMemo keeps durable context that stays useful after the current chat or task ends: project facts, decisions, preferences, corrections and handoff notes. Transient conversation noise, one-off answers and raw tool output do not belong in memory.

- semantic — durable facts and decisions that stay true across sessions.
- episodic — something that happened, tied to a moment in a task or session.
- procedural — how a task is performed in this project.
- working — active state for the task currently in progress.
- identity — stable information about the owner or the agent itself.

## Write a durable memory

A durable write needs the content, a logical path that attaches it to a project or namespace, and the memory type. The path is what later recalls filter on.

```ts
remember({
  content: "Use OAuth for hosted ChatGPT connections.",
  path: "projects/memory-os/decisions"
})
```

## Memory types in the SDK

MemoryCandidate.memory_type accepts the same set through the TypeScript SDK, so a normalized agent event carries the type it should be stored under.

```ts
import { normalizeAgentEvent, toMemoryCandidate } from '@xmemo/client';

const event = normalizeAgentEvent(
  { type: 'command_completed', command: 'pytest', exit_code: 0, output: '12 passed' },
  { source: 'shell', defaultAgentId: 'codex' },
);

console.log(toMemoryCandidate(event).memory_type); // episodic
```

## Interactive Provenance and Lifecycle Walkthrough (Synthetic Demo)

A step-by-step verifiable lifecycle demonstration showing memory creation, cross-client retrieval, realtime user correction with version supersession (v1 -> v2), token budget protection, soft-deletion tombstoning, and isolated synthetic teardown. Every step is backed by disposable runtime evidence with zero exposure of real user memories:

- Step 1 [STATE_1_CREATED_ACTIVE_V1]: Agent A (Claude Desktop) writes initial preference with immutable author, instance hash, and device metadata via tools.py::remember — Receipt: Status 200 OK, demo_mem_lifecycle_001@v1, active — Status: [SOURCE_BACKED_PUBLIC_CONTRACT (VERIFIED)] — Boundary: [DEMO_DATA: SYNTHETIC].
- Step 2 [STATE_2_ACCESSED_ATTRIBUTED]: Agent B (Codex CLI) in the same authorized scope immediately retrieves the memory with citation receipt and zero cross-client drift via tools.py::recall — Receipt: Status 200 OK, cited demo_mem_lifecycle_001@v1 — Status: [SOURCE_BACKED_PUBLIC_CONTRACT (VERIFIED)] — Boundary: [DEMO_DATA: SYNTHETIC].
- Step 3 [STATE_3_CORRECTED_SUPERSEDED_V2]: User corrects the meeting room and time via tools.py::update_memory. VersionController creates an immutable snapshot of v1 with status='superseded' and bumps active record to v2 — Receipt: Status 200 OK, v2, parent v1, diff: Room Orion -> Room Polaris — Status: [SOURCE_BACKED_PUBLIC_CONTRACT (VERIFIED)] — Boundary: [DEMO_DATA: SYNTHETIC].
- Step 4 [STATE_4_RETRIEVAL_FILTERED]: Subsequent recall query selects only active v2 while obsolete v1 is strictly filtered out of LLM context window to prevent hallucinations and conserve token budget — Receipt: Status 200 OK, selected v2, superseded v1 excluded — Status: [SOURCE_BACKED_PUBLIC_CONTRACT (VERIFIED)] — Boundary: [DEMO_DATA: SYNTHETIC].
- Step 5 [STATE_5_TOMBSTONE_DELETED]: Owner marks fact as deleted via tools.py::forget. It is immediately excluded from recall candidate queries and moved to Trash view with Restore action — Receipt: Status 200 OK, status: deleted, candidate_count: 0 — Status: [SOURCE_BACKED_PUBLIC_CONTRACT (VERIFIED)] — Boundary: [DEMO_DATA: SYNTHETIC].
- Step 6 [STATE_6_RESET_PURGED]: Isolated disposable teardown (reset_synthetic_state) purges demo scope records to exactly 0 residual rows on disk. Personal account hard-reset (POST /api/v1/me/memories/reset) is strictly excluded — Receipt: teardown_status: SUCCESS_PURGED, residual_rows: 0, account_hard_reset_called: FALSE — Status: [SOURCE_BACKED_PUBLIC_CONTRACT (VERIFIED)] — Boundary: [DEMO_DATA: SYNTHETIC].

```text
+------------------------------------------------------------------------------------------------------------------------+
| [PROVENANCE & LIFECYCLE 6-STATE STATE MACHINE: DISPOSABLE HARNESS WALKTHROUGH]                                        |
|                                                                                                                        |
|  Agent A (Claude Desktop)    XMemo FastMCP & Engine           Agent B (Codex CLI)          Demo Owner (Supervising)    |
|  [04f9b8c2 / MacBook]        [VersionController / Scope]      [e81d7a31 / Workstation]     [user:demo_owner]           |
|         |                               |                              |                              |                |
|  (1) remember(sync in Orion)            |                              |                              |                |
|  -------------------------------------> |                              |                              |                |
|         |                          [STATE 1: Created Active v1]        |                              |                |
|  <------------------------------------- |                              |                              |                |
|    Receipt: mem-001@v1                  |                              |                              |                |
|         |                               |      (2) recall(sync)        |                              |                |
|         |                               | <--------------------------- |                              |                |
|         |                               |  [STATE 2: Cited @v1]        |                              |                |
|         |                               | ---------------------------> |                              |                |
|         |                               |   Citation: mem-001@v1       |                              |                |
|         |                               |                              |   (3) update_memory(Polaris) |                |
|         |                               | <---------------------------------------------------------- |                |
|         |                               |                          [STATE 3: Bump v2, Supersede v1]   |                |
|         |                               | ----------------------------------------------------------> |                |
|         |                               |                          Receipt: mem-001@v2 (parent: v1)   |                |
|         |                               |                              |                              |                |
|         |                               |      (4) recall(Polaris)     |                              |                |
|         |                               | <--------------------------- |                              |                |
|         |                               |  [STATE 4: Select v2,        |                              |                |
|         |                               |   Filter superseded v1]      |                              |                |
|         |                               | ---------------------------> |                              |                |
|         |                               |   Citation: mem-001@v2 only  |                              |                |
|         |                               |                              |   (5) forget(mem-001)        |                |
|         |                               | <---------------------------------------------------------- |                |
|         |                               |                          [STATE 5: Tombstone / Trash View]  |                |
|         |                               | ----------------------------------------------------------> |                |
|         |                               |                          Receipt: status=deleted            |                |
|         |                               |                              |                              |                |
|         |                               |   (6) reset_synthetic_state()                               |                |
|         |                               | <---------------------------------------------------------- |                |
|         |                               | [STATE 6: Teardown Purge]                                   |                |
|         |                               | Scope purged: 0 residual rows (account reset excluded)      |                |
|         |                               | ----------------------------------------------------------> |                |
|         |                               | Teardown Status: SUCCESS_PURGED                             |                |
+------------------------------------------------------------------------------------------------------------------------+
```

## ChatGPT user

Give ChatGPT durable access to your XMemo preferences, project facts, decisions, and TODOs without pasting bearer tokens into a chat.

Connect the hosted XMemo MCP server through the ChatGPT/OpenAI app OAuth flow, then approve the memory:read and memory:write grant for your XMemo account.

Save a synthetic preference or project note, start a new chat, then ask ChatGPT to recall it through XMemo before continuing work.

If OAuth fails or tools do not appear, sign out of the MCP server in the host app, reconnect the XMemo server URL, and retry before creating direct tokens.

## Copilot / Codex developer

Carry repo decisions, coding conventions, bug-fix notes, and task history between IDE and CLI agents.

Use OAuth for VS Code / GitHub Copilot and Gemini CLI when available. For Copilot CLI, Codex, Cursor, or other direct MCP clients, keep XMEMO_KEY in the local environment or secret store and set a stable XMEMO_AGENT_INSTANCE_ID.

Record a codebase decision or bug fix, then ask the next IDE or CLI agent to recall the relevant XMemo context before editing.

If recalls are empty, verify the selected MCP config path, the XMEMO_KEY environment variable for direct clients, and any stale OAuth credential in the host app.

## Team / enterprise pilot owner

Evaluate shared memory with account controls, source attribution, export/delete workflows, and reviewer-safe setup evidence.

Create or enter the protected XMemo workspace, invite approved users, then connect each client through OAuth or a scoped direct credential according to the readiness badges.

Have a pilot member save a synthetic team memory, confirm source attribution in XMemo, then review delete/export and support paths.

If a member cannot connect, check role permissions, OAuth approval, client readiness status, and support guidance before issuing a new token.

## Autonomous agent operator

Let headless or scheduled agents record progress, retrieve prior decisions, and keep a stable non-secret instance identity.

Fetch /api/v1/mcp/config/autonomous-agent. Prefer auth_modes.oauth when the runner supports OAuth + custom headers; use auth_modes.xmemo_key with XMEMO_KEY from a secret store only for fully headless runners.

Run one synthetic task that writes progress to XMemo, restart the runner, and confirm it recalls that progress using the same XMEMO_AGENT_INSTANCE_ID.

If attribution changes or recalls split across instances, persist XMEMO_AGENT_INSTANCE_ID outside git and verify the runner is not regenerating it on every start.
