Skip to main content
Caravanserai

PyPI Python License: MIT

The idea, before the code

For a thousand years, caravans crossing the Silk Road never made the journey from Samarkand to Xi'an in one unbroken push. They couldn't - no camel, no person, survives that. Instead the route was strung with caravanserai: walled waystations spaced a day's travel apart. A caravan arrived, rested, traded news with whoever else was passing through, and the next morning someone - often not the same person - picked the journey back up from exactly where the last leg ended. The road didn't care who carried the load across any one stretch. It only cared that the relay never lost its place.

A long-running AI agent has the same problem and none of the same infrastructure. It runs for hours, hits a crash, a rate limit, a killed process - and unlike the caravan, there's no waystation. Everything since the last save is just gone. Worse: even when a framework does checkpoint, what it leaves behind is a raw state blob - readable by a resume function, unreadable by you or by whichever agent instance picks the job back up next.

Caravanserai is the waystation. Your agent checkpoints at natural stopping points, saving both its exact state and a plain-English note - what happened, what's next - the way a courier arriving at a real caravanserai would report the state of the road to whoever rides out next.

Quickstart

Looping over a list of things (files, tasks, rows)? Use resumable_iterate - zero manual state bookkeeping:

from caravanserai import resumable_iterate

for f in resumable_iterate(all_files(), run_id="my-run"):
    convert_file(f)

Kill it mid-run. Run it again - it picks up right where it left off, no checkpoint() call, no state dict to design yourself. One caveat, honestly stated: it's at-least-once, not exactly-once - the item you were mid-way through when the crash happened may get reprocessed once (never more, never half-processed), since a generator only learns you finished an item when the loop asks for the next one. Fine for idempotent work; worth knowing if not.

For anything that isn't a flat list - a while-loop, a state machine, multiple things changing per step - use checkpoint() + @resumable directly and shape your own state dict:

from caravanserai import checkpoint, resumable

@resumable
def do_the_task(run_id, state):
    step = state.get("step", 0)
    while step < 5:
        step += 1
        # ... do the actual work ...
        checkpoint(run_id, {"step": step}, f"finished step {step}, next is step {step+1}")

do_the_task("my-run", {"step": 0})

Kill it mid-run. Run it again with the same run_id - @resumable loads the last saved state automatically instead of starting from scratch.

How a checkpoint works

  your agent loop
        │
        ▼
   step 1 ──► checkpoint() ──► .caravanserai/<run_id>/
        │                        ├── state.json       (exact state, atomic write)
        │                        ├── waypoint-1.md     (human-readable note)
        │                        └── latest            (pointer → 1)
        ▼
   step 2 ──► checkpoint() ──► waypoint-2.md, latest → 2
        │
        ✕  crash / kill / rate limit
        │
   re-run with same run_id
        │
        ▼
   @resumable loads latest ──► state = {step: 2} ──► continues from step 3

A waypoint file looks like this - meant to be read, by a person or by a different agent picking up the same job:

.caravanserai/my-run/waypoint-3.md
# Waypoint 3 - 2026-08-20T22:41:03+00:00

finished step 3, next is step 4

Why not just use LangGraph or Temporal?

Caravanserai LangGraph checkpointing Temporal
Framework lock-in None - any Python loop LangGraph only Its own workflow engine
What's saved State + a human-readable note Raw state snapshot only Raw event history
Infra required None - local files None (or a DB backend) A Temporal server/cluster
Setup for v1 use pip install, call one function Adopt LangGraph's graph model Adopt Temporal's workflow model
Guarantees Save/load state (this is v1 scope) Full replay semantics Full durable execution, replay, idempotency

They solve the mechanical replay problem well and Temporal in particular solves it far more rigorously than Caravanserai attempts to - this isn't a durable-execution engine. What none of them do is leave behind something a human can read at a glance to understand what the agent actually did. That gap is the entire reason this exists.

CLI

caravanserai list                # every run, waypoint count, last-updated
caravanserai show <run_id>       # inspect the latest waypoint note + state
caravanserai resume <run_id>     # re-run the exact command that started it
caravanserai clean <run_id>      # delete a run's checkpoints

resume works because the first checkpoint() call for a run records the command it was launched with (sys.argv) - caravanserai resume just replays that command as a subprocess, so @resumable picks up from the last checkpoint the normal way.

Try it yourself

pip install caravanserai
python demo.py
# ^C it partway through, then:
python demo.py
# picks up where it left off
caravanserai show demo

Real transcript (not staged)

$ python demo.py
[1/5] doing work...
[2/5] doing work...
[3/5] doing work...
^C
crashed/killed mid-task. run me again - I'll resume, not restart.

$ python demo.py
[4/5] doing work...
[5/5] doing work...
done.

$ caravanserai show demo
waypoint 5

finished step 5/5

state: {'step': 5}

Killed at step 3, resumed straight to step 4 - no restart, no redone work. This was also verified against the actual published PyPI package, installed fresh into an empty virtualenv, not just the dev source.

Works with

Any Python agent loop you control - LangChain, LangGraph, the Claude Agent SDK, OpenAI Agents SDK, CrewAI, or plain scripts. No database, no server, just local JSON + Markdown files.

Not for the Claude Code CLI itself - it already has its own session resume (--resume/--continue) and you don't write its agent loop. This is for agents you build in Python that don't have that built in.

Status

0.2.0 - resumable_iterate for the common list-processing case, checkpoint/@resumable for everything else, a CLI that can actually resume a run (not just inspect it). Still single-process local files only (no distributed state), still no auto-detection of checkpoint intervals - deliberately not attempting LangGraph/Temporal-grade replay-with- re-execution semantics. Save/load state, kept simple on purpose.

License

MIT - see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

caravanserai-0.2.0.tar.gz (8.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

caravanserai-0.2.0-py3-none-any.whl (10.0 kB view details)

Uploaded Python 3

File details

Details for the file caravanserai-0.2.0.tar.gz.

File metadata

  • Download URL: caravanserai-0.2.0.tar.gz
  • Upload date:
  • Size: 8.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.10

File hashes

Hashes for caravanserai-0.2.0.tar.gz
Algorithm Hash digest
SHA256 defb4beb984badf4851b8722a63ee5245423f6cce19c3a4a4820e6ce7d994dee
MD5 4523a201fe15b7ca44f9385f42dc9c56
BLAKE2b-256 85ec282ec48edd1f855ed903a18f844c8f3120e27c56941210df74e6004c1722

See more details on using hashes here.

File details

Details for the file caravanserai-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: caravanserai-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 10.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.10

File hashes

Hashes for caravanserai-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0e1e2e3b5f060e47e52ded9efe174e64533e5d747af0e443411ccd921ed7ea6d
MD5 228e535727e1f940b0276a44f3e1a5d6
BLAKE2b-256 e9c556b94e88d7be4815cb1572ea6668609f10ccc344929d8eed39a8645c1334

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page