- SDKs & APIs
- SDK Comparison
SDK Comparison
This page records what each Ironflow SDK can do — use it to pick an SDK, or to check whether a capability you need is reachable from the one you already have. For the exhaustive per-capability view — every transport, test and documentation status, and gap classification — see the SDK Parity Matrix.
The tables record capabilities, not transport. An SDK may reach a capability over ConnectRPC or a WebSocket instead of the equivalent REST path: the Go SDK resumes a run over ConnectRPC, the Browser SDK watches config over a WebSocket topic. ✅ means you can do it, ❌ means you cannot, and N/A means it is deliberately excluded — as secrets are from the browser. The Agents table reads by a narrower rule, stated above it.
The four SDKs
Section titled “The four SDKs”| SDK | Package | Tier | What it is |
|---|---|---|---|
| Go | github.com/sahina/ironflow-go/ironflow | 1 | Worker runtime + client, for servers and workers |
| Node | @ironflow/node | 1 | Worker runtime + client, for servers, workers and handlers |
| Browser | @ironflow/browser | — | Outside the tiers: hand-written like Tier 1 (it shares @ironflow/core with Node), client-only like Tier 2, plus real-time subscriptions |
| Python | ironflow (distribution ironflow-py on PyPI) | 1 | Worker runtime + generated client |
SDK Tiers
Section titled “SDK Tiers”The dividing line between the tiers is which direction the call goes.
Tier 1 — worker runtime + client (Go, Node, Python)
Section titled “Tier 1 — worker runtime + client (Go, Node, Python)”Tier-1 SDKs carry the worker runtime: the engine that runs your function code
under Ironflow’s control — durable-step memoization, crash-resume replay,
step.sleep / waitForEvent suspension and pull mode (long-running workers).
The worker runtime is hand-written; the client surface can be generated
(Python’s is, per ADR 0062).
The Durable Step Primitives table below lists what each Tier-1 SDK ships.
Go, TypeScript and Python are the Tier-1 languages.
The three Tier-1 SDKs are peers. A capability added to one is incomplete until the other two have it. The implementations do not need to land in the same commit or release. If one ships first, its peer gap must be filed before the release notes are published and those notes must link it. This also applies when a Tier-2 SDK reaches a capability before either Tier-1 SDK. The release may proceed, but the missing Tier-1 work cannot remain implicit.
scripts/check-tier1-sdk-parity.py enforces this mechanically for the public
fields of SubscribeOptions, the option type that exposed the first concrete
drift. An unmatched field fails unless tier1-sdk-parity.json names the missing
SDK and links its implementation issue. The check also rejects an exception
after the field reaches all three SDKs. The real-server
tests/conformance/ suite checks shared worker behavior.
This source check is intentionally narrow.
sdk-coverage.json records which routes SDK source calls, not which capabilities
or options the SDK exposes, so it is not evidence of Tier-1 capability parity.
Broader parity remains a review rule until another concrete case supports a
reliable source-level check.
Published blog posts, tutorials, and how-to guides follow the same peer model. When material demonstrates a Tier-1 capability with code, it includes Go, TypeScript and Python examples (or links to all three). Browser-only and Tier-2 capabilities are exempt. This is an editorial review rule rather than a code-fence-counting gate, because a document may also contain SQL, shell, frontend, or transport-specific examples. New material follows this rule from its first publication. Existing material is being backfilled in #2386.
Tier 2 — generated client only (Rust and Java later; C# not planned)
Section titled “Tier 2 — generated client only (Rust and Java later; C# not planned)”Tier-2 SDKs call the Ironflow REST API and its ConnectRPC surface, and contain no worker runtime. Each is built in two parts: a generated surface, machine-generated from the server’s REST API so the client tracks it as the API changes, and a small hand-written transport core supplying retry, backoff, auth, and the error taxonomy.
A Tier-2 SDK is a smaller SDK, not a lesser one. Applications in Tier-2 languages still get their functions executed by Ironflow via push mode: the server POSTs to an HTTP endpoint you own, which needs no SDK runtime at all. What Tier 2 does not get is pull mode and durable steps — workflows that need crash-resume, long sleeps, or sagas are written in a Tier-1 language.
The same REST surface is published as an OpenAPI 3.1 spec at
GET /api/v1/openapi.json, so a language with no SDK starts from a
machine-readable contract rather than from scratch.
Two protocols, two pipelines
Section titled “Two protocols, two pipelines”The server speaks two protocols to clients:
- REST — plain HTTP paths under
/api/v1, published with a machine-readable description and schemas for most of them. - ConnectRPC — a protobuf protocol. Paths look like
POST /ironflow.v1.WebhookService/CreateWebhookSource. These sit outside the REST contract and carry no schema in it.
The REST client generator reads the REST description only, so the ConnectRPC surface needs a second pipeline (below). Tier-1 worker runtimes are hand-written and call whichever protocol fits. Run resume and step patch now use ConnectRPC in all SDKs. Their duplicate REST routes have been removed (#1972).
The generated REST client covers the remaining REST routes, including environment CRUD, event reads, secrets, and projection deletion and partition listing.
The migrated capabilities are delivered by IronflowRPC — 102 capability methods generated
from the protobuf definitions (98 unary, 4 server streams), covering webhook
management, agent tools, time travel, pub/sub consumer groups, function
versioning, executable deployments, raw SQL, and the environment compatibility
RPCs. The two clients are not
supersets of each other; each carries what its protocol serves.
One gap remains:
| Still out of reach | Why |
|---|---|
PubSubService/SubscribeBidirectional | Go and Node join consumer groups over it. Python has no client yet (#2973). The browser cannot stream both ways |
IronflowRPC retries a unary call only when the protobuf method is annotated
idempotency_level = NO_SIDE_EFFECTS. It reconnects Subscribe when the caller
positions it with start_after_sequence, and no other stream — the rest are
positioned by the server on a durable consumer, so re-issuing the call resumes
them (#1848). Which of the 112 served RPCs the Python SDK exposes, and why, is
recorded row by row in sdk/python/rpc-capabilities.yaml.
No SDK at all
Section titled “No SDK at all”A language with no SDK is not locked out. It reaches almost everything in this
document over plain HTTP — the REST API under /api/v1, plus the ironflow CLI
and the MCP server (ironflow mcp) as no-codegen alternatives. But “generate a
client from the OpenAPI spec and you are done” is not true, for the same reason
the generated Python client needs two pipelines: the spec describes REST only.
Some ✅ rows below have no REST route at all. They are ConnectRPC, so a
client generated from api/openapi.json will not contain them:
| Capability | ConnectRPC method | What REST gives you |
|---|---|---|
| Register functions | IronflowService/RegisterFunction | No REST sibling |
| Create projection | ProjectionService/RegisterProjection, CreateSQLProjection | Deletion and partition listing, but no create |
| TriggerSync (blocking) | IronflowService/TriggerSync | No REST sibling |
| Invoke one function and block | IronflowService/InvokeFunctionSync | No REST sibling. IronflowService/InvokeFunction returns IDs immediately; InvokeFunctionSync waits for the result (ADR 0067) |
| Webhook management (11 RPCs) | WebhookService/* | The redacted GET /api/v1/flow/webhooks view |
| Join a consumer group | PubSubService/JoinConsumerGroup | Nothing |
The unary ones cost you a second path shape, not a second toolchain: a Connect
unary call is an ordinary POST /ironflow.v1.Service/Method carrying proto3
JSON, which any HTTP client can send. What you give up is the schema — these sit
outside the REST contract, and the field names are camelCase where REST is
snake_case. Use Ironflow from any
language walks the
registration call end to end.
Registration being RPC-only has a knock-on effect: an OpenAPI-only client has
nothing to invoke until something else registers a function, and no scheduled
work either — a cron is a field on the function, so api/openapi.json contains
no cron at all.
Three carve-outs, not two. Durable Step Primitives and agent authoring run
inside a worker and have no equivalent outside one. The third is receiving
pushed events, and it is not a worker feature: PubSubService/Subscribe and
JoinConsumerGroup are server streams, SubscribeBidirectional is a
bidirectional stream, and the OpenAPI artifact carries no streaming media
type — no text/event-stream, no WebSocket upgrade. The GET /ws and KV/config
/watch upgrades exist on the server and are documented in the REST API
reference, but they are absent from the generated spec, so
codegen never sees them. Inbound from generated code means push mode: an HTTP
endpoint you own, which the engine calls.
Events
Section titled “Events”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Emit events | ✅ | ✅ | ✅ | ✅ |
| Trigger workflows | ✅ | ✅ | ✅ | ✅ |
| TriggerSync (blocking) | ✅ | ✅ | ✅ | ✅ |
| Trigger a batch of events | ✅ | ✅ | ✅ | ✅ |
| List stored events | ✅ | ✅ | ✅ | ✅ |
| Get a stored event | ✅ | ✅ | ✅ | ✅ |
| List event names | ✅ | ✅ | ✅ | ✅ |
| Offline write queue (durable outbox) | N/A | N/A | ✅ | N/A |
Functions
Section titled “Functions”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Define functions | ✅ | ✅ | N/A | ✅ |
| Register functions | ✅ | ✅ | N/A | ✅ |
| List functions | ✅ | ✅ | ✅ | ✅ |
| Get function detail | ✅ | ✅ | ✅ | ✅ |
| Enable or disable function | ✅ | ✅ | ✅ | ✅ |
| Delete function | ✅ | ✅ | ✅ | ✅ |
| List function version history | ✅ | ✅ | ✅ | ✅ |
| Get function at version | ✅ | ✅ | ✅ | ✅ |
| Roll back function version | ✅ | ✅ | ✅ | ✅ |
| Invoke function directly | ✅ | ✅ | ✅ | ✅ |
| Register executable deployment | ✅ | ✅ | N/A | ✅ |
| Read deployments and execution routing | ✅ | ✅ | N/A | ✅ |
“Invoke function directly” is the client-level call, keyed by function id:
InvokeSync in Go, invoke() in Node and the browser,
rpc.functions.invoke or rpc.runs.invoke_function_sync in Python. All
four block for a result except Python’s rpc.functions.invoke, which answers
with the run and event IDs immediately — see ADR 0067. It is a different thing from step.invoke / step.invokeAsync, which
invoke a function from inside a workflow and memoize — see Durable Step
Primitives below.
Durable Step Primitives (Tier 1)
Section titled “Durable Step Primitives (Tier 1)”These run inside a function handler, under Ironflow’s control. They are the worker runtime, so only Tier-1 SDKs have them.
| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
Memoized step (step.run) | ✅ | ✅ | N/A | ✅ |
| Sleep / sleep-until | ✅ | ✅ | N/A | ✅ |
| Durable wait for event | ✅ | ✅ | N/A | ✅ |
| Parallel branches | ✅ | ✅ | N/A | ✅ |
| Map over items | ✅ | ✅ | N/A | ✅ |
| Saga compensation | ✅ | ✅ | N/A | ✅ |
| Branch-scoped steps (nested fan-out, invoke, publish inside a branch) | ✅ | ✅ | N/A | ✅ |
| Invoke another function (sync / async) | ✅ | ✅ | N/A | ✅ |
| Publish to a topic from a step | ✅ | ✅ | N/A | ✅ |
| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Get run details | ✅ | ✅ | ✅ | ✅ |
| List runs | ✅ | ✅ | ✅ | ✅ |
| Get run steps | ✅ | ✅ | ✅ | ✅ |
| Get entity streams touched by a run | ✅ | ✅ | ✅ | ✅ |
| Cancel run | ✅ | ✅ | ✅ | ✅ |
| Resume run | ✅ | ✅ | ✅ | ✅ |
| Get audit trail (run events) | ✅ | ✅ | ✅ | ✅ |
| Delete run (one terminal run, or terminal runs by filter) | ✅ | ✅ | ❌ | ✅ |
| Redact a run, step or event payload | ✅ | ✅ | ❌ | ✅ |
Scoped Injection (Hot Patching & History Editing)
Section titled “Scoped Injection (Hot Patching & History Editing)”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Pause run | ✅ | ✅ | ✅ | ✅ |
| Get paused state | ✅ | ✅ | ✅ | ✅ |
| Inject step output | ✅ | ✅ | ✅ | ✅ |
| Patch step (modify outputs) | ✅ | ✅ | ✅ | ✅ |
The Python entry is rpc.runs.patch_step(PatchStepRequest(...)).
Time Travel Debugging
Section titled “Time Travel Debugging”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Get run state at timestamp | ✅ | ✅ | ✅ | ✅ |
| Get run timeline | ✅ | ✅ | ✅ | ✅ |
| Get step output at timestamp | ✅ | ✅ | ✅ | ✅ |
Entity Streams (Event Sourcing)
Section titled “Entity Streams (Event Sourcing)”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Append event to stream | ✅ | ✅ | ✅ | ✅ |
| Read stream events | ✅ | ✅ | ✅ | ✅ |
| Get stream info | ✅ | ✅ | ✅ | ✅ |
| Create snapshot | ✅ | ✅ | ✅ | ✅ |
| Get snapshot | ✅ | ✅ | ✅ | ✅ |
| List all streams | ✅ | ✅ | ✅ | ✅ |
| Get entity event history | ✅ | ✅ | ✅ | ✅ |
| Delete stream (tombstone, optional purge) | ✅ | ✅ | ❌ | ✅ |
Projections
Section titled “Projections”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| List projections | ✅ | ✅ | ✅ | ✅ |
| Get projection | ✅ | ✅ | ✅ | ✅ |
| Get projection status | ✅ | ✅ | ✅ | ✅ |
| List projection partitions | ✅ | ✅ | N/A | ✅ |
| Create projection | ✅ | ✅ | N/A | ✅ |
| Rebuild projection | ✅ | ✅ | N/A | ✅ |
| Get rebuild job status | ✅ | ✅ | N/A | ✅ |
| Create SQL projection | N/A | ✅ | N/A | ✅ |
| Query SQL projection | N/A | ✅ | ✅ | ✅ |
| Execute raw SQL | ✅ | N/A | ✅ | ✅ |
| List and read projection definition history | ✅ | ✅ | ✅ | ✅ |
| Pause projection | ✅ | ✅ | N/A | ✅ |
| Resume projection | ✅ | ✅ | N/A | ✅ |
| Cancel rebuild | ✅ | ✅ | N/A | ✅ |
| Delete projection | ✅ | ✅ | N/A | ✅ |
| Wait for catch-up (read-your-writes) | ✅ | ✅ | ✅ | ✅ |
Pub/Sub (Developer Topics)
Section titled “Pub/Sub (Developer Topics)”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Publish to topic | ✅ | ✅ | ✅ | ✅ |
| List topics | ✅ | ✅ | N/A | ✅ |
| Get topic statistics | ✅ | ✅ | N/A | ✅ |
| Join a consumer group (subscribe with acks) | ✅ | ✅ | ✅ | ✅ |
| Manage consumer groups (create/get/list/update/delete) | ✅ | ✅ | ✅ | ✅ |
KV Store (Key-Value Storage)
Section titled “KV Store (Key-Value Storage)”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Create bucket | ✅ | ✅ | ✅ | ✅ |
| List buckets | ✅ | ✅ | ✅ | ✅ |
| Get bucket | ✅ | ✅ | ✅ | ✅ |
| Delete bucket | ✅ | ✅ | ✅ | ✅ |
| Get key | ✅ | ✅ | ✅ | ✅ |
| Put key | ✅ | ✅ | ✅ | ✅ |
| Create key (fails if present) | ✅ | ✅ | ✅ | ✅ |
| Update key (compare-and-set) | ✅ | ✅ | ✅ | ✅ |
| Delete key | ✅ | ✅ | ✅ | ✅ |
| Purge key (drop history) | ✅ | ✅ | ✅ | ✅ |
| List keys | ✅ | ✅ | ✅ | ✅ |
| Watch keys | ✅ | ✅ | ✅ | ✅ |
Exclusive create and compare-and-set both ride on conditional request headers.
The generated Python kv_update_buckets_keys() method exposes them as
if_none_match and if_match keyword arguments.
File Storage
Section titled “File Storage”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Create, list, get, update and delete buckets | ✅ | ✅ | ✅ | ✅ |
| Put, get, inspect, list and delete files | ✅ | ✅ | ✅ | ✅ |
| Move or copy a file, move a directory | ✅ | ✅ | ✅ | ✅ |
| Create signed upload and download URLs | ✅ | ✅ | ✅ | ✅ |
See the Files guide.
Config Management
Section titled “Config Management”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Get config (read) | ✅ | ✅ | ✅ | ✅ |
| List configs | ✅ | ✅ | ✅ | ✅ |
| Set config (full replacement) | ✅ | ✅ | N/A | ✅ |
| Patch config (shallow merge) | ✅ | ✅ | N/A | ✅ |
| Delete config | ✅ | ✅ | N/A | ✅ |
| Watch config (real-time) | ✅ | ✅ | ✅ | ✅ |
Secrets Management
Section titled “Secrets Management”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Get secret | ✅ | ✅ | N/A | ✅ |
| Set secret | ✅ | ✅ | N/A | ✅ |
| Replace secret value | ✅ | ✅ | N/A | ✅ |
| Patch secret name or description | ✅ | ✅ | N/A | ✅ |
| Delete secret | ✅ | ✅ | N/A | ✅ |
| List secrets | ✅ | ✅ | N/A | ✅ |
Event Schema Registry
Section titled “Event Schema Registry”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Register schema | ✅ | ✅ | ✅ | ✅ |
| List schemas | ✅ | ✅ | ✅ | ✅ |
| Get schema (latest) | ✅ | ✅ | ✅ | ✅ |
| Get schema version | ✅ | ✅ | ✅ | ✅ |
| Delete schema version | ✅ | ✅ | ✅ | ✅ |
| Test upcast | ✅ | ✅ | ✅ | ✅ |
| List and read schema definition history | ✅ | ✅ | ✅ | ✅ |
Agents
Section titled “Agents”Authoring an agent is worker-runtime work, so it is Tier-1 only. The Browser SDK carries the client half — start a run, follow it, read its memory.
This table is the one place that records named SDK helpers rather than raw reachability. An agent’s memory is an ordinary entity stream behind an ordinary projection, and an agent run starts from an ordinary event, so any client that can append an event, read a projection, or emit can do those three things by hand. For the last two rows, ❌ means the SDK ships no method named for the agent use of them — not that the data is out of reach. The note under the table says the same thing about Go and Node.
| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Define an agent handler | ✅ | ✅ | N/A | ✅ |
| Define a tool | ✅ | ✅ | N/A | ✅ |
| Human approval gate | ✅ | ✅ | N/A | ✅ |
| LLM call wrapper | ✅ | ✅ | N/A | ✅ |
| Spawn a sub-agent | ✅ | ✅ | N/A | ✅ |
| Expose tools over MCP | ✅ | ✅ | N/A | ✅ |
| Write agent memory | ✅ | ✅ | ❌ | ✅ |
| Read agent memory | ✅ | ✅ | ✅ | ✅ |
| Invoke an agent from a client | ❌ | ❌ | ✅ | ❌ |
| Subscribe to agent run events | ❌ | ❌ | ✅ | ❌ |
| List visible agent tools | ✅ | ✅ | N/A | ✅ |
The last two rows are a client convenience the Browser SDK has and the others do not. From Go, Node, or Python you start an agent by emitting its trigger event, and follow it with an ordinary run subscription.
Webhooks
Section titled “Webhooks”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Create webhook source | ✅ | ✅ | ✅ | ✅ |
| Get webhook source | ✅ | ✅ | ✅ | ✅ |
| List webhook sources | ✅ | ✅ | ✅ | ✅ |
| Update webhook source | ✅ | ✅ | ✅ | ✅ |
| Delete webhook source | ✅ | ✅ | ✅ | ✅ |
| Rotate verify secret | ✅ | ✅ | ✅ | ✅ |
| Expire previous secret | ✅ | ✅ | ✅ | ✅ |
| Disable signature verification | ✅ | ✅ | ✅ | ✅ |
| Rotate ingest token | ✅ | ✅ | ✅ | ✅ |
| Test verify config | ❌ | ❌ | ❌ | ✅ |
| List webhook deliveries | ✅ | ✅ | ✅ | ✅ |
Webhook mutation is ConnectRPC-only. Python reaches all of it through
rpc.webhooks — create_source, get_source, rotate_secret and the rest —
which is the capability IronflowRPC was added for. IronflowClient still sees
only the redacted flow-map view (names, prefixes, delivery counts).
Test verify config is a Dashboard-facing diagnostic. Python wraps it because the generated facade covers every WebhookService method; Go, Node and Browser have no wrapper for it.
API Keys
Section titled “API Keys”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Create API key | ✅ | ✅ | ✅ | ✅ |
| List API keys | ✅ | ✅ | ✅ | ✅ |
| Get API key | ✅ | ✅ | ✅ | ✅ |
| Delete API key | ✅ | ✅ | ✅ | ✅ |
| Rotate API key | ✅ | ✅ | ✅ | ✅ |
Organizations
Section titled “Organizations”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Create org | ✅ | ✅ | ✅ | ✅ |
| List orgs | ✅ | ✅ | ✅ | ✅ |
| Get org | ✅ | ✅ | ✅ | ✅ |
| Update org | ✅ | ✅ | ✅ | ✅ |
| Delete org | ✅ | ✅ | ✅ | ✅ |
Roles & Policy Set
Section titled “Roles & Policy Set”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Create role | ✅ | ✅ | ✅ | ✅ |
| List roles | ✅ | ✅ | ✅ | ✅ |
| Get role | ✅ | ✅ | ✅ | ✅ |
| Update role | ✅ | ✅ | ✅ | ✅ |
| Delete role | ✅ | ✅ | ✅ | ✅ |
| Get the Rego policy set | ✅ | ✅ | ✅ | ✅ |
Replace the policy set (with If-Match) | ✅ | ✅ | ✅ | ✅ |
| Validate a policy set | ✅ | ✅ | ✅ | ✅ |
| Dry-run a policy set | ✅ | ✅ | ✅ | ✅ |
| List policy-set versions | ✅ | ✅ | ✅ | ✅ |
| Get one policy-set version | ✅ | ✅ | ✅ | ✅ |
| Roll back the policy set | ✅ | ✅ | ✅ | ✅ |
Admin Management
Section titled “Admin Management”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Manage projects | ✅ | ✅ | N/A | ✅ |
| Manage environments | ✅ | ✅ | N/A | ✅ |
| Manage users | ✅ | ✅ | N/A | ✅ |
| Change own password | ✅ | ✅ | N/A | ✅ |
| List workers | ✅ | ✅ | ✅ | ✅ |
| List tenants | ✅ | ✅ | ✅ | ✅ |
| Provision tenant | ✅ | ✅ | ✅ | ✅ |
Operations
Section titled “Operations”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| List / requeue / discard outbox dead letters | N/A | N/A | N/A | ✅ |
| List circuit breakers, reset a breaker | N/A | N/A | N/A | ✅ |
| List / clear debounce entries | ✅ | ✅ | N/A | ✅ |
| Inspect capacity (lanes, queue, leases, credits, sessions) | ✅ | ✅ | N/A | ✅ |
| Rotate the cluster join token | N/A | N/A | N/A | ✅ |
| Read the org-wide audit log | ✅ | ✅ | ✅ | ✅ |
The generated Python client remains widest here because its methods come from the
whole REST surface. Go and Node also expose debounce entries and the capacity
views. Go, Node, and Browser expose the environment-wide audit log. For the other
operational routes, use the ironflow CLI or call REST directly.
Platform-tier administration — platform keys, tenant provisioning, impersonation — is a separate surface; see the Platform API reference.
Server Introspection
Section titled “Server Introspection”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Check liveness | ✅ | ✅ | ✅ | ✅ |
| Check readiness | ✅ | ✅ | ✅ | ✅ |
| Discover server capabilities | ✅ | ✅ | ✅ | ✅ |
Extended Administration
Section titled “Extended Administration”| Capability | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Replace an API key’s roles | N/A | N/A | N/A | ✅ |
| Read authentication and authorization audit | N/A | N/A | N/A | ✅ |
These are intentionally outside the curated Go, Node, and Browser clients. They are not license-gated: the generated Python client reaches them because it covers the full REST and mounted ConnectRPC admin surface. Operators can also use the dashboard, CLI where available, or the underlying endpoint.
Execution Modes
Section titled “Execution Modes”| Feature | Go SDK | Node SDK | Browser SDK | Python SDK |
|---|---|---|---|---|
| Push mode (serverless functions) | ✅ | ✅ | N/A | ✅ |
| Pull mode (long-running workers) | ✅ | ✅ | N/A | ✅ |
| Subscriptions (real-time events) | ✅ | ✅ | ✅ | ✅ |
| WebSocket support | ✅ | ✅ | ✅ | ❌ |
| ConnectRPC support | ✅ | ✅ | ✅ | ✅ |
| HTTP/REST support | ✅ | ✅ | ✅ | ✅ |
Push mode ✅ for Python is ironflow.serve: serve() returns an ASGI app,
handle() is the framework-free core, and register() registers functions as
push. See Push mode.
Python workers support both polling (Worker) and ConnectRPC streaming (StreamingWorker).
Python real-time subscriptions use the tested
IronflowRPC.pubsub.subscribe() ConnectRPC server stream. Python has no
WebSocket subscription client. Its only WebSocket use is the KV and config
watch (watch_kv, watch_config). It also has no agents.subscribe()
convenience for following an agent run. Those are the narrower gaps recorded in
those rows.
Recorded Tier-1 differences
Section titled “Recorded Tier-1 differences”Go, Node and Python are peers, but four differences between them are intended. ADR 0065 records each one.
- Subscribe transport. Go has WebSocket and ConnectRPC clients. Node has a WebSocket client. Python has the generated ConnectRPC stream. All three can subscribe.
- Python client surface. Python reaches entity streams, subscriptions,
consumer groups, SQL projections and webhook management through the generated
IronflowRPCmethods. It has no hand-written helpers for them. Go and Node have asubscribeEntityStreamhelper that builds theentity:{type}.{id}.>pattern; Python callers build that pattern themselves. - SQL. Go runs raw SQL and cannot create or query a SQL projection. Node creates and queries SQL projections and cannot run raw SQL. The browser SDK does both. Python does both.
- Worker error hook. Only the Go worker has one (
WorkerConfig.OnError).
Recommendations
Section titled “Recommendations”Use Go SDK when:
Section titled “Use Go SDK when:”- Building high-performance backend services
- Implementing complex state machines or sagas
- Integrating with existing Go applications
- Need the broadest coverage of the workflow, event-sourcing and pub/sub surface
Use Node SDK when:
Section titled “Use Node SDK when:”- Building serverless functions (AWS Lambda, Vercel)
- Using JavaScript/TypeScript throughout your stack
- Need full control over step execution and error handling
- Prefer working in TypeScript for type safety
Use Browser SDK when:
Section titled “Use Browser SDK when:”- Building real-time frontends with live event subscriptions
- Implementing interactive dashboards or monitoring tools
- Need lightweight client-side integrations
- Want to display projection data and KV store values in UI
Use Python SDK when:
Section titled “Use Python SDK when:”- Running durable AI agents and long-lived pull workers
- Building data pipelines or scripts that interact with Ironflow
- Integrating Ironflow with Python-based AI/ML workflows
- Running operational tasks — it is the only SDK that reaches the outbox DLQ and circuit breakers. Go, Node and Python all reach the capacity views and debounce entries
- Want to manage Ironflow resources from Jupyter notebooks or CLI tools
Python also runs pull workers with durable steps. See the Python SDK reference.
Feature Parity Status
Section titled “Feature Parity Status”Features are implemented incrementally, and these tables reflect the current state of each SDK.
The Python SDK in this codebase is Tier 1, with a hand-written polling worker
and a push handler (ironflow.serve), plus generated client methods. The
ironflow-py distribution (import name ironflow) first appeared on PyPI
at v0.33.1; that release was client-only. See the
Python SDK reference for the current surface.