> ## 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.

# Teach an Agent From Its Own Tool Traces

> Turn an agent's tool-call successes and failures into agent-profile session guidance, distill it into the knowledge graph, and read it back before the next run

Your coding agent has already hit the errors that matter — a test run that failed on a missing dependency, a lint pass that flagged an unused import — and the next run will hit them again unless something remembers what happened. This demo turns that raw tool-call history into guidance the agent can be handed before it starts.

## What You'll Build

Five tool-call traces from one agent working a task — a failing `pytest` run, a `uv sync` that fixed it, a passing test run, a file read, and a lint failure — are stored one by one into a session as `TraceEntry` records. Cognee extracts agent-profile lessons from them as they accumulate, then distillation rewrites the accepted lessons into markdown documents and cognifies them into the dataset, so they outlive the session. The payoff is the last act: `recall()` returns those lessons as a read-only context block for the agent-profile question "what should I know before running tests in this repo?", while the same query under the QA profile returns nothing and the raw traces are still retrievable as evidence.

The complete runnable script is
[`examples/demos/sessions/agentic_session_context_demo.py`](https://github.com/topoteretes/cognee/blob/main/examples/demos/sessions/agentic_session_context_demo.py) —
this page walks through its key moments rather than reproducing it.

## Features in Play

* [Agent Session Traces](/guides/agent-session-traces) — each tool call becomes a `TraceEntry` in the session, carrying its parameters, return value, or error message
* [Sessions and Caching](/core-concepts/sessions-and-caching) — the session cache holds both the raw traces and the agent-profile guidance extracted from them
* [Session Distillation](/guides/session-distillation) — rewrites the accepted guidance into markdown documents and cognifies them into the dataset
* [Recall](/core-concepts/main-operations/recall) — reads the guidance back with `scope` and `context_profile`, and the raw traces alongside it as evidence

## Before You Start

* Complete [Quickstart](/getting-started/quickstart) to understand basic operations
* Ensure you have [LLM Providers](/setup-configuration/llm-providers) configured — lesson extraction and distillation are LLM-backed, so the full run needs one; `--offline` skips both
* The script sets its own environment before importing cognee: `CACHING=true`, `CACHE_BACKEND=fs`, `AUTO_FEEDBACK=true`, `ENABLE_BACKEND_ACCESS_CONTROL=false`, and `LOG_LEVEL=ERROR` unless you already set it. The [filesystem cache adapter](/core-concepts/sessions-and-caching#cache-adapters) is what stores the session
* Run it from a checkout of the cognee repo; it writes `agentic_session_context_demo_output.json` into the working directory with every snapshot the run took
* The run starts by pruning data and system metadata and deleting any previous `agentic_demo_session`, so point it at a scratch instance rather than memory you want to keep

## How It Works

### Stage 1: Script the Agent's Tool Traces

```python theme={null}
TRACES = [
    {
        "origin_function": "run_tests",
        "status": "error",
        "method_params": {"command": "pytest -q"},
        "error_message": "ModuleNotFoundError: No module named 'dotenv'",
    },
    {
        "origin_function": "run_command",
        "status": "success",
        "method_params": {"command": "uv sync"},
        "method_return_value": "Installed 42 packages in 1.2s",
    },
    {
        "origin_function": "run_tests",
        "status": "success",
        "method_params": {"command": "uv run pytest -q"},
        "method_return_value": "188 passed in 4.1s",
    },
    {
        "origin_function": "read_file",
        "status": "success",
        "method_params": {"path": "pyproject.toml"},
        "method_return_value": "[project] name = 'demo'  # managed with uv",
    },
    {
        "origin_function": "run_lint",
        "status": "error",
        "method_params": {"command": "uv run ruff check ."},
        "error_message": "F401 'os' imported but unused",
    },
]
```

These five dictionaries stand in for what a real agent's tool layer would emit: the tool name, whether the call succeeded, its input, and either the return value or the error. The story they tell — bare `pytest` fails, `uv sync` fixes it, `uv run pytest` passes — is the raw material a lesson can be drawn from, and nothing in the run tells the extractor what that lesson is.

### Stage 2: Store Each Trace and Extract as You Go

```python theme={null}
    for index, trace in enumerate(TRACES, start=1):
        before = await snapshot(user)
        await cognee.remember(
            TraceEntry(**trace),
            dataset_name=DATASET_NAME,
            session_id=SESSION_ID,
            self_improvement=False,
            user=user,
        )
        if drive_periodic_extraction:
            await extract_pending_agent_context(
                session_manager=get_session_manager(),
                user_id=str(user.id),
                session_id=SESSION_ID,
                min_new_traces=DEMO_TRACE_EXTRACTION_INTERVAL,
                overlap=DEMO_TRACE_EXTRACTION_OVERLAP,
            )
```

`remember()` with a `session_id` writes each `TraceEntry` to the session cache rather than the graph. The trace-write path already runs the periodic extraction pass for you on its own interval; the demo calls it directly with `DEMO_TRACE_EXTRACTION_INTERVAL = 2` and `DEMO_TRACE_EXTRACTION_OVERLAP = 1` so a five-trace run actually shows the pass firing — after traces 2 and 4 — instead of only at the end. The snapshot taken before and after each trace is what lets the run print whether that trace advanced the processed-trace watermark.

### Stage 3: Flush the Tail and Distill Into the Graph

```python theme={null}
        before_flush = await snapshot(user)
        touched_ids = await extract_pending_agent_context(
            session_manager=get_session_manager(),
            user_id=str(user.id),
            session_id=SESSION_ID,
            min_new_traces=1,
        )
        distillation_input = await snapshot(user)
        result = await distill_session(SESSION_ID, dataset=DATASET_NAME, user=user)
```

Traces 2 and 4 triggered extraction, which leaves the fifth trace — the lint failure — pending. Dropping `min_new_traces` to 1 forces that tail through, so distillation sees the complete set of lessons. `distill_session()` then rewrites the accepted guidance into markdown documents and cognifies them into the demo dataset, which is what makes the lessons outlast this session. The script reaches it through its internal module path; in your own code call it as [`cognee.session.distill_session()`](/guides/session-distillation), or let [`improve(session_ids=[...])`](/core-concepts/main-operations/improve) run the same distillation as part of a wider pass.

### Stage 4: Recall Guidance by Profile

```python theme={null}
    agent_ctx = await cognee.recall(
        "what should I know before running tests in this repo?",
        scope=["session_context"],
        context_profile="agent",
        session_id=SESSION_ID,
        only_context=True,
        user=user,
    )
    qa_ctx = await cognee.recall(
        "what should I know before running tests in this repo?",
        scope=["session_context"],
        context_profile="qa",
        session_id=SESSION_ID,
        only_context=True,
        user=user,
    )
    raw_traces = await cognee.recall(
        "dotenv",
        scope=["trace"],
        session_id=SESSION_ID,
        only_context=True,
        user=user,
    )
```

Three recalls against the same session show what the profile does. `scope=["session_context"]` with `context_profile="agent"` returns the distilled guidance block, ready to prepend to the next agent run; the identical query under `context_profile="qa"` comes back empty, because this demo wrote no QA-profile entries. `scope=["trace"]` reaches past the lessons to the raw evidence they were drawn from, so a lesson about `dotenv` can be traced back to the call that failed. `only_context=True` keeps all three as context reads rather than completions.

### Stage 5: Prove the Reads Changed Nothing

```python theme={null}
async def served_state(user) -> dict:
    """Map of agent-lesson id -> last_served_at, to prove recall does not stamp anything."""
    rows = await get_session_manager().get_session_context_entries(
        user_id=str(user.id), session_id=SESSION_ID
    )
    return {
        row.get("id"): row.get("last_served_at")
        for row in rows
        if row.get("context_profile", "qa") == "agent"
    }
```

The recall act captures this map of agent-lesson id to `last_served_at` before and after the three queries and compares them. Serving guidance to an agent is a read: nothing is stamped, no entry is aged, and the run prints the comparison so you do not have to take that on faith.

## Run It

```bash theme={null}
uv run python examples/demos/sessions/agentic_session_context_demo.py
```

The run narrates itself on stderr in three acts. Act 1 prints each trace — tool, status, input, and output or error — followed by the session memory after it, with every entry labeled by section, content, confidence, and whether it came from a live trace or a batch LLM pass; traces 2 and 4 are marked as the first and second batch context extraction. Act 2 prints the pending-trace count before and after the final flush, how many context entries it touched, the session memory that distillation consumed, and then the status and full text of each cognified document. Act 3 prints the agent-profile guidance block, the QA-profile result count, the number of raw trace results, and whether recall performed any writes. The run finishes by writing `agentic_session_context_demo_output.json` and printing its path. Exact lesson wording varies by model.

## Offline Mode

```bash theme={null}
uv run python examples/demos/sessions/agentic_session_context_demo.py --offline
```

`--offline` runs the same trace capture and recall without any LLM calls: the periodic extraction passes are skipped, Act 2 is skipped entirely, and the only session-memory entries that appear are the deterministic ones written when a failing trace is stored. Use it to see the capture-and-recall shape of the demo without a configured provider — and, in the full run, as the baseline that shows which entries the LLM added.

<Columns cols={2}>
  <Card title="Agent Session Traces" icon="footprints" href="/guides/agent-session-traces">
    Recording tool calls as traces and recalling them later.
  </Card>

  <Card title="Session Distillation" icon="graduation-cap" href="/guides/session-distillation">
    How gated session guidance becomes permanent lessons in the graph.
  </Card>

  <Card title="Sessions and Caching" icon="message-square" href="/core-concepts/sessions-and-caching">
    The session cache behind traces, guidance, and the `fs` backend this demo uses.
  </Card>

  <Card title="Watch a Session Become Permanent Memory" icon="repeat" href="/examples/memory-loop-walkthrough">
    The same distillation loop, driven by a conversation instead of tool traces.
  </Card>
</Columns>
