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

# Federate LangGraph long-term memory

> Connect an existing LangGraph BaseStore to Praxa's read-only memory federation while keeping checkpoints and namespaces separate.

LangGraph separates thread checkpoints from cross-thread long-term stores.
Praxa adapts the long-term <code>BaseStore</code> lane only. It rejects
checkpoints because execution state is not a portable durable-memory record.

```mermaid theme={null}
flowchart LR
  Thread["LangGraph thread"] --> Checkpoint["Checkpointer"]
  Agent["Agent recall"] --> Store["Long-term BaseStore"]
  Store --> Adapter["Praxa LangGraph adapter"]
  Adapter --> Federation["MemoryFederation result"]
  Checkpoint -. "excluded" .-> Adapter
```

## Prerequisites

Before you begin, prepare:

* a backend-owned provider client and explicit tenant-subject namespace resolver;
* synthetic records for at least two tenants and two subjects per tenant;
* the exact @praxa/sdk memory package version and supported provider contract;
* a provider cleanup procedure plus degraded-state and timeout fixtures;
* an acceptance assertion that proves the adapter reads long-term store records, excludes checkpoints, and passes 2x2 namespace isolation.

## 1. Keep a tenant-subject namespace

```ts theme={null}
import { createLangGraphMemorySource } from "@praxa/sdk/memory";

const source = createLangGraphMemorySource({
  store,
  mapNamespace: ({ tenantId, subjectId }) => [
    tenantId,
    subjectId,
    "memory",
  ],
  kind: "document",
});
```

The mapper must be derived from authenticated application context. Do not use a
model-authored namespace or a browser-supplied tenant ID.

## 2. Recall through Praxa

```ts theme={null}
import { MemoryFederation } from "@praxa/sdk/memory";

const memory = new MemoryFederation({ sources: [source] });
const result = await memory.recall({
  query: "What has this user told us about response style?",
  namespace: {
    tenantId: "tenant-a",
    subjectId: "user-42",
    scope: ["support"],
  },
  limit: 10,
});

if (result.status === "failed") {
  throw new Error(JSON.stringify(result.sources));
}
```

Inspect <code>result.status</code> and <code>result.sources</code>. Provider
failures are represented in the returned result, not converted into an empty
success.

## 3. Prove isolation and compatibility

Seed one known memory through the normal LangGraph store API, then test:

1. The intended tenant and subject retrieve it.
2. A second subject in the same tenant does not.
3. The same subject ID in a second tenant does not.
4. A checkpointer record is never returned through the adapter.
5. A store outage returns an explicit source status.
6. Deleting the provider record removes it from later recalls.

Praxa does not copy or delete the provider record. Provider lifecycle remains
under your LangGraph store.

<Card title="LangGraph persistence" icon="arrow-up-right-from-square" href="https://docs.langchain.com/oss/javascript/langgraph/persistence">
  Review the official distinction between checkpointers and long-term stores.
</Card>

## Troubleshooting

| Symptom                              | Resolution                                                                                                      |
| ------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
| Expected record is absent            | Verify provider-native data shape, namespace mapping, filters, and source status.                               |
| Another subject sees a record        | Stop the rollout and repair server-owned tenant-subject resolution before further tests.                        |
| Provider outage looks like no memory | Expose the source status and keep unavailable distinct from an empty successful recall.                         |
| Delete did not remove provider data  | Use the provider's lifecycle; read-only federation and hosted-candidate deletion do not erase provider sources. |

## Best practices

* Keep provider writes and lifecycle under the provider's documented API.
* Resolve tenant and subject in trusted backend code and test 2x2 isolation.
* Preserve provenance, source matches, contradictions, and per-source status.
* Bound concurrency, result count, context bytes, and source timeout.
* Never promote checkpoint, hidden, or unverified content into portable recall.

## Optimize for production

* Query only providers and record kinds relevant to the current purpose.
* Use bounded parallel recall and give each source an explicit timeout budget.
* Deduplicate normalized content while retaining every source match and contradiction.
* Measure source p50/p95 latency, partial/failed recalls, result precision, context bytes, and isolation failures.

Optimize only after the correctness and isolation matrix passes. Lower latency or cost is not an improvement if verified outcomes, authority checks, or recovery rates regress.

## Cleanup and next steps

1. Delete synthetic provider records using the provider's normal API.
2. Hard-erase disposable hosted candidates and verify content-free receipts when used.
3. Revoke test credentials and remove namespace fixtures for every tenant and subject.
4. Retain only non-content source statuses, identifiers, and test results required for audit.

After cleanup, run the [shared integration test matrix](/tutorials/test-your-integration) and record any environment-specific check that remains pending.

## Frequently asked questions

### What proves this tutorial works?

The minimum observable result is that the adapter reads long-term store records, excludes checkpoints, and passes 2x2 namespace isolation. A compile, package import, mocked response, or initial admission alone does not prove the complete workflow.

### Can a browser, mobile app, or model prompt hold the credential?

No. Provider clients and Praxa credentials stay in the backend; adapters receive clients, not raw credentials.

### How should an ambiguous mutation be retried?

Persist the exact logical input and idempotency key before the first attempt. Reconcile through authoritative readback or replay the exact request with that same key before creating new work.

### What should we monitor after release?

Monitor per-source latency/status, partial and failed recall rates, result precision, context bytes, provenance coverage, and isolation failures. Alert on authorization bypass, cross-tenant disclosure, repeated conflicts, or cleanup failure.
