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

# How Exo works

> Content goes in, a knowledge graph comes out, and every read is conditioned on the person it belongs to. The mental model in one page.

Exo is cognition middleware. It gives a model more than a user's context: it gives it how that user reasons. Three things happen to get there, and the API exposes all three.

## The loop

```mermaid theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
flowchart TB
  A["Content in<br/>ingest, import, sessions, connectors"] --> B["Chunk, embed, link<br/>background worker"]
  B --> C["Knowledge graph<br/>nodes, edges, domains"]
  C --> D["Background cycle<br/>identity, phases, contradictions, proposals"]
  D --> C
  C --> E["ExoBrain<br/>one trained model per org"]
  E --> F["Reads<br/>retrieve, recall, condition"]
  C --> F
  F --> G["Your product"]
```

Every arrow into the graph is asynchronous, and every arrow out is a normal request. That asymmetry is the single most important thing to internalise: **writes return a job id, reads return data.**

## Step one: content in

You push anything a person thinks in. Raw text through `POST /v1/ingest`, files and transcripts through `POST /v1/import`, coding-agent sessions through the session family, and repositories through the GitHub connector.

Each call returns immediately with a job id:

```json 202 application/json theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
{ "jobId": "b1f0c6d2-8a44-4b21-9a1e-6d1f0c6d28a4", "status": "pending" }
```

A background worker then chunks the content, embeds it, writes the nodes and links them into the graph. Poll `GET /v1/ingest/{job_id}/status` for progress, or `GET /v1/jobs/{job_id}` for the canonical cross-family view, where a finished import reports what your content actually became:

```json 200 application/json theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
{
  "id": "b1f0c6d2-8a44-4b21-9a1e-6d1f0c6d28a4",
  "jobType": "import",
  "status": "succeeded",
  "result": { "nodesCreated": 41, "edgesCreated": 118, "domainsDetected": 6 },
  "createdAt": "2026-07-29T16:40:11Z",
  "completedAt": "2026-07-29T16:42:05Z",
  "error": null
}
```

That `result` block is the multi-phase import pipeline reporting itself. A single `POST /v1/ingest` writes one node through a leaner path and reports no result block at all, so `result` is `null` on those jobs. Read the absence as "this job type does not report", not as "nothing happened".

<Warning>
  The two status routes speak different vocabularies for the same job. `GET /v1/jobs/{job_id}` returns the public set, `pending | running | succeeded | failed | canceled`. `GET /v1/ingest/{job_id}/status` is the older permanent alias and returns the worker's own set, where success is spelled `done`. Poll for a terminal state rather than for one spelling of success.
</Warning>

Send an `Idempotency-Key` and a retry returns the original job id rather than a second copy. See [Ingesting content](/guides/ingesting).

## Step two: the graph

What comes out is not an index of passages. It is a graph.

* **Nodes** are units of content with a title, text and an authority level. Authority is why an imported document outranks a line an agent narrated about itself.
* **Edges** are typed relations between nodes, some derived from structure, some from similarity, some asserted by you. An edge you assert has capped authority, so organic evidence always outranks a hand-written link.
* **Domains** are communities the graph discovers in itself rather than a taxonomy you supply.

<Warning>
  **Node ids are opaque strings, and they contain colons.** Their shape depends on how the content arrived, for example `ingest:<user_id>:<content_hash>` for a generic ingest and `import:<user_id>:<index>:<hash>` for an imported note. Store them as text with room to spare, encode them when you put one in a URL path, and never parse or regenerate one. The content hash is why re-ingesting identical content updates the same node instead of duplicating it.
</Warning>

Then a background cycle runs over it and writes the parts that make Exo different: identity signals and the cognitive manifold, phases clustered from real content dates, contradictions mined from belief reversals and retractions, and proposed edges the system is not confident enough to assert on its own.

That cycle is why **a brand-new organization returns empty recall collections.** Nothing is broken. There is not enough content yet for the structure to exist. See [How a memory is made](/concepts/memory-lifecycle).

## Step three: reads

Four surfaces read the graph, and choosing between them is most of the integration design.

