Skip to main content

Durable checkpoint/resume runner for async state-machine loops built on loom-tailcalls.

Project description

loom-runner

Small durable checkpoint/resume runner for async state-machine loops built on top of loom-tailcalls and flow-xray.

This is not a planner, memory system, graph DSL, hosted tracing product, or full agent SDK. It is the first slice of a Loom-based agent runtime: run a typed async transition loop, checkpoint each state transition, resume later, inspect history, and explain a run.

Runtime transitions are logged as logical steps with attempt history. A retry does not create a new transition: for the same run_id, step_index, and stable input hash, the runner reuses the committed outcome. Transient errors are retryable by default; validation, business, permission, and unknown errors fail the run unless the caller supplies a different policy.

Tool side effects are only idempotent when invoked through RunContext.call_tool(...). Direct tool calls or external effects inside a transition are intentionally treated as unmanaged user code in this first runtime slice.

Long runs can use bounded reads and explicit storage policies. By default the runner keeps every checkpoint and every inline tool payload for maximum inspectability. For larger runs, use CheckpointPolicy(mode="interval", every=N) to retain only periodic history checkpoints while preserving the current resumable state, and PayloadPolicy(max_inline_bytes=N) to replace large managed tool payloads with hash/size metadata.

The import package remains loom_agent; the distribution and CLI are named loom-runner because loom-agent is already occupied by an unrelated package on PyPI.

Install

python3.13 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

Minimal Shape

from dataclasses import dataclass

from loom_agent import AgentRunner, Complete, Continue, RunContext, SQLiteCheckpointStore


@dataclass(frozen=True)
class State:
    current: int
    target: int


async def step(state: State, ctx: RunContext):
    if state.current >= state.target:
        return Complete({"current": state.current})
    return Continue(State(current=state.current + 1, target=state.target))


runner = AgentRunner(
    step=step,
    store=SQLiteCheckpointStore("runs.sqlite"),
    encode_state=lambda state: {"current": state.current, "target": state.target},
    decode_state=lambda data: State(**data),
    encode_result=lambda result: result,
    decode_result=lambda data: data,
)

Example

loom-runner run examples/counter_agent.py --run-id demo --db runs.sqlite --max-steps 5
loom-runner resume examples/counter_agent.py --run-id demo --db runs.sqlite --max-steps 100
loom-runner list examples/counter_agent.py --db runs.sqlite
loom-runner get examples/counter_agent.py --run-id demo --db runs.sqlite
loom-runner history examples/counter_agent.py --run-id demo --db runs.sqlite
loom-runner attempts examples/counter_agent.py --run-id demo --db runs.sqlite --limit 20
loom-runner tool-calls examples/counter_agent.py --run-id demo --db runs.sqlite --limit 20
loom-runner explain examples/counter_agent.py --run-id demo --db runs.sqlite

Add --trace trace.html to either command to emit a local flow-xray HTML trace. The runner traces step leaves and keeps the tail-recursive driver as the durable loop boundary.

Or directly:

python3.13 examples/counter_agent.py

Tests

python3.13 -m pytest

Runtime Benchmark

python3.13 scripts/bench_runtime.py --steps 100000
python3.13 scripts/bench_runtime.py --steps 100000 --checkpoint-every 100

The benchmark reports wall time, retained checkpoint rows, attempt rows, DB size, and peak Python memory. It is a local regression tool, not a hosted-scale performance claim.

Project details


Download files

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

Source Distribution

loom_runner-0.1.0.tar.gz (21.7 kB view details)

Uploaded Source

Built Distribution

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

loom_runner-0.1.0-py3-none-any.whl (16.7 kB view details)

Uploaded Python 3

File details

Details for the file loom_runner-0.1.0.tar.gz.

File metadata

  • Download URL: loom_runner-0.1.0.tar.gz
  • Upload date:
  • Size: 21.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for loom_runner-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2071db201dc0dce6cab1eb2bdb5caa735aabc085acca1e0fbbf476648f870244
MD5 7019a7d8778b5f6851412d25fccdbcbe
BLAKE2b-256 bf2a5d550cede5b544c6813c979d8ce0c6bc40a493add4cd83cd4a7b577d939a

See more details on using hashes here.

File details

Details for the file loom_runner-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: loom_runner-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 16.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for loom_runner-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1c4d6c459b59685e4e78bde5ee872d450965371773a105c2450c8b0fd588c5f9
MD5 fd5d3b3f20cdd93b16c873420cb750c2
BLAKE2b-256 4a26956463a093c3f1921fc86c22ae3bcc0ac696eeb0a6e288158ee922c4e840

See more details on using hashes here.

Supported by

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