> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cognee.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Session Persistence

> Persist cached conversation sessions into the knowledge graph

## When to use this

You want to persist cached conversation sessions into the knowledge graph so the Q\&A history becomes part of the searchable graph. In the current API, the user-facing way to do this is `cognee.improve(dataset=..., session_ids=[...])`.

Use the lower-level Memify pipeline in this guide when you need direct control over only the session persistence step.

**Before you start:**

* Complete [Quickstart](/getting-started/quickstart) to understand basic operations
* Ensure you have [LLM Providers](/setup-configuration/llm-providers) configured
* Have an existing knowledge graph created with `remember()`
* [Caching must be enabled](/core-concepts/sessions-and-caching#cache-adapters) and at least one session must exist (created by prior `cognee.recall()` calls with a `session_id`)

## Code in Action

```python theme={null}
import asyncio
import cognee
from cognee import SearchType
from cognee.memify_pipelines.persist_sessions_in_knowledge_graph import (
    persist_sessions_in_knowledge_graph_pipeline,
)
from cognee.modules.users.methods import get_default_user

async def main():
    await cognee.remember(
        "Alice moved to Paris in 2010. She works as a software engineer.",
        dataset_name="session_demo",
        self_improvement=False,
    )

    # Build session history with recall
    await cognee.recall(
        query_type=SearchType.GRAPH_COMPLETION,
        query_text="Where does Alice live?",
        datasets=["session_demo"],
        session_id="demo_session",
    )
    await cognee.recall(
        query_type=SearchType.GRAPH_COMPLETION,
        query_text="What does she do for work?",
        datasets=["session_demo"],
        session_id="demo_session",
    )

    # Persist the session into the graph
    user = await get_default_user()
    await persist_sessions_in_knowledge_graph_pipeline(
        user=user,
        session_ids=["demo_session"],
        dataset="session_demo",
    )

asyncio.run(main())
```

## What Just Happened

1. **Remember** — builds a knowledge graph from your text.
2. **Recall with `session_id`** — runs two recalls that accumulate Q\&A history in the session cache under `"demo_session"`.
3. **`get_default_user()`** — retrieves the authenticated user. This pipeline requires a `User` object with write access.
4. **`persist_sessions_in_knowledge_graph_pipeline(user, session_ids, dataset)`** — reads the cached session data and writes it into the knowledge graph.

## What Changed in Your Graph

* New nodes are created from the session Q\&A history, grouped under the `user_sessions_from_cache` node set.
* The session data is processed internally into graph memory, so entities and relationships from the session content become part of the graph.
* Persistence is incremental: each run only ingests the Q\&A entries added since the last successful persist for that session. Re-running on an unchanged session adds nothing new, so you can safely call it repeatedly as a session grows without re-embedding or duplicating the earlier history.

## Additional Information

You can find the runnable session persistence demo on our [GitHub](https://github.com/topoteretes/cognee/blob/dev/examples/advanced_guides/conversation_session_persistence_example.py). It builds two conversation sessions with `recall()`, persists both into the knowledge graph in one pipeline run, and renders a visualization of the resulting graph.

<Accordion title="Full example script">
  ```python theme={null}
  import asyncio
  import os

  import cognee
  from cognee import SearchType, visualize_graph
  from cognee.memify_pipelines.persist_sessions_in_knowledge_graph import (
      persist_sessions_in_knowledge_graph_pipeline,
  )
  from cognee.modules.users.methods import get_default_user
  from cognee.shared.logging_utils import get_logger

  logger = get_logger("conversation_session_persistence_example")


  async def main():
      # NOTE: CACHING has to be enabled for this example to work
      await cognee.forget(everything=True)

      text_1 = "Cognee is a solution that can build knowledge graph from text, creating an AI memory system"
      text_2 = "Germany is a country located next to the Netherlands"

      await cognee.remember([text_1, text_2], self_improvement=False)

      question = "What can I use to create a knowledge graph?"
      search_results = await cognee.recall(
          query_type=SearchType.GRAPH_COMPLETION,
          query_text=question,
          session_id="first_session",
      )
      print("\nSession ID: first_session")
      print(f"Question: {question}")
      print(f"Answer: {search_results}\n")

      question = "You sure about that?"
      search_results = await cognee.recall(
          query_type=SearchType.GRAPH_COMPLETION,
          query_text=question,
          session_id="first_session",
      )
      print("\nSession ID: first_session")
      print(f"Question: {question}")
      print(f"Answer: {search_results}\n")

      question = "This is awesome!"
      search_results = await cognee.recall(
          query_type=SearchType.GRAPH_COMPLETION,
          query_text=question,
          session_id="first_session",
      )
      print("\nSession ID: first_session")
      print(f"Question: {question}")
      print(f"Answer: {search_results}\n")

      question = "Where is Germany?"
      search_results = await cognee.recall(
          query_type=SearchType.GRAPH_COMPLETION,
          query_text=question,
          session_id="different_session",
      )
      print("\nSession ID: different_session")
      print(f"Question: {question}")
      print(f"Answer: {search_results}\n")

      question = "Next to which country again?"
      search_results = await cognee.recall(
          query_type=SearchType.GRAPH_COMPLETION,
          query_text=question,
          session_id="different_session",
      )
      print("\nSession ID: different_session")
      print(f"Question: {question}")
      print(f"Answer: {search_results}\n")

      question = "So you remember everything I asked from you?"
      search_results = await cognee.recall(
          query_type=SearchType.GRAPH_COMPLETION,
          query_text=question,
          session_id="different_session",
      )
      print("\nSession ID: different_session")
      print(f"Question: {question}")
      print(f"Answer: {search_results}\n")

      session_ids_to_persist = ["first_session", "different_session"]
      default_user = await get_default_user()

      await persist_sessions_in_knowledge_graph_pipeline(
          user=default_user,
          session_ids=session_ids_to_persist,
      )

      visualize_graph_path = os.path.join(
          os.path.dirname(__file__), ".artifacts/conversation_session_persistence.html"
      )
      await visualize_graph(visualize_graph_path)


  if __name__ == "__main__":
      asyncio.run(main())
  ```
</Accordion>

<Accordion title="Parameters">
  * **`user`** (`User`, required) — authenticated user with write access. Obtain via `await get_default_user()`.
  * **`session_ids`** (`Optional[List[str]]`) — list of session IDs to persist. If `None`, no sessions are extracted.
  * **`dataset`** (`str`, default: `"main_dataset"`) — the dataset to write session data into.
  * **`run_in_background`** (`bool`, default: `False`) — run asynchronously and return immediately.
</Accordion>

<Accordion title="Under the hood">
  Two tasks run in sequence, coordinated by a per-`(user, session)` persist watermark:

  1. **`extract_user_sessions`** — reads Q\&A data from the `SessionManager` for the specified `session_ids`, then consults the persist watermark (the number of Q\&A entries already persisted for that session) and yields only the entries added since the last successful run. A session with no new entries yields nothing, so re-running on an unchanged session does no ingestion work.
  2. **`cognify_session`** — calls `cognee.add` and `cognee.cognify` on the extracted entries, writing the results into the graph under the `user_sessions_from_cache` node set. Only after both succeed does it advance that session's watermark. If cognify fails, the watermark is left untouched and the same entries are retried on the next run (add-level content-hash deduplication keeps the retry safe).

  The watermark is stored as an internal session-context row via the `SessionManager` — it reuses the existing session cache and introduces no new backend, configuration, or credentials.
</Accordion>

<Accordion title="Troubleshooting">
  * **No sessions found** — caching must be enabled and `recall()` with a `session_id` must have been run first. See [Sessions and Caching](/core-concepts/sessions-and-caching).
  * **Error: no graph data found** — run `cognee.remember(..., dataset_name=...)` before calling this pipeline.
  * **LLM errors** — verify that your LLM provider is configured. See [LLM Providers](/setup-configuration/llm-providers).
  * **Permission errors** — the user must have write access to the target dataset. See [Permissions](/core-concepts/multi-user-mode/permissions-system/datasets).
</Accordion>

<Columns cols={3}>
  <Card title="Improve" icon="sparkles" href="/core-concepts/main-operations/improve">
    Bridge sessions with the current improvement workflow
  </Card>

  <Card title="Sessions Guide" icon="message-circle" href="/guides/sessions">
    Learn how sessions and caching work in Cognee
  </Card>

  <Card title="Recall" icon="search" href="/core-concepts/main-operations/recall">
    Query the enriched graph with v1.0 retrieval
  </Card>
</Columns>
