Migrating a large amount of data? Chat with us and we’ll help you plan it.
What is COGX?
COGX (the Cognee eXchange format) is a common shape that all memory imports are translated into before they enter Cognee. Instead of writing one importer for every memory tool, Cognee defines a single intermediate format and a single loader:cognee.export() writes, so the same
format powers backup, restore, and Cognee-to-Cognee migration. For a full
breakdown of the format and its record kinds, see
COGX Exchange Format.
You never construct COGX records by hand. You hand a source object to
cognee.remember() and it does the rest:
Quickstart: import from Mem0
The import itself is a single call — construct aMem0Source from your export
and hand it to cognee.remember():
Mem0Source, pass it to
cognee.remember(), then query with cognee.recall(). Your Mem0 memories are
now a queryable Cognee knowledge graph.
Simple runnable example
Simple runnable example
This script uses a small inline sample in the exact shape Mem0 returns, so
you can run it without a Mem0 account. Swap in real data using the patterns at
the bottom of this page.
Requires
LLM_API_KEY to be set (in .env or your environment) — both the
import and recall() use the LLM.migrate_from_mem0.py
examples/tutorials/migrate_from_mem0_tutorial.py.
It imports a bundled sample export of four mem0 memories
(examples/tutorials/data/mem0_export.json)
in preserve mode — calling cognee.cognify() right after, since a preserve
import alone isn’t recall-queryable (see Import modes below) —
and verifies the result with two recall() queries, then clears everything,
re-imports the same export in re-derive mode, and queries again so you can
compare the two modes side by side. It finishes with forget(everything=True)
so re-runs start clean. Run it with:
Import modes
Every source accepts amode argument that controls how much work Cognee does
on import. Pick it based on whether your source already has an extracted graph
and how much you want to spend on LLM calls.
re-derive mode for Mem0 imports when you want Cognee to build a knowledge
graph from those memories. preserve is also valid for Mem0: each memory is
stored as a raw data item with zero LLM calls — the cheapest way to get the
records in, ready for a later cognify() run.
That makes preserve a two-call pattern whenever you want to query the
imported memories: remember() lands the raw records, and a separate
cognify() builds the graph recall() reads from.
recall() returns nothing for the imported memories. With
re-derive or hybrid the extraction is part of the import, so no extra
cognify() call is needed. The
runnable tutorial
imports the same export both ways so you can compare.
Other sources you can import from
Every source has the same interface — construct it from a file path (or in-memory data) and pass it tocognee.remember().
LangMem (JSON memory exports)
LangMem (JSON memory exports)
LangMemSource reads a LangMem memory export and imports each item as an
atomic memory record. It accepts a file path, an already-parsed list, or a
dict wrapping the list under memories, results, items, or data — any
other shape raises ValueError.Those aliases are scanned in that order, and only dict items count as records.
An alias that is present but empty does not shadow a populated one later in the
order, so {"memories": [], "results": [...]} imports the results records.
A wrapper whose recognized aliases are all empty imports zero records without
raising.Per memory:- content is the first string found among
content,text,memory,data, andmessage; items with none of those are skipped - scope takes
user_id(falling back tonamespace), plusagent_id,session_id, andrun_idwhen present - categories accepts either a single string or a list
- timestamps are read from
created_at/createdAt/timestampandupdated_at/updatedAt - any
metadatais carried over nested underlangmem_metadata
re-derive mode.Letta / MemGPT (.af agent files)
Letta / MemGPT (.af agent files)
LettaSource reads a Letta Agent File (.af, a JSON serialization of one
or more agents) and imports:- core memory blocks → memory blocks in the graph
- message history → one conversation episode per agent
- archival memory → one document per passage
- text is read from
content, falling back to thetextalias whencontentis missing or explicitlynull— Letta serializers that write unset fields asnullrather than omitting them import correctly. An explicitly emptycontent("") counts as a message with no text and does not fall through totext - either key may hold a plain string or a list of typed parts, of which only the text parts are imported
- messages that end up with no text, and messages whose role is
systemortool, are skipped; if that leaves an agent with no messages, no conversation episode is emitted for it
Zep / Graphiti (graph exports)
Zep / Graphiti (graph exports)
ZepSource reads a JSON export of a Zep or Graphiti knowledge graph and
imports:- episodes (verbatim ingested content)
- entity nodes
- relation edges (“facts”), including their bi-temporal
valid_at/invalid_atvalidity windows
session_id the same way: from
group_id, falling back to a session_id key when group_id is absent. When
a record carries both, group_id wins.It defaults to hybrid mode because Zep/Graphiti keep both verbatim episodes
and a derived graph.Another Cognee instance (COGX archive)
Another Cognee instance (COGX archive)
COGXArchiveSource re-imports an archive produced by cognee.export(..., format="cogx"). This is the restore half of backup/restore and the receiving
end of Cognee-to-Cognee migration. It defaults to preserve mode (zero-LLM),
because a Cognee archive already carries a fully extracted graph.Export: Cognee → COGX
Migration runs both ways.cognee.export() writes a dataset’s graph to a
portable COGX archive that you can back up, move to another Cognee instance, or
re-import later with COGXArchiveSource:
Using real data
The Mem0 example above uses an inline sample. Here’s how to point any source at real data. From a provider’s client (live API). Fetch with the provider’s own SDK and pass the response straight in — sources accept already-parsed Python lists and dicts, not just file paths:Mem0Source scans a wrapper dict for results, memories, then items, in
that order, counting only dict items as records; an alias that is present but
empty does not shadow a populated one later in the order, so
{"results": [], "memories": [...]} imports the memories records. A wrapper
whose recognized aliases are all empty imports zero records without raising,
and any other shape raises ValueError.
From an exported file. Point the source at the export on disk:
Next steps
remember()
How import and ingestion work under the hood
recall()
Query your migrated memory
COGX Exchange Format
The portable format behind every import and export
Configuration
Configure LLM, embedding, and storage backends