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

# Provider semantics

> Preserve each provider's memory model instead of flattening every record into a generic fact.

Federation normalizes the retrieval envelope, not the meaning of the underlying record. Every hit
keeps a provider ID, external record identity, source kind, provenance, timestamps, and provider
metadata that passed the adapter's bounds.

```mermaid theme={null}
flowchart LR
  Hits["Provider-local hits"] --> Normalize["Normalize portable envelope"]
  Normalize --> Rank["Ordinal reciprocal-rank fusion"]
  Rank --> Group["Group exact kind and normalized text"]
  Group --> Preserve["Preserve every source match"]
  Preserve --> Output["Bounded federated result"]
  Conflict["Contradictory content"] --> Output
```

## Compatibility model

| Provider ID     | Source model preserved                                                   | Published adapter boundary                                                                                                              |
| --------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `mem0`          | Memory IDs, text, metadata, and user/agent/run scope                     | Inject a Mem0 client and explicit namespace mapper. Mem0 add processing may be asynchronous, so a queued write is not a settled mirror. |
| `langgraph`     | Long-term store items and namespaces                                     | Inject a LangGraph store. Checkpoints are thread execution state and never become facts automatically.                                  |
| `zep`           | User graph context, episodes, entity nodes, and relationship edges       | Inject a Zep client. Graph ingestion can be asynchronous; exact-key semantics must not be inferred from graph search.                   |
| `graphiti`      | Episodes, temporal facts, nodes, edges, validity windows, and provenance | Inject a caller-owned transport. Episode lineage is retained when the transport supplies it.                                            |
| `letta`         | Core memory blocks and recent messages as different kinds                | Inject a Letta client. Blocks map to `pinned_context`; messages map to `message`. The adapter does not claim Letta archival retrieval.  |
| `openai_agents` | Ordered session items and conversation history                           | Inject an Agents SDK session. Session items remain conversation state, not durable user facts.                                          |

These distinctions follow the providers' official models:

* [Mem0 memory operations](https://docs.mem0.ai/api-reference) distinguish add, search, update,
  delete, entities, and asynchronous events.
* [LangGraph persistence](https://docs.langchain.com/oss/python/langgraph/persistence) stores graph
  state as checkpoints, while its [memory guide](https://docs.langchain.com/oss/python/langgraph/add-memory)
  separates thread state from cross-thread stores.
* [Zep's graph model](https://help.getzep.com/v2/understanding-the-graph) distinguishes episodes,
  entity nodes, and relationship edges.
* [Graphiti](https://github.com/getzep/graphiti) models temporal facts with validity and episode
  provenance.
* [Letta memory blocks](https://docs.letta.com/guides/core-concepts/memory/memory-blocks) are
  persistent, always-visible agent context; archival memory is a separate retrieval surface.
* [OpenAI Agents SDK sessions](https://openai.github.io/openai-agents-python/sessions/) maintain
  ordered conversation history across runs.

## Result rules

* A result is always source-labelled.
* Source-local relevance scores stay source-local. Do not compare `0.8` from one provider with
  `0.8` from another as if they shared a calibration.
* Source-qualified duplicates may be grouped for display, but provenance is never discarded.
* Contradictions remain visible. Federation does not silently pick a universal truth.
* Each source reports `ok`, `timed_out`, `unavailable`, or `error`. The aggregate status is
  `partial` only when at least one source succeeds, and `failed` when none succeeds. Provider
  failures are returned with per-source errors rather than thrown, so callers must inspect
  `result.status` and `result.sources`; `failed` is never disguised as an empty success.

## Candidate is not personal memory

The hosted plane uses portable candidate records so developers can opt into Praxa storage later.
A candidate is not promptable Praxa personal memory and carries no AHCE consent. Any future
promotion requires a separate authenticated owner-review contract and canonical erasure fencing.

The hosted vocabulary is deliberately closed. It accepts `message`, `fact`, `summary`, `episode`,
`pinned_context`, `document`, `entity`, and `edge`. It rejects LangGraph checkpoints: a checkpoint
is execution state, not a portable durable-memory record. A `custom` provider ID is available for a
caller-defined adapter only when its records still satisfy the same bounded envelope.
