LangGraph
@rekall/langgraph is a LangGraph checkpointer backed by Rekall execution memory. Give your LangGraph agents durable, server-persisted state — resume after a crash, time-travel, and human-in-the-loop — in one line.
Overview
LangGraph ships in-memory and SQLite savers; production agents need a durable, multi-host store. RekallSaver makes Rekall that store, reusing its execution-memory layer — the same one that powers Rekall's HITL pause/resume. Benchmarked, crash-recovery repeats 0% of completed work versus 33% for a stateless agent.
Crash recovery
Resume exactly where the graph left off — state lives in Rekall, not memory.
Time-travel
Full checkpoint history per thread, so list and parent lineage work.
HITL
Pending writes (putWrites) persist for human-in-the-loop pauses.
Installation
npm install @rekall/langgraph @langchain/langgraph-checkpoint
@langchain/langgraph-checkpoint is a peer dependency — you already have it transitively via @langchain/langgraph.
Usage
Build a saver with RekallSaver.fromApi and pass it to compile. The thread_id is the persistence key — one Rekall blob per thread.
import { StateGraph } from '@langchain/langgraph';import { RekallSaver } from '@rekall/langgraph';const checkpointer = RekallSaver.fromApi({apiUrl: 'https://api.rekall.app', // or http://localhost:9876 in devapiKey: process.env.REKALL_API_KEY, // rk_… key, or accessToken: 'rat_…'});const graph = workflow.compile({ checkpointer });// thread_id is the persistence key — one Rekall blob per thread.await graph.invoke(input, { configurable: { thread_id: 'user-42' } });// …process restarts / crashes…// Resumes exactly where it left off — state lives in Rekall, not memory.await graph.invoke(null, { configurable: { thread_id: 'user-42' } });
That's it. Every checkpoint LangGraph emits is persisted to Rekall and read back on resume.
How It Maps
- check_circleEach LangGraph thread (
configurable.thread_id) maps to one Rekall external-state blob (provider: "langgraph",providerAgentId: thread_id). - check_circleThe blob holds the full checkpoint history per checkpoint namespace, so
getTuple,list(time-travel), parent lineage, andputWrites(pending writes) all work. - check_circleNo Rekall backend changes — it's a pure client of the existing
POST /api/v1/execution-memory/external/saveandGET …/external/loadendpoints.
Authentication
Pass apiKey (rk_…) or accessToken (rat_…) — sent as Authorization: Bearer. For local dev against a server using header auth, pass headers instead:
const checkpointer = RekallSaver.fromApi({apiUrl: 'http://localhost:9876',headers: { 'x-user-id': 'dev-user' },});
Advanced
Inject any store (e.g. for tests). The store must implement load(key) / save(key, blob) / delete(key):
import { RekallSaver, InMemoryCheckpointStateStore } from '@rekall/langgraph';const saver = new RekallSaver(new InMemoryCheckpointStateStore());
Notes
Single-runner-per-thread
Persistence is read-modify-write on the per-thread blob; ideal for the common single-runner-per-thread pattern. For high-concurrency writes to one thread, front it with your own locking.
