Inside one agent, memory can sound like a narrow task: save what the user said and search it next time. A deployed product makes the job much larger. Content arrives from chats, files, web pages, drives, code repositories, and SaaS connectors. Processing may be queued. Results need user, project, or tenant scoping. Deletion has to be operational. Cognee and Supermemory are useful because they make those platform duties visible.

Scenario: a team knowledge assistant needs long-term memory

Inputs are no longer only chat:
  meeting notes, design docs, web pages, Google Drive, GitHub issues, support history

Callers are no longer only one agent:
  chat agent, search page, ticket assistant, coding assistant, background sync worker

The platform must answer:
  Who owns this content?
  Which processing stage is it in?
  Should retrieval return a profile, evidence snippets, or graph relations?
  When the user withdraws data, what exactly must be deleted?

That is why Cognee and Supermemory should not be read as merely bigger RAG systems. They provide a shared memory service: how data enters, how it is processed, how each query stays within the right user or project, and how several callers can reuse the same knowledge safely.

Questions this article answers. After this chapter, you should be able to explain why Cognee's simple remember() call still expands into add(), cognify(), and optional improve(); why Supermemory's add, profile, search, and connectors read more like a product context API; and when a system needs a knowledge layer versus a packaged context platform.

A single document makes the contrast easier: a “customer escalation policy.” In Cognee, the question is how that document becomes reusable knowledge. In Supermemory, the question is how a product gets profile, search, and connector context through an API. The lifecycle table below lines up the two routes before the chapter studies them separately.

Stage Cognee route Supermemory route
Write entry add / remember accepts files, text, or URLs. add creates a memory object with content, URL, metadata, and containerTag.
Processing state cognify turns a dataset into a graph / vector retrieval layer. The API exposes queued, processing, and done states while the hosted pipeline extracts and indexes.
Retrieval output search reads like a query against the processed knowledge layer. profile returns a stable profile; search returns query evidence.
Deletion scope Deleting a dataset must account for source material and derived graphs or vector indexes. Removing a product object or connector must clear data under the relevant containerTag.

Source scope. This chapter uses the public topoteretes/cognee and supermemoryai/supermemory repositories, READMEs, docs, and visible source, pinned respectively to c0d18c8 and 2415a5c. Cognee's local SDK path can be traced directly. For Supermemory's hosted service, the discussion stays with public docs, SDK examples, and API schemas rather than inferring private extraction internals.

1. Why the last chapter covers a shared memory service

1.1 The earlier layers reappear when many callers share memory

Cognee and Supermemory are easier to read after the lower layers are clear. Otherwise both can be mistaken for larger RAG products. In this series order, they answer the next question: after write policies, state ownership, temporal graphs, execution paths, and context offload are known, what happens when memory becomes a shared service?

At platform scale, memory is no longer a capability of one agent. A product may ingest chats, documents, webpages, email, code repositories, and third-party apps. The same object may belong to a user, team, project, dataset, or tenant. A query may need a user profile, similar snippets, related files, graph relations, and permission-filtered evidence. Cognee and Supermemory therefore ask how long-term memory becomes infrastructure that several users, data sources, and callers can rely on.

1.2 User isolation, processing status, and deletion all matter

A memory platform has at least four public duties. Scope: user, project, dataset, and tenant boundaries. Process: extraction, chunking, embedding, graphing, indexing, or profile generation. Retrieve: returning graph context, user profiles, related documents, or model-ready context instead of only text chunks. Delete: giving callers a boundary they can remove when content, projects, or users are withdrawn.

Those duties map directly to common failures. If scope is unclear, one user's material can leak into another user's context. If process state is unclear, callers cannot tell whether content is queued, extracted, chunked, embedded, or indexed. If retrieval contracts are unclear, profile facts, evidence, and document snippets blur into one list. If deletion boundaries are unclear, disconnected connectors can keep influencing the model. The platform value is moving those responsibilities out of ad hoc application prompts.

Cognee turns source material into a searchable knowledge layer through cognify; Supermemory memory can build profiles while superrag supports retrieval only.
The figure focuses on two processing routes: Cognee turns ordinary material into searchable knowledge; Supermemory memory can build profiles and support retrieval, while superrag supports retrieval without updating profiles.

2. Cognee: turn data into a reusable knowledge layer

Cognee presents itself as an open-source AI memory platform: ingest data in any format, build a self-hosted knowledge graph, and let agents recall and act with context. Its README also emphasizes domain entities, relationships, and custom ontologies. That positions Cognee as more than a vector index wrapper; it is trying to turn raw material into a connected intermediate layer. See the README overview.

2.1 The user API is simple; the processing pipeline is not

