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

# Cognition

> The reasoning trace behind a retrieval: which nodes the model settled on, how strongly it settled, and whether it thought fast or slow.

The `cognition` block of a retrieval. Returned by [`POST /v1/retrieve`](/api-reference/retrieve/post-retrieve).

```json 200 application/json theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
{
  "cognition": {
    "confidence": 0.83,
    "driftRate": 0.02,
    "tier": "growing",
    "useSystem2": false,
    "focalNodeIds": ["ingest:4a1e88f0-9c2d-4f31-b7a0-5e6c1d820b93:7d3c9b1e04a2", "ingest:4a1e88f0-9c2d-4f31-b7a0-5e6c1d820b93:2b8f0c6d91a4"]
  },
  "path": "brain",
  "degraded": false,
  "degradationReason": null
}
```

## What it is

Every retrieval API can tell you what it found. This one tells you what it did.

**Cognition**, the trace of how the org's trained model arrived at an answer (in practice, five numbers that say which nodes it settled on, how sure it was, how hard it worked, and whether the graph has moved out from under it).

The block exists because "here are eight chunks and a score" is not enough to build on. If you are putting an answer in front of a user, deciding whether to ask a follow-up question, or choosing between showing a result and admitting uncertainty, you need the model's own read on the answer. That is what `confidence` and `useSystem2` are for. If you are running Exo in production over months, you need to know when the model has drifted away from the graph it learned. That is what `driftRate` is for.

## Where it comes from

The block is produced by the ExoBrain forward pass, so it is present on the brain path and null on the hybrid fallback. A hybrid search ranks chunks; it has no reasoning state, so reporting a fabricated one would be worse than reporting nothing.

```mermaid theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
flowchart LR
  A[Query] --> B[Seed set from<br/>nearest neighbours]
  B --> C[ExoBrain<br/>forward pass]
  C --> D[focalNodeIds<br/>confidence<br/>driftRate]
  C --> E{confidence<br/>below boundary}
  E -->|yes| F[useSystem2 true<br/>slow deliberate pass]
  E -->|no| G[useSystem2 false<br/>fast associative pass]
  classDef focus stroke-width:2px;
  class C focus;
```

## Fields

| Field          | Type         | What it means                                                                                                                                |
| -------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `confidence`   | number       | How strongly the model settled on this answer, from 0 to 1. Low confidence is the signal to ask a clarifying question rather than to assert. |
| `driftRate`    | number       | How far the region the model activated has moved from the state it trained on. 0 means aligned; it rises as the graph grows past the brain.  |
| `tier`         | string       | The graph-maturity tier that served the call: `seed`, `sprout`, `growing`, `mature` or `deep`.                                               |
| `useSystem2`   | boolean      | True when the model escalated to slow deliberate reasoning instead of a fast associative lookup.                                             |
| `focalNodeIds` | string array | The knowledge-graph nodes the model settled on as the centre of the answer.                                                                  |

### tier and useSystem2 are two different things

They are easy to conflate and they measure nothing alike.

`tier` is about the **graph**. It is derived from how many nodes were in the served subgraph, so it reports how much material the model had to work with:

| Tier      | Served subgraph   |
| --------- | ----------------- |
| `seed`    | Under 20 nodes    |
| `sprout`  | Under 100 nodes   |
| `growing` | Under 500 nodes   |
| `mature`  | Under 5000 nodes  |
| `deep`    | 5000 nodes and up |

A `seed` tier is not a worse answer, it is a smaller graph. It is the honest read on how much history a subject has accumulated, which makes it the field to watch during onboarding.

`useSystem2` is about **this one query**. The model escalates when its own confidence falls below the decision boundary, so a hard question against a large graph can still come back `useSystem2: true`. The escalation fires on low confidence, not on high drift.

Read them together: `tier: "deep"` with `useSystem2: true` means a rich graph and a genuinely hard question. `tier: "seed"` with `useSystem2: true` means the model does not have enough to go on yet.

## How to use it

