LangGraph
Resume a LangGraph agent after its process dies.
recall-langgraph
records the agent's working state, pointers to its work, and every turn to
Recall as it runs. The next process that opens the same agent id
starts from a briefing built from those records.
It sits beside LangGraph's checkpointer, not in place of it. The checkpointer still handles threads and interrupts however you configure it. The launch post explains the design and what we measured.
Install and use
pip install recall-langgraph langchain-openai
recall-langgraph also installs the polign_db server and polign CLI for
Linux, macOS and Windows, so there is no separate database to download.
langchain-openai is only for the model in this example.
from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent from recall_langgraph import RecallResume, recall_tools with RecallResume("billing-migrator", local_dir="./recall-data") as resume: agent = create_react_agent( ChatOpenAI(model="gpt-4.1"), tools=[*your_tools, *recall_tools(resume)], prompt="Keep your working state current with update_working_state when your plan changes.", pre_model_hook=resume.pre_model_hook, post_model_hook=resume.post_model_hook, ) agent.invoke({"messages": [("user", "Carry on with the migration.")]})
Run it, kill it halfway, and run it again: the second run starts from what the first one wrote.
create_react_agent is deprecated in LangGraph 1.x in favor of
langchain.agents.create_agent, but it still ships in
langgraph.prebuilt and the hooks work with it.
What the hooks do
- Entering the
withblock takes a lease on the agent id, so only one process acts for the agent at a time, and reads back its records. The first time an id is used, it starts fresh. pre_model_hookputs the briefing in front of the messages before every model call: the working state, pointers, relevant memories and the most recent turns, within the token budget. It goes to the model only, so the graph's state never holds it.post_model_hookrecords the model's reply. Each message is recorded once, by its message id.- On the old thread id, a persistent checkpointer restores the old messages as well, and they are not recorded twice. The model then sees both the restored history and the briefing. Start a new thread if you want it to see only the briefing.
- Leaving the block hands the lease over, so the next process can resume at once. A process that dies without leaving it holds the lease until it expires.
The tools
recall_tools(resume) gives the model four tools.
| Tool | What the model uses it for |
|---|---|
update_working_state | Save its goal, plan, progress, focus, decisions, open questions and notes. Fields it leaves out are kept. |
milestone | Mark a durable point, such as tests passing. |
fetch_output | Read a large stored output in full, by the reference the briefing shows. |
set_pointer | Record where a piece of work lives: a git branch or commit, an object, an environment, an external item, or a process. |
Options
| Option | Default | What it does |
|---|---|---|
client | none | A polign_recall.Client opened with agent=True, to share one subprocess. Without it, RecallResume opens its own. |
local_dir | none | Keep the records in this directory on this machine and run a server for it. |
env | process environment | POLIGN_URL, POLIGN_API_KEY and the rest, for a server you run yourself. |
token_budget | 8000 | Upper bound on the briefing, in tokens. |
lease_ttl | 60 | Seconds each lease lasts. It is renewed in the background while the process runs. |
holder | host, pid and a random suffix | Names this process in the lease records. |
output_threshold | 2000 | Turns longer than this many tokens are stored whole as outputs and shown in the briefing as a reference. |
Where the records live
local_dir keeps the records on one machine. Agents that move between machines
need one shared server: run polign-server with its store in your S3, GCS or
Azure bucket where they can all reach it (Get started shows
how) and pass its address through env or the environment:
RecallResume(
"billing-migrator",
env={"POLIGN_URL": "http://memory.internal:23000", "POLIGN_API_KEY": key},
)
The agent's records live in their own collection, named after the memory collection with
_agents added to the end.
Errors
lease_held: another process holds the agent, including one that died less than a lease time ago. Resuming raisespolign_recall.RecallErrorwith this code. Wait and try again, or stop.lease_lost: another process took the agent over mid-run. The next record fails with this code, which stops the graph run. This process should stop acting for the agent.
Limits
- There is no reconcile step yet. If a process dies after a tool ran but before its result was recorded, the resumed agent may run it again, so resume is safest for read-only, idempotent, or easily checked actions.
- The briefing replaces exact state. Reasoning the agent never wrote down is not carried over.
Source & license
recall-langgraph is open source under the Apache License 2.0 and lives next to the
Python client in
github.com/Polign/polign,
along with its own StateGraph nodes and the benchmark harness. Bug reports and pull requests
go there.