- AI & Agents
- How Ironflow Fits with Agent Frameworks
How Ironflow Fits with Agent Frameworks
Ironflow is a durable runtime for AI agents and event-driven systems. It does not choose prompts, models, planning strategies, or graph edges for you.
Use Ironflow to protect the work that must survive: model calls, tool calls, external waits, events, and derived state. Keep the reasoning layer you already use, or build a straightforward agent directly with Ironflow’s native API.
The division of responsibility
Section titled “The division of responsibility”| Layer | Owns |
|---|---|
| Reasoning framework or provider SDK | Prompts, model access, planning, routing, graph structure, and model-specific tool formats |
| Ironflow runtime | Durable steps, crash-resume, external waits, entity streams, projections, and optional recorded execution |
| Your application | Domain rules, tool implementations, permissions, and the boundary between model output and side effects |
This boundary matters. A framework can decide what an agent should do next. Ironflow makes the protected work resumable and connects it to the same runtime as the rest of your event-driven application.
What ships today
Section titled “What ships today”Native agent APIs
Section titled “Native agent APIs”The Node package exports agent(), defineTool(), and exposeMcp() from
@ironflow/node/agent. The agent context provides durable wrappers for tools,
model calls, approvals, memory operations, and child agents.
Go exposes the same agent-shaped concepts through its agent package.
Browser agent client
Section titled “Browser agent client”@ironflow/browser can invoke agents, subscribe to progress, and read agent
memory from a browser application while the worker and provider credentials
remain server-side.
invoke() is keyed by a function ID. It blocks until the run finishes and
returns that one run’s result. Abort the call and the server cancels the run.
Because the call returns the runId only when it settles, the sync path cannot
drive a live progress UI: to watch a run as it executes, use emit() and
subscribe to the run. Read ADR 0067 for the full decision, including the
emitSync() fan-out contract and the deprecation of the onRunStarted hook.
LangGraph checkpoint saver
Section titled “LangGraph checkpoint saver”@ironflow/langgraph ships an IronflowSaver implementation of LangGraph’s
checkpoint saver interface. It stores checkpoints and pending writes in an
Ironflow entity stream for each LangGraph thread.
No adapter yet for Claude SDK or CrewAI
Section titled “No adapter yet for Claude SDK or CrewAI”Claude SDK and CrewAI adapters are planned. Until those adapters ship, use their SDKs inside your application and put Ironflow durable boundaries around the calls and side effects you need to protect. Do not assume automatic instrumentation.
Build directly with the native agent API
Section titled “Build directly with the native agent API”Use the native API when your loop is straightforward and you want agent-shaped durable primitives without adopting a graph framework.
import { agent, defineTool } from "@ironflow/node/agent";import { z } from "zod";
const fetchDiff = defineTool({ name: "fetch-diff", input: z.object({ pr: z.number() }), handler: async ({ pr }) => github.fetchDiff(pr),});
export const reviewAgent = agent( { id: "code-review", triggers: [{ event: "pr.opened" }], tools: [fetchDiff], recording: true, }, async ({ event, tool, llm, approve }) => { const { pr } = event.data as { pr: number }; const diff = await tool(fetchDiff, { pr });
const findings = await llm.complete({ messages: [{ role: "user", content: `Review:\n${diff}` }], call: () => provider.complete(diff), });
const decision = await approve("post-review", { ttl: "24h", payload: findings, });
return { approved: decision.approved, findings }; },);Each tool() and llm.complete() call runs through an Ironflow durable step.
After a worker crash, completed step results are restored instead of repeated.
An approval can wait without holding the worker.
recording: true in this example is intentional. Durable step memoization does
not mean recorded execution is enabled by default.
Use Ironflow with LangGraph
Section titled “Use Ironflow with LangGraph”Use the shipped saver when LangGraph should keep ownership of the graph while Ironflow persists its checkpoints.
import { StateGraph } from "@langchain/langgraph";import { IronflowClient } from "@ironflow/node";import { IronflowSaver } from "@ironflow/langgraph";
const client = new IronflowClient({ serverUrl: process.env.IRONFLOW_URL!,});
const saver = new IronflowSaver({ client });
const graph = new StateGraph(State) .addNode("plan", planNode) .addNode("act", actNode) .addEdge("plan", "act") .compile({ checkpointer: saver });
await graph.invoke(input, { configurable: { thread_id: "thread-1" },});The saver:
- writes LangGraph checkpoints to an entity stream keyed by
thread_id; - stores pending writes;
- supports checkpoint lookup and listing within a thread;
- resumes from the last persisted checkpoint when you invoke the graph again with the same thread ID;
- handles LangGraph checkpoint namespaces and logical thread deletion.
The saver does not:
- turn every LangGraph node into an Ironflow durable step;
- expose LangGraph tools over MCP;
- add Ironflow approval waits to graph nodes;
- inject scoped values at node boundaries;
- create parent-child Ironflow run links for subgraphs;
- enable Ironflow execution recording for the graph.
Add those behaviors explicitly with the native agent or workflow APIs when your application needs them.
Use Ironflow alongside another framework
Section titled “Use Ironflow alongside another framework”For a framework without a shipped adapter, place durable boundaries at the side-effecting parts of your application:
- Run model access through
llm.complete()and provide the actual provider call incall. - Register external side effects with
defineTool()and invoke them throughtool(). - Use
approve()or a workflow event wait when input may arrive later. - Append domain facts to entity streams after the side effect succeeds.
- Enable recording explicitly when you need an inspectable execution-step history.
This is manual integration, not automatic framework hosting.
Which path should you choose?
Section titled “Which path should you choose?”| Your application | Start here |
|---|---|
| A straightforward model and tool loop | Native Node or Go agent API |
| An existing LangGraph application that needs persistent checkpoints | @ironflow/langgraph saver |
| A graph that also needs Ironflow durable tools or approvals | LangGraph saver plus explicit Ironflow agent or workflow boundaries |
| Claude SDK, CrewAI, or another framework today | Manual durable boundaries around provider calls, tools, and waits |
| A non-agent business process | Ironflow durable function and workflow APIs |
| A browser UI that calls one agent and waits for the answer | @ironflow/browser invoke() |
| A browser UI that follows a run as it executes | @ironflow/browser emit() plus a run subscription |
Deployment boundary
Section titled “Deployment boundary”Local Ironflow runs as one binary with SQLite and embedded NATS. That is enough to develop and to recover work from a worker crash while the server remains available.
For durable recovery across server failures or a multi-node deployment, use Postgres and persistent external NATS. See Self Hosting for the topology and operational requirements.