# xmemory vs Letta

> Letta is an agent runtime whose memory is a git-backed filesystem of Markdown the agent edits itself, consolidated by background "dreaming" subagents. xmemory is a memory engine with a schema the instance owns, so facts are records resolved on write and queried as state, from any runtime.

Canonical page: https://xmemory.ai/compare/letta/

Letta descends from MemGPT, the paper that framed an LLM as an operating system paging memory in
and out of a fixed context window. The product today is an agent runtime: conversations, tools,
hosted computers, skills, and a memory model where the agent keeps what it knows in Markdown files
inside a git repository and edits them with ordinary file tools. xmemory is not a runtime. It is a
memory engine a runtime calls, so the honest frame is agent-directed file editing versus
schema-directed record mutation, and a Letta agent can use both. The file-memory half of that is
what the [Why page](https://xmemory.ai/why/#why-not-markdown) argues against; this page is the comparison in full.

Documentation reviewed 23 October 2026: Letta
[MemFS](https://docs.letta.com/concepts/memfs), [memory and dreaming](https://docs.letta.com/configuration/memory),
[memory in the Agent SDK](https://docs.letta.com/agent-sdk/memory),
[shared memory](https://docs.letta.com/concepts/shared-memory) and the
[MemGPT paper](https://arxiv.org/abs/2310.08560); on our side [How xmemory works](https://xmemory.ai/integration-overview/),
[XMD](https://xmemory.ai/xmd/) and the [API](https://xmemory.ai/api/).

## What Letta does

Each Letta agent owns a git repository, which MemFS projects onto wherever the agent runs. Every
memory is a Markdown file with `name` and `description` frontmatter; files at the root (or under
`system/` for older agents) are loaded into the system prompt every turn, and directories with
their own `MEMORY.md` index stay out of context until the agent follows a signpost into them.
Edits become memory when committed and pushed, so there is a history, and cloud agents can share a
repository. Skills live in the same tree and travel with the agent.

Consolidation is done by *dreaming*: background subagents that review recent conversations and
update memory, triggered after a number of steps or on context compaction, optionally with a
second subagent reviewing proposals first. `/init`, `/doctor` and `/remember` give the user ways
to bootstrap, audit and teach. There is no semantic index by default; a search mod adds keyword search, with semantic and hybrid
modes when an index is configured, and conversation history is searched separately.

For a single agent working on a codebase or with one person, this is a pleasant system. The
memory is readable, diffable and portable, and the agent is good at files.

## Where xmemory is stronger

**Structure is a contract, not a habit.** In Letta the structure of memory is whatever the agent
decided to write, under the headings and files it chose; `/doctor` exists because that drifts. An [XMD schema](https://xmemory.ai/xmd/) fixes the structure outside the agent: these objects,
these fields, these allowed values, this key. The agent still writes in plain language, but what
lands is a record the next agent, the next model version and your own code can rely on. That is
the difference between a convention and a specification, and it is the whole thesis of
[Schema as the Core of Reliability](https://xmemory.ai/schema-as-the-core-of-reliability/).

**Updates resolve by key, not by editing prose.** A Letta agent updates memory immediately when it
learns something, by finding the right sentence in the right file and editing it; dreaming adds
consolidation on top. Whether the edit lands in the right place, and whether another file repeats
the old fact, depends on the agent's judgement each time. In xmemory "the customer moved to Pro" is
extracted, matched to the customer's record by key, applied, and kept as lineage, inside the write.
The rule for where a fact lives is in the schema, not in the agent's reading of the tree.

**Reads are a typed query contract, not an agent task.** MemFS leaves exhaustive filtering, joins
and aggregation to the agent or application: it can follow the index, search files, or write code
to scan them, and the answer is as complete as that work was. xmemory provides those operations
over schema-defined records through its read interface, and can hand back the rows. "How many",
"which ones", "since when" and "what is still missing" are the questions a file tree has no
primitive for, and the ones operational memory exists for.

**Context cost is a schema decision, not a filing decision.** Letta keeps root files in the
prompt every turn and relies on the agent's filing discipline to keep that small. In xmemory
stored records need not be included on every turn; they are retrieved on demand, and a read
returns the slice of state the question needs. Toloka's
[independent evaluation](https://xmemory.ai/toloka-agent-memory-evaluation/) measured that effect against document
search rather than against Letta, and found xmemory's compact answers cut the model bill by 26%.

**Access control reaches the field.** Letta has organisation roles, agent and conversation
visibility and tool permissions, and shared memory is a repository several cloud agents commit to,
with git history recording who changed what. Those documented controls do not establish
field-level permissions within memory records. xmemory scopes by field: which agents may read or write which values, with lineage on every one. Once memory is
shared across agents, teams or customers, that granularity is what lets one store serve all of
them.

**On evidence.** Letta publishes a [leaderboard](https://leaderboard.letta.com) of model
performance inside its runtime, and the MemGPT paper evaluated document analysis and multi-session
chat; we have not run Letta on our benchmarks and will not quote numbers we do not have. What we
can point to is adjacent: in the [white paper](https://arxiv.org/abs/2604.27906), code-generated
Markdown memory harnesses reached 12% and 40% on the Splitwise task against xmemory's 95.2%. Those
harnesses were not Letta. These results motivate testing file-based memory on stateful workloads;
they do not establish Letta's performance.

## Choosing

Choose Letta when you want a complete agent runtime and memory that agents and people read as
files: readable, diffable, shared through a repository, reviewed in a diff. Choose xmemory for the
part of memory that has to behave as state: written by several agents, read by code, filtered and
counted, and correct by construction rather than by review. The two fit together: xmemory exposes
MCP, and a Letta agent that keeps its persona in a file can keep its facts in a schema.

## Letta's memory files as an XMD schema

Letta's bootstrap memory is a persona file, a file about the human, and durable project facts and
workflow rules. Here is the human and project half as a schema for one project, which is what you
would put beside a runtime like Letta's rather than inside its repository.

```yaml
xmd_version: v1
title: Working memory
description: What the agent knows about the person it works with and the project, as current facts.
objects:
  Person:
    description: The person the agent works with. One record per person.
    fields:
      name: { type: str, required: true }
      role: { type: str, required: false }
      timezone: { type: str, required: false, description: "IANA name such as Europe/London." }
    primary_key: [name]
  Preference:
    description: >-
      One stated working preference of a person, on one topic. A new statement on the
      same topic replaces the previous value.
    fields:
      person_name: { type: str, required: true }
      topic:
        type: str
        required: true
        enum: [reply_length, commit_style, review_depth, tone, working_hours]
        description: >-
          The aspect the preference is about. Map wording to the closest label, so
          "keep answers short" and "shorter responses" both go to reply_length.
          Extract only preferences that fit one of these categories. Skip unrelated
          preferences rather than forcing a match.
      value: { type: str, required: true, description: "The preference as stated, in a short phrase." }
    primary_key: [person_name, topic]
  WorkflowRule:
    description: >-
      A durable rule about how work on this project is done, such as a branch policy
      or a release checklist step. This instance covers one project. A restated rule
      updates the existing record and leaves status unchanged; a statement that the
      rule no longer applies sets status to retired; only an explicit statement that
      it applies again sets it back to active.
    fields:
      name: { type: str, required: true, description: "A stable short identifier for the rule." }
      rule: { type: str, required: true }
      status: { type: str, required: true, enum: [active, retired], default: active }
    primary_key: [name]
relations:
  prefers:
    description: Connect a Preference to the Person who holds it.
    objects:
      preference: { type: Preference, on_delete: cascade }
      person: { type: Person, on_delete: cascade }
    keys:
      one_person_per_preference: [preference]
```

`human.md` becomes a `Person` plus keyed `Preference` records, with `topic` bounded so that "keep
replies short" and "shorter responses" land on the same `(Alex, reply_length)` record instead of
two. A project rule that gets restated updates by name; one that is dropped is set to `retired`,
and the old text stays in lineage; the description says what reactivates it. The persona can
remain in the prompt as a file.

## Why we think this matters, and for whom

xmemory works well for short-running agents, and it is at its best for repeated tasks, where each run adds to a body of knowledge the next run can use. Long-horizon agents deserve a special mention, because there is very little objective evidence yet about what memory design works for them. Our working belief, and the reason xmemory exists: an agent running a long, multi-step task does better on structured state than on accumulated context. A schema gives it an explicit feedback loop at write time (what was accepted, what was rejected, what changed), so memory is updated rather than bloated and the trajectory stays on course: fewer re-reads, faster steps, more reliable outcomes.

If that is your workload, try xmemory on it. We are building objective measurements for this claim. The [Toloka evaluation](https://xmemory.ai/toloka-agent-memory-evaluation/) is our first independent measurement of the benefits of structured memory; evaluating changing working state over long-horizon tasks is next, and we would welcome collaborators on it. Write to [info@xmemory.ai](mailto:info@xmemory.ai).