Gate on the model's own uncertainty instead of assuming every answer is equally good.

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  curl -sS -X POST https://api.get-exo.com/v1/retrieve \
    -H "X-Exo-API-Key: $EXO_KEY" \
    -H "Content-Type: application/json" \
    -d '{"query": "Where did we land on the pricing model?", "topK": 8}'
  ```

  ```python Python theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  import os, requests

  r = requests.post(
      "https://api.get-exo.com/v1/retrieve",
      headers={"X-Exo-API-Key": os.environ["EXO_KEY"]},
      json={"query": "Where did we land on the pricing model?", "topK": 8},
  )
  r.raise_for_status()
  body = r.json()

  cog = body.get("cognition")
  if cog is None:
      answer_mode = "sources_only"          # hybrid path, no reasoning state
  elif cog["confidence"] < 0.5 or cog["useSystem2"]:
      answer_mode = "ask_a_follow_up"       # the model is not settled
  else:
      answer_mode = "assert"

  print(answer_mode, body["path"], body["degraded"])
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  const r = await fetch("https://api.get-exo.com/v1/retrieve", {
    method: "POST",
    headers: {
      "X-Exo-API-Key": process.env.EXO_KEY!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query: "Where did we land on the pricing model?",
      topK: 8,
    }),
  });
  if (!r.ok) throw new Error(`${r.status} ${await r.text()}`);
  const body = await r.json();

  const cog = body.cognition;
  const answerMode =
    cog == null
      ? "sources_only"
      : cog.confidence < 0.5 || cog.useSystem2
        ? "ask_a_follow_up"
        : "assert";

  console.log(answerMode, body.path, body.degraded);
  ```
</CodeGroup>

`focalNodeIds` are ordinary node ids, so you can drill straight into one with [`GET /v1/graph/nodes/{node_id}`](/api-reference/graph/get-graph-node) to show a user exactly which memory the answer rests on.

## Details worth knowing

<AccordionGroup>
  <Accordion title="Why cognition is null" icon="circle-question">
    The hybrid path served the call. Check `path`: it is `hybrid` whenever the org has no trained brain, the brain is unavailable, or the subject has no content yet. The hybrid path is vector plus keyword search with reciprocal-rank fusion, which produces rankings but no reasoning state, so `cognition` is null rather than zero-filled. [Brain path and hybrid path](/concepts/retrieval-paths) covers how to tell the cases apart.
  </Accordion>

  <Accordion title="What a rising driftRate means in practice" icon="circle-question">
    The brain trained on a snapshot of the graph. Every ingest, edit and forget moves the graph away from that snapshot, and `driftRate` reports how far the region this query activated has moved. It is an early warning rather than an error: the answer is still the best one available. When it climbs, retrain with [`POST /v1/brain/train`](/api-reference/brain/post-brain-train).

    `driftRate` and `degradationReason: "brain_stale"` are related but not the same. Drift is measured per query, at the region the query touched. Staleness is a property of the whole brain, and it is also raised when a mutation through the API dirties the graph in a way a node count would not notice.
  </Accordion>

  <Accordion title="Whether unknown keys in the block are safe to ignore" icon="circle-question">
    Yes, and you should plan on them. The block is versioned additively: a future reasoning tier may report extra fields, so treat unknown keys as forward compatible rather than as an error. Do not use a strict schema that rejects them.
  </Accordion>

  <Accordion title="How to see more of the reasoning than this block carries" icon="circle-question">
    [`POST /v1/brain/query`](/api-reference/brain/post-brain-query) runs one forward pass and returns the full glass-box result: the focal set with a per-node snippet, the plain nearest-neighbour head alongside it for comparison, the subgraph it ran over, and how many negative edges were in play. It is the route behind a "what did the model attend to" visualisation. It requires a trained brain and reads the key owner's own content, so it does not accept the `X-Exo-Subject` selector.
  </Accordion>
</AccordionGroup>

## Limits

* `cognition` is null on every hybrid retrieval. Write your reader so a missing block is a normal branch, not an exception.
* `tier` is documented as a string rather than a closed enum. The five values above are what ships today; do not switch exhaustively on them without a default.
* The block reports the model's own confidence, which is a statement about how firmly it settled, not a probability that the answer is factually correct.
* There is no field that says which contradiction influenced the answer. Contradictions come back in their own array on the same response; the link between the two is the node id.

## Next

<Columns cols={2}>
  <Card title="Brain path and hybrid path" icon="split" href="/concepts/retrieval-paths">
    Why cognition is null, what degraded means, and how to read degradationReason.
  </Card>

  <Card title="ExoBrain" icon="cpu" href="/concepts/exobrain">
    The per-org model that produces this block, and when to retrain it.
  </Card>
</Columns>
