Skip to main content

Ironflow Python SDK

Python client for Ironflow — the Continuous History platform for backend systems.

Installation

pip install ironflow-py
import ironflow

Install ironflow-py, not ironflow. The distribution name is ironflow-py; the import name is ironflow. The bare name ironflow on PyPI belongs to an unrelated third-party project (a materials-science tool from the pyiron group), which also installs a top-level ironflow module — a virtualenv holding both has two claimants on that name and the install order silently decides which wins. Keep them in separate environments.

Requires Python 3.10+.

Available from v0.33.0. Versions track the Ironflow engine release, so ironflow-py 0.33.0 is the client for engine 0.33.0.

Status

Experimental and client-only. It can emit events and query runs, projections, KV, and config, but it ships no worker runtime — there is no step.run, no step.sleep, and no push or pull mode.

Two clients, two protocols, neither a superset of the other. IronflowClient speaks REST and retries idempotent methods. IronflowRPC / AsyncIronflowRPC speak ConnectRPC and reach 46 capabilities REST does not serve — webhook management, agent tools, time travel, pub/sub consumer groups, function versioning, and environment lookup/key rotation — including four server streams. IronflowRPC retries only the unary methods the protos annotate side-effect-free, and reconnects a subscription only when you position it (see Retries).

Routes the server's manifest annotates with schemas get a typed models.* TypedDict return and keyword-only query parameters; routes it does not annotate still return Any and take no query kwargs. TypedDict is a type-checker construct only — there is no runtime validation. Headers declared by a route, including If-Match, If-None-Match, and Idempotency-Key, are generated as typed keyword arguments. BaseClient.request() remains the escape hatch for undeclared headers. WebSocket and watch endpoints (/ws, config watch, KV watch) have no generated methods at all and request() cannot reach them either; poll the corresponding read method, use a ConnectRPC subscription, or use the Go or JavaScript SDK for a live watch.

For durable step execution, use the Go or JavaScript SDK.

Quick Start

from ironflow import IronflowClient

client = IronflowClient(
    server_url="http://localhost:9123",
    api_key="ifkey_...",
)

# Emit an event
client.events_create(body={
    "name": "user.created",
    "data": {"user_id": "123", "email": "user@example.com"},
})

# List runs
runs = client.runs_list()

# Get a specific run
run = client.runs_get("run_abc123")

# List projections
projections = client.projections_list()

# Public server inspection
health = client.health()
readiness = client.ready()
capabilities = client.capabilities()

ConnectRPC client

For the capabilities REST does not serve. Request and response types come from ironflow.rpc.v1; ironflow._gen is private and its layout may change.

from ironflow import IronflowRPC
from ironflow.rpc.v1 import CreateWebhookSourceRequest, SubscribeRequest

with IronflowRPC(server_url="http://localhost:9123", api_key="ifkey_...") as rpc:
    source = rpc.webhooks.create_source(
        CreateWebhookSourceRequest(name="Stripe", event_prefix="stripe.")
    )

    # Server streams are ordinary iterators; breaking out cancels.
    for event in rpc.pubsub.subscribe(SubscribeRequest(pattern="topic:orders.*")):
        print(event.event_id)
        break

AsyncIronflowRPC mirrors it method for method — await the unary calls, async for the streams, and await rpc.aclose() instead of close().

Failures raise IronflowRPCError, which subclasses IronflowError, so except IronflowError still catches every failure from either client. Full reference, including timeouts, NO_TIMEOUT, and stream lifetime: docs.ironflow.run/reference/api/python-sdk.

Retries, and what can still go wrong

A unary call that fails with unavailable — a refused connection, a socket dropped mid-response, a server shedding load — is sent again, up to 3 attempts with exponential backoff. Nothing else is retried: every other Connect code is a decision the server will reach again identically.

Only side-effect-free methods are retried. The protobuf definitions annotate them idempotency_level = NO_SIDE_EFFECTS, and the client reads that annotation rather than any list of its own. A method without it — every create, update, delete, rotate and emit — is sent exactly once and its failure is raised to you immediately, because a transport error cannot tell you whether the server committed the write before the connection dropped.

Two things this does not promise:

  • A retried read may execute more than once on the server. A response lost on the way back is indistinguishable from a request that never arrived, so the retry re-runs the method. That is harmless for a read by definition, and it is the reason the annotation gates the behaviour.
  • A write is never retried for you. If you need one repeated safely, repeat it yourself with an idempotency key — EmitRequest and PublishRequest both carry idempotency_key — and treat a failed write as unknown, not failed.

timeout= still bounds the whole call including every retry and backoff, not each attempt. Pass max_attempts=1 to the constructor to switch retries off.