The user-facing API offers four common verbs: remember, recall, forget, and improve. remember() can store permanently in the knowledge graph, or store in a fast session memory when a session_id is supplied. recall() then routes a natural language query. The public shape is intentionally light; the pipeline under it is where the work happens.

The source makes that layering explicit. The remember() docstring splits ordinary text and document inputs into permanent memory and session memory. Permanent memory runs add() plus cognify(); session memory stores in a session cache and, by default, bridges into the permanent graph through self-improvement. The permanent path's internal _run() calls add(...), then cognify(...), then optionally improve(...).

async def remember(data, dataset_name="main_dataset", session_id=None, self_improvement=True):
    if session_id:
        # session memory: fast cache, then optional bridge into permanent graph
        ...

    async def _run():
        await add(data=data, dataset_name=dataset_name, ...)
        cognify_result = await cognify(datasets=[dataset_name], ...)

        if self_improvement:
            await improve(dataset=dataset_name, user=user)

This makes the public API easier to reason about. remember() is the facade. add() owns ingestion, cognify() turns material into graph and vector-searchable structure, and improve() enriches it later. The caller sees one verb; the platform keeps explicit stages.

User action Platform responsibility Why it matters
remember(data) add ingests raw data, cognify builds the graph, and improve enriches it. The caller asks Cognee to remember; Cognee owns the multi-stage processing path.
remember(data, session_id) Session cache first, then optional bridge into the permanent graph. The current session stays fast while long-term knowledge can catch up.
recall(query) Route across session, graph, and graph-context sources depending on scope and query type. The same query may need fresh session context or durable graph knowledge.

The point at which “remember” returns depends on the calling mode. Default permanent writes await add, cognify, and enabled improve work. With run_in_background=True, the first await returns a running RememberResult. A second await result waits for the task. Background processing errors are stored in status/error rather than re-raised as they are on the default blocking path. done therefore means finished, not successful; inspect status too. This example disables improve to isolate graph construction:

result = await cognee.remember(
    "Customer escalation policy...",
    dataset_name="company_docs",
    run_in_background=True,
    self_improvement=False,
)
await result
if result.status != "completed":
    raise RuntimeError(result.error or f"Pipeline status: {result.status}")

The background path retains an in-process asyncio task so garbage collection does not abandon it; that is not a durable queue that survives a process restart. The session path differs again: session_stored only says the session-write step returned, while background improve failures are logged. It cannot establish that the permanent graph has synchronized. Verify session readability, graph completion, and subsequent improvement separately.

2.2 add and cognify turn source material into a knowledge graph

add() accepts strings, files, URLs, binary streams, and datasets. Its documented workflow resolves data, extracts content, stores it in a dataset, tracks metadata, and assigns permissions. Cognee therefore begins before retrieval: it first makes ingestion a platform concern.

cognify() is the transformation step. Its docstring describes document classification, text chunking, entity extraction, relationship detection, graph construction, and content summarization. The point is not that a graph is always better than vectors. The point is that raw content becomes a reusable knowledge layer that several agents and search strategies can share.

Retrieval then exposes that layer. search() takes query type, datasets, node filters, neighborhood controls, references, and ranking parameters. Its documentation names GRAPH_COMPLETION, RAG_COMPLETION, CHUNKS, CYPHER, and lexical chunk search. The caller is not only asking for similar text; it is choosing how to interrogate the knowledge layer.

await add(data, dataset_name="company_docs")

await cognify(
    datasets=["company_docs"],
    graph_model=KnowledgeGraph,
    chunker=TextChunker,
)

results = await search(
    query_text="How should we handle customer escalation?",
    query_type=SearchType.GRAPH_COMPLETION,
    datasets=["company_docs"],
    include_references=True,
)
Shape-level example: one document moving through Cognee

add / remember:
  source = "Customer escalation policy..."
  dataset = "company_docs"

cognify:
  the dataset is chunked, entities and relationships are extracted,
  and graph / vector retrieval layers are built

search:
  query = "Who should receive a customer escalation?"
  results come from the processed knowledge layer and can include references

Read through this chain and Cognee stops looking like "upload a file and vector-search it." add places material into a dataset; cognify performs classification, chunking, entity and relation extraction, and graph construction; search lets the caller choose graph answer, RAG answer, chunk search, Cypher, or lexical retrieval.

Current remember also accepts explicit content_type="code" or "skills" to select code-graph or Skill ingestion. It does not infer these intentions from a path alone. The add → cognify skeleton above describes ordinary material, not a single mandatory pipeline for every input type.

2.3 Cognee fits domain knowledge that many Agents must reuse

Cognee fits cases where an organization has documents, code, customer history, or expert patterns that should not be pasted into prompts turn by turn. The material should first be processed, connected, scoped, and made reusable. That is why its README examples lean toward company brain, customer support, and expert knowledge distillation scenarios.

