Metadata-Version: 2.4
Name: larzstate
Version: 0.1.0
Summary: Durable, resumable workflows with retries and saga compensation, plus a finite state machine. Pure Python, zero dependencies.
Author: larz-scripter
License: MIT
Project-URL: Homepage, https://github.com/larz-scripter/larzstate
Project-URL: Repository, https://github.com/larz-scripter/larzstate
Project-URL: Documentation, https://github.com/larz-scripter/larzstate#readme
Project-URL: Issues, https://github.com/larz-scripter/larzstate/issues
Keywords: workflow,workflow-engine,saga,state-machine,fsm,durable,orchestration,resumable,compensation,temporal-alternative,zero-dependency,pure-python
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Distributed Computing
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# larzstate

**Durable workflows, sagas, and state machines. Pure Python, zero dependencies.**

Two complementary tools for modelling processes that must stay correct even when
things crash:

- **`Workflow`** — an ordered pipeline of steps with **durable, resumable
  execution**. Progress is checkpointed after every step, so an interrupted run
  resumes exactly where it stopped. Steps retry on failure, and a failed workflow
  **compensates** (rolls back) its completed steps in reverse — the saga pattern.
- **`StateMachine`** — a finite state machine with guards, actions, and
  enter/exit callbacks, defined as plain data.

No broker and no database required — bring your own checkpoint store (memory or
file, or plug in [larzdb](https://github.com/larz-scripter/larzdb)).

```python
from larzstate import Workflow

wf = Workflow("checkout")

@wf.step(retries=3)
def reserve(ctx):
    ctx["reservation"] = reserve_stock(ctx["items"])

@reserve.compensate
def _(ctx):
    release_stock(ctx["reservation"])

@wf.step()
def charge(ctx):
    ctx["charge_id"] = charge_card(ctx["amount"])

result = wf.run("order-123", {"items": [...], "amount": 100})
result.status        # "completed"  — or WorkflowFailed (after rollback)
```

## Why

- **Crash-resumable.** Kill the process mid-workflow and call `run(run_id)` again
  — completed steps are skipped, execution continues from the first unfinished
  one. State is checkpointed (and fsync'd, with `FileStore`) after every step.
- **Sagas built in.** When something fails partway through, the compensations of
  already-completed steps run in reverse to undo their effects — the standard way
  to get "all-or-nothing" across systems that don't share a transaction.
- **Retries per step.** Set `retries` (and optional `retry_delay`) per step.
- **Zero dependencies, no infrastructure.** No Temporal server, no queue, no DB.
  A directory (or memory) is enough.
- **A clean state machine too.** Guards, actions, enter/exit hooks, wildcard
  transitions, history — as plain, inspectable data.

## Install

```bash
pip install larzstate
```

## Durable workflows

```python
from larzstate import Workflow, FileStore, WorkflowFailed

wf = Workflow("payment", store=FileStore("workflows/"))

@wf.step(retries=2)
def authorize(ctx): ctx["auth"] = gateway.authorize(ctx["amount"])

@authorize.compensate
def _(ctx): gateway.void(ctx["auth"])

@wf.step()
def capture(ctx): ctx["capture"] = gateway.capture(ctx["auth"])

try:
    wf.run("txn-42", {"amount": 5000})
except WorkflowFailed as e:
    e.step          # which step failed
    e.cause         # the exception
    e.compensated   # whether rollback ran
```

- The shared, mutable `ctx` dict flows through every step and is part of the
  checkpoint, so resumed runs see the same state.
- On resume, pass just the `run_id` — the checkpointed context is authoritative.

## State machines

```python
from larzstate import StateMachine

sm = StateMachine(initial="draft", transitions=[
    {"event": "submit",  "from": "draft",  "to": "review"},
    {"event": "approve", "from": "review", "to": "published",
     "guard": lambda m, **k: k["by"] == "editor"},
    {"event": "archive", "from": "*",      "to": "archived"},
])

sm.trigger("submit")                 # -> "review"
sm.can("approve")                    # True
sm.trigger("approve", by="editor")   # guard passes -> "published"
sm.history                           # ["draft", "review", "published"]
```

Supports `guard`, `action`, `on_enter`/`on_exit` callbacks, wildcard `from: "*"`,
and `allowed_events()`.

## Scope

larzstate runs workflows **in-process** — it's the durable orchestration core, not
a distributed cluster. Pair it with
[larztask](https://github.com/larz-scripter/larztask) to run workflows off a
queue, or [larzdb](https://github.com/larz-scripter/larzdb) as a store. It gives
you exactly-once-ish step semantics via checkpointing and idempotent resume — the
hard part — without any infrastructure.

## Tests

```bash
python -m unittest discover -s tests -v      # 16 tests incl. crash-resume + saga
```

## The Larz stack

Pure-Python, zero-dependency building blocks:

- **[larz](https://github.com/larz-scripter/larz)** — money-native web framework
- **[larzchain](https://github.com/larz-scripter/larzchain)** — from-scratch PoW blockchain
- **[larzmoney](https://github.com/larz-scripter/larzmoney)** — exact, penny-perfect money
- **[larzcrypt](https://github.com/larz-scripter/larzcrypt)** — pure-Python cryptography toolkit
- **[larzdb](https://github.com/larz-scripter/larzdb)** — crash-safe embedded database
- **[larzagent](https://github.com/larz-scripter/larzagent)** — zero-dep AI agent framework
- **[larzchart](https://github.com/larz-scripter/larzchart)** — data to inline SVG charts
- **[larzmark](https://github.com/larz-scripter/larzmark)** — Markdown + SEO static sites
- **[larztask](https://github.com/larz-scripter/larztask)** — durable background job queue
- **[larzvault](https://github.com/larz-scripter/larzvault)** — encrypted secrets manager
- **[larzvm](https://github.com/larz-scripter/larzvm)** — deterministic gas-metered VM
- **[larzcache](https://github.com/larz-scripter/larzcache)** — LRU/TTL/tiered caching
- **[larzvalidate](https://github.com/larz-scripter/larzvalidate)** — schema validation
- **[larzid](https://github.com/larz-scripter/larzid)** — decentralized identity
- **[larzrpc](https://github.com/larz-scripter/larzrpc)** — JSON-RPC over HTTP
- **larzstate** — this library

## License

MIT © larz-scripter
