Metadata-Version: 2.5
Name: rotorcore
Version: 0.0.1
Summary: A durable process runtime for Python.
License-Expression: Apache-2.0
License-File: LICENSE
Requires-Python: >=3.11
Provides-Extra: postgres
Requires-Dist: asyncpg>=0.29; extra == 'postgres'
Provides-Extra: redis
Requires-Dist: redis>=5; extra == 'redis'
Provides-Extra: s3
Requires-Dist: boto3>=1.34; extra == 's3'
Provides-Extra: vercel
Requires-Dist: asyncpg>=0.29; extra == 'vercel'
Requires-Dist: vercel-queue>=0.8.0; extra == 'vercel'
Provides-Extra: web
Requires-Dist: fastapi>=0.110; extra == 'web'
Requires-Dist: uvicorn>=0.29; extra == 'web'
Description-Content-Type: text/markdown

# rotor

**A durable process runtime for Python.**

> [!WARNING]
> Rotor is experimental and unstable. APIs, storage formats, and behavior may change
> without notice. Do not use it for production workloads.

A process is persisted as a checkpoint and mailbox. A worker leases it for one or
more messages, committing each transition independently.

```python
from dataclasses import field
from rotor import DurableProcess, Start, message, on

@message
class Ask:
    question: str

class State:
    asked: list = field(default_factory=list)

class Oracle(DurableProcess[State]):
    @on
    async def start(self, msg: Start):
        self.state.asked.append(f"born knowing: {msg.input}")

    @on
    async def ask(self, msg: Ask):
        self.state.asked.append(msg.question)
        if len(self.state.asked) > 3:
            self.stop(output=self.state.asked)
```

Timers, child completion, approvals, and limit notifications all arrive as messages.
Application code defines their meaning in handlers.

## Install

```bash
pip install rotorcore              # SQLite tier: zero dependencies
pip install "rotorcore[postgres]"  # + asyncpg for production
pip install "rotorcore[vercel]"    # Queue SDK + Postgres + S3 adapter
```