Build with AI Assistants
Use your favorite AI coding assistant to build a complete Continuous History system — events, durable functions, projections, and time-travel debugging — guided by AI-generated code.
Prerequisites
- Ironflow running locally (
ironflow serve --dev) - An AI coding assistant (Claude Code, Cursor, Copilot, Windsurf, etc.)
- Node.js 20+ and pnpm (or Go 1.25+ if following the Go track)
Step 1: Add the Agent Template
The agent template gives your AI assistant context about Ironflow’s SDK, patterns, and best practices. Copy it from the Agent Template page and save it in your project:
your-project/├── agent.md # AI context file├── src/│ └── workflows/└── package.jsonDifferent AI tools read different files:
| Tool | Recommended File |
|---|---|
| Claude Code | CLAUDE.md or agent.md |
| Cursor | .cursor/rules/*.mdc (preferred) or agent.md |
| GitHub Copilot | .github/copilot-instructions.md or agent.md |
| Windsurf | .windsurfrules or agent.md |
| Other | agent.md (most tools read markdown) |
The MCP server (ironflow mcp) and shipped agent skills are deeper integration paths — see AI MCP Server and AI Skills.
Step 2: Start Ironflow
ironflow serve --devThe --dev flag disables authentication so you can start building immediately. Server runs at http://localhost:9123.
Production Mode
When you’re ready for real workloads, drop the --dev flag. See Security for details.
Step 3: Ask the AI to Build a Recorded System
Use this prompt with your AI assistant. Notice it covers all four Continuous History pillars — emit, react, derive, and rewind:
Build an Ironflow system using TypeScript with @ironflow/node that:
1. REACT: Create a function triggered by "order.placed" events with recording enabled. It should have three durable steps: - "validate-order" — validates the order - "process-payment" — charges the amount - "send-confirmation" — sends email confirmation
2. DERIVE: Create a managed projection called "order-stats" that listens to "order.placed" events and maintains a running total of orders and revenue.
3. Wire both into a createWorker and start it.
Use pull mode (createWorker), not push mode (serve).Enable recording: true on the function for time-travel debugging.Expected AI Response
The AI should generate code like this:
import { createFunction, createProjection, createWorker, type IronflowProjection,} from "@ironflow/node";
interface OrderData { orderId: string; total: number; email: string;}
// REACT: A recorded function that processes orders// Every step is memoized and permanently recorded.const processOrder = createFunction( { id: "process-order", triggers: [{ event: "order.placed" }], recording: true, // Enables time-travel debugging }, async ({ event, step }) => { const data = event.data as OrderData;
const order = await step.run("validate-order", async () => { return { valid: true, orderId: data.orderId, total: data.total }; });
const payment = await step.run("process-payment", async () => { return { charged: true, amount: order.total, transactionId: `txn_${Date.now()}`, }; });
await step.run("send-confirmation", async () => { return { sent: true, email: data.email }; });
return { order, payment }; },);
// DERIVE: A projection that computes order statistics// Pure reducer — state is automatically persisted and queryable.const orderStats = createProjection({ name: "order-stats", events: ["order.placed"], initialState: () => ({ totalOrders: 0, totalRevenue: 0 }), handler: ( state: { totalOrders: number; totalRevenue: number }, event: { name: string; data: unknown }, ) => ({ totalOrders: state.totalOrders + 1, totalRevenue: state.totalRevenue + ((event.data as OrderData).total ?? 0), }),});
// Start the worker — functions and projections run togetherconst worker = createWorker({ functions: [processOrder], projections: [orderStats as IronflowProjection],});
worker.start().then(() => { console.log("Worker started — listening for events");});package main
import ( "context" "fmt" "log" "os"
"github.com/sahina/ironflow/sdk/go/ironflow")
var processOrder = ironflow.CreateFunction(ironflow.FunctionConfig{ ID: "process-order", Triggers: []ironflow.Trigger{{Event: "order.placed"}}, Recording: true, // Enables time-travel debugging}, func(ctx ironflow.Context) (any, error) { var data struct { OrderID string `json:"orderId"` Total float64 `json:"total"` Email string `json:"email"` } if err := ctx.Event.Data(&data); err != nil { return nil, fmt.Errorf("parse order: %w", err) }
order, err := ironflow.Run(ctx, "validate-order", func() (map[string]any, error) { return map[string]any{"valid": true, "orderId": data.OrderID, "total": data.Total}, nil }) if err != nil { return nil, err }
payment, err := ironflow.Run(ctx, "process-payment", func() (map[string]any, error) { return map[string]any{"charged": true, "amount": data.Total}, nil }) if err != nil { return nil, err }
_, err = ironflow.Run(ctx, "send-confirmation", func() (map[string]any, error) { return map[string]any{"sent": true, "email": data.Email}, nil }) if err != nil { return nil, err }
return map[string]any{"order": order, "payment": payment}, nil})
func main() { worker := ironflow.NewWorker(ironflow.WorkerConfig{ ServerURL: "http://localhost:9123", APIKey: os.Getenv("IRONFLOW_API_KEY"), Functions: []ironflow.Function{processOrder}, })
log.Println("Worker starting...") if err := worker.Run(context.Background()); err != nil { log.Fatal(err) }}The Go SDK supports both push mode (Serve()) and pull mode (NewWorker()) and ships full projection support via ironflow.CreateProjection and WorkerConfig.Projections — see sdk/go/ironflow/projection.go and the Projections guide.
Step 4: Emit Events
With the server and worker running, emit events to build up history:
ironflow emit order.placed --data '{"orderId": "order-1", "total": 99.99, "email": "customer@example.com"}'ironflow emit order.placed --data '{"orderId": "order-2", "total": 49.50, "email": "another@example.com"}'ironflow emit order.placed --data '{"orderId": "order-3", "total": 149.00, "email": "third@example.com"}'Watch the worker terminal — you’ll see each event trigger the function and execute all three steps.
Step 5: Ask the AI to Query What Was Derived
How do I check the current state of the "order-stats" projection?Show me the curl command and explain what I should see.The AI should tell you:
curl -s http://localhost:9123/api/v1/projections/order-stats | jq '.state.state'{ "totalOrders": 3, "totalRevenue": 298.49}No aggregation queries. The projection derived this state automatically from the recorded events.
Step 6: Rewind Time
Every step of every function run was permanently recorded. Ask the AI:
How do I use Ironflow's time-travel debugging to replay a function run?The AI should point you to:
Dashboard: Open http://localhost:9123, navigate to Runs, click any completed run, and use the timeline scrubber to drag back through the execution.
CLI:
ironflow run listironflow inspect <run_id> --replayIn replay mode: →/l next frame, ←/h prev frame, g/G first/last, j/k navigate steps, Tab switch panels, q quit.
Step 7: Iterate with AI
Now ask the AI to extend the system with more Continuous History features:
Add error handling to the process-order function:1. If validation fails, throw a NonRetryableError2. Add retry configuration for the payment step3. Add a step.sleep of 1 second between payment and confirmationOr try adding event sourcing:
Create an entity stream for orders using Ironflow's event sourcing.Append "order.placed", "order.shipped", and "order.delivered" eventsto an entity stream keyed by orderId. Then show me how to read thefull history of a single order.Verification Checklist
After the AI generates code, verify:
- Each step has a unique, descriptive ID
- Step functions are idempotent (safe to retry)
-
recording: trueis set on functions you want to time-travel debug - Event data types match your expected payload
- Projections use
initialStateas a function (not a plain object) - Error handling uses
NonRetryableErrorwhere appropriate
What Just Happened?
You used an AI assistant to build a Continuous History system:
- Emit — Recorded events as permanent, immutable facts
- React — A durable function processed each event with memoized steps
- Derive — A projection automatically computed statistics from the event stream
- Rewind — Time-travel debugging let you replay any execution
The AI agent template ensures your assistant generates code that follows these patterns correctly.
What’s Next
- Getting Started — The hands-on tutorial (no AI required)
- Agent Template — Full AI context template
- Common Pitfalls — Mistakes AI makes with Ironflow
- Event Sourcing — Entity streams and projections
- Time-Travel Debugging — Dashboard and CLI replay