subscribe reconnects only if you positioned it. Set options.start_after_sequence to the last event.sequence you processed, and a dropped connection is retried from there. That field is both the cursor and the opt-in: without it there is no honest place to resume from, so the stream raises and re-subscribing is yours.

from ironflow.rpc.v1 import SubscribeRequest, SubscribeOptions

cursor = 0
for event in rpc.pubsub.subscribe(SubscribeRequest(
    pattern="topic:orders.*",
    options=SubscribeOptions(start_after_sequence=cursor),
)):
    handle(event)
    cursor = event.sequence   # persist this if you need to resume across restarts

A resumed stream is at-least-once: the frame in flight when the connection dropped may arrive twice, because the server sending it is not you having processed it. Make handle idempotent, or dedupe on event.sequence.

The other three streams are not reconnected, and do not need to be. stream_events, wait_catchup_stream and join_consumer_group are positioned by the server on a durable consumer, so simply calling them again resumes where they left off. A client-side cursor there would move a position other readers share.

API Coverage

This SDK is auto-generated from the Ironflow server's route manifest. Run make sdk-health for the current method count — it changes on every regeneration, so it is not reproduced here. Route coverage is not the same as usable coverage; see the Status section above.

See the SDK Comparison Matrix for full coverage details.

Dependencies

Two direct runtime dependencies, connectrpc and pyqwest, which resolve to six packages — two of them compiled:

connectrpc ─┬─ protobuf-py ── protobuf-py-ext   (native, CPython only)
            ├─ pyqwest                          (Rust)
            │    └─ opentelemetry-api
            └─ typing_extensions

They are required, not an extra. The ConnectRPC client is part of the default contract, so putting it behind a flag would turn a heavier install into a runtime ImportError — see ADR 0062 (engine repo, internal).

IronflowClient itself still uses only the standard library (urllib, json), and import ironflow does not load the ConnectRPC stack — that cost is paid on first use of IronflowRPC.

Where this package is published from

The Ironflow engine is closed source. This SDK's source is mirrored to sahina/ironflow-py at each release, and PyPI uploads happen from there over Trusted Publishing. No PyPI API token exists for this project, so every release carries an attestation binding the artifact to a public commit you can inspect.

The mirror is read-only. Pull requests against it are closed without review; source changes land in the engine repo and appear at the next release.

Bugs and security

Issues are disabled on the mirror. Everything goes to one tracker:

  • Bugs and feature requests → sahina/ironflow-issues, component Python SDK. Include your Python version, platform, and a minimal repro.
  • Security issues → private advisory. Do not open a public issue.
  • Commercial licensing → the contact in LICENSE.

License

See LICENSE — SPDX LicenseRef-Ironflow-EULA. Not an OSI-approved open source licence; read it before deploying commercially.

Download files

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

Source Distribution

ironflow_py-0.33.1.tar.gz (172.3 kB view details)

Uploaded Source

Built Distribution

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

ironflow_py-0.33.1-py3-none-any.whl (138.2 kB view details)

Uploaded Python 3

File details

Details for the file ironflow_py-0.33.1.tar.gz.

File metadata

  • Download URL: ironflow_py-0.33.1.tar.gz
  • Upload date:
  • Size: 172.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ironflow_py-0.33.1.tar.gz
Algorithm Hash digest
SHA256 afab30ea34a877343f1e0e741963697b24aa418c363b8c80c1b24d25c2202dfe
MD5 d0460862a8691f0f5ba4797600cd4358
BLAKE2b-256 ee6cc30f337a229a079f9c90a1e1d76866c129cdb5b35f7e2068805a158b0c8f

See more details on using hashes here.

Provenance

The following attestation bundles were made for ironflow_py-0.33.1.tar.gz:

Publisher: publish.yml on sahina/ironflow-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ironflow_py-0.33.1-py3-none-any.whl.

File metadata

  • Download URL: ironflow_py-0.33.1-py3-none-any.whl
  • Upload date:
  • Size: 138.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ironflow_py-0.33.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d11852ecc34ca930863d4470ed1608c66fa935c1dd587e37dd035fe8940c85ee
MD5 566861cd8616c911616d315345734428
BLAKE2b-256 ed38128f83a4e2813987638e0b7c4e73a4ee74f68024f221fc0a21fe2b62557a

See more details on using hashes here.

Provenance

The following attestation bundles were made for ironflow_py-0.33.1-py3-none-any.whl:

Publisher: publish.yml on sahina/ironflow-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.37.1

2 files

0.37.0

2 files

0.36.1

2 files

0.36.0

2 files

0.35.0

2 files

0.34.0

2 files

This release

0.33.1 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page