The cost follows from the same design. A heavier knowledge layer brings processing latency, dataset permissions, graph schema choices, ontology questions, search modes, and deployment responsibilities. For a small user preference, this may be too much. For shared domain knowledge that many agents need to revisit, the Cognee route is natural.

2.4 Cognee is a knowledge-processing layer, not lightweight preference storage

A useful test is whether the material deserves to become an intermediate knowledge layer. The answer is usually yes when the material will be reused by several agents or workflows, when relationships and provenance matter more than a single text span, and when self-hosting or governance of the processing chain matters. If those signals are weak, datasets, cognify, graph search, and ontology choices may be unnecessary weight.

When those signals are strong, Cognee's benefit is not merely another search mode. It moves source material out of temporary prompts and into a reusable knowledge layer that can be improved, searched again, scoped by dataset, and shared by different agents working over the same organizational knowledge.

For documents worth graph construction whose processing cost is still unknown, remember(..., dry_run=True) offers a preliminary estimate. Its current scope is ordinary permanent ingestion in local mode: it does not ingest or call an LLM, and reports stage-level token and rough cost estimates. Extra model calls made by improve are excluded. Use it to compare input size and chunking choices, then measure quality and cost on the real pipeline.

3. Supermemory: package memory as a context API

Supermemory's README describes a memory and context layer for AI, with memory, user profiles, hybrid search, connectors, and multi-modal extractors in one stack. It also pitches a single API for AI products. That shifts the center of gravity from designing your own graph pipeline to calling packaged context APIs. See the README opening and developer quickstart.

3.1 Decide whether material is searchable reference or also user memory

The docs tell callers to send raw content: conversations, documents, files, and URLs. The default taskType="memory" triggers memory extraction. The Add context docs recommend customId for conversation or document identity, so updates and deduplication have a stable key. The parameter table also gives containerTag, metadata, entityContext, and the dreaming processing mode.

The public schema exposes the same lifecycle. MemorySchema includes content, metadata, source, status, summary, title, type, URL, containerTags, and chunkCount. The platform is not only accepting text; it is returning an object with source, status, grouping, and processing shape.

const MemorySchema = z.object({
  customId: z.string().nullable().optional(),
  content: z.string().nullable().optional(),
  metadata: MetadataSchema.nullable().optional(),
  source: z.string().nullable().optional(),
  status: DocumentSchema.shape.status,
  summary: z.string().nullable().optional(),
  containerTags: z.array(z.string()).optional(),
  chunkCount: z.number().default(0),
});

This schema shows that add is not just storing a text span. customId connects a memory back to the application's document or conversation identity. containerTags express user, project, or workspace grouping; the application must still bind caller identity to allowed tags. status exposes progress, while chunkCount counts output and cannot establish completion on its own.

The processing pipeline is documented as validation, storage and queueing, content extraction, chunking into searchable memories, embedding, and indexing. That public sequence appears in Processing Pipeline. In product terms, memory becomes a background workflow with observable status, not an in-prompt list.

Supermemory add pipeline:
  validate request
  -> store document and queue processing
  -> extract content (OCR / transcription / web scraping)
  -> chunk into searchable memories
  -> embed
  -> index

Progress:
  GET /v3/documents/{id} -> queued | processing | done
Shape-level example: one document moving through Supermemory

add:
  content = "Customer escalation policy..."
  containerTag = "support-team"
  status = "queued"

worker:
  status = "processing"
  derived searchable artifacts are being generated

later search:
  status = "done"
  profile / search can return background and evidence for the current question

A customer-escalation policy is reference material; reading it should not turn it into that user's personal preference. The current ingestion contract expresses this with taskType: default memory ingestion extracts facts, updates profiles, and builds search indexes; superrag only chunks, embeds, and indexes, without fact extraction or profile updates. dreaming answers a different question: dynamic processes related documents together, while instant processes each document independently. It does not decide whether the material should become memory.

await client.add({
  content: "Customer escalation policy...",
  customId: "support-escalation-policy",
  containerTag: "support-team",
  taskType: "superrag",
});

Updates also separate append from replacement. The guide accepts new content or a complete updated body under the same customId, with the service identifying additions. Its example uses client.documents.update() for full replacement and reprocessing; metadata-only updates happen in place without reindexing. filterByMetadata filters existing memories used as context during ingestion. It neither sets metadata on the new document nor replaces retrieval-time access and scope controls.

3.2 Profiles provide stable background; search provides current evidence

Supermemory makes a useful product distinction by separating user profiles from ordinary search. The User Profiles docs split profiles into static long-term facts and dynamic recent context. That keeps a model from having to run several narrow searches just to reconstruct who the user is.

