Waymark

Waymark is a library for durable background workflows that survive server restarts, task crashes, and long-running jobs. It's built for Python and Postgres and ships without any additional deploy-time requirements.

You write workflows as plain async def Python. Waymark parses the AST of your run() method at registration time and compiles it into a Waymark Runtime Language: a for loop becomes a filter node, an asyncio.gather becomes a parallel fan-out, an if/else becomes a branch. Nothing executes inline in your webserver - the DAG is stored in Postgres and orchestrated by a Rust runtime across your worker cluster.

  • πŸͺΆ No broker, no separate hosted service. Just Postgres.
  • 🐍 Real Python control flow - loops, conditionals, try/except, parallel gather.
  • πŸ¦€ Rust runtime for queue claims, lock heartbeats, and DAG execution.
  • πŸ” Customizable retry policies and durable sleep that survives restarts.
  • 🟒 Same code path locally and in production.

Get started

Guides

Quickstart

Install Waymark, write your first workflow, and run it against a local Postgres.

Read more

Workflows & Actions

Understand the split: actions are distributed work, workflows are durable control flow.

Read more

Control Flow

Loops, conditionals, parallel gather, durable sleep - what compiles and what doesn't.

Read more

Retries & Timeouts

Configure retry policies and timeouts for actions that flake, time out, or fail outright.

Read more

How it differs

Most durable-workflow engines are replay-based: your run() body re-executes from the top on every step, with completed activities returning cached results. Temporal and Vercel Workflows both work this way. The constraint that falls out of replay is determinism - no random(), no datetime.now(), no side effects in workflow logic.

Waymark takes a different approach. It's compile-once: parse the AST, produce an intermediate representation, store it as a DAG, and execute that DAG directly. Your authored run() body never runs again after registration. The constraint shifts from "must be deterministic" to "must use supported patterns" - which the compiler tells you about up front, rather than surfacing as a recovery-time bug.

ApproachHow it worksWhat it constrains
Temporal / VercelReplay. Workflow code re-executes on each step; completed activities return cached results.Code must be deterministic. No random(), no datetime.now(), no side effects in workflow logic.
WaymarkCompile-once. Parse Python AST β†’ IR β†’ DAG. Execute the DAG; the original Python body never re-runs.Code must use supported patterns. The compiler reports unsupported constructs at registration time.

The full motivation, scope, and the workloads we explicitly don't try to target are written up in Why Waymark.