| Surface                                              | Ask it for                                   | Returns                                                                        |
| ---------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------ |
| [`POST /v1/retrieve`](/guides/retrieving)            | The answer to a question about a person      | Ranked `sources`, `contradictions`, `cognition`, and the `path` that served it |
| `POST /v1/search`                                    | Ranked passages, without the reasoning layer | `results` and `usage`                                                          |
| `GET /v1/recall/{type}`                              | The cognitive state itself                   | `identity`, `graph`, `insights` or `temporal`                                  |
| [`POST /v1/condition/session`](/guides/conditioning) | A prompt for your own model                  | `systemPrompt`, `userVoiceHint`, `orgRecentContext`, `expiresAt`               |

`retrieve` is the flagship because it is the one that answers with provenance. `condition` is the one that matters if you are wiring Exo into an agent you already own: it hands back a prompt artifact rather than more text for you to rank.

## The one asymmetry to plan around

Retrieval runs on the org's trained **ExoBrain** when there is one, and falls back to hybrid vector plus keyword search when there is not. The response always says which:

| `path`   | `degraded` | `degradationReason` | What it means                                                                   |
| -------- | ---------- | ------------------- | ------------------------------------------------------------------------------- |
| `brain`  | `false`    | `null`              | The trained model served the call                                               |
| `brain`  | `true`     | `brain_stale`       | The model answered, but the graph has changed since it trained                  |
| `hybrid` | `true`     | `no_brain`          | No model exists for this org yet, and the fallback found matching content       |
| `hybrid` | `true`     | `cold_start`        | The fallback ran and matched nothing at all. Usually an org with no content yet |

`cognition` is populated only on the brain path. On the hybrid path it is `null`, because there is no reasoning state to report. Build for `null` from day one: every new org starts there. See [Brain path and hybrid path](/concepts/retrieval-paths).

## The objects you will meet

Seven named objects carry the capability that a vector store cannot express. Each has its own page with a real payload.

<Columns cols={2}>
  <Card title="Cognition" icon="brain-circuit" href="/concepts/cognition">
    Confidence, reasoning tier, whether it escalated to slow deliberate reasoning, and the nodes it settled on. From `POST /v1/retrieve`.
  </Card>

  <Card title="Contradiction" icon="git-compare" href="/concepts/contradiction">
    Two poles of a belief conflict and how tense it is. From `GET /v1/contradictions`.
  </Card>

  <Card title="Belief and supersession" icon="history" href="/concepts/belief-and-supersession">
    How a belief was replaced and where authority went. From `GET /v1/graph/nodes/{id}/history`.
  </Card>

  <Card title="ManifoldState" icon="axis-3d" href="/concepts/manifold">
    Discovered thinking dimensions, basins and trajectory. From `GET /v1/recall/identity`.
  </Card>

  <Card title="Phase" icon="calendar-range" href="/concepts/phase">
    Eras of thought clustered from content dates. From `GET /v1/recall/temporal`.
  </Card>

  <Card title="ConditioningPack" icon="message-square-quote" href="/concepts/conditioning-pack">
    A ready-to-inject prompt with a voice profile and an expiry. From `POST /v1/condition/session`.
  </Card>

  <Card title="AgentFailurePattern" icon="bug" href="/concepts/agent-failure-pattern">
    The recurring ways a team's coding agents go wrong, anonymised. Defined in the contract, surface not in v1.
  </Card>
</Columns>

## One layer per end user

If you are building a product with your own users, provision a **subject** for each of them. A subject is an isolated memory partition, backed by physical per-organization schema isolation rather than a filter on a shared table.

```bash cURL theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl -X PUT https://api.get-exo.com/v1/subjects/customer_6412 \
  -H "X-Exo-API-Key: $EXO_KEY"
```

After that, every call acts as that subject when you send the `X-Exo-Subject` header, and acts as the key owner when you do not. `DELETE /v1/subjects/{id}` erases everything that end user ever stored, which is the documented erasure path. See [One memory per end user](/guides/subjects) and [Subjects and isolation](/concepts/isolation).

## Where to go next

<Columns cols={3}>
  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Five calls, from a key to a retrieve response you can read.
  </Card>

  <Card title="Concepts" icon="book-open" href="/concepts">
    What Exo stores, and why it is a graph rather than an index.
  </Card>

  <Card title="API reference" icon="code" href="/api-reference/overview">
    All 80 operations, with the traps the generated schema cannot carry.
  </Card>
</Columns>