The README examples follow the same shape. client.add({ content, containerTag }) stores a conversation; client.profile({ containerTag, q }) can return profile.static, profile.dynamic, and relevant searchResults together. The broad background and the query-specific evidence are separate outputs, which gives the caller a cleaner prompt assembly boundary.

await client.add({
  content: conversation,
  customId: "conv_123",
  containerTag: "user_123",
});

const { profile, searchResults } = await client.profile({
  containerTag: "user_123",
  q: "programming style",
});

// profile.static  -> stable long-term facts
// profile.dynamic -> recent context
// searchResults   -> evidence related to this turn

On retrieval, Searchv4RequestSchema exposes containerTag, threshold, filters, include flags, limit, query, rerank, and query rewrite. Its MemorySearchResult can carry memory text, similarity, version, parent and child context, and associated documents. The response is a context object, not just a chunk list.

const Searchv4RequestSchema = z.object({
  containerTag: z.string().optional(),
  threshold: z.number().default(0.6),
  filters: SearchFiltersSchema.optional(),
  include: z.object({
    documents: z.boolean().default(false),
    summaries: z.boolean().default(false),
    relatedMemories: z.boolean().default(false),
  }),
  limit: z.number().default(10),
  q: z.string().min(1),
  rerank: z.boolean().default(false),
  rewriteQuery: z.boolean().default(false),
});

const MemorySearchResult = z.object({
  memory: z.string(),
  similarity: z.number(),
  version: z.number().nullable().optional(),
  context: z.object({ parents: z.array(...), children: z.array(...) }).optional(),
  documents: z.array(MemorySearchDocumentSchema).optional(),
});

Supermemory's retrieval contract therefore has two layers. On the request side, containerTag, filters, and threshold control scope and recall breadth. On the response side, similarity, version, parents / children, and documents explain why this memory is relevant. That is closer to a product API than a plain vector-store top-k response.

Connectors push the platform edge further outward. The docs list Google Drive, Gmail, Notion, OneDrive, GitHub, Granola, and Web Crawler as external sources that can sync into Supermemory. The connector workflow includes connection creation, user authorization, automatic setup, and continuous sync through webhooks or schedules. Once memory owns connectors, it also inherits OAuth, webhooks, file versions, sync status, and user-space boundaries.

Having a connector does not imply one uniform freshness guarantee. In the current capability table, Granola is manual on-demand only, Web Crawler supports scheduled recrawling, and sources such as Google Drive support webhooks. Define freshness by source rather than treating authorization as a guarantee of continuous real-time sync.

3.4 Supermemory is a product context API, not only an Agent library

Supermemory's strength is reducing integration work to API and connector surfaces. A product can send conversations, documents, URLs, or files to the platform, then ask profile and search for usable context. The tradeoff is that some internals remain hosted-service behavior: public materials show request parameters, response shapes, and processing states, but not every extraction, consolidation, or reranking policy.

Deployment is no longer limited to the hosted service. The Supermemory local guide provides a single-binary local entry point and documents reuse of the Memory API by pointing the SDK baseURL at that server. The same page lists connectors and hosted Supermemory MCP as platform capabilities; local extraction uses the model you configure, while the platform uses proprietary extraction models. This chapter verifies the public deployment contract, not a local binary run or equivalent output quality. Compare API integration, data and model placement, and the need to modify processing internals as separate decisions.

4. Choose the route that matches the system

4.1 Start with the problem the system must solve

Cognee and Supermemory both make memory more platform-like, but they start from different questions. Cognee asks how raw material becomes a reusable knowledge layer. Supermemory asks how a product gets memory, profiles, search, connectors, and file processing through one API.

System pressure Natural route What to inspect first
You want an external memory layer between app and model, with write policy, decay, temporal reasoning, and retrieval ranking. Mem0 Write and retrieval algorithms.
Memory is part of agent state alongside persona, human profile, tools, and messages. Letta Agent state ownership and context compilation.
Facts change over time, and old facts need provenance rather than deletion. Graphiti Temporal graph and episode provenance.
Memory work affects the current execution path, so hot path tools and background managers must be separated. LangMem / LangGraph Hot path, background manager, store, and checkpointer.
Documents, code, expert patterns, or company knowledge need to become a reusable knowledge layer. Cognee add, cognify, search, datasets, graph/vector configuration.
A product needs memory, profiles, search, connectors, and file processing behind one API. Supermemory add, profile, search, connectors, and containerTag boundaries.

The reusable lesson is to classify history before choosing infrastructure. Is this record evidence, a profile fact, a relationship, workflow state, a knowledge-layer artifact, or context for this turn only? Cognee and Supermemory push that question to platform scale, where the hard part is often not finding content, but making data sources, processing responsibility, retrieval contracts, and deletion boundaries explicit.

Sources