Waypoint
A Python SDK for building fault-tolerant multi-step workflows via event sourcing.
When a workflow crashes mid-execution, Waypoint resumes from the last successful step, without re-running expensive operations that already completed. Every step's input and output is logged to an append-only PostgreSQL journal; on recovery, the journal is replayed from the last checkpoint.
Getting Started
Prerequisites
- Docker + Docker Compose
- uv (Python 3.13+)
Clone & Start
git clone git@github.com:aybruhm/waypoint.git
cd waypoint
make up
This starts the API gateway on http://localhost:9654 and PostgreSQL. The gateway auto-reloads on code changes.
Run Migrations
make run_migrations
Run Examples
# 3-step search workflow with crash recovery
uv run python -m sdk.examples.simple_agent
# Mocked LLM + crash recovery demo
uv run python -m sdk.examples.agent_with_llm_mock
# Nightly ETL sync: cache=True on expensive external API fetch
uv run python -m sdk.examples.data_pipeline
# E-commerce order pipeline: WaypointSession + cache on payment to prevent double-charge
uv run python -m sdk.examples.order_processing
# RAG pipeline: @waypoint.checkpoint instance decorator + class-based steps
uv run python -m sdk.examples.document_rag
See sdk/examples/ for the full source of each example, including crash recovery demos.
Stop
make down
Makefile Reference
| Command | Description |
|---|---|
make up / make start |
Build & start containers (detached) |
make down / make stop |
Stop & remove containers |
make run_migrations |
Apply pending Alembic migrations |
make revert_migrations |
Roll back last migration |
make add_migration MSG="msg" |
Auto-generate new migration |
make show_current_db_head |
Show current migration version |
make show_db_heads |
List all migration heads |
What It Solves
Any multi-step process where re-running from scratch is expensive, slow, or dangerous:
- Wasted computation: Steps that succeeded before the crash get re-run on retry: re-fetching from slow APIs, re-processing records, re-calling LLM endpoints.
- Lost state: No record of which step failed, what the inputs were, or how far execution got.
- Duplicate side effects: Retrying a workflow that already charged a card, sent an email, or wrote to an external system creates duplicates or breaks idempotency.
Waypoint avoids all three by persisting every step's result. On crash, resume from the checkpoint: completed steps return their stored outputs instantly and execution continues from the next uncompleted step.
Architecture
Workflow Code
↓
@checkpoint decorators (Waypoint SDK)
↓
+----------------+-----------------+------------------+
| Event Journal | Checkpoint Mgr | Replay Engine |
| (append-only) | (progress) | (deterministic) |
+----------------+-----------------+------------------+
↓
PostgreSQL
Core Concepts
| Concept | Description |
|---|---|
| Execution | A single run of a workflow, identified by a UUID. |
| Step | A decorated async function (@checkpoint("name")). Each step runs at most once per execution. |
| Checkpoint | A persisted record of a step's input/output + execution position. |
| Event Journal | Append-only log of all steps across all executions (PostgreSQL). |
| Replay | Reconstructing state by reading checkpoints in order, without re-executing steps. |
How It Works
@checkpoint("step_name", cache=True)
async def my_step(input: dict) -> dict:
return output
The decorator:
- Checks if a checkpoint exists for this step in the current execution.
- If yes and
cache=True: returns stored output immediately (no re-execution). - If no: runs the function, persists input/output as a checkpoint, returns output.
On crash, create a new Waypoint instance and call resume(execution_id). The SDK rebuilds state from the journal and continues from the next uncompleted step.
Integration Patterns
Standalone decorator: simplest, steps registered at module level:
waypoint = Waypoint(base_url=..., workflow_id="my_pipeline").use()
@checkpoint("fetch_data", cache=True)
async def fetch_data(url: str) -> dict: ...
Instance decorator: steps explicitly bound to a specific Waypoint instance:
waypoint = Waypoint(base_url=..., workflow_id="my_pipeline")
@waypoint.checkpoint("fetch_data", cache=True)
async def fetch_data(url: str) -> dict: ...
Session context manager: scopes a series of steps to a single execution, useful when steps are defined as plain functions rather than decorated at import time:
async with waypoint.session(execution_id) as sess:
result = await sess.async_execute("step_name", {"arg": val, "__callable__": fn}, cache=True)
Key Properties
- Deterministic replay: Same inputs always produce the same outputs; completed steps never re-execute.
- Step output caching: Outputs marked
cache=Trueare served from the journal on replay (zero re-computation cost). - Non-idempotent step protection: Mark payment charges, email sends, or any one-shot side effect as
cache=Trueto guarantee they run at most once across retries. - Framework-agnostic: Works with LangChain, CrewAI, FastAPI, plain asyncio, or any async Python code.
- Minimal integration: Add
@checkpointto each step. ~3 lines of change per step. - Full history: Query every step, error, duration, and state transition by execution ID.
When to Use
- Long-running workflows (minutes to hours) where restarting from scratch is expensive.
- Cost-sensitive pipelines where re-running steps wastes money (LLM API calls, paid data sources, cloud processing).
- Financial or transactional workflows where duplicate side effects (double charges, duplicate sends) must be prevented.
- ETL jobs where the extraction phase is slow or rate-limited and re-fetching on failure is unacceptable.
- Teams needing a full audit trail of step inputs, outputs, and errors for debugging.
When Not to Use
- Distributed/multi-machine workflows (Waypoint is single-process per execution).
- Stateless, fire-and-forget tasks with no recovery requirement: if a task fails you're happy restarting it from scratch, use Celery, SQS, or similar.
- Simple linear scripts with no expensive steps and no side effects worth protecting.
Metadata
Release files for waypoint-sdk 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| waypoint_sdk-0.1.1.tar.gz | 26.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| waypoint_sdk-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 56.2 kB
Release files / waypoint_sdk-0.1.1.tar.gz
| Download URL | waypoint_sdk-0.1.1.tar.gz |
|---|---|
| Size | 26.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d3631b9719ee3a45e19d5e1f21817e45565888f954c8e581fed0216d841e7fa7
|
|
BLAKE2b-256 checksum How to use checksums |
d6c22a4e54325528be42cdc6dcd3cc220cb1e86463c5efb63d7dfcd6d3fa5a9f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / waypoint_sdk-0.1.1-py3-none-any.whl
| Download URL | waypoint_sdk-0.1.1-py3-none-any.whl |
|---|---|
| Size | 29.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1a9406f7a68f07a455f1f42be9bda57de7ae8cd433654a418a3666217f6709fa
|
|
BLAKE2b-256 checksum How to use checksums |
64a6c18fda07d48cf2eed67ecff03ea40e3847072003ad62402258f90223537f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for waypoint-sdk